feat(server): add http2_max_concurrent_streams builder option
				
					
				
			Closes #1772
This commit is contained in:
		| @@ -50,9 +50,8 @@ where | |||||||
|     B: Payload, |     B: Payload, | ||||||
|     E: H2Exec<S::Future, B>, |     E: H2Exec<S::Future, B>, | ||||||
| { | { | ||||||
|     pub(crate) fn new(io: T, service: S, exec: E) -> Server<T, S, B, E> { |     pub(crate) fn new(io: T, service: S, builder: &Builder, exec: E) -> Server<T, S, B, E> { | ||||||
|         let handshake = Builder::new() |         let handshake = builder.handshake(io); | ||||||
|             .handshake(io); |  | ||||||
|         Server { |         Server { | ||||||
|             exec, |             exec, | ||||||
|             state: State::Handshaking(handshake), |             state: State::Handshaking(handshake), | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ use std::sync::Arc; | |||||||
| use bytes::Bytes; | use bytes::Bytes; | ||||||
| use futures::{Async, Future, Poll, Stream}; | use futures::{Async, Future, Poll, Stream}; | ||||||
| use futures::future::{Either, Executor}; | use futures::future::{Either, Executor}; | ||||||
|  | use h2; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| #[cfg(feature = "runtime")] use tokio_reactor::Handle; | #[cfg(feature = "runtime")] use tokio_reactor::Handle; | ||||||
|  |  | ||||||
| @@ -46,6 +47,7 @@ pub struct Http<E = Exec> { | |||||||
|     exec: E, |     exec: E, | ||||||
|     h1_half_close: bool, |     h1_half_close: bool, | ||||||
|     h1_writev: bool, |     h1_writev: bool, | ||||||
|  |     h2_builder: h2::server::Builder, | ||||||
|     mode: ConnectionMode, |     mode: ConnectionMode, | ||||||
|     keep_alive: bool, |     keep_alive: bool, | ||||||
|     max_buf_size: Option<usize>, |     max_buf_size: Option<usize>, | ||||||
| @@ -120,14 +122,14 @@ where | |||||||
|  |  | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| enum Fallback<E> { | enum Fallback<E> { | ||||||
|     ToHttp2(E), |     ToHttp2(h2::server::Builder, E), | ||||||
|     Http1Only, |     Http1Only, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<E> Fallback<E> { | impl<E> Fallback<E> { | ||||||
|     fn to_h2(&self) -> bool { |     fn to_h2(&self) -> bool { | ||||||
|         match *self { |         match *self { | ||||||
|             Fallback::ToHttp2(_) => true, |             Fallback::ToHttp2(..) => true, | ||||||
|             Fallback::Http1Only => false, |             Fallback::Http1Only => false, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -165,6 +167,7 @@ impl Http { | |||||||
|             exec: Exec::Default, |             exec: Exec::Default, | ||||||
|             h1_half_close: true, |             h1_half_close: true, | ||||||
|             h1_writev: true, |             h1_writev: true, | ||||||
|  |             h2_builder: h2::server::Builder::default(), | ||||||
|             mode: ConnectionMode::Fallback, |             mode: ConnectionMode::Fallback, | ||||||
|             keep_alive: true, |             keep_alive: true, | ||||||
|             max_buf_size: None, |             max_buf_size: None, | ||||||
| @@ -236,6 +239,19 @@ impl<E> Http<E> { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2 | ||||||
|  |     /// connections. | ||||||
|  |     /// | ||||||
|  |     /// Default is no limit (`None`). | ||||||
|  |     /// | ||||||
|  |     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS | ||||||
|  |     pub fn http2_max_concurrent_streams(&mut self, max: impl Into<Option<u32>>) -> &mut Self { | ||||||
|  |         if let Some(max) = max.into() { | ||||||
|  |             self.h2_builder.max_concurrent_streams(max); | ||||||
|  |         } | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Enables or disables HTTP keep-alive. |     /// Enables or disables HTTP keep-alive. | ||||||
|     /// |     /// | ||||||
|     /// Default is true. |     /// Default is true. | ||||||
| @@ -278,6 +294,7 @@ impl<E> Http<E> { | |||||||
|             exec, |             exec, | ||||||
|             h1_half_close: self.h1_half_close, |             h1_half_close: self.h1_half_close, | ||||||
|             h1_writev: self.h1_writev, |             h1_writev: self.h1_writev, | ||||||
|  |             h2_builder: self.h2_builder, | ||||||
|             mode: self.mode, |             mode: self.mode, | ||||||
|             keep_alive: self.keep_alive, |             keep_alive: self.keep_alive, | ||||||
|             max_buf_size: self.max_buf_size, |             max_buf_size: self.max_buf_size, | ||||||
| @@ -350,7 +367,7 @@ impl<E> Http<E> { | |||||||
|             } |             } | ||||||
|             ConnectionMode::H2Only => { |             ConnectionMode::H2Only => { | ||||||
|                 let rewind_io = Rewind::new(io); |                 let rewind_io = Rewind::new(io); | ||||||
|                 let h2 = proto::h2::Server::new(rewind_io, service, self.exec.clone()); |                 let h2 = proto::h2::Server::new(rewind_io, service, &self.h2_builder, self.exec.clone()); | ||||||
|                 Either::B(h2) |                 Either::B(h2) | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
| @@ -358,7 +375,7 @@ impl<E> Http<E> { | |||||||
|         Connection { |         Connection { | ||||||
|             conn: Some(either), |             conn: Some(either), | ||||||
|             fallback: if self.mode == ConnectionMode::Fallback { |             fallback: if self.mode == ConnectionMode::Fallback { | ||||||
|                 Fallback::ToHttp2(self.exec.clone()) |                 Fallback::ToHttp2(self.h2_builder.clone(), self.exec.clone()) | ||||||
|             } else { |             } else { | ||||||
|                 Fallback::Http1Only |                 Fallback::Http1Only | ||||||
|             }, |             }, | ||||||
| @@ -538,11 +555,16 @@ where | |||||||
|         }; |         }; | ||||||
|         let mut rewind_io = Rewind::new(io); |         let mut rewind_io = Rewind::new(io); | ||||||
|         rewind_io.rewind(read_buf); |         rewind_io.rewind(read_buf); | ||||||
|         let exec = match self.fallback { |         let (builder, exec) = match self.fallback { | ||||||
|             Fallback::ToHttp2(ref exec) => exec.clone(), |             Fallback::ToHttp2(ref builder, ref exec) => (builder, exec), | ||||||
|             Fallback::Http1Only => unreachable!("upgrade_h2 with Fallback::Http1Only"), |             Fallback::Http1Only => unreachable!("upgrade_h2 with Fallback::Http1Only"), | ||||||
|         }; |         }; | ||||||
|         let h2 = proto::h2::Server::new(rewind_io, dispatch.into_service(), exec); |         let h2 = proto::h2::Server::new( | ||||||
|  |             rewind_io, | ||||||
|  |             dispatch.into_service(), | ||||||
|  |             builder, | ||||||
|  |             exec.clone(), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|         debug_assert!(self.conn.is_none()); |         debug_assert!(self.conn.is_none()); | ||||||
|         self.conn = Some(Either::B(h2)); |         self.conn = Some(Either::B(h2)); | ||||||
|   | |||||||
| @@ -302,6 +302,17 @@ impl<I, E> Builder<I, E> { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Sets the [`SETTINGS_MAX_CONCURRENT_STREAMS`][spec] option for HTTP2 | ||||||
|  |     /// connections. | ||||||
|  |     /// | ||||||
|  |     /// Default is no limit (`None`). | ||||||
|  |     /// | ||||||
|  |     /// [spec]: https://http2.github.io/http2-spec/#SETTINGS_MAX_CONCURRENT_STREAMS | ||||||
|  |     pub fn http2_max_concurrent_streams(mut self, max: impl Into<Option<u32>>) -> Self { | ||||||
|  |         self.protocol.http2_max_concurrent_streams(max.into()); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Set the maximum buffer size. |     /// Set the maximum buffer size. | ||||||
|     /// |     /// | ||||||
|     /// Default is ~ 400kb. |     /// Default is ~ 400kb. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user