Skip to content

Commit 5654959

Browse files
authored
Fix token and uri parsers to disallow empty results (#111)
This fixes cases where the parser would accept non-compliant request lines including empty methods and paths. For the `token` grammar, [the spec][spec-token] is: ``` token = 1*tchar ``` `1*` is shorthand for one-or-more, so the empty string is not a valid `token`. For the path component of the request line, [the spec][spec-path] we're concerned with the `absolute-path` grammar: ``` absolute-path = 1*( "/" segment ) ``` While `segment` might be empty, there must be at least a `"/"` for it to be syntactically valid. I've added tests for these cases and their combination, and had to update the expected error of one of the existing URI tests which now fails sooner due to the empty path. [spec-token]: https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#tokens [spec-path]: https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#uri.references
1 parent 6f6ff10 commit 5654959

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

src/lib.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,12 @@ fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
660660

661661
#[inline]
662662
fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
663+
let b = next!(bytes);
664+
if !is_token(b) {
665+
// First char must be a token char, it can't be a space which would indicate an empty token.
666+
return Err(Error::Token);
667+
}
668+
663669
loop {
664670
let b = next!(bytes);
665671
if b == b' ' {
@@ -675,6 +681,12 @@ fn parse_token<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
675681

676682
#[inline]
677683
fn parse_uri<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
684+
let b = next!(bytes);
685+
if !is_uri_token(b) {
686+
// First char must be a URI char, it can't be a space which would indicate an empty path.
687+
return Err(Error::Token);
688+
}
689+
678690
simd::match_uri_vectored(bytes);
679691

680692
loop {
@@ -1310,6 +1322,27 @@ mod tests {
13101322
|_r| {}
13111323
}
13121324

1325+
req! {
1326+
test_request_with_empty_method,
1327+
b" / HTTP/1.1\r\n\r\n",
1328+
Err(::Error::Token),
1329+
|_r| {}
1330+
}
1331+
1332+
req! {
1333+
test_request_with_empty_path,
1334+
b"GET HTTP/1.1\r\n\r\n",
1335+
Err(::Error::Token),
1336+
|_r| {}
1337+
}
1338+
1339+
req! {
1340+
test_request_with_empty_method_and_path,
1341+
b" HTTP/1.1\r\n\r\n",
1342+
Err(::Error::Token),
1343+
|_r| {}
1344+
}
1345+
13131346
macro_rules! res {
13141347
($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
13151348
res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }

tests/uri.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ req! {
111111
req! {
112112
urltest_007,
113113
b"GET foo.com HTTP/1.1\r\nHost: \r\n\r\n",
114-
Err(Error::Version),
114+
Err(Error::Token),
115115
|_r| {}
116116
}
117117

0 commit comments

Comments
 (0)