1use crate::{
5 Endpoint, Error, Options, ResponseBody,
6 body::Consumption,
7 driver::{Assigned, Operation, Queue, checked, linked, lock},
8 outgoing::Interim,
9 writable::{
10 COMPLETE, ExchangeCompletion, FINALIZE, Open, OpenFactory, Opening, Return, ReturnTo,
11 },
12};
13use base_endpoint::{
14 AddressEndpoint, ConnectEndpoint,
15 stream::{ReadableStream, WritableStream},
16};
17use base_http::{
18 InterimResponses, Response,
19 body::{BodyError, BodyReader, ReadableBody},
20};
21use base_http1::{RequestWriter, ResponseReader};
22use base_pool::{Admission, MultiplexBuildPermit, MultiplexResource};
23use base_scheduler::{
24 Cancellation, OperationError, OperationResult, SocketClose, SocketConnect, SocketOpen,
25 SocketSetOption, SocketStreamReading, SocketStreamWriting, TcpNoDelay,
26};
27use event_listener::Event;
28use futures_channel::oneshot;
29use futures_util::future::join;
30use std::sync::{
31 Arc, Mutex, Weak,
32 atomic::{AtomicBool, Ordering},
33};
34
35struct Inner<'scope> {
36 assigned: Mutex<Option<Assigned<'scope>>>,
37 direct: Mutex<Option<Arc<dyn DirectConnection<'scope> + 'scope>>>,
38 changed: Event,
39 stop: Cancellation,
40 result: Mutex<Option<Result<(), Error>>>,
41}
42
43#[derive(Clone)]
47pub struct Connection<'scope> {
48 inner: Arc<Inner<'scope>>,
49}
50impl<'scope> Connection<'scope> {
51 fn new() -> Self {
52 Self {
53 inner: Arc::new(Inner {
54 assigned: Mutex::new(None),
55 direct: Mutex::new(None),
56 changed: Event::new(),
57 stop: Cancellation::new(),
58 result: Mutex::new(None),
59 }),
60 }
61 }
62 pub(crate) fn clone_handle(&self) -> Self {
63 self.clone()
64 }
65 pub(crate) fn submit(&self, assigned: Assigned<'scope>) {
66 let mut slot = lock(&self.inner.assigned);
67 assert!(slot.is_none(), "HTTP/1 admits one exchange at a time");
68 *slot = Some(assigned);
69 drop(slot);
70 self.inner.changed.notify(usize::MAX);
71 }
72 pub(crate) fn open(&self, opening: Open<'scope>) -> Opening<'scope> {
73 let direct = lock(&self.inner.direct)
75 .clone()
76 .expect("an admitted connection has direct state");
77 direct.open(opening)
78 }
79 pub(crate) fn probe(&self) -> bool {
83 let direct = lock(&self.inner.direct)
84 .clone()
85 .expect("an admitted connection has direct state");
86 direct.probe()
87 }
88 async fn next(&self, lifetime: &Cancellation) -> Option<Assigned<'scope>> {
89 loop {
90 event_listener::listener!(self.inner.changed => listener);
91 if let Some(assigned) = lock(&self.inner.assigned).take() {
92 return Some(assigned);
93 }
94 if checked(
95 checked(
96 async {
97 listener.await;
98 Ok(())
99 },
100 &self.inner.stop,
101 ),
102 lifetime,
103 )
104 .await
105 .is_err()
106 {
107 return None;
108 }
109 }
110 }
111 pub(crate) fn stop(&self) {
112 self.inner.stop.cancel();
113 }
114 pub(crate) async fn wait_closed(&self) -> Result<(), Error> {
115 loop {
116 event_listener::listener!(self.inner.changed => listener);
117 if let Some(result) = lock(&self.inner.result).clone() {
118 return result;
119 }
120 listener.await;
121 }
122 }
123 fn finish(&self, result: Result<(), Error>) {
124 let mut current = lock(&self.inner.result);
125 if current.is_none() {
126 *current = Some(result);
127 }
128 drop(current);
129 self.inner.changed.notify(usize::MAX);
130 }
131}
132
133struct Owner<'scope> {
134 connection: Connection<'scope>,
135 registration: Option<MultiplexResource<Connection<'scope>>>,
136}
137impl Drop for Owner<'_> {
138 fn drop(&mut self) {
139 if let Some(registration) = &self.registration {
140 registration.retire();
141 }
142 let abandoned = lock(&self.connection.inner.assigned).take();
143 drop(abandoned);
144 self.connection.finish(Err(Error::Closed));
145 }
146}
147
148#[allow(clippy::too_many_arguments)]
149pub(crate) async fn run<'scope, S>(
150 scheduler: &'scope S,
151 endpoint: Endpoint,
152 options: Options,
153 build: MultiplexBuildPermit<Connection<'scope>>,
154 cancellation: Cancellation,
155 lifetime: Cancellation,
156 ready: oneshot::Sender<Result<(), Error>>,
157 queue: Weak<Queue<'scope>>,
158) where
159 S: SocketOpen
160 + SocketConnect
161 + SocketClose
162 + SocketSetOption<TcpNoDelay>
163 + SocketStreamReading
164 + SocketStreamWriting,
165 S::Socket: 'static,
166{
167 let connection = Connection::new();
168 let mut owner = Owner {
169 connection: connection.clone(),
170 registration: None,
171 };
172 let mut build = Some(build);
173 let mut ready = Some(ready);
174 let result = async {
175 let address = endpoint.address;
176 let endpoint_transport = TcpEndpoint {
177 address: AddressEndpoint::new(address),
178 nodelay: options.tcp_nodelay,
179 };
180 #[cfg(feature = "rustls")]
181 if let Some(tls) = endpoint.tls {
182 use base_endpoint::tls::{TlsClientEndpoint, TlsSession, rustls::RustlsConnector};
183 let mut config = (*tls.config).clone();
184 config.alpn_protocols = options.protocols.alpn_protocols();
185 let endpoint = TlsClientEndpoint::new(
186 endpoint_transport,
187 RustlsConnector::new(Arc::new(config)),
188 tls.server_name,
189 );
190 let transport = endpoint
191 .connect(scheduler, &cancellation)
192 .await
193 .map_err(|error| Error::connect(address, error))?;
194 let selected = transport.negotiated_protocol().map(<[u8]>::to_vec);
195 return transport
196 .with_duplex(scheduler, &lifetime, |reader, writer| async {
197 let protocol = options.protocols.negotiated(selected.as_deref())?;
198 let (input, output) = protocol
199 .client(reader, writer, options.http1.clone())
200 .expect("Client::new validated the HTTP/1 options");
201 session(
202 input,
203 output,
204 &mut owner,
205 &mut build,
206 &mut ready,
207 &options,
208 &cancellation,
209 &lifetime,
210 queue.clone(),
211 )
212 .await
213 })
214 .await;
215 }
216 let socket = endpoint_transport
217 .connect(scheduler, &cancellation)
218 .await
219 .map_err(|error| Error::connect(address, error))?;
220 let initialized = async {
221 let mut reader = scheduler.socket_stream_reader(&socket)?;
222 let writer = match scheduler.socket_stream_writer(&socket) {
223 Ok(writer) => writer,
224 Err(error) => {
225 let _ = ReadableStream::close(&mut reader).await;
226 return Err(Error::from(error));
227 }
228 };
229 Ok::<_, Error>(
230 options
231 .protocols
232 .plaintext()
233 .client(reader, writer, options.http1.clone())
234 .expect("Client::new validated the HTTP/1 options"),
235 )
236 }
237 .await;
238 let result = match initialized {
239 Ok((input, output)) => {
240 session(
241 input,
242 output,
243 &mut owner,
244 &mut build,
245 &mut ready,
246 &options,
247 &cancellation,
248 &lifetime,
249 queue.clone(),
250 )
251 .await
252 }
253 Err(error) => Err(error),
254 };
255 let closed = scheduler.socket_close(socket).await;
256 result?;
257 closed?;
258 Ok(())
259 }
260 .await;
261 drop(build);
263 if let Some(ready) = ready {
264 let _ = ready.send(Err(result.as_ref().err().cloned().unwrap_or(Error::Closed)));
265 }
266 connection.finish(result);
267}
268
269struct TcpEndpoint {
271 address: AddressEndpoint,
272 nodelay: bool,
273}
274impl<S> ConnectEndpoint<S> for TcpEndpoint
275where
276 S: SocketOpen + SocketConnect + SocketClose + SocketSetOption<TcpNoDelay>,
277{
278 type Connection = S::Socket;
279
280 async fn connect(
281 &self,
282 scheduler: &S,
283 cancellation: &Cancellation,
284 ) -> OperationResult<S::Socket> {
285 let socket = self.address.connect(scheduler, cancellation).await?;
286 if self.nodelay {
287 let result = scheduler
290 .socket_set_option(&socket, TcpNoDelay, true, cancellation)
291 .await;
292 if let Err(error @ OperationError::Cancelled(_)) = result {
293 let _ = scheduler.socket_close(socket).await;
294 return Err(error);
295 }
296 }
297 Ok(socket)
298 }
299}
300
301trait DirectConnection<'scope>: Send + Sync {
304 fn open(self: Arc<Self>, opening: Open<'scope>) -> Opening<'scope>;
305 fn probe(&self) -> bool;
306}
307struct Codecs<R, W> {
308 input: Option<ResponseReader<R>>,
309 output: Option<RequestWriter<W>>,
310}
311struct Http1Connection<'scope, R, W> {
312 codecs: Mutex<Codecs<R, W>>,
313 changed: Event,
314 closing: AtomicBool,
315 registration: MultiplexResource<Connection<'scope>>,
316 queue: Weak<Queue<'scope>>,
317 open: OpenFactory<'scope, R, W>,
318}
319impl<R: ReadableStream, W: WritableStream> Http1Connection<'_, R, W> {
320 fn take(&self) -> Result<(ResponseReader<R>, RequestWriter<W>), Error> {
321 let mut codecs = lock(&self.codecs);
322 if self.closing.load(Ordering::Acquire) || codecs.input.is_none() || codecs.output.is_none()
323 {
324 return Err(Error::Closed);
325 }
326 Ok((codecs.input.take().unwrap(), codecs.output.take().unwrap()))
327 }
328 fn returned(&self) {
329 if self.closing.load(Ordering::Acquire) {
330 self.changed.notify(usize::MAX);
331 }
332 }
333 async fn close(&self) -> Result<(), Error> {
334 self.closing.store(true, Ordering::Release);
335 let (mut input, mut output) = loop {
336 event_listener::listener!(self.changed => listener);
337 let returned = {
338 let mut codecs = lock(&self.codecs);
339 if codecs.input.is_some() && codecs.output.is_some() {
340 Some((codecs.input.take().unwrap(), codecs.output.take().unwrap()))
341 } else {
342 None
343 }
344 };
345 if let Some(codecs) = returned {
346 break codecs;
347 }
348 listener.await;
349 };
350 let a = input.close().await;
351 let b = output.close().await;
352 drop(input);
353 drop(output);
354 a?;
355 b?;
356 Ok(())
357 }
358}
359impl<'scope, R: ReadableStream + 'scope, W: WritableStream + 'scope> DirectConnection<'scope>
360 for Http1Connection<'scope, R, W>
361{
362 fn open(self: Arc<Self>, opening: Open<'scope>) -> Opening<'scope> {
363 let (input, output) = match self.take() {
364 Ok(codecs) => codecs,
365 Err(error) => {
366 self.registration.retire();
367 opening.active.complete();
368 return crate::writable::failed_open(error);
369 }
370 };
371 let completion = ExchangeCompletion::new(
372 opening.active,
373 opening.pending,
374 opening.cancellation.clone(),
375 self.registration.clone(),
376 );
377 let input = Return::new(input, completion.clone(), self.clone(), false);
380 let output = Return::new(output, completion, self.clone(), true);
381 (self.open)(
382 input,
383 output,
384 opening.metadata,
385 opening.interim,
386 opening.lifetime,
387 )
388 }
389 fn probe(&self) -> bool {
390 let viable = match self.take() {
392 Ok((mut input, output)) => {
393 let viable = input.probe_viable();
394 {
395 let mut codecs = lock(&self.codecs);
396 codecs.input = Some(input);
397 codecs.output = Some(output);
398 }
399 self.returned();
400 viable
401 }
402 Err(_) => false,
403 };
404 if !viable {
405 self.registration.retire();
406 }
407 viable
408 }
409}
410impl<'scope, R: ReadableStream + 'scope, W: WritableStream + 'scope>
411 ReturnTo<'scope, ResponseReader<R>> for Http1Connection<'scope, R, W>
412{
413 fn give_back(
414 self: Arc<Self>,
415 input: ResponseReader<R>,
416 mode: u8,
417 completion: Arc<ExchangeCompletion<'scope>>,
418 ) {
419 let reusable = mode == COMPLETE && input.is_reusable();
420 lock(&self.codecs).input = Some(input);
421 self.returned();
422 completion.returned(1, reusable, None);
423 }
424}
425impl<'scope, R: ReadableStream + 'scope, W: WritableStream + 'scope>
426 ReturnTo<'scope, RequestWriter<W>> for Http1Connection<'scope, R, W>
427{
428 fn give_back(
429 self: Arc<Self>,
430 output: RequestWriter<W>,
431 mode: u8,
432 completion: Arc<ExchangeCompletion<'scope>>,
433 ) {
434 if mode == FINALIZE {
435 let queue = self
437 .queue
438 .upgrade()
439 .expect("an unfinished exchange retains its queue");
440 let cancellation = completion.cancellation().clone();
441 let mut owner = Return::new(output, completion, self, true);
442 let work = Box::pin(async move {
443 let result = owner
444 .value
445 .as_mut()
446 .unwrap()
447 .write_frame(base_http::body::BodyFrame::<Vec<u8>>::End, &cancellation)
448 .await;
449 match result {
450 Ok(()) => owner.complete(),
451 Err(error) => owner.report_error(error.into()),
452 }
453 });
455 let _ = queue.push_work(work);
457 return;
458 }
459 let reusable = mode == COMPLETE && output.is_reusable();
460 lock(&self.codecs).output = Some(output);
461 self.returned();
462 completion.returned(
463 2,
464 reusable,
465 Some(if mode == COMPLETE {
466 Ok(())
467 } else {
468 Err(Error::Abandoned)
469 }),
470 );
471 }
472}
473
474#[allow(clippy::too_many_arguments)]
475async fn session<'scope, R, W>(
476 mut input: ResponseReader<R>,
477 mut output: RequestWriter<W>,
478 owner: &mut Owner<'scope>,
479 build: &mut Option<MultiplexBuildPermit<Connection<'scope>>>,
480 ready: &mut Option<oneshot::Sender<Result<(), Error>>>,
481 options: &Options,
482 cancellation: &Cancellation,
483 lifetime: &Cancellation,
484 queue: Weak<Queue<'scope>>,
485) -> Result<(), Error>
486where
487 R: ReadableStream + 'scope,
488 W: WritableStream + 'scope,
489{
490 if cancellation.is_cancelled() {
491 let _ = input.close().await;
492 let _ = output.close().await;
493 return Err(Error::Cancelled);
494 }
495 let Ok(registration) = build
498 .take()
499 .unwrap()
500 .commit(owner.connection.clone(), Admission::concurrent(0))
501 else {
502 let ready = ready.take().expect("a session reports readiness once");
504 let _ = ready.send(Err(Error::Closed));
505 let input = input.close().await;
506 let output = output.close().await;
507 input?;
508 output?;
509 return Ok(());
510 };
511 owner.registration = Some(registration.clone());
512 let state = Arc::new(Http1Connection {
513 codecs: Mutex::new(Codecs {
514 input: Some(input),
515 output: Some(output),
516 }),
517 changed: Event::new(),
518 closing: AtomicBool::new(false),
519 registration,
520 queue,
521 open: crate::writable::factory(),
522 });
523 *lock(&owner.connection.inner.direct) = Some(state.clone());
524 state.registration.update(Admission::concurrent(1));
526 let ready = ready.take().expect("a session reports readiness once");
528 let _ = ready.send(Ok(()));
529 while let Some(Assigned {
531 mut operation,
532 active,
533 }) = owner.connection.next(lifetime).await
534 {
535 let (mut input, mut output) = state
537 .take()
538 .expect("an admitted exchange finds both codec directions");
539 let local = operation.cancellation.clone();
540 let caller = operation.lifetime.clone();
541 let outcome = linked(
542 exchange(&mut input, &mut output, &mut operation, options),
543 &local,
544 &caller,
545 lifetime,
546 )
547 .await;
548 operation.request.body.close(None);
549 if let Some(reply) = operation.reply.take() {
550 let _ = reply.send(Err(outcome
551 .as_ref()
552 .err()
553 .cloned()
554 .unwrap_or(Error::Closed)));
555 }
556 let reusable = matches!(outcome, Ok(true));
557 if !reusable {
558 state.registration.retire();
559 }
560 {
561 let mut codecs = lock(&state.codecs);
562 codecs.input = Some(input);
563 codecs.output = Some(output);
564 }
565 drop(operation);
566 active.complete();
567 if !reusable {
568 break;
569 }
570 }
571 state.registration.retire();
572 state.close().await
573}
574
575async fn exchange<R: ReadableStream, W: WritableStream>(
576 input: &mut ResponseReader<R>,
577 output: &mut RequestWriter<W>,
578 operation: &mut Operation<'_>,
579 options: &Options,
580) -> Result<bool, Error> {
581 let Operation {
582 request,
583 interim,
584 reply,
585 cancellation,
586 ..
587 } = operation;
588 let metadata = request.metadata.clone();
589 let headers = AtomicBool::new(false);
590 let send = async {
591 let result = checked(
592 async {
593 output
594 .write_request(request, cancellation)
595 .await
596 .map_err(Error::from)
597 },
598 cancellation,
599 )
600 .await;
601 if result.is_err() && !headers.load(Ordering::Acquire) {
604 cancellation.cancel();
605 }
606 result
607 };
608 let receive = async {
609 let mut writer = None;
610 let result = checked(
611 async {
612 let mut observer = InterimResponses::new(Interim(interim.as_mut()));
613 let mut response = input
614 .read_response(&metadata, &mut observer, cancellation)
615 .await?;
616 let consumption = Consumption::new(cancellation.clone());
617 let empty = response.body.is_empty();
618 let (reader, mut producer) = BodyReader::bounded(
619 options.response_buffer_bytes,
620 options.response_buffer_frames,
621 );
622 if empty {
626 consumption.complete();
627 producer.close_write(None);
628 }
629 let body = ResponseBody {
630 reader,
631 consumption: consumption.clone(),
632 length: response.body.length(),
633 trailers: response.body.may_have_trailers(),
634 };
635 writer = Some(producer);
636 let returned = Response::from_parts(response.metadata, body);
637 if reply.take().unwrap().send(Ok(returned)).is_err() {
638 return Err(Error::Abandoned);
639 }
640 headers.store(true, Ordering::Release);
641 if !empty {
642 loop {
643 let frame = response.body.read(cancellation).await?;
644 let end = frame.is_end();
645 writer
646 .as_mut()
647 .unwrap()
648 .write_frame(frame, cancellation)
649 .await?;
650 if end {
651 break;
652 }
653 }
654 }
655 consumption.wait().await
656 },
657 cancellation,
658 )
659 .await;
660 if let Err(error) = &result {
661 if let Some(writer) = &mut writer {
662 writer.close_write(Some(match error {
663 Error::Body(error) => error.clone(),
664 error => BodyError::new(error.clone()),
665 }));
666 }
667 cancellation.cancel();
668 }
669 result
670 };
671 let (sent, received) = join(send, receive).await;
672 match (sent, received) {
673 (Ok(persistent), Ok(())) => Ok(persistent && input.is_reusable()),
674 (Err(_), Ok(())) => Ok(false),
675 (Err(error), Err(Error::Cancelled)) if !matches!(error, Error::Cancelled) => Err(error),
676 (_, Err(error)) => Err(error),
677 }
678}
679
680#[cfg(test)]
681mod tests {
682 use super::*;
683 use crate::{Client, driver::Pending, outgoing::tests::ignore};
684 use base_http::{Method, RequestMetadata};
685 use base_scheduler_native::NativeScheduler;
686 use futures_lite::future::{block_on, yield_now, zip};
687 use std::{io::Read, net::TcpListener, thread};
688
689 #[test]
690 fn opening_an_admitted_use_after_the_session_closes_fails_and_releases_it() {
691 let listener = TcpListener::bind("127.0.0.1:0").unwrap();
692 let address = listener.local_addr().unwrap();
693 let peer = thread::spawn(move || {
694 let (mut stream, _) = listener.accept().unwrap();
695 let mut bytes = Vec::new();
696 stream.read_to_end(&mut bytes).unwrap();
697 assert!(bytes.is_empty());
698 });
699 let scheduler = NativeScheduler::new().unwrap();
700 let (client, driver) =
701 Client::new(&scheduler, Endpoint::new(address), Options::default()).unwrap();
702 let lifetime = Cancellation::new();
703 let application = async {
704 let active = client
705 .context
706 .acquire(&Cancellation::never())
707 .await
708 .unwrap();
709 let connection = active.clone_handle();
710 let pending = Pending::new(client.queue.clone()).unwrap();
711 lifetime.cancel();
713 while lock(&connection.inner.result).is_none() {
714 yield_now().await;
715 }
716 assert!(!connection.probe());
717 let opening = Open {
718 metadata: RequestMetadata::new(Method::GET),
719 interim: Box::new(ignore),
720 active,
721 pending,
722 cancellation: Cancellation::new(),
723 lifetime: Cancellation::never(),
724 };
725 let error = connection.open(opening).await.err().unwrap();
726 assert_eq!(error.to_string(), Error::Closed.to_string());
727 };
728 let (result, ()) = block_on(zip(driver.run(&lifetime), application));
729 result.unwrap();
730 assert_eq!(client.pool_stats().total(), 0);
731 peer.join().unwrap();
732 block_on(scheduler.shutdown());
733 }
734}