diff --git a/Cargo.toml b/Cargo.toml index 793745e819..6c270b39de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ atomic-waker = { version = "1.1.2", optional = true } futures-channel = { version = "0.3", optional = true } futures-core = { version = "0.3.31", optional = true } futures-util = { version = "0.3", default-features = false, features = ["alloc"], optional = true } -h2 = { version = "0.4.6", optional = true } +h2 = { version = "0.4.14", optional = true } http-body-util = { version = "0.1", optional = true } httparse = { version = "1.9", optional = true } httpdate = { version = "1.0", optional = true } diff --git a/src/proto/h2/server.rs b/src/proto/h2/server.rs index 483ed96dd9..6180ce8f80 100644 --- a/src/proto/h2/server.rs +++ b/src/proto/h2/server.rs @@ -53,6 +53,7 @@ pub(crate) struct Config { pub(crate) keep_alive_interval: Option, pub(crate) keep_alive_timeout: Duration, pub(crate) max_send_buffer_size: usize, + pub(crate) header_table_size: Option, pub(crate) max_header_list_size: u32, pub(crate) date_header: bool, } @@ -68,6 +69,7 @@ impl Default for Config { max_concurrent_streams: Some(200), max_pending_accept_reset_streams: None, max_local_error_reset_streams: Some(DEFAULT_MAX_LOCAL_ERROR_RESET_STREAMS), + header_table_size: None, keep_alive_interval: None, keep_alive_timeout: Duration::from_secs(20), max_send_buffer_size: DEFAULT_MAX_SEND_BUF_SIZE, @@ -142,6 +144,9 @@ where if let Some(max) = config.max_pending_accept_reset_streams { builder.max_pending_accept_reset_streams(max); } + if let Some(size) = config.header_table_size { + builder.header_table_size(size); + } if config.enable_connect_protocol { builder.enable_connect_protocol(); } diff --git a/src/server/conn/http2.rs b/src/server/conn/http2.rs index 0452109c3c..77b605a086 100644 --- a/src/server/conn/http2.rs +++ b/src/server/conn/http2.rs @@ -260,6 +260,18 @@ impl Builder { self } + /// Sets the header table size. + /// + /// This setting informs the peer of the maximum size of the header compression + /// table used to encode header blocks, in octets. The encoder may select any value + /// equal to or less than the header table size specified by the sender. + /// + /// The default value of crate `h2` is 4,096. + pub fn header_table_size(&mut self, size: impl Into>) -> &mut Self { + self.h2_builder.header_table_size = size.into(); + self + } + /// Sets the max size of received header frames. /// /// Default is currently 16KB, but can change. diff --git a/tests/server.rs b/tests/server.rs index 651fbdf40d..126a6e83fb 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2805,6 +2805,36 @@ async fn http2_keep_alive_count_server_pings() { .expect("timed out waiting for pings"); } +#[tokio::test] +async fn http2_header_table_size() { + let (listener, addr) = setup_tcp_listener(); + + tokio::spawn(async move { + let (socket, _) = listener.accept().await.expect("accept"); + let socket = TokioIo::new(socket); + + http2::Builder::new(TokioExecutor) + .header_table_size(8192) + .serve_connection(socket, HelloWorld) + .await + .expect("serve_connection"); + }); + + let tcp = TokioIo::new(connect_async(addr).await); + let (mut client, conn) = hyper::client::conn::http2::Builder::new(TokioExecutor) + .handshake(tcp) + .await + .expect("http handshake"); + + tokio::spawn(async move { + conn.await.expect("client conn"); + }); + + let req = http::Request::new(Empty::::new()); + let res = client.send_request(req).await.expect("client.send_request"); + assert_eq!(res.status(), StatusCode::OK); +} + #[test] fn http1_trailer_send_fields() { let body = futures_util::stream::once(async move { Ok("hello".into()) });