Skip to content

Commit

Permalink
Add a setter for header_table_size (hyperium#638)
Browse files Browse the repository at this point in the history
Signed-off-by: Sven Pfennig <s.pfennig@reply.de>
  • Loading branch information
4JX authored and 0xE282B0 committed Jan 16, 2024
1 parent 7dda57a commit a885cb1
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 2 deletions.
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

0 comments on commit a885cb1

Please sign in to comment.