Skip to content

Commit 030d9d4

Browse files
authored
Merge pull request #110 from jbr/100-continue
Add support for `Expect` header
2 parents 7261194 + bfcfd31 commit 030d9d4

File tree

1 file changed

+65
-15
lines changed

1 file changed

+65
-15
lines changed

src/server/decode.rs

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
33
use std::str::FromStr;
44

5-
use async_std::io::BufReader;
6-
use async_std::io::Read;
5+
use async_std::io::{BufReader, Read, Write};
76
use async_std::prelude::*;
87
use http_types::headers::{HeaderName, HeaderValue, CONTENT_LENGTH, HOST, TRANSFER_ENCODING};
98
use http_types::{ensure, ensure_eq, format_err};
@@ -18,11 +17,11 @@ const LF: u8 = b'\n';
1817
const HTTP_1_1_VERSION: u8 = 1;
1918

2019
/// Decode an HTTP request on the server.
21-
pub(crate) async fn decode<R>(reader: R) -> http_types::Result<Option<Request>>
20+
pub(crate) async fn decode<IO>(mut io: IO) -> http_types::Result<Option<Request>>
2221
where
23-
R: Read + Unpin + Send + Sync + 'static,
22+
IO: Read + Write + Clone + Send + Sync + Unpin + 'static,
2423
{
25-
let mut reader = BufReader::new(reader);
24+
let mut reader = BufReader::new(io.clone());
2625
let mut buf = Vec::new();
2726
let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
2827
let mut httparse_req = httparse::Request::new(&mut headers);
@@ -82,6 +81,7 @@ where
8281
}
8382

8483
set_url_and_port_from_host_header(&mut req)?;
84+
handle_100_continue(&req, &mut io).await?;
8585

8686
let content_length = req.header(&CONTENT_LENGTH);
8787
let transfer_encoding = req.header(&TRANSFER_ENCODING);
@@ -130,22 +130,58 @@ fn set_url_and_port_from_host_header(req: &mut Request) -> http_types::Result<()
130130
Ok(())
131131
}
132132

133+
async fn handle_100_continue<IO: Write + Unpin>(
134+
req: &Request,
135+
io: &mut IO,
136+
) -> http_types::Result<()> {
137+
let expect_header_value = req
138+
.header(&HeaderName::from_str("expect").unwrap())
139+
.and_then(|v| v.last())
140+
.map(|v| v.as_str());
141+
142+
if let Some("100-continue") = expect_header_value {
143+
io.write_all("HTTP/1.1 100 Continue\r\n".as_bytes()).await?;
144+
}
145+
146+
Ok(())
147+
}
148+
133149
#[cfg(test)]
134150
mod tests {
135151
use super::*;
136152

137-
fn request_with_host_header(host: &str) -> Request {
138-
let mut req = Request::new(
139-
Method::from_str("GET").unwrap(),
140-
url::Url::parse("http://_")
141-
.unwrap()
142-
.join("/some/path")
143-
.unwrap(),
144-
);
153+
#[test]
154+
fn handle_100_continue_does_nothing_with_no_expect_header() {
155+
let request = Request::new(Method::Get, url::Url::parse("x:").unwrap());
156+
let mut io = async_std::io::Cursor::new(vec![]);
157+
let result = async_std::task::block_on(handle_100_continue(&request, &mut io));
158+
assert_eq!(std::str::from_utf8(&io.into_inner()).unwrap(), "");
159+
assert!(result.is_ok());
160+
}
145161

146-
req.insert_header(HOST, host).unwrap();
162+
#[test]
163+
fn handle_100_continue_sends_header_if_expects_is_exactly_right() {
164+
let mut request = Request::new(Method::Get, url::Url::parse("x:").unwrap());
165+
request.append_header("expect", "100-continue").unwrap();
166+
let mut io = async_std::io::Cursor::new(vec![]);
167+
let result = async_std::task::block_on(handle_100_continue(&request, &mut io));
168+
assert_eq!(
169+
std::str::from_utf8(&io.into_inner()).unwrap(),
170+
"HTTP/1.1 100 Continue\r\n"
171+
);
172+
assert!(result.is_ok());
173+
}
147174

148-
req
175+
#[test]
176+
fn handle_100_continue_does_nothing_if_expects_header_is_wrong() {
177+
let mut request = Request::new(Method::Get, url::Url::parse("x:").unwrap());
178+
request
179+
.append_header("expect", "110-extensions-not-allowed")
180+
.unwrap();
181+
let mut io = async_std::io::Cursor::new(vec![]);
182+
let result = async_std::task::block_on(handle_100_continue(&request, &mut io));
183+
assert_eq!(std::str::from_utf8(&io.into_inner()).unwrap(), "");
184+
assert!(result.is_ok());
149185
}
150186

151187
#[test]
@@ -209,4 +245,18 @@ mod tests {
209245
let mut request = request_with_host_header(" ");
210246
assert!(set_url_and_port_from_host_header(&mut request).is_err());
211247
}
248+
249+
fn request_with_host_header(host: &str) -> Request {
250+
let mut req = Request::new(
251+
Method::Get,
252+
url::Url::parse("http://_")
253+
.unwrap()
254+
.join("/some/path")
255+
.unwrap(),
256+
);
257+
258+
req.insert_header(HOST, host).unwrap();
259+
260+
req
261+
}
212262
}

0 commit comments

Comments
 (0)