Skip to content

Commit 6eae286

Browse files
committed
Add optional max header list size
Prior to parsing headers, both the request and response parsers now check that the remaining buffer length does not exceed the configured max size. If the length does exceed the max size, a new HeadersTooLarge error is returned.
1 parent 0f5e6fb commit 6eae286

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

src/lib.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ pub enum Error {
161161
TooManyHeaders,
162162
/// Invalid byte in HTTP version.
163163
Version,
164+
/// Unparsed headers are larger than the configured max size.
165+
HeadersTooLarge,
164166
}
165167

166168
impl Error {
@@ -174,6 +176,7 @@ impl Error {
174176
Error::Token => "invalid token",
175177
Error::TooManyHeaders => "too many headers",
176178
Error::Version => "invalid HTTP version",
179+
Error::HeadersTooLarge => "headers too large",
177180
}
178181
}
179182
}
@@ -262,6 +265,7 @@ pub struct ParserConfig {
262265
allow_space_before_first_header_name: bool,
263266
ignore_invalid_headers_in_responses: bool,
264267
ignore_invalid_headers_in_requests: bool,
268+
max_header_list_size: Option<usize>,
265269
}
266270

267271
impl ParserConfig {
@@ -474,6 +478,18 @@ impl ParserConfig {
474478
) -> Result<usize> {
475479
response.parse_with_config_and_uninit_headers(buf, self, headers)
476480
}
481+
482+
/// Set the maximum size of all headers.
483+
///
484+
/// The value is based on the size of unparsed header fields, including the
485+
/// length of the name and value in octets, an overhead of 24 octets for
486+
/// each header field and 8 octets for each additional whitespace.
487+
///
488+
/// Default is unlimited.
489+
pub fn max_header_list_size(&mut self, val: usize) -> &mut Self {
490+
self.max_header_list_size = Some(val);
491+
self
492+
}
477493
}
478494

479495
/// A parsed Request.
@@ -547,6 +563,11 @@ impl<'h, 'b> Request<'h, 'b> {
547563
newline!(bytes);
548564

549565
let len = orig_len - bytes.len();
566+
if let Some(max) = config.max_header_list_size {
567+
if len > max {
568+
return Err(Error::HeadersTooLarge);
569+
}
570+
}
550571
let headers_len = complete!(parse_headers_iter_uninit(
551572
&mut headers,
552573
&mut bytes,
@@ -745,6 +766,11 @@ impl<'h, 'b> Response<'h, 'b> {
745766

746767

747768
let len = orig_len - bytes.len();
769+
if let Some(max) = config.max_header_list_size {
770+
if len > max {
771+
return Err(Error::HeadersTooLarge);
772+
}
773+
}
748774
let headers_len = complete!(parse_headers_iter_uninit(
749775
&mut headers,
750776
&mut bytes,
@@ -2558,7 +2584,7 @@ mod tests {
25582584
assert!(method.as_ptr() <= buf_end);
25592585
}
25602586

2561-
static RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER: &[u8] =
2587+
static RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER: &[u8] =
25622588
b"HTTP/1.1 200 OK\r\n Space-Before-Header: hello there\r\n\r\n";
25632589

25642590
#[test]
@@ -2591,4 +2617,40 @@ mod tests {
25912617
assert_eq!(response.headers[0].name, "Space-Before-Header");
25922618
assert_eq!(response.headers[0].value, &b"hello there"[..]);
25932619
}
2620+
2621+
#[test]
2622+
fn test_request_max_header_list_size() {
2623+
const REQUEST: &[u8] = b"GET / HTTP/1.1\r\nHeader: value\r\n\r\n";
2624+
2625+
let mut headers = [EMPTY_HEADER; 1];
2626+
let mut request = Request::new(&mut headers[..]);
2627+
2628+
let result = crate::ParserConfig::default()
2629+
.max_header_list_size(10)
2630+
.parse_request(&mut request, REQUEST);
2631+
assert_eq!(result, Err(crate::Error::HeadersTooLarge));
2632+
2633+
let result = crate::ParserConfig::default()
2634+
.max_header_list_size(17)
2635+
.parse_request(&mut request, REQUEST);
2636+
assert_eq!(result, Ok(Status::Complete(REQUEST.len())));
2637+
}
2638+
2639+
#[test]
2640+
fn test_response_max_header_list_size() {
2641+
const RESPONSE: &[u8] = b"HTTP/1.1 200 OK\r\nHeader: value\r\n\r\n";
2642+
2643+
let mut headers = [EMPTY_HEADER; 1];
2644+
let mut response = Response::new(&mut headers[..]);
2645+
2646+
let result = crate::ParserConfig::default()
2647+
.max_header_list_size(10)
2648+
.parse_response(&mut response, RESPONSE);
2649+
assert_eq!(result, Err(crate::Error::HeadersTooLarge));
2650+
2651+
let result = crate::ParserConfig::default()
2652+
.max_header_list_size(17)
2653+
.parse_response(&mut response, RESPONSE);
2654+
assert_eq!(result, Ok(Status::Complete(RESPONSE.len())));
2655+
}
25942656
}

0 commit comments

Comments
 (0)