Skip to content

Commit 68dccc6

Browse files
committed
split server
1 parent 06763f6 commit 68dccc6

File tree

3 files changed

+422
-402
lines changed

3 files changed

+422
-402
lines changed

src/server/decode.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//! Process HTTP connections on the server.
2+
3+
use std::str::FromStr;
4+
5+
use async_std::io::BufReader;
6+
use async_std::io::Read;
7+
use async_std::prelude::*;
8+
use http_types::headers::{HeaderName, HeaderValue, CONTENT_LENGTH, TRANSFER_ENCODING};
9+
use http_types::{ensure, ensure_eq, format_err};
10+
use http_types::{Body, Method, Request};
11+
12+
use crate::chunked::ChunkedDecoder;
13+
use crate::{MAX_HEADERS, MAX_HEAD_LENGTH};
14+
15+
const LF: u8 = b'\n';
16+
17+
/// The number returned from httparse when the request is HTTP 1.1
18+
const HTTP_1_1_VERSION: u8 = 1;
19+
20+
/// Decode an HTTP request on the server.
21+
pub(crate) async fn decode<R>(addr: &str, reader: R) -> http_types::Result<Option<Request>>
22+
where
23+
R: Read + Unpin + Send + Sync + 'static,
24+
{
25+
let mut reader = BufReader::new(reader);
26+
let mut buf = Vec::new();
27+
let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
28+
let mut httparse_req = httparse::Request::new(&mut headers);
29+
30+
// Keep reading bytes from the stream until we hit the end of the stream.
31+
loop {
32+
let bytes_read = reader.read_until(LF, &mut buf).await?;
33+
// No more bytes are yielded from the stream.
34+
if bytes_read == 0 {
35+
return Ok(None);
36+
}
37+
38+
// Prevent CWE-400 DDOS with large HTTP Headers.
39+
ensure!(
40+
buf.len() < MAX_HEAD_LENGTH,
41+
"Head byte length should be less than 8kb"
42+
);
43+
44+
// We've hit the end delimiter of the stream.
45+
let idx = buf.len() - 1;
46+
if idx >= 3 && &buf[idx - 3..=idx] == b"\r\n\r\n" {
47+
break;
48+
}
49+
}
50+
51+
// Convert our header buf into an httparse instance, and validate.
52+
let status = httparse_req.parse(&buf)?;
53+
54+
ensure!(!status.is_partial(), "Malformed HTTP head");
55+
56+
// Convert httparse headers + body into a `http_types::Request` type.
57+
let method = httparse_req.method;
58+
let method = method.ok_or_else(|| format_err!("No method found"))?;
59+
60+
let uri = httparse_req.path;
61+
let uri = uri.ok_or_else(|| format_err!("No uri found"))?;
62+
let uri = url::Url::parse(&format!("{}{}", addr, uri))?;
63+
64+
let version = httparse_req.version;
65+
let version = version.ok_or_else(|| format_err!("No version found"))?;
66+
ensure_eq!(version, HTTP_1_1_VERSION, "Unsupported HTTP version");
67+
68+
let mut req = Request::new(Method::from_str(method)?, uri);
69+
for header in httparse_req.headers.iter() {
70+
let name = HeaderName::from_str(header.name)?;
71+
let value = HeaderValue::from_str(std::str::from_utf8(header.value)?)?;
72+
req.insert_header(name, value)?;
73+
}
74+
75+
let content_length = req.header(&CONTENT_LENGTH);
76+
let transfer_encoding = req.header(&TRANSFER_ENCODING);
77+
78+
http_types::ensure!(
79+
content_length.is_none() || transfer_encoding.is_none(),
80+
"Unexpected Content-Length header"
81+
);
82+
83+
// Check for Transfer-Encoding
84+
if let Some(encoding) = transfer_encoding {
85+
if !encoding.is_empty() && encoding.last().unwrap().as_str() == "chunked" {
86+
let trailer_sender = req.send_trailers();
87+
let reader = BufReader::new(ChunkedDecoder::new(reader, trailer_sender));
88+
req.set_body(Body::from_reader(reader, None));
89+
return Ok(Some(req));
90+
}
91+
// Fall through to Content-Length
92+
}
93+
94+
// Check for Content-Length.
95+
if let Some(len) = content_length {
96+
let len = len.last().unwrap().as_str().parse::<usize>()?;
97+
req.set_body(Body::from_reader(reader.take(len as u64), Some(len)));
98+
}
99+
100+
Ok(Some(req))
101+
}

0 commit comments

Comments
 (0)