Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a setter for header_table_size #638

Merged
merged 2 commits into from Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/client.rs
Expand Up @@ -1072,6 +1072,39 @@ 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 is 4,096.
///
/// # Examples
///
/// ```
/// # use tokio::io::{AsyncRead, AsyncWrite};
/// # use h2::client::*;
/// # use bytes::Bytes;
/// #
/// # async fn doc<T: AsyncRead + AsyncWrite + Unpin>(my_io: T)
/// # -> Result<((SendRequest<Bytes>, Connection<T, Bytes>)), h2::Error>
/// # {
/// // `client_fut` is a future representing the completion of the HTTP/2
/// // handshake.
/// let client_fut = Builder::new()
/// .header_table_size(1_000_000)
/// .handshake(my_io);
/// # client_fut.await
/// # }
/// #
/// # pub fn main() {}
/// ```
pub fn header_table_size(&mut self, size: u32) -> &mut Self {
self.settings.set_header_table_size(Some(size));
self
}

/// Sets the first stream ID to something other than 1.
#[cfg(feature = "unstable")]
pub fn initial_stream_id(&mut self, stream_id: u32) -> &mut Self {
Expand Down
6 changes: 6 additions & 0 deletions src/codec/framed_read.rs
Expand Up @@ -88,6 +88,12 @@ impl<T> FramedRead<T> {
pub fn set_max_header_list_size(&mut self, val: usize) {
self.max_header_list_size = val;
}

/// Update the header table size setting.
#[inline]
pub fn set_header_table_size(&mut self, val: usize) {
self.hpack.queue_size_update(val);
}
}

/// Decodes a frame.
Expand Down
5 changes: 5 additions & 0 deletions src/codec/mod.rs
Expand Up @@ -95,6 +95,11 @@ impl<T, B> Codec<T, B> {
self.framed_write().set_header_table_size(val)
}

/// Set the decoder header table size size.
pub fn set_recv_header_table_size(&mut self, val: usize) {
self.inner.set_header_table_size(val)
}

/// Set the max header list size that can be received.
pub fn set_max_recv_header_list_size(&mut self, val: usize) {
self.inner.set_max_header_list_size(val);
Expand Down
2 changes: 0 additions & 2 deletions src/frame/settings.rs
Expand Up @@ -121,11 +121,9 @@ impl Settings {
self.header_table_size
}

/*
pub fn set_header_table_size(&mut self, size: Option<u32>) {
self.header_table_size = size;
}
*/

pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
use self::Setting::*;
Expand Down
4 changes: 4 additions & 0 deletions src/proto/settings.rs
Expand Up @@ -60,6 +60,10 @@ impl Settings {
codec.set_max_recv_header_list_size(max as usize);
}

if let Some(val) = local.header_table_size() {
codec.set_recv_header_table_size(val as usize);
}

streams.apply_local_settings(local)?;
self.local = Local::Synced;
Ok(())
Expand Down
5 changes: 5 additions & 0 deletions tests/h2-support/src/frames.rs
Expand Up @@ -391,6 +391,11 @@ impl Mock<frame::Settings> {
self.0.set_enable_connect_protocol(Some(val));
self
}

pub fn header_table_size(mut self, val: u32) -> Self {
self.0.set_header_table_size(Some(val));
self
}
}

impl From<Mock<frame::Settings>> for frame::Settings {
Expand Down
34 changes: 34 additions & 0 deletions tests/h2-tests/tests/client_request.rs
Expand Up @@ -1627,6 +1627,40 @@ async fn rogue_server_reused_headers() {
join(srv, h2).await;
}

#[tokio::test]
async fn client_builder_header_table_size() {
h2_support::trace_init!();
let (io, mut srv) = mock::new();
let mut settings = frame::Settings::default();

settings.set_header_table_size(Some(10000));

let srv = async move {
let recv_settings = srv.assert_client_handshake().await;
assert_frame_eq(recv_settings, settings);

srv.recv_frame(
frames::headers(1)
.request("GET", "https://example.com/")
.eos(),
)
.await;
srv.send_frame(frames::headers(1).response(200).eos()).await;
};

let mut builder = client::Builder::new();
builder.header_table_size(10000);

let h2 = async move {
let (mut client, mut h2) = builder.handshake::<_, Bytes>(io).await.unwrap();
let request = Request::get("https://example.com/").body(()).unwrap();
let (response, _) = client.send_request(request, true).unwrap();
h2.drive(response).await.unwrap();
};

join(srv, h2).await;
}

const SETTINGS: &[u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0];
const SETTINGS_ACK: &[u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0];

Expand Down