1use crate::{
6 Client, Error,
7 driver::{CancelOnDrop, Pending, checked, lock},
8 outgoing::{Interim, Observer},
9 reuse::{Cache, Recycle, Reused},
10 sink::owned_sink,
11};
12use base_endpoint::stream::{ReadableStream, WritableStream};
13use base_http::{
14 InterimHandler, InterimResponses, Method, Path, RequestMetadata, Response, ResponseMetadata,
15 body::{BodyFrame, ReadableBody, WritableBody},
16};
17use base_http1::{RequestWriter, ResponseReader};
18use base_scheduler::Cancellation;
19use futures_util::{Sink, SinkExt, Stream, StreamExt, task::AtomicWaker};
20use std::{
21 convert::Infallible,
22 future::Future,
23 pin::Pin,
24 sync::{
25 Arc, Mutex,
26 atomic::{AtomicU8, Ordering},
27 },
28 task::{Context, Poll},
29};
30
31trait Push: Sink<(BodyFrame<Vec<u8>>, Cancellation), Error = Error> + Recycle {}
32impl<T: Sink<(BodyFrame<Vec<u8>>, Cancellation), Error = Error> + Recycle> Push for T {}
33trait Receive: Stream<Item = Result<ResponseEvent, Error>> + Recycle {}
34impl<T: Stream<Item = Result<ResponseEvent, Error>> + Recycle> Receive for T {}
35pub(crate) trait OpeningOperation<'scope>:
36 Future<Output = Result<WritableRequest<'scope>, Error>> + Recycle
37{
38}
39impl<'scope, T: Future<Output = Result<WritableRequest<'scope>, Error>> + Recycle>
40 OpeningOperation<'scope> for T
41{
42}
43type PushSink<'scope> = Reused<dyn Push + Send + 'scope>;
44type ResponseStream<'scope> = Reused<dyn Receive + Send + 'scope>;
45pub(crate) type Opening<'scope> = Reused<dyn OpeningOperation<'scope> + Send + 'scope>;
46pub(crate) type OpenFactory<'scope, R, W> = Box<
47 dyn Fn(
48 Return<'scope, ResponseReader<R>>,
49 Return<'scope, RequestWriter<W>>,
50 RequestMetadata,
51 Box<dyn Observer + 'scope>,
52 Cancellation,
53 ) -> Opening<'scope>
54 + Send
55 + Sync
56 + 'scope,
57>;
58
59pub(crate) fn failed_open<'scope>(error: Error) -> Opening<'scope> {
60 Reused::new(Cache::new().take(|| std::future::ready(Err(error))))
61}
62
63impl<'scope> Client<'scope> {
64 pub async fn open(
69 &self,
70 method: Method,
71 path: impl Into<Path>,
72 cancellation: &Cancellation,
73 ) -> Result<WritableRequest<'scope>, Error> {
74 let mut metadata = RequestMetadata::new(method);
75 metadata.path = Some(path.into());
76 self.open_request(metadata, cancellation).await
77 }
78
79 pub async fn open_request(
82 &self,
83 metadata: RequestMetadata,
84 cancellation: &Cancellation,
85 ) -> Result<WritableRequest<'scope>, Error> {
86 self.open_request_with_interim(
87 metadata,
88 |_: ResponseMetadata| async { Ok::<_, Infallible>(()) },
89 cancellation,
90 )
91 .await
92 }
93
94 pub async fn open_request_with_interim<I: InterimHandler + 'scope>(
97 &self,
98 mut metadata: RequestMetadata,
99 interim: I,
100 cancellation: &Cancellation,
101 ) -> Result<WritableRequest<'scope>, Error> {
102 if cancellation.is_cancelled() {
103 return Err(Error::Cancelled);
104 }
105 if metadata.method == Method::CONNECT
106 || metadata.protocol.is_some()
107 || metadata.fields.contains("upgrade")
108 {
109 return Err(Error::Unsupported("managed client tunnels and upgrades"));
110 }
111 if metadata
112 .scheme
113 .as_deref()
114 .is_some_and(|scheme| scheme != self.endpoint.scheme())
115 {
116 return Err(Error::Unsupported(
117 "request scheme does not match the endpoint",
118 ));
119 }
120 metadata
121 .scheme
122 .get_or_insert_with(|| self.endpoint.request_scheme());
123 metadata
124 .authority
125 .get_or_insert_with(|| self.endpoint.authority.clone());
126 let pending = Pending::new(self.queue.clone())?;
127 let local = self.context.cancellation.child();
128 let mut guard = CancelOnDrop(local.clone(), true);
129 let active = checked(
130 checked(self.context.acquire(&local), &self.context.cancellation),
131 cancellation,
132 )
133 .await?;
134 let connection = active.clone_handle();
135 let opening = Open {
136 metadata,
137 interim: Box::new(interim),
138 active,
139 pending,
140 cancellation: local,
141 lifetime: cancellation.clone(),
142 };
143 let result = checked(connection.open(opening), cancellation).await?;
144 guard.1 = false;
145 Ok(result)
146 }
147}
148
149#[must_use = "finish or split the request; dropping it abandons the exchange"]
155pub struct WritableRequest<'scope> {
156 output: RequestBodyWriter<'scope>,
157 response: PendingResponse<'scope>,
158}
159impl<'scope> WritableRequest<'scope> {
160 pub async fn write(
161 &mut self,
162 data: impl Into<Vec<u8>>,
163 cancellation: &Cancellation,
164 ) -> Result<(), Error> {
165 self.output.write(data, cancellation).await
166 }
167 pub async fn write_frame(
168 &mut self,
169 frame: BodyFrame<Vec<u8>>,
170 cancellation: &Cancellation,
171 ) -> Result<(), Error> {
172 self.output.write_frame(frame, cancellation).await
173 }
174 pub async fn flush(&mut self, cancellation: &Cancellation) -> Result<(), Error> {
175 self.output.flush(cancellation).await
176 }
177 pub fn split(self) -> (RequestBodyWriter<'scope>, PendingResponse<'scope>) {
178 (self.output, self.response)
179 }
180 pub async fn finish(
183 self,
184 cancellation: &Cancellation,
185 ) -> Result<Response<StreamingResponseBody<'scope>>, Error> {
186 let (output, response) = self.split();
187 output.finish(cancellation).await?;
188 checked(response, cancellation).await
189 }
190}
191
192#[must_use = "finish request output or explicitly abort it"]
196pub struct RequestBodyWriter<'scope> {
197 sink: Option<PushSink<'scope>>,
198 exchange: Arc<ExchangeCompletion<'scope>>,
199 ended: bool,
200 completion: Option<Result<(), Error>>,
201}
202struct Writing<'a, 'scope> {
203 sink: &'a mut Option<PushSink<'scope>>,
204 cancellation: Cancellation,
205 armed: bool,
206}
207impl Drop for Writing<'_, '_> {
208 fn drop(&mut self) {
209 if self.armed {
210 self.cancellation.cancel();
211 self.sink.take();
212 }
213 }
214}
215impl RequestBodyWriter<'_> {
216 pub async fn write(
217 &mut self,
218 data: impl Into<Vec<u8>>,
219 cancellation: &Cancellation,
220 ) -> Result<(), Error> {
221 self.write_frame(
222 BodyFrame::Data {
223 data: data.into(),
224 end: false,
225 },
226 cancellation,
227 )
228 .await
229 }
230 pub async fn write_frame(
231 &mut self,
232 frame: BodyFrame<Vec<u8>>,
233 cancellation: &Cancellation,
234 ) -> Result<(), Error> {
235 if cancellation.is_cancelled() || self.exchange.cancellation.is_cancelled() {
236 return Err(Error::Cancelled);
237 }
238 if self.ended {
239 return Err(Error::Closed);
240 }
241 let end = frame.is_end();
242 let mut guard = Writing {
243 sink: &mut self.sink,
244 cancellation: self.exchange.cancellation.clone(),
245 armed: true,
246 };
247 checked(
248 guard
249 .sink
250 .as_mut()
251 .expect("unended output retains its sink until the exchange is cancelled")
252 .send((frame, cancellation.clone())),
253 cancellation,
254 )
255 .await?;
256 guard.armed = false;
257 drop(guard);
258 if end {
259 self.ended = true;
260 self.sink.take();
261 self.completion = Some(Ok(()));
262 }
263 Ok(())
264 }
265 pub async fn flush(&mut self, cancellation: &Cancellation) -> Result<(), Error> {
269 if cancellation.is_cancelled() {
270 return Err(Error::Cancelled);
271 }
272 if let Some(result) = &self.completion {
273 return result.clone();
274 }
275 if self.exchange.cancellation.is_cancelled() {
276 return Err(Error::Cancelled);
277 }
278 if self.ended {
279 self.wait_finished(cancellation).await
280 } else {
281 Ok(())
282 }
283 }
284 async fn wait_finished(&mut self, cancellation: &Cancellation) -> Result<(), Error> {
285 if let Some(result) = &self.completion {
286 return result.clone();
287 }
288 let result = self.exchange.wait_output(cancellation).await;
291 if matches!(result, Err(Error::Cancelled)) {
292 return result;
293 }
294 self.completion = Some(result.clone());
295 result
296 }
297 pub async fn finish(mut self, cancellation: &Cancellation) -> Result<(), Error> {
298 if !self.ended {
299 self.write_frame(BodyFrame::End, cancellation).await?;
300 }
301 self.wait_finished(cancellation).await
302 }
303 pub fn close_write(&mut self, error: Option<Error>) {
306 if !self.ended {
307 if let Some(error) = error {
308 self.completion = Some(Err(error));
309 self.exchange.cancellation.cancel();
310 } else {
311 self.exchange.output_mode.store(FINALIZE, Ordering::Release);
312 }
313 self.sink.take();
314 self.ended = true;
315 }
316 }
317 pub fn abort(&mut self) {
318 self.exchange.cancellation.cancel();
319 self.sink.take();
320 self.ended = true;
321 }
322}
323impl WritableBody for RequestBodyWriter<'_> {
324 type Data = Vec<u8>;
325 type Error = Error;
326 async fn write_frame(
327 &mut self,
328 frame: BodyFrame<Vec<u8>>,
329 cancellation: &Cancellation,
330 ) -> Result<(), Error> {
331 Self::write_frame(self, frame, cancellation).await
332 }
333 async fn flush(&mut self, cancellation: &Cancellation) -> Result<(), Error> {
334 Self::flush(self, cancellation).await
335 }
336 fn close_write(&mut self, error: Option<Error>) {
337 Self::close_write(self, error);
338 }
339 fn abort(&mut self) {
340 Self::abort(self);
341 }
342}
343
344#[must_use = "poll the response or drop it to abandon input"]
347pub struct PendingResponse<'scope> {
348 stream: Option<ResponseStream<'scope>>,
349 cancellation: Cancellation,
350}
351impl<'scope> Future for PendingResponse<'scope> {
352 type Output = Result<Response<StreamingResponseBody<'scope>>, Error>;
353 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
354 let event = if self.cancellation.is_cancelled() {
355 Err(Error::Cancelled)
356 } else {
357 match self
358 .stream
359 .as_mut()
360 .expect("response already polled")
361 .poll_next_unpin(cx)
362 {
363 Poll::Pending => return Poll::Pending,
364 Poll::Ready(event) => event
365 .transpose()
366 .and_then(|event| event.ok_or(Error::Closed)),
367 }
368 };
369 match event {
370 Ok(ResponseEvent::Metadata(metadata, length, trailers, empty)) => {
371 let mut stream = self.stream.take();
372 if empty {
373 stream.take();
376 }
377 Poll::Ready(Ok(Response::from_parts(
378 metadata,
379 StreamingResponseBody {
380 stream,
381 cancellation: self.cancellation.clone(),
382 length,
383 trailers,
384 empty,
385 },
386 )))
387 }
388 Ok(ResponseEvent::Frame(_)) => unreachable!("first response event is metadata"),
389 Err(error) => {
390 self.cancellation.cancel();
391 self.stream.take();
392 Poll::Ready(Err(error))
393 }
394 }
395 }
396}
397impl Drop for PendingResponse<'_> {
398 fn drop(&mut self) {
399 if self.stream.is_some() {
400 self.cancellation.cancel();
401 }
402 }
403}
404enum ResponseEvent {
405 Metadata(ResponseMetadata, Option<u64>, bool, bool),
406 Frame(BodyFrame<Vec<u8>>),
407}
408
409pub struct StreamingResponseBody<'scope> {
414 stream: Option<ResponseStream<'scope>>,
415 cancellation: Cancellation,
416 length: Option<u64>,
417 trailers: bool,
418 empty: bool,
419}
420impl ReadableBody for StreamingResponseBody<'_> {
421 type Data = Vec<u8>;
422 type Error = Error;
423 fn length(&self) -> Option<u64> {
424 self.length
425 }
426 fn may_have_trailers(&self) -> bool {
427 self.trailers
428 }
429 fn is_empty(&self) -> bool {
430 self.empty
431 }
432 fn close(&mut self, _: Option<Error>) {
433 self.stream.take();
434 self.empty = true;
435 }
436 async fn read(&mut self, cancellation: &Cancellation) -> Result<BodyFrame<Vec<u8>>, Error> {
437 if cancellation.is_cancelled() {
438 return Err(Error::Cancelled);
439 }
440 if self.empty {
441 return Ok(BodyFrame::End);
442 }
443 let event = checked(
444 async {
445 self.stream
446 .as_mut()
447 .ok_or(Error::Closed)?
448 .next()
449 .await
450 .transpose()?
451 .ok_or(Error::Closed)
452 },
453 cancellation,
454 )
455 .await;
456 match event {
457 Ok(ResponseEvent::Frame(frame)) => {
458 if frame.is_end() {
459 self.empty = true;
460 self.stream.take();
461 }
462 Ok(frame)
463 }
464 Ok(ResponseEvent::Metadata(..)) => unreachable!("response metadata is delivered once"),
465 Err(error) => {
466 self.cancellation.cancel();
467 self.stream.take();
468 Err(error)
469 }
470 }
471 }
472}
473
474pub(crate) struct Open<'scope> {
475 pub metadata: RequestMetadata,
476 pub interim: Box<dyn Observer + 'scope>,
477 pub active: base_pool::MultiplexUse<crate::Connection<'scope>>,
478 pub pending: Pending<'scope>,
479 pub cancellation: Cancellation,
480 pub lifetime: Cancellation,
481}
482
483pub(crate) struct ExchangeCompletion<'scope> {
486 state: Mutex<CompletionState<'scope>>,
487 cancellation: Cancellation,
488 registration: base_pool::MultiplexResource<crate::Connection<'scope>>,
489 output_mode: AtomicU8,
490 output_finished: AtomicWaker,
491}
492struct CompletionState<'scope> {
493 active: Option<base_pool::MultiplexUse<crate::Connection<'scope>>>,
494 pending: Option<Pending<'scope>>,
495 directions: u8,
496 reusable: bool,
497 output_result: Option<Result<(), Error>>,
498}
499impl<'scope> ExchangeCompletion<'scope> {
500 pub(crate) fn new(
501 active: base_pool::MultiplexUse<crate::Connection<'scope>>,
502 pending: Pending<'scope>,
503 cancellation: Cancellation,
504 registration: base_pool::MultiplexResource<crate::Connection<'scope>>,
505 ) -> Arc<Self> {
506 Arc::new(Self {
507 state: Mutex::new(CompletionState {
508 active: Some(active),
509 pending: Some(pending),
510 directions: 0,
511 reusable: true,
512 output_result: None,
513 }),
514 cancellation,
515 registration,
516 output_mode: AtomicU8::new(ABANDONED),
517 output_finished: AtomicWaker::new(),
518 })
519 }
520 pub(crate) fn cancellation(&self) -> &Cancellation {
521 &self.cancellation
522 }
523 async fn wait_output(&self, cancellation: &Cancellation) -> Result<(), Error> {
524 struct Waiting<'a>(&'a AtomicWaker);
527 impl Drop for Waiting<'_> {
528 fn drop(&mut self) {
529 self.0.take();
530 }
531 }
532 let _waiting = Waiting(&self.output_finished);
533 checked(
534 std::future::poll_fn(|cx| {
535 self.output_finished.register(cx.waker());
536 match lock(&self.state).output_result.clone() {
537 Some(result) => Poll::Ready(result),
538 None => Poll::Pending,
539 }
540 }),
541 cancellation,
542 )
543 .await
544 }
545 pub(crate) fn returned(
546 &self,
547 direction: u8,
548 reusable: bool,
549 output: Option<Result<(), Error>>,
550 ) {
551 let mut state = lock(&self.state);
552 state.directions |= direction;
553 state.reusable &= reusable;
554 if let Some(output) = output {
555 state.output_result.get_or_insert(output);
556 }
557 let completed = if state.directions == 3 {
558 Some((
559 state.pending.take(),
560 state.active.take().unwrap(),
561 !state.reusable || self.cancellation.is_cancelled(),
562 ))
563 } else {
564 None
565 };
566 drop(state);
567 if let Some((pending, active, retire)) = completed {
568 if retire {
569 self.registration.retire();
570 }
571 drop(pending);
572 active.complete();
573 }
574 if direction == 2 {
575 self.output_finished.wake();
576 }
577 }
578}
579
580pub(crate) const ABANDONED: u8 = 0;
581pub(crate) const COMPLETE: u8 = 1;
582pub(crate) const FINALIZE: u8 = 2;
583pub(crate) trait ReturnTo<'scope, T>: Send + Sync {
584 fn give_back(self: Arc<Self>, value: T, mode: u8, completion: Arc<ExchangeCompletion<'scope>>);
585}
586pub(crate) struct Return<'scope, T> {
587 pub value: Option<T>,
588 return_to: Arc<dyn ReturnTo<'scope, T> + 'scope>,
589 mode: u8,
590 output: bool,
591 completion: Arc<ExchangeCompletion<'scope>>,
592}
593impl<'scope, T> Return<'scope, T> {
594 pub(crate) fn new(
595 value: T,
596 completion: Arc<ExchangeCompletion<'scope>>,
597 return_to: Arc<dyn ReturnTo<'scope, T> + 'scope>,
598 output: bool,
599 ) -> Self {
600 Self {
601 value: Some(value),
602 return_to,
603 mode: ABANDONED,
604 output,
605 completion,
606 }
607 }
608 pub(crate) fn complete(&mut self) {
609 self.mode = COMPLETE;
610 self.release();
611 }
612 pub(crate) fn report_error(&mut self, error: Error) {
613 lock(&self.completion.state)
614 .output_result
615 .get_or_insert(Err(error));
616 }
617 fn release(&mut self) {
618 if let Some(value) = self.value.take() {
619 let mode = if self.output && self.mode == ABANDONED {
620 self.completion
623 .output_mode
624 .swap(ABANDONED, Ordering::AcqRel)
625 } else {
626 self.mode
627 };
628 if mode == ABANDONED {
629 self.completion.cancellation.cancel();
630 }
631 self.return_to
632 .clone()
633 .give_back(value, mode, self.completion.clone());
634 }
635 }
636}
637impl<T> Drop for Return<'_, T> {
638 fn drop(&mut self) {
639 self.release();
640 }
641}
642
643pub(crate) fn factory<'scope, R, W>() -> OpenFactory<'scope, R, W>
646where
647 R: ReadableStream + 'scope,
648 W: WritableStream + 'scope,
649{
650 let writing_cache = Cache::new();
651 let receiving_cache = Cache::new();
652 let adapters = move |mut input: Return<'scope, ResponseReader<R>>,
653 output: Return<'scope, RequestWriter<W>>,
654 metadata: RequestMetadata,
655 observer: Box<dyn Observer + 'scope>,
656 lifetime: Cancellation| {
657 let exchange = output.completion.clone();
658 let local = exchange.cancellation.clone();
659 let writing_lifetime = lifetime.clone();
660 let writing = writing_cache.take(|| {
661 owned_sink(
662 output,
663 move |mut owner, (frame, cancellation): (BodyFrame<Vec<u8>>, Cancellation)| {
664 let lifetime = writing_lifetime.clone();
665 async move {
666 let end = frame.is_end();
667 checked(
668 checked(
669 async {
670 owner
671 .value
672 .as_mut()
673 .expect(
674 "request output drops its sink after the final frame",
675 )
676 .write_frame(frame, &owner.completion.cancellation)
677 .await
678 .map_err(Error::from)
679 },
680 &cancellation,
681 ),
682 &lifetime,
683 )
684 .await?;
685 if end {
686 owner.complete();
687 }
688 Ok(owner)
689 }
690 },
691 )
692 });
693 let receive_cancel = local.clone();
694 let receiving = receiving_cache.take(|| {
695 async_stream::try_stream! {
696 let mut observer = observer;
697 let mut interim = InterimResponses::new(Interim(observer.as_mut()));
698 let response = checked(
701 async {
702 input.value.as_mut().unwrap()
703 .read_response(&metadata, &mut interim, &receive_cancel)
704 .await.map_err(Error::from)
705 },
706 &lifetime,
707 ).await?;
708 let (metadata, mut body) = response.into_parts();
709 let length = body.length();
710 let trailers = body.may_have_trailers();
711 if body.is_empty() {
712 drop(body);
713 input.complete();
714 yield ResponseEvent::Metadata(metadata, length, trailers, true);
715 } else {
716 yield ResponseEvent::Metadata(metadata, length, trailers, false);
717 loop {
718 let frame = checked(
719 async { body.read(&receive_cancel).await.map_err(Error::from) },
720 &lifetime,
721 ).await?;
722 if frame.is_end() {
723 drop(body);
724 input.complete();
725 yield ResponseEvent::Frame(frame);
726 break;
727 }
728 yield ResponseEvent::Frame(frame);
729 }
730 }
731 }
732 });
733 let response = PendingResponse {
734 stream: Some(Reused::new(receiving)),
735 cancellation: local.clone(),
736 };
737 WritableRequest {
738 output: RequestBodyWriter {
739 sink: Some(Reused::new(writing)),
740 exchange,
741 ended: false,
742 completion: None,
743 },
744 response,
745 }
746 };
747 let adapters = Arc::new(adapters);
748 let opening_cache = Cache::new();
749 Box::new(move |input, mut output, metadata, observer, lifetime| {
750 let adapters = adapters.clone();
751 Reused::new(opening_cache.take(|| async move {
752 let local = output.completion.cancellation.clone();
753 checked(
754 async {
755 output
756 .value
757 .as_mut()
758 .unwrap()
759 .begin_request(&metadata, &local)
760 .await
761 .map_err(Error::from)
762 },
763 &lifetime,
764 )
765 .await?;
766 Ok(adapters(input, output, metadata, observer, lifetime))
767 }))
768 })
769}
770
771#[cfg(test)]
772mod tests {
773 use super::*;
774
775 #[test]
776 fn failed_opening_reports_its_error() {
777 let opening = failed_open(Error::Closed);
778 let error = futures_lite::future::block_on(opening).err().unwrap();
779 assert_eq!(error.to_string(), "HTTP client is closed");
780 }
781}