Respect SETTINGS_HEADER_TABLE_SIZE (#459)
This commit is contained in:
@@ -271,6 +271,11 @@ impl<T, B> FramedWrite<T, B> {
|
|||||||
self.max_frame_size = val as FrameSize;
|
self.max_frame_size = val as FrameSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the peer's header table size.
|
||||||
|
pub fn set_header_table_size(&mut self, val: usize) {
|
||||||
|
self.hpack.update_max_size(val);
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve the last data frame that has been sent
|
/// Retrieve the last data frame that has been sent
|
||||||
pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> {
|
pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> {
|
||||||
self.last_data_frame.take()
|
self.last_data_frame.take()
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ impl<T, B> Codec<T, B> {
|
|||||||
self.framed_write().set_max_frame_size(val)
|
self.framed_write().set_max_frame_size(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the peer's header table size size.
|
||||||
|
pub fn set_send_header_table_size(&mut self, val: usize) {
|
||||||
|
self.framed_write().set_header_table_size(val)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the max header list size that can be received.
|
/// Set the max header list size that can be received.
|
||||||
pub fn set_max_recv_header_list_size(&mut self, val: usize) {
|
pub fn set_max_recv_header_list_size(&mut self, val: usize) {
|
||||||
self.inner.set_max_header_list_size(val);
|
self.inner.set_max_header_list_size(val);
|
||||||
|
|||||||
@@ -107,6 +107,16 @@ impl Settings {
|
|||||||
self.enable_push = Some(enable as u32);
|
self.enable_push = Some(enable as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn header_table_size(&self) -> Option<u32> {
|
||||||
|
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> {
|
pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
|
||||||
use self::Setting::*;
|
use self::Setting::*;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ impl Encoder {
|
|||||||
/// Queues a max size update.
|
/// Queues a max size update.
|
||||||
///
|
///
|
||||||
/// The next call to `encode` will include a dynamic size update frame.
|
/// The next call to `encode` will include a dynamic size update frame.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn update_max_size(&mut self, val: usize) {
|
pub fn update_max_size(&mut self, val: usize) {
|
||||||
match self.size_update {
|
match self.size_update {
|
||||||
Some(SizeUpdate::One(old)) => {
|
Some(SizeUpdate::One(old)) => {
|
||||||
|
|||||||
@@ -117,6 +117,10 @@ impl Settings {
|
|||||||
|
|
||||||
log::trace!("ACK sent; applying settings");
|
log::trace!("ACK sent; applying settings");
|
||||||
|
|
||||||
|
if let Some(val) = settings.header_table_size() {
|
||||||
|
dst.set_send_header_table_size(val as usize);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(val) = settings.max_frame_size() {
|
if let Some(val) = settings.max_frame_size() {
|
||||||
dst.set_max_send_frame_size(val as usize);
|
dst.set_max_send_frame_size(val as usize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ pub use tokio::io::{AsyncRead, AsyncWrite};
|
|||||||
pub use std::thread;
|
pub use std::thread;
|
||||||
pub use std::time::Duration;
|
pub use std::time::Duration;
|
||||||
|
|
||||||
|
pub static MAGIC_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
|
||||||
|
|
||||||
// ===== Everything under here shouldn't be used =====
|
// ===== Everything under here shouldn't be used =====
|
||||||
// TODO: work on deleting this code
|
// TODO: work on deleting this code
|
||||||
|
|
||||||
@@ -62,14 +64,20 @@ use std::pin::Pin;
|
|||||||
|
|
||||||
pub trait MockH2 {
|
pub trait MockH2 {
|
||||||
fn handshake(&mut self) -> &mut Self;
|
fn handshake(&mut self) -> &mut Self;
|
||||||
|
|
||||||
|
fn handshake_read_settings(&mut self, settings: &[u8]) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockH2 for tokio_test::io::Builder {
|
impl MockH2 for tokio_test::io::Builder {
|
||||||
fn handshake(&mut self) -> &mut Self {
|
fn handshake(&mut self) -> &mut Self {
|
||||||
self.write(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
|
self.handshake_read_settings(frames::SETTINGS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handshake_read_settings(&mut self, settings: &[u8]) -> &mut Self {
|
||||||
|
self.write(MAGIC_PREFACE)
|
||||||
// Settings frame
|
// Settings frame
|
||||||
.write(frames::SETTINGS)
|
.write(frames::SETTINGS)
|
||||||
.read(frames::SETTINGS)
|
.read(settings)
|
||||||
.read(frames::SETTINGS_ACK)
|
.read(frames::SETTINGS_ACK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,3 +51,90 @@ async fn write_continuation_frames() {
|
|||||||
|
|
||||||
join(srv, client).await;
|
join(srv, client).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn client_settings_header_table_size() {
|
||||||
|
// A server sets the SETTINGS_HEADER_TABLE_SIZE to 0, test that the
|
||||||
|
// client doesn't send indexed headers.
|
||||||
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
|
let io = mock_io::Builder::new()
|
||||||
|
// Read SETTINGS_HEADER_TABLE_SIZE = 0
|
||||||
|
.handshake_read_settings(&[
|
||||||
|
0, 0, 6, // len
|
||||||
|
4, // type
|
||||||
|
0, // flags
|
||||||
|
0, 0, 0, 0, // stream id
|
||||||
|
0, 0x1, // id = SETTINGS_HEADER_TABLE_SIZE
|
||||||
|
0, 0, 0, 0, // value = 0
|
||||||
|
])
|
||||||
|
// Write GET / (1st)
|
||||||
|
.write(&[
|
||||||
|
0, 0, 0x10, 1, 5, 0, 0, 0, 1, 0x82, 0x87, 0x41, 0x8B, 0x9D, 0x29, 0xAC, 0x4B, 0x8F,
|
||||||
|
0xA8, 0xE9, 0x19, 0x97, 0x21, 0xE9, 0x84,
|
||||||
|
])
|
||||||
|
.write(frames::SETTINGS_ACK)
|
||||||
|
// Read response
|
||||||
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 137])
|
||||||
|
// Write GET / (2nd, doesn't use indexed headers)
|
||||||
|
// - Sends 0x20 about size change
|
||||||
|
// - Sends :authority as literal instead of indexed
|
||||||
|
.write(&[
|
||||||
|
0, 0, 0x11, 1, 5, 0, 0, 0, 3, 0x20, 0x82, 0x87, 0x1, 0x8B, 0x9D, 0x29, 0xAC, 0x4B,
|
||||||
|
0x8F, 0xA8, 0xE9, 0x19, 0x97, 0x21, 0xE9, 0x84,
|
||||||
|
])
|
||||||
|
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 3, 137])
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let (mut client, mut conn) = client::handshake(io).await.expect("handshake");
|
||||||
|
|
||||||
|
let req1 = client.get("https://http2.akamai.com");
|
||||||
|
conn.drive(req1).await.expect("req1");
|
||||||
|
|
||||||
|
let req2 = client.get("https://http2.akamai.com");
|
||||||
|
conn.drive(req2).await.expect("req1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn server_settings_header_table_size() {
|
||||||
|
// A client sets the SETTINGS_HEADER_TABLE_SIZE to 0, test that the
|
||||||
|
// server doesn't send indexed headers.
|
||||||
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
|
let io = mock_io::Builder::new()
|
||||||
|
.read(MAGIC_PREFACE)
|
||||||
|
// Read SETTINGS_HEADER_TABLE_SIZE = 0
|
||||||
|
.read(&[
|
||||||
|
0, 0, 6, // len
|
||||||
|
4, // type
|
||||||
|
0, // flags
|
||||||
|
0, 0, 0, 0, // stream id
|
||||||
|
0, 0x1, // id = SETTINGS_HEADER_TABLE_SIZE
|
||||||
|
0, 0, 0, 0, // value = 0
|
||||||
|
])
|
||||||
|
.write(frames::SETTINGS)
|
||||||
|
.write(frames::SETTINGS_ACK)
|
||||||
|
.read(frames::SETTINGS_ACK)
|
||||||
|
// Write GET /
|
||||||
|
.read(&[
|
||||||
|
0, 0, 0x10, 1, 5, 0, 0, 0, 1, 0x82, 0x87, 0x41, 0x8B, 0x9D, 0x29, 0xAC, 0x4B, 0x8F,
|
||||||
|
0xA8, 0xE9, 0x19, 0x97, 0x21, 0xE9, 0x84,
|
||||||
|
])
|
||||||
|
// Read response
|
||||||
|
//.write(&[0, 0, 6, 1, 5, 0, 0, 0, 1, 136, 64, 129, 31, 129, 143])
|
||||||
|
.write(&[0, 0, 7, 1, 5, 0, 0, 0, 1, 32, 136, 0, 129, 31, 129, 143])
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let mut srv = server::handshake(io).await.expect("handshake");
|
||||||
|
|
||||||
|
let (_req, mut stream) = srv.accept().await.unwrap().unwrap();
|
||||||
|
|
||||||
|
let rsp = http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("a", "b")
|
||||||
|
.body(())
|
||||||
|
.unwrap();
|
||||||
|
stream.send_response(rsp, true).unwrap();
|
||||||
|
|
||||||
|
assert!(srv.accept().await.is_none());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user