Skip to content

Commit b71e346

Browse files
authored
Merge pull request #166 from http-rs/400-on-content-len-chunked
400 on content len chunked
2 parents b1651f3 + b22c7e6 commit b71e346

File tree

2 files changed

+21
-13
lines changed

2 files changed

+21
-13
lines changed

src/server/decode.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::str::FromStr;
55
use async_dup::{Arc, Mutex};
66
use async_std::io::{BufReader, Read, Write};
77
use async_std::{prelude::*, task};
8-
use http_types::headers::{CONTENT_LENGTH, EXPECT, TRANSFER_ENCODING};
8+
use http_types::content::ContentLength;
9+
use http_types::headers::{EXPECT, TRANSFER_ENCODING};
910
use http_types::{ensure, ensure_eq, format_err};
1011
use http_types::{Body, Method, Request, Url};
1112

@@ -82,11 +83,16 @@ where
8283
req.append_header(header.name, std::str::from_utf8(header.value)?);
8384
}
8485

85-
let content_length = req.header(CONTENT_LENGTH);
86+
let content_length = ContentLength::from_headers(&req)?;
8687
let transfer_encoding = req.header(TRANSFER_ENCODING);
8788

88-
http_types::ensure!(
89+
// Return a 400 status if both Content-Length and Transfer-Encoding headers
90+
// are set to prevent request smuggling attacks.
91+
//
92+
// https://tools.ietf.org/html/rfc7230#section-3.3.3
93+
http_types::ensure_status!(
8994
content_length.is_none() || transfer_encoding.is_none(),
95+
400,
9096
"Unexpected Content-Length header"
9197
);
9298

@@ -123,11 +129,11 @@ where
123129
req.set_body(Body::from_reader(reader, None));
124130
return Ok(Some((req, BodyReader::Chunked(reader_clone))));
125131
} else if let Some(len) = content_length {
126-
let len = len.last().as_str().parse::<usize>()?;
127-
let reader = Arc::new(Mutex::new(reader.take(len as u64)));
132+
let len = len.len();
133+
let reader = Arc::new(Mutex::new(reader.take(len)));
128134
req.set_body(Body::from_reader(
129135
BufReader::new(ReadNotifier::new(reader.clone(), body_read_sender)),
130-
Some(len),
136+
Some(len as usize),
131137
));
132138
Ok(Some((req, BodyReader::Fixed(reader))))
133139
} else {

tests/test_utils.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use async_h1::{
55
use async_std::io::{Read, Write};
66
use http_types::{Request, Response, Result};
77
use std::{
8-
fmt::Debug,
8+
fmt::{Debug, Display},
99
future::Future,
1010
io,
1111
pin::Pin,
@@ -122,17 +122,19 @@ impl CloseableCursor {
122122
self.len() == self.cursor()
123123
}
124124

125-
pub fn to_string(&self) -> String {
126-
std::str::from_utf8(&*self.data.read().unwrap())
127-
.unwrap_or("not utf8")
128-
.to_owned()
129-
}
130-
131125
fn close(&self) {
132126
*self.closed.write().unwrap() = true;
133127
}
134128
}
135129

130+
impl Display for CloseableCursor {
131+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132+
let data = &*self.data.read().unwrap();
133+
let s = std::str::from_utf8(data).unwrap_or("not utf8");
134+
write!(f, "{}", s)
135+
}
136+
}
137+
136138
impl TestIO {
137139
pub fn new() -> (TestIO, TestIO) {
138140
let client = Arc::new(CloseableCursor::default());

0 commit comments

Comments
 (0)