Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ impl Error {
Error::new(Kind::Parse(Parse::TooLarge))
}

#[cfg(all(feature = "server", feature = "http1"))]
pub(super) fn new_uri_too_long() -> Error {
Error::new(Kind::Parse(Parse::UriTooLong))
}

#[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
pub(super) fn new_version_h2() -> Error {
Error::new(Kind::Parse(Parse::VersionH2))
Expand Down
97 changes: 97 additions & 0 deletions src/proto/h1/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@ where
let curr_len = self.read_buf.len();
if curr_len >= max {
debug!("max_buf_size ({}) reached, closing", max);
// When parsing a request and the start-line (request
// line) hasn't even finished — i.e. no newline has been
// seen yet — the overflow is caused by an oversized URI
// rather than the header fields, so report `414 URI Too
// Long` instead of `431 Request Header Fields Too Large`.
if S::is_server() && !self.read_buf.contains(&b'\n') {
return Poll::Ready(Err(crate::Error::new_uri_too_long()));
}
return Poll::Ready(Err(crate::Error::new_too_large()));
}
if curr_len > 0 {
Expand Down Expand Up @@ -968,4 +976,93 @@ mod tests {
// write_buf.headers.bytes.clear();
// })
// }

#[cfg(not(miri))]
#[cfg(feature = "server")]
#[tokio::test]
async fn parse_overlong_uri_is_uri_too_long() {
use crate::proto::h1::ServerTransaction;

let _ = pretty_env_logger::try_init();

// A request line whose URI overflows `max_buf_size` before any line
// terminator is seen should be reported as `414 URI Too Long` rather
// than `431 Request Header Fields Too Large`.
let max = MINIMUM_MAX_BUFFER_SIZE;
let mut req = b"GET /".to_vec();
req.resize(max, b'a');

let mock = Mock::new().read(&req).build();

let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(Compat::new(mock));
buffered.set_max_buf_size(max);

let err = futures_util::future::poll_fn(|cx| {
let parse_ctx = ParseContext {
cached_headers: &mut None,
req_method: &mut None,
h1_parser_config: Default::default(),
h1_max_headers: None,
preserve_header_case: false,
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
#[cfg(feature = "client")]
on_informational: &mut None,
};
buffered.parse::<ServerTransaction>(cx, parse_ctx)
})
.await
.expect_err("parse should fail");

assert!(
matches!(err.kind(), crate::error::Kind::Parse(crate::error::Parse::UriTooLong)),
"expected UriTooLong, got {:?}",
err,
);
}

#[cfg(not(miri))]
#[cfg(feature = "server")]
#[tokio::test]
async fn parse_overlong_headers_is_too_large() {
use crate::proto::h1::ServerTransaction;

let _ = pretty_env_logger::try_init();

// A complete request line followed by header fields that overflow
// `max_buf_size` should remain a `431` (`TooLarge`) error.
let max = MINIMUM_MAX_BUFFER_SIZE;
let mut req = b"GET / HTTP/1.1\r\nHost: x\r\nX: ".to_vec();
req.resize(max, b'a');

let mock = Mock::new().read(&req).build();

let mut buffered = Buffered::<_, Cursor<Vec<u8>>>::new(Compat::new(mock));
buffered.set_max_buf_size(max);

let err = futures_util::future::poll_fn(|cx| {
let parse_ctx = ParseContext {
cached_headers: &mut None,
req_method: &mut None,
h1_parser_config: Default::default(),
h1_max_headers: None,
preserve_header_case: false,
#[cfg(feature = "ffi")]
preserve_header_order: false,
h09_responses: false,
#[cfg(feature = "client")]
on_informational: &mut None,
};
buffered.parse::<ServerTransaction>(cx, parse_ctx)
})
.await
.expect_err("parse should fail");

assert!(
matches!(err.kind(), crate::error::Kind::Parse(crate::error::Parse::TooLarge)),
"expected TooLarge, got {:?}",
err,
);
}
}
6 changes: 4 additions & 2 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2739,7 +2739,9 @@ async fn max_buf_size() {
let mut buf = [0; 256];
tcp.read(&mut buf).expect("read 1");

let expected = "HTTP/1.1 431 ";
// The request line overflows the buffer before it is even complete,
// so this is reported as `414 URI Too Long`, not `431`.
let expected = "HTTP/1.1 414 ";
assert_eq!(s(&buf[..expected.len()]), expected);
});

Expand All @@ -2749,7 +2751,7 @@ async fn max_buf_size() {
.max_buf_size(MAX)
.serve_connection(socket, HelloWorld)
.await
.expect_err("should TooLarge error");
.expect_err("should UriTooLong error");
}

#[cfg(feature = "http1")]
Expand Down