Skip to content

Commit 5f938ff

Browse files
authoredNov 29, 2021
fix(http1): return 414 when URI contains more than 65534 characters (#2706)
Previous behavior returned a 404 Bad Request. Conforms to HTTP 1.1 RFC. Closes #2701
1 parent 1010614 commit 5f938ff

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed
 

‎src/error.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub(super) enum Parse {
7171
#[cfg(feature = "http1")]
7272
VersionH2,
7373
Uri,
74+
UriTooLong,
7475
Header(Header),
7576
TooLarge,
7677
Status,
@@ -152,7 +153,10 @@ impl Error {
152153

153154
/// Returns true if this was an HTTP parse error caused by a message that was too large.
154155
pub fn is_parse_too_large(&self) -> bool {
155-
matches!(self.inner.kind, Kind::Parse(Parse::TooLarge))
156+
matches!(
157+
self.inner.kind,
158+
Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong)
159+
)
156160
}
157161

158162
/// Returns true if this was an HTTP parse error caused by an invalid response status code or
@@ -398,6 +402,7 @@ impl Error {
398402
#[cfg(feature = "http1")]
399403
Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
400404
Kind::Parse(Parse::Uri) => "invalid URI",
405+
Kind::Parse(Parse::UriTooLong) => "URI too long",
401406
Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed",
402407
#[cfg(feature = "http1")]
403408
Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => {

‎src/proto/h1/role.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::proto::{BodyLength, MessageHead, RequestHead, RequestLine};
2525

2626
const MAX_HEADERS: usize = 100;
2727
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
28+
const MAX_URI_LEN: usize = (u16::MAX - 1) as usize;
2829

2930
macro_rules! header_name {
3031
($bytes:expr) => {{
@@ -148,9 +149,13 @@ impl Http1Transaction for Server {
148149
Ok(httparse::Status::Complete(parsed_len)) => {
149150
trace!("Request.parse Complete({})", parsed_len);
150151
len = parsed_len;
152+
let uri = req.path.unwrap();
153+
if uri.len() > MAX_URI_LEN {
154+
return Err(Parse::UriTooLong);
155+
}
151156
subject = RequestLine(
152157
Method::from_bytes(req.method.unwrap().as_bytes())?,
153-
req.path.unwrap().parse()?,
158+
uri.parse()?,
154159
);
155160
version = if req.version.unwrap() == 1 {
156161
keep_alive = true;
@@ -408,6 +413,7 @@ impl Http1Transaction for Server {
408413
| Kind::Parse(Parse::Uri)
409414
| Kind::Parse(Parse::Version) => StatusCode::BAD_REQUEST,
410415
Kind::Parse(Parse::TooLarge) => StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE,
416+
Kind::Parse(Parse::UriTooLong) => StatusCode::URI_TOO_LONG,
411417
_ => return None,
412418
};
413419

‎tests/server.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,23 @@ fn http_10_request_receives_http_10_response() {
10251025
assert_eq!(s(&buf[..expected.len()]), expected);
10261026
}
10271027

1028+
#[test]
1029+
fn http_11_uri_too_long() {
1030+
let server = serve();
1031+
1032+
let long_path = "a".repeat(65534);
1033+
let request_line = format!("GET /{} HTTP/1.1\r\n\r\n", long_path);
1034+
1035+
let mut req = connect(server.addr());
1036+
req.write_all(request_line.as_bytes()).unwrap();
1037+
1038+
let expected = "HTTP/1.1 414 URI Too Long\r\ncontent-length: 0\r\n";
1039+
let mut buf = [0; 256];
1040+
let n = req.read(&mut buf).unwrap();
1041+
assert!(n >= expected.len(), "read: {:?} >= {:?}", n, expected.len());
1042+
assert_eq!(s(&buf[..expected.len()]), expected);
1043+
}
1044+
10281045
#[tokio::test]
10291046
async fn disable_keep_alive_mid_request() {
10301047
let listener = tcp_bind(&"127.0.0.1:0".parse().unwrap()).unwrap();

0 commit comments

Comments
 (0)
Please sign in to comment.