Skip to content

Commit 7244d92

Browse files
committed
Allow ignoring invalid header lines (fixes #61, #83)
1 parent dcb18ab commit 7244d92

File tree

1 file changed

+104
-7
lines changed

1 file changed

+104
-7
lines changed

src/lib.rs

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,11 @@ pub struct ParserConfig {
247247
allow_obsolete_multiline_headers_in_responses: bool,
248248
allow_multiple_spaces_in_request_line_delimiters: bool,
249249
allow_multiple_spaces_in_response_status_delimiters: bool,
250+
ignore_invalid_header_lines_in_responses: bool,
250251
}
251252

252253
impl ParserConfig {
253-
/// Sets whether spaces should be allowed after header name.
254+
/// Sets whether spaces and tabs should be allowed after header names in responses.
254255
pub fn allow_spaces_after_header_name_in_responses(
255256
&mut self,
256257
value: bool,
@@ -361,6 +362,15 @@ impl ParserConfig {
361362
request.parse_with_config_and_uninit_headers(buf, self, headers)
362363
}
363364

365+
/// Sets whether invalid header lines should be silently ignored in responses.
366+
pub fn ignore_invalid_header_lines_in_responses(
367+
&mut self,
368+
value: bool,
369+
) -> &mut Self {
370+
self.ignore_invalid_header_lines_in_responses = value;
371+
self
372+
}
373+
364374
/// Parses a response with the given config.
365375
pub fn parse_response<'headers, 'buf>(
366376
&self,
@@ -935,11 +945,6 @@ fn parse_headers_iter_uninit<'a, 'b>(
935945
return Err(Error::HeaderName);
936946
}
937947

938-
let uninit_header = match iter.next() {
939-
Some(header) => header,
940-
None => break 'headers
941-
};
942-
943948
// parse header name until colon
944949
let header_name: &str = 'name: loop {
945950
let mut b = next!(bytes);
@@ -969,7 +974,23 @@ fn parse_headers_iter_uninit<'a, 'b>(
969974
}
970975
}
971976

972-
return Err(Error::HeaderName);
977+
if !config.ignore_invalid_header_lines_in_responses {
978+
return Err(Error::HeaderName);
979+
}
980+
981+
while b != b'\n' {
982+
b = next!(bytes);
983+
}
984+
985+
count += bytes.pos();
986+
bytes.slice();
987+
988+
continue 'headers;
989+
};
990+
991+
let uninit_header = match iter.next() {
992+
Some(header) => header,
993+
None => break 'headers
973994
};
974995

975996
let mut b;
@@ -1629,6 +1650,23 @@ mod tests {
16291650
assert_eq!(response.headers[1].value, &b"baguette"[..]);
16301651
}
16311652

1653+
#[test]
1654+
fn test_ignore_header_line_with_whitespaces_after_header_name() {
1655+
let mut headers = [EMPTY_HEADER; 2];
1656+
let mut response = Response::new(&mut headers[..]);
1657+
let result = ::ParserConfig::default()
1658+
.ignore_invalid_header_lines_in_responses(true)
1659+
.parse_response(&mut response, RESPONSE_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
1660+
1661+
assert_eq!(result, Ok(Status::Complete(77)));
1662+
assert_eq!(response.version.unwrap(), 1);
1663+
assert_eq!(response.code.unwrap(), 200);
1664+
assert_eq!(response.reason.unwrap(), "OK");
1665+
assert_eq!(response.headers.len(), 1);
1666+
assert_eq!(response.headers[0].name, "Bread");
1667+
assert_eq!(response.headers[0].value, &b"baguette"[..]);
1668+
}
1669+
16321670
static REQUEST_WITH_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &'static [u8] =
16331671
b"GET / HTTP/1.1\r\nHost : localhost\r\n\r\n";
16341672

@@ -1914,4 +1952,63 @@ mod tests {
19141952

19151953
assert_eq!(result, Err(::Error::HeaderName));
19161954
}
1955+
1956+
#[test]
1957+
fn test_ignore_header_line_with_invalid_char_after_header_name() {
1958+
let mut headers = [EMPTY_HEADER; 2];
1959+
let mut response = Response::new(&mut headers[..]);
1960+
let result = ::ParserConfig::default()
1961+
.ignore_invalid_header_lines_in_responses(true)
1962+
.parse_response(&mut response, RESPONSE_WITH_INVALID_CHAR_BETWEEN_HEADER_NAME_AND_COLON);
1963+
1964+
assert_eq!(result, Ok(Status::Complete(77)));
1965+
assert_eq!(response.version.unwrap(), 1);
1966+
assert_eq!(response.code.unwrap(), 200);
1967+
assert_eq!(response.reason.unwrap(), "OK");
1968+
assert_eq!(response.headers.len(), 1);
1969+
assert_eq!(response.headers[0].name, "Bread");
1970+
assert_eq!(response.headers[0].value, &b"baguette"[..]);
1971+
}
1972+
1973+
static RESPONSE_WITH_MISSING_COLON: &'static [u8] =
1974+
b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials\r\nBread: baguette\r\n\r\n";
1975+
1976+
#[test]
1977+
fn test_ignore_header_line_with_missing_colon() {
1978+
let mut headers = [EMPTY_HEADER; 2];
1979+
let mut response = Response::new(&mut headers[..]);
1980+
let result = ::ParserConfig::default()
1981+
.ignore_invalid_header_lines_in_responses(true)
1982+
.parse_response(&mut response, RESPONSE_WITH_MISSING_COLON);
1983+
1984+
assert_eq!(result, Ok(Status::Complete(70)));
1985+
assert_eq!(response.version.unwrap(), 1);
1986+
assert_eq!(response.code.unwrap(), 200);
1987+
assert_eq!(response.reason.unwrap(), "OK");
1988+
assert_eq!(response.headers.len(), 1);
1989+
assert_eq!(response.headers[0].name, "Bread");
1990+
assert_eq!(response.headers[0].value, &b"baguette"[..]);
1991+
}
1992+
1993+
static RESPONSE_WITH_INVALID_CHAR_AFTER_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON: &'static [u8] =
1994+
b"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Credentials \xFF: true\r\nBread: baguette\r\n\r\n";
1995+
1996+
#[test]
1997+
fn test_ignore_header_line_with_invalid_char_after_whitespace() {
1998+
let mut headers = [EMPTY_HEADER; 2];
1999+
let mut response = Response::new(&mut headers[..]);
2000+
let result = ::ParserConfig::default()
2001+
.allow_spaces_after_header_name_in_responses(true)
2002+
.ignore_invalid_header_lines_in_responses(true)
2003+
.parse_response(&mut response, RESPONSE_WITH_INVALID_CHAR_AFTER_WHITESPACE_BETWEEN_HEADER_NAME_AND_COLON);
2004+
2005+
assert_eq!(result, Ok(Status::Complete(81)));
2006+
assert_eq!(response.version.unwrap(), 1);
2007+
assert_eq!(response.code.unwrap(), 200);
2008+
assert_eq!(response.reason.unwrap(), "OK");
2009+
assert_eq!(response.headers.len(), 1);
2010+
assert_eq!(response.headers[0].name, "Bread");
2011+
assert_eq!(response.headers[0].value, &b"baguette"[..]);
2012+
}
2013+
19172014
}

0 commit comments

Comments
 (0)