1pub mod upgrade;
4
5use hyper::service::HttpService;
6use std::marker::PhantomPinned;
7use std::mem::MaybeUninit;
8use std::pin::Pin;
9use std::task::{Context, Poll, ready};
10use std::{error::Error as StdError, io, time::Duration};
11
12use bytes::Bytes;
13use http::{Request, Response};
14use http_body::Body;
15use hyper::{
16 body::Incoming,
17 rt::{Read, ReadBuf, Timer, Write},
18 service::Service,
19};
20
21#[cfg(feature = "http1")]
22use hyper::server::conn::http1;
23
24#[cfg(feature = "http2")]
25use hyper::{rt::bounds::Http2ServerConnExec, server::conn::http2};
26
27#[cfg(any(not(feature = "http2"), not(feature = "http1")))]
28use std::marker::PhantomData;
29
30use pin_project_lite::pin_project;
31
32use crate::common::rewind::Rewind;
33
34type Error = Box<dyn std::error::Error + Send + Sync>;
35
36type Result<T> = std::result::Result<T, Error>;
37
38const H2_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
39
40#[cfg(feature = "http2")]
42pub trait HttpServerConnExec<A, B: Body>: Http2ServerConnExec<A, B> {}
43
44#[cfg(feature = "http2")]
45impl<A, B: Body, T: Http2ServerConnExec<A, B>> HttpServerConnExec<A, B> for T {}
46
47#[cfg(not(feature = "http2"))]
49pub trait HttpServerConnExec<A, B: Body> {}
50
51#[cfg(not(feature = "http2"))]
52impl<A, B: Body, T> HttpServerConnExec<A, B> for T {}
53
54#[derive(Clone, Debug)]
56pub struct Builder<E> {
57 #[cfg(feature = "http1")]
58 http1: http1::Builder,
59 #[cfg(feature = "http2")]
60 http2: http2::Builder<E>,
61 #[cfg(any(feature = "http1", feature = "http2"))]
62 version: Option<Version>,
63 #[cfg(not(feature = "http2"))]
64 _executor: E,
65}
66
67impl<E: Default> Default for Builder<E> {
68 fn default() -> Self {
69 Self::new(E::default())
70 }
71}
72
73impl<E> Builder<E> {
74 pub fn new(executor: E) -> Self {
93 Self {
94 #[cfg(feature = "http1")]
95 http1: http1::Builder::new(),
96 #[cfg(feature = "http2")]
97 http2: http2::Builder::new(executor),
98 #[cfg(any(feature = "http1", feature = "http2"))]
99 version: None,
100 #[cfg(not(feature = "http2"))]
101 _executor: executor,
102 }
103 }
104
105 #[cfg(feature = "http1")]
107 pub fn http1(&mut self) -> Http1Builder<'_, E> {
108 Http1Builder { inner: self }
109 }
110
111 #[cfg(feature = "http2")]
113 pub fn http2(&mut self) -> Http2Builder<'_, E> {
114 Http2Builder { inner: self }
115 }
116
117 #[cfg(feature = "http2")]
123 pub fn http2_only(mut self) -> Self {
124 assert!(self.version.is_none());
125 self.version = Some(Version::H2);
126 self
127 }
128
129 #[cfg(feature = "http1")]
135 pub fn http1_only(mut self) -> Self {
136 assert!(self.version.is_none());
137 self.version = Some(Version::H1);
138 self
139 }
140
141 pub fn is_http1_available(&self) -> bool {
143 match self.version {
144 #[cfg(feature = "http1")]
145 Some(Version::H1) => true,
146 #[cfg(feature = "http2")]
147 Some(Version::H2) => false,
148 #[cfg(any(feature = "http1", feature = "http2"))]
149 _ => true,
150 }
151 }
152
153 pub fn is_http2_available(&self) -> bool {
155 match self.version {
156 #[cfg(feature = "http1")]
157 Some(Version::H1) => false,
158 #[cfg(feature = "http2")]
159 Some(Version::H2) => true,
160 #[cfg(any(feature = "http1", feature = "http2"))]
161 _ => true,
162 }
163 }
164
165 #[cfg(feature = "http1")]
188 pub fn title_case_headers(mut self, enabled: bool) -> Self {
189 self.http1.title_case_headers(enabled);
190 self
191 }
192
193 #[cfg(feature = "http1")]
215 pub fn preserve_header_case(mut self, enabled: bool) -> Self {
216 self.http1.preserve_header_case(enabled);
217 self
218 }
219
220 pub fn serve_connection<I, S, B>(&self, io: I, service: S) -> Connection<'_, I, S, E>
222 where
223 S: Service<Request<Incoming>, Response = Response<B>>,
224 S::Future: 'static,
225 S::Error: Into<Box<dyn StdError + Send + Sync>>,
226 B: Body + 'static,
227 B::Error: Into<Box<dyn StdError + Send + Sync>>,
228 I: Read + Write + Unpin + 'static,
229 E: HttpServerConnExec<S::Future, B>,
230 {
231 let state = match self.version {
232 #[cfg(feature = "http1")]
233 Some(Version::H1) => {
234 let io = Rewind::new_buffered(io, Bytes::new());
235 let conn = self.http1.serve_connection(io, service);
236 ConnState::H1 { conn }
237 }
238 #[cfg(feature = "http2")]
239 Some(Version::H2) => {
240 let io = Rewind::new_buffered(io, Bytes::new());
241 let conn = self.http2.serve_connection(io, service);
242 ConnState::H2 { conn }
243 }
244 #[cfg(any(feature = "http1", feature = "http2"))]
245 _ => ConnState::ReadVersion {
246 read_version: read_version(io),
247 builder: Cow::Borrowed(self),
248 service: Some(service),
249 },
250 };
251
252 Connection { state }
253 }
254
255 pub fn serve_connection_with_upgrades<I, S, B>(
265 &self,
266 io: I,
267 service: S,
268 ) -> UpgradeableConnection<'_, I, S, E>
269 where
270 S: Service<Request<Incoming>, Response = Response<B>>,
271 S::Future: 'static,
272 S::Error: Into<Box<dyn StdError + Send + Sync>>,
273 B: Body + 'static,
274 B::Error: Into<Box<dyn StdError + Send + Sync>>,
275 I: Read + Write + Unpin + Send + 'static,
276 E: HttpServerConnExec<S::Future, B>,
277 {
278 UpgradeableConnection {
279 state: UpgradeableConnState::ReadVersion {
280 read_version: read_version(io),
281 builder: Cow::Borrowed(self),
282 service: Some(service),
283 },
284 }
285 }
286}
287
288#[derive(Copy, Clone, Debug)]
289enum Version {
290 H1,
291 H2,
292}
293
294impl Version {
295 #[must_use]
296 #[cfg(any(not(feature = "http2"), not(feature = "http1")))]
297 pub fn unsupported(self) -> Error {
298 match self {
299 Version::H1 => Error::from("HTTP/1 is not supported"),
300 Version::H2 => Error::from("HTTP/2 is not supported"),
301 }
302 }
303}
304
305fn read_version<I>(io: I) -> ReadVersion<I>
306where
307 I: Read + Unpin,
308{
309 ReadVersion {
310 io: Some(io),
311 buf: [MaybeUninit::uninit(); 24],
312 filled: 0,
313 version: Version::H2,
314 cancelled: false,
315 _pin: PhantomPinned,
316 }
317}
318
319pin_project! {
320 struct ReadVersion<I> {
321 io: Option<I>,
322 buf: [MaybeUninit<u8>; 24],
323 filled: usize,
325 version: Version,
326 cancelled: bool,
327 #[pin]
329 _pin: PhantomPinned,
330 }
331}
332
333impl<I> ReadVersion<I> {
334 pub fn cancel(self: Pin<&mut Self>) {
335 *self.project().cancelled = true;
336 }
337}
338
339impl<I> Future for ReadVersion<I>
340where
341 I: Read + Unpin,
342{
343 type Output = io::Result<(Version, Rewind<I>)>;
344
345 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
346 let this = self.project();
347 if *this.cancelled {
348 return Poll::Ready(Err(io::Error::new(io::ErrorKind::Interrupted, "Cancelled")));
349 }
350
351 let mut buf = ReadBuf::uninit(&mut *this.buf);
352 unsafe {
355 buf.unfilled().advance(*this.filled);
356 };
357
358 while buf.filled().len() < H2_PREFACE.len() {
360 let len = buf.filled().len();
361 ready!(Pin::new(this.io.as_mut().unwrap()).poll_read(cx, buf.unfilled()))?;
362 *this.filled = buf.filled().len();
363
364 if buf.filled().len() == len
366 || buf.filled()[len..] != H2_PREFACE[len..buf.filled().len()]
367 {
368 *this.version = Version::H1;
369 break;
370 }
371 }
372
373 let io = this.io.take().unwrap();
374 let buf = buf.filled().to_vec();
375 Poll::Ready(Ok((
376 *this.version,
377 Rewind::new_buffered(io, Bytes::from(buf)),
378 )))
379 }
380}
381
382pin_project! {
383 #[must_use = "futures do nothing unless polled"]
389 pub struct Connection<'a, I, S, E>
390 where
391 S: HttpService<Incoming>,
392 {
393 #[pin]
394 state: ConnState<'a, I, S, E>,
395 }
396}
397
398enum Cow<'a, T> {
400 Borrowed(&'a T),
401 Owned(T),
402}
403
404impl<T> std::ops::Deref for Cow<'_, T> {
405 type Target = T;
406 fn deref(&self) -> &T {
407 match self {
408 Cow::Borrowed(t) => &*t,
409 Cow::Owned(t) => t,
410 }
411 }
412}
413
414#[cfg(feature = "http1")]
415type Http1Connection<I, S> = hyper::server::conn::http1::Connection<Rewind<I>, S>;
416
417#[cfg(not(feature = "http1"))]
418type Http1Connection<I, S> = (PhantomData<I>, PhantomData<S>);
419
420#[cfg(feature = "http2")]
421type Http2Connection<I, S, E> = hyper::server::conn::http2::Connection<Rewind<I>, S, E>;
422
423#[cfg(not(feature = "http2"))]
424type Http2Connection<I, S, E> = (PhantomData<I>, PhantomData<S>, PhantomData<E>);
425
426pin_project! {
427 #[project = ConnStateProj]
428 enum ConnState<'a, I, S, E>
429 where
430 S: HttpService<Incoming>,
431 {
432 ReadVersion {
433 #[pin]
434 read_version: ReadVersion<I>,
435 builder: Cow<'a, Builder<E>>,
436 service: Option<S>,
437 },
438 H1 {
439 #[pin]
440 conn: Http1Connection<I, S>,
441 },
442 H2 {
443 #[pin]
444 conn: Http2Connection<I, S, E>,
445 },
446 }
447}
448
449impl<I, S, E, B> Connection<'_, I, S, E>
450where
451 S: HttpService<Incoming, ResBody = B>,
452 S::Error: Into<Box<dyn StdError + Send + Sync>>,
453 I: Read + Write + Unpin,
454 B: Body + 'static,
455 B::Error: Into<Box<dyn StdError + Send + Sync>>,
456 E: HttpServerConnExec<S::Future, B>,
457{
458 pub fn graceful_shutdown(self: Pin<&mut Self>) {
467 match self.project().state.project() {
468 ConnStateProj::ReadVersion { read_version, .. } => read_version.cancel(),
469 #[cfg(feature = "http1")]
470 ConnStateProj::H1 { conn } => conn.graceful_shutdown(),
471 #[cfg(feature = "http2")]
472 ConnStateProj::H2 { conn } => conn.graceful_shutdown(),
473 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
474 _ => unreachable!(),
475 }
476 }
477
478 pub fn into_owned(self) -> Connection<'static, I, S, E>
480 where
481 Builder<E>: Clone,
482 {
483 Connection {
484 state: match self.state {
485 ConnState::ReadVersion {
486 read_version,
487 builder,
488 service,
489 } => ConnState::ReadVersion {
490 read_version,
491 service,
492 builder: Cow::Owned(builder.clone()),
493 },
494 #[cfg(feature = "http1")]
495 ConnState::H1 { conn } => ConnState::H1 { conn },
496 #[cfg(feature = "http2")]
497 ConnState::H2 { conn } => ConnState::H2 { conn },
498 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
499 _ => unreachable!(),
500 },
501 }
502 }
503}
504
505impl<I, S, E, B> Future for Connection<'_, I, S, E>
506where
507 S: Service<Request<Incoming>, Response = Response<B>>,
508 S::Future: 'static,
509 S::Error: Into<Box<dyn StdError + Send + Sync>>,
510 B: Body + 'static,
511 B::Error: Into<Box<dyn StdError + Send + Sync>>,
512 I: Read + Write + Unpin + 'static,
513 E: HttpServerConnExec<S::Future, B>,
514{
515 type Output = Result<()>;
516
517 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
518 loop {
519 let mut this = self.as_mut().project();
520
521 match this.state.as_mut().project() {
522 ConnStateProj::ReadVersion {
523 read_version,
524 builder,
525 service,
526 } => {
527 let (version, io) = ready!(read_version.poll(cx))?;
528 let service = service.take().unwrap();
529 match version {
530 #[cfg(feature = "http1")]
531 Version::H1 => {
532 let conn = builder.http1.serve_connection(io, service);
533 this.state.set(ConnState::H1 { conn });
534 }
535 #[cfg(feature = "http2")]
536 Version::H2 => {
537 let conn = builder.http2.serve_connection(io, service);
538 this.state.set(ConnState::H2 { conn });
539 }
540 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
541 _ => return Poll::Ready(Err(version.unsupported())),
542 }
543 }
544 #[cfg(feature = "http1")]
545 ConnStateProj::H1 { conn } => {
546 return conn.poll(cx).map_err(Into::into);
547 }
548 #[cfg(feature = "http2")]
549 ConnStateProj::H2 { conn } => {
550 return conn.poll(cx).map_err(Into::into);
551 }
552 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
553 _ => unreachable!(),
554 }
555 }
556 }
557}
558
559pin_project! {
560 #[must_use = "futures do nothing unless polled"]
566 pub struct UpgradeableConnection<'a, I, S, E>
567 where
568 S: HttpService<Incoming>,
569 {
570 #[pin]
571 state: UpgradeableConnState<'a, I, S, E>,
572 }
573}
574
575#[cfg(feature = "http1")]
576type Http1UpgradeableConnection<I, S> = hyper::server::conn::http1::UpgradeableConnection<I, S>;
577
578#[cfg(not(feature = "http1"))]
579type Http1UpgradeableConnection<I, S> = (PhantomData<I>, PhantomData<S>);
580
581pin_project! {
582 #[project = UpgradeableConnStateProj]
583 enum UpgradeableConnState<'a, I, S, E>
584 where
585 S: HttpService<Incoming>,
586 {
587 ReadVersion {
588 #[pin]
589 read_version: ReadVersion<I>,
590 builder: Cow<'a, Builder<E>>,
591 service: Option<S>,
592 },
593 H1 {
594 #[pin]
595 conn: Http1UpgradeableConnection<Rewind<I>, S>,
596 },
597 H2 {
598 #[pin]
599 conn: Http2Connection<I, S, E>,
600 },
601 }
602}
603
604impl<I, S, E, B> UpgradeableConnection<'_, I, S, E>
605where
606 S: HttpService<Incoming, ResBody = B>,
607 S::Error: Into<Box<dyn StdError + Send + Sync>>,
608 I: Read + Write + Unpin,
609 B: Body + 'static,
610 B::Error: Into<Box<dyn StdError + Send + Sync>>,
611 E: HttpServerConnExec<S::Future, B>,
612{
613 pub fn graceful_shutdown(self: Pin<&mut Self>) {
622 match self.project().state.project() {
623 UpgradeableConnStateProj::ReadVersion { read_version, .. } => read_version.cancel(),
624 #[cfg(feature = "http1")]
625 UpgradeableConnStateProj::H1 { conn } => conn.graceful_shutdown(),
626 #[cfg(feature = "http2")]
627 UpgradeableConnStateProj::H2 { conn } => conn.graceful_shutdown(),
628 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
629 _ => unreachable!(),
630 }
631 }
632
633 pub fn into_owned(self) -> UpgradeableConnection<'static, I, S, E>
635 where
636 Builder<E>: Clone,
637 {
638 UpgradeableConnection {
639 state: match self.state {
640 UpgradeableConnState::ReadVersion {
641 read_version,
642 builder,
643 service,
644 } => UpgradeableConnState::ReadVersion {
645 read_version,
646 service,
647 builder: Cow::Owned(builder.clone()),
648 },
649 #[cfg(feature = "http1")]
650 UpgradeableConnState::H1 { conn } => UpgradeableConnState::H1 { conn },
651 #[cfg(feature = "http2")]
652 UpgradeableConnState::H2 { conn } => UpgradeableConnState::H2 { conn },
653 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
654 _ => unreachable!(),
655 },
656 }
657 }
658}
659
660impl<I, S, E, B> Future for UpgradeableConnection<'_, I, S, E>
661where
662 S: Service<Request<Incoming>, Response = Response<B>>,
663 S::Future: 'static,
664 S::Error: Into<Box<dyn StdError + Send + Sync>>,
665 B: Body + 'static,
666 B::Error: Into<Box<dyn StdError + Send + Sync>>,
667 I: Read + Write + Unpin + Send + 'static,
668 E: HttpServerConnExec<S::Future, B>,
669{
670 type Output = Result<()>;
671
672 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
673 loop {
674 let mut this = self.as_mut().project();
675
676 match this.state.as_mut().project() {
677 UpgradeableConnStateProj::ReadVersion {
678 read_version,
679 builder,
680 service,
681 } => {
682 let (version, io) = ready!(read_version.poll(cx))?;
683 let service = service.take().unwrap();
684 match version {
685 #[cfg(feature = "http1")]
686 Version::H1 => {
687 let conn = builder.http1.serve_connection(io, service).with_upgrades();
688 this.state.set(UpgradeableConnState::H1 { conn });
689 }
690 #[cfg(feature = "http2")]
691 Version::H2 => {
692 let conn = builder.http2.serve_connection(io, service);
693 this.state.set(UpgradeableConnState::H2 { conn });
694 }
695 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
696 _ => return Poll::Ready(Err(version.unsupported())),
697 }
698 }
699 #[cfg(feature = "http1")]
700 UpgradeableConnStateProj::H1 { conn } => {
701 return conn.poll(cx).map_err(Into::into);
702 }
703 #[cfg(feature = "http2")]
704 UpgradeableConnStateProj::H2 { conn } => {
705 return conn.poll(cx).map_err(Into::into);
706 }
707 #[cfg(any(not(feature = "http1"), not(feature = "http2")))]
708 _ => unreachable!(),
709 }
710 }
711 }
712}
713
714#[cfg(feature = "http1")]
716pub struct Http1Builder<'a, E> {
717 inner: &'a mut Builder<E>,
718}
719
720#[cfg(feature = "http1")]
721impl<E> Http1Builder<'_, E> {
722 #[cfg(feature = "http2")]
724 pub fn http2(&mut self) -> Http2Builder<'_, E> {
725 Http2Builder { inner: self.inner }
726 }
727
728 pub fn auto_date_header(&mut self, enabled: bool) -> &mut Self {
734 self.inner.http1.auto_date_header(enabled);
735 self
736 }
737
738 pub fn half_close(&mut self, val: bool) -> &mut Self {
747 self.inner.http1.half_close(val);
748 self
749 }
750
751 pub fn keep_alive(&mut self, val: bool) -> &mut Self {
755 self.inner.http1.keep_alive(val);
756 self
757 }
758
759 pub fn title_case_headers(&mut self, enabled: bool) -> &mut Self {
766 self.inner.http1.title_case_headers(enabled);
767 self
768 }
769
770 pub fn ignore_invalid_headers(&mut self, enabled: bool) -> &mut Self {
778 self.inner.http1.ignore_invalid_headers(enabled);
779 self
780 }
781
782 pub fn preserve_header_case(&mut self, enabled: bool) -> &mut Self {
796 self.inner.http1.preserve_header_case(enabled);
797 self
798 }
799
800 pub fn max_headers(&mut self, val: usize) -> &mut Self {
816 self.inner.http1.max_headers(val);
817 self
818 }
819
820 pub fn header_read_timeout(&mut self, read_timeout: impl Into<Option<Duration>>) -> &mut Self {
830 self.inner.http1.header_read_timeout(read_timeout);
831 self
832 }
833
834 pub fn writev(&mut self, val: bool) -> &mut Self {
847 self.inner.http1.writev(val);
848 self
849 }
850
851 pub fn max_buf_size(&mut self, max: usize) -> &mut Self {
859 self.inner.http1.max_buf_size(max);
860 self
861 }
862
863 pub fn pipeline_flush(&mut self, enabled: bool) -> &mut Self {
869 self.inner.http1.pipeline_flush(enabled);
870 self
871 }
872
873 pub fn timer<M>(&mut self, timer: M) -> &mut Self
875 where
876 M: Timer + Send + Sync + 'static,
877 {
878 self.inner.http1.timer(timer);
879 self
880 }
881
882 #[cfg(feature = "http2")]
884 pub async fn serve_connection<I, S, B>(&self, io: I, service: S) -> Result<()>
885 where
886 S: Service<Request<Incoming>, Response = Response<B>>,
887 S::Future: 'static,
888 S::Error: Into<Box<dyn StdError + Send + Sync>>,
889 B: Body + 'static,
890 B::Error: Into<Box<dyn StdError + Send + Sync>>,
891 I: Read + Write + Unpin + 'static,
892 E: HttpServerConnExec<S::Future, B>,
893 {
894 self.inner.serve_connection(io, service).await
895 }
896
897 #[cfg(not(feature = "http2"))]
899 pub async fn serve_connection<I, S, B>(&self, io: I, service: S) -> Result<()>
900 where
901 S: Service<Request<Incoming>, Response = Response<B>>,
902 S::Future: 'static,
903 S::Error: Into<Box<dyn StdError + Send + Sync>>,
904 B: Body + 'static,
905 B::Error: Into<Box<dyn StdError + Send + Sync>>,
906 I: Read + Write + Unpin + 'static,
907 {
908 self.inner.serve_connection(io, service).await
909 }
910
911 #[cfg(feature = "http2")]
915 pub fn serve_connection_with_upgrades<I, S, B>(
916 &self,
917 io: I,
918 service: S,
919 ) -> UpgradeableConnection<'_, I, S, E>
920 where
921 S: Service<Request<Incoming>, Response = Response<B>>,
922 S::Future: 'static,
923 S::Error: Into<Box<dyn StdError + Send + Sync>>,
924 B: Body + 'static,
925 B::Error: Into<Box<dyn StdError + Send + Sync>>,
926 I: Read + Write + Unpin + Send + 'static,
927 E: HttpServerConnExec<S::Future, B>,
928 {
929 self.inner.serve_connection_with_upgrades(io, service)
930 }
931}
932
933#[cfg(feature = "http2")]
935pub struct Http2Builder<'a, E> {
936 inner: &'a mut Builder<E>,
937}
938
939#[cfg(feature = "http2")]
940impl<E> Http2Builder<'_, E> {
941 #[cfg(feature = "http1")]
942 pub fn http1(&mut self) -> Http1Builder<'_, E> {
944 Http1Builder { inner: self.inner }
945 }
946
947 pub fn max_pending_accept_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {
954 self.inner.http2.max_pending_accept_reset_streams(max);
955 self
956 }
957
958 pub fn max_local_error_reset_streams(&mut self, max: impl Into<Option<usize>>) -> &mut Self {
967 self.inner.http2.max_local_error_reset_streams(max);
968 self
969 }
970
971 pub fn initial_stream_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
980 self.inner.http2.initial_stream_window_size(sz);
981 self
982 }
983
984 pub fn initial_connection_window_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
990 self.inner.http2.initial_connection_window_size(sz);
991 self
992 }
993
994 pub fn adaptive_window(&mut self, enabled: bool) -> &mut Self {
1000 self.inner.http2.adaptive_window(enabled);
1001 self
1002 }
1003
1004 pub fn max_frame_size(&mut self, sz: impl Into<Option<u32>>) -> &mut Self {
1010 self.inner.http2.max_frame_size(sz);
1011 self
1012 }
1013
1014 pub fn max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self {
1021 self.inner.http2.max_concurrent_streams(max);
1022 self
1023 }
1024
1025 pub fn keep_alive_interval(&mut self, interval: impl Into<Option<Duration>>) -> &mut Self {
1035 self.inner.http2.keep_alive_interval(interval);
1036 self
1037 }
1038
1039 pub fn keep_alive_timeout(&mut self, timeout: Duration) -> &mut Self {
1049 self.inner.http2.keep_alive_timeout(timeout);
1050 self
1051 }
1052
1053 pub fn max_send_buf_size(&mut self, max: usize) -> &mut Self {
1061 self.inner.http2.max_send_buf_size(max);
1062 self
1063 }
1064
1065 pub fn enable_connect_protocol(&mut self) -> &mut Self {
1069 self.inner.http2.enable_connect_protocol();
1070 self
1071 }
1072
1073 pub fn max_header_list_size(&mut self, max: u32) -> &mut Self {
1077 self.inner.http2.max_header_list_size(max);
1078 self
1079 }
1080
1081 pub fn timer<M>(&mut self, timer: M) -> &mut Self
1083 where
1084 M: Timer + Send + Sync + 'static,
1085 {
1086 self.inner.http2.timer(timer);
1087 self
1088 }
1089
1090 pub fn auto_date_header(&mut self, enabled: bool) -> &mut Self {
1096 self.inner.http2.auto_date_header(enabled);
1097 self
1098 }
1099
1100 pub async fn serve_connection<I, S, B>(&self, io: I, service: S) -> Result<()>
1102 where
1103 S: Service<Request<Incoming>, Response = Response<B>>,
1104 S::Future: 'static,
1105 S::Error: Into<Box<dyn StdError + Send + Sync>>,
1106 B: Body + 'static,
1107 B::Error: Into<Box<dyn StdError + Send + Sync>>,
1108 I: Read + Write + Unpin + 'static,
1109 E: HttpServerConnExec<S::Future, B>,
1110 {
1111 self.inner.serve_connection(io, service).await
1112 }
1113
1114 pub fn serve_connection_with_upgrades<I, S, B>(
1118 &self,
1119 io: I,
1120 service: S,
1121 ) -> UpgradeableConnection<'_, I, S, E>
1122 where
1123 S: Service<Request<Incoming>, Response = Response<B>>,
1124 S::Future: 'static,
1125 S::Error: Into<Box<dyn StdError + Send + Sync>>,
1126 B: Body + 'static,
1127 B::Error: Into<Box<dyn StdError + Send + Sync>>,
1128 I: Read + Write + Unpin + Send + 'static,
1129 E: HttpServerConnExec<S::Future, B>,
1130 {
1131 self.inner.serve_connection_with_upgrades(io, service)
1132 }
1133}
1134
1135#[cfg(all(feature = "tokio", test))]
1136mod tests {
1137 use crate::{
1138 rt::{TokioExecutor, TokioIo},
1139 server::conn::auto,
1140 };
1141 use http::{Request, Response};
1142 use http_body::Body;
1143 use http_body_util::{BodyExt, Empty, Full};
1144 use hyper::{body, body::Bytes, client, service::service_fn};
1145 use std::{convert::Infallible, error::Error as StdError, net::SocketAddr, time::Duration};
1146 use tokio::{
1147 net::{TcpListener, TcpStream},
1148 pin,
1149 };
1150
1151 const BODY: &[u8] = b"Hello, world!";
1152
1153 #[test]
1154 fn configuration() {
1155 auto::Builder::new(TokioExecutor::new())
1157 .http1()
1158 .keep_alive(true)
1159 .http2()
1160 .keep_alive_interval(None);
1161 let mut builder = auto::Builder::new(TokioExecutor::new());
1165
1166 builder.http1().keep_alive(true);
1167 builder.http2().keep_alive_interval(None);
1168 }
1170
1171 #[test]
1172 #[cfg(feature = "http1")]
1173 fn title_case_headers_configuration() {
1174 auto::Builder::new(TokioExecutor::new()).title_case_headers(true);
1176
1177 auto::Builder::new(TokioExecutor::new())
1179 .title_case_headers(true)
1180 .http1_only();
1181 }
1182
1183 #[test]
1184 #[cfg(feature = "http1")]
1185 fn preserve_header_case_configuration() {
1186 auto::Builder::new(TokioExecutor::new()).preserve_header_case(true);
1188
1189 auto::Builder::new(TokioExecutor::new())
1191 .preserve_header_case(true)
1192 .http1_only();
1193 }
1194
1195 #[cfg(not(miri))]
1196 #[tokio::test]
1197 async fn http1() {
1198 let addr = start_server(false, false).await;
1199 let mut sender = connect_h1(addr).await;
1200
1201 let response = sender
1202 .send_request(Request::new(Empty::<Bytes>::new()))
1203 .await
1204 .unwrap();
1205
1206 let body = response.into_body().collect().await.unwrap().to_bytes();
1207
1208 assert_eq!(body, BODY);
1209 }
1210
1211 #[cfg(not(miri))]
1212 #[tokio::test]
1213 async fn http2() {
1214 let addr = start_server(false, false).await;
1215 let mut sender = connect_h2(addr).await;
1216
1217 let response = sender
1218 .send_request(Request::new(Empty::<Bytes>::new()))
1219 .await
1220 .unwrap();
1221
1222 let body = response.into_body().collect().await.unwrap().to_bytes();
1223
1224 assert_eq!(body, BODY);
1225 }
1226
1227 #[cfg(not(miri))]
1228 #[tokio::test]
1229 async fn http2_only() {
1230 let addr = start_server(false, true).await;
1231 let mut sender = connect_h2(addr).await;
1232
1233 let response = sender
1234 .send_request(Request::new(Empty::<Bytes>::new()))
1235 .await
1236 .unwrap();
1237
1238 let body = response.into_body().collect().await.unwrap().to_bytes();
1239
1240 assert_eq!(body, BODY);
1241 }
1242
1243 #[cfg(not(miri))]
1244 #[tokio::test]
1245 async fn http2_only_fail_if_client_is_http1() {
1246 let addr = start_server(false, true).await;
1247 let mut sender = connect_h1(addr).await;
1248
1249 let _ = sender
1250 .send_request(Request::new(Empty::<Bytes>::new()))
1251 .await
1252 .expect_err("should fail");
1253 }
1254
1255 #[cfg(not(miri))]
1256 #[tokio::test]
1257 async fn http1_only() {
1258 let addr = start_server(true, false).await;
1259 let mut sender = connect_h1(addr).await;
1260
1261 let response = sender
1262 .send_request(Request::new(Empty::<Bytes>::new()))
1263 .await
1264 .unwrap();
1265
1266 let body = response.into_body().collect().await.unwrap().to_bytes();
1267
1268 assert_eq!(body, BODY);
1269 }
1270
1271 #[cfg(not(miri))]
1272 #[tokio::test]
1273 async fn http1_only_fail_if_client_is_http2() {
1274 let addr = start_server(true, false).await;
1275 let mut sender = connect_h2(addr).await;
1276
1277 let _ = sender
1278 .send_request(Request::new(Empty::<Bytes>::new()))
1279 .await
1280 .expect_err("should fail");
1281 }
1282
1283 #[cfg(not(miri))]
1284 #[tokio::test]
1285 async fn graceful_shutdown() {
1286 let listener = TcpListener::bind(SocketAddr::from(([127, 0, 0, 1], 0)))
1287 .await
1288 .unwrap();
1289
1290 let listener_addr = listener.local_addr().unwrap();
1291
1292 let listen_task = tokio::spawn(async move { listener.accept().await.unwrap() });
1294 let _stream = TcpStream::connect(listener_addr).await.unwrap();
1296
1297 let (stream, _) = listen_task.await.unwrap();
1298 let stream = TokioIo::new(stream);
1299 let builder = auto::Builder::new(TokioExecutor::new());
1300 let connection = builder.serve_connection(stream, service_fn(hello));
1301
1302 pin!(connection);
1303
1304 connection.as_mut().graceful_shutdown();
1305
1306 let connection_error = tokio::time::timeout(Duration::from_millis(200), connection)
1307 .await
1308 .expect("Connection should have finished in a timely manner after graceful shutdown.")
1309 .expect_err("Connection should have been interrupted.");
1310
1311 let connection_error = connection_error
1312 .downcast_ref::<std::io::Error>()
1313 .expect("The error should have been `std::io::Error`.");
1314 assert_eq!(connection_error.kind(), std::io::ErrorKind::Interrupted);
1315 }
1316
1317 async fn connect_h1<B>(addr: SocketAddr) -> client::conn::http1::SendRequest<B>
1318 where
1319 B: Body + Send + 'static,
1320 B::Data: Send,
1321 B::Error: Into<Box<dyn StdError + Send + Sync>>,
1322 {
1323 let stream = TokioIo::new(TcpStream::connect(addr).await.unwrap());
1324 let (sender, connection) = client::conn::http1::handshake(stream).await.unwrap();
1325
1326 tokio::spawn(connection);
1327
1328 sender
1329 }
1330
1331 async fn connect_h2<B>(addr: SocketAddr) -> client::conn::http2::SendRequest<B>
1332 where
1333 B: Body + Unpin + Send + 'static,
1334 B::Data: Send,
1335 B::Error: Into<Box<dyn StdError + Send + Sync>>,
1336 {
1337 let stream = TokioIo::new(TcpStream::connect(addr).await.unwrap());
1338 let (sender, connection) = client::conn::http2::Builder::new(TokioExecutor::new())
1339 .handshake(stream)
1340 .await
1341 .unwrap();
1342
1343 tokio::spawn(connection);
1344
1345 sender
1346 }
1347
1348 async fn start_server(h1_only: bool, h2_only: bool) -> SocketAddr {
1349 let addr: SocketAddr = ([127, 0, 0, 1], 0).into();
1350 let listener = TcpListener::bind(addr).await.unwrap();
1351
1352 let local_addr = listener.local_addr().unwrap();
1353
1354 tokio::spawn(async move {
1355 loop {
1356 let (stream, _) = listener.accept().await.unwrap();
1357 let stream = TokioIo::new(stream);
1358 tokio::task::spawn(async move {
1359 let mut builder = auto::Builder::new(TokioExecutor::new());
1360 if h1_only {
1361 builder = builder.http1_only();
1362 builder.serve_connection(stream, service_fn(hello)).await
1363 } else if h2_only {
1364 builder = builder.http2_only();
1365 builder.serve_connection(stream, service_fn(hello)).await
1366 } else {
1367 builder
1368 .http2()
1369 .max_header_list_size(4096)
1370 .serve_connection_with_upgrades(stream, service_fn(hello))
1371 .await
1372 }
1373 .unwrap();
1374 });
1375 }
1376 });
1377
1378 local_addr
1379 }
1380
1381 async fn hello(_req: Request<body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
1382 Ok(Response::new(Full::new(Bytes::from(BODY))))
1383 }
1384}