Skip to content

Commit 24bd096

Browse files
authored
Merge pull request #124 from jbr/head-reqs-no-body-content
do not send body content in reply to HEAD requests
2 parents 352a4e0 + d0c44a0 commit 24bd096

File tree

5 files changed

+42
-11
lines changed

5 files changed

+42
-11
lines changed

src/server/encode.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use async_std::io;
66
use async_std::io::prelude::*;
77
use async_std::task::{Context, Poll};
88
use http_types::headers::{CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
9-
use http_types::Response;
9+
use http_types::{Method, Response};
1010

1111
use crate::chunked::ChunkedEncoder;
1212
use crate::date::fmt_http_date;
@@ -36,6 +36,8 @@ pub(crate) struct Encoder {
3636
body_bytes_written: usize,
3737
/// An encoder for chunked encoding.
3838
chunked: ChunkedEncoder,
39+
/// the http method that this response is in reply to
40+
method: Method,
3941
}
4042

4143
#[derive(Debug)]
@@ -69,7 +71,7 @@ impl Read for Encoder {
6971

7072
impl Encoder {
7173
/// Create a new instance of Encoder.
72-
pub(crate) fn new(res: Response) -> Self {
74+
pub(crate) fn new(res: Response, method: Method) -> Self {
7375
Self {
7476
res,
7577
depth: 0,
@@ -80,6 +82,7 @@ impl Encoder {
8082
body_len: 0,
8183
body_bytes_written: 0,
8284
chunked: ChunkedEncoder::new(),
85+
method,
8386
}
8487
}
8588

@@ -97,7 +100,7 @@ impl Encoder {
97100
match self.state {
98101
Start => assert!(matches!(state, ComputeHead)),
99102
ComputeHead => assert!(matches!(state, EncodeHead)),
100-
EncodeHead => assert!(matches!(state, EncodeChunkedBody | EncodeFixedBody)),
103+
EncodeHead => assert!(matches!(state, EncodeChunkedBody | EncodeFixedBody | End)),
101104
EncodeFixedBody => assert!(matches!(state, End)),
102105
EncodeChunkedBody => assert!(matches!(state, End)),
103106
End => panic!("No state transitions allowed after the ServerEncoder has ended"),
@@ -176,14 +179,20 @@ impl Encoder {
176179
// If we've read the total length of the head we're done
177180
// reading the head and can transition to reading the body
178181
if self.head_bytes_written == head_len {
179-
// The response length lets us know if we are encoding
180-
// our body in chunks or not
181-
match self.res.len() {
182-
Some(body_len) => {
183-
self.body_len = body_len;
184-
self.dispatch(State::EncodeFixedBody, cx, buf)
182+
if self.method == Method::Head {
183+
// If we are responding to a HEAD request, we MUST NOT send
184+
// body content
185+
self.dispatch(State::End, cx, buf)
186+
} else {
187+
// The response length lets us know if we are encoding
188+
// our body in chunks or not
189+
match self.res.len() {
190+
Some(body_len) => {
191+
self.body_len = body_len;
192+
self.dispatch(State::EncodeFixedBody, cx, buf)
193+
}
194+
None => self.dispatch(State::EncodeChunkedBody, cx, buf),
185195
}
186-
None => self.dispatch(State::EncodeChunkedBody, cx, buf),
187196
}
188197
} else {
189198
// If we haven't read the entire header it means `buf` isn't

src/server/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ where
7070
}
7171
};
7272

73+
let method = req.method();
7374
// Pass the request to the endpoint and encode the response.
7475
let res = endpoint(req).await?;
75-
let mut encoder = Encoder::new(res);
76+
77+
let mut encoder = Encoder::new(res, method);
7678

7779
// Stream the response to the writer.
7880
io::copy(&mut encoder, &mut io).await?;

tests/fixtures/head_request.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
HEAD / HTTP/1.1
2+
host: example.com
3+
user-agent: curl/7.54.0
4+

tests/fixtures/head_response.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
HTTP/1.1 200 OK
2+
content-length: 5
3+
date: {DATE}
4+
content-type: text/plain;charset=utf-8
5+

tests/server.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,14 @@ async fn test_invalid_trailer() {
144144

145145
assert!(case.read_result().await.is_empty());
146146
}
147+
#[async_std::test]
148+
async fn empty_body_for_head_requests() {
149+
let case =
150+
TestCase::new_server("fixtures/head_request.txt", "fixtures/head_response.txt").await;
151+
152+
async_h1::accept(case.clone(), |_| async { Ok("hello".into()) })
153+
.await
154+
.unwrap();
155+
156+
case.assert().await;
157+
}

0 commit comments

Comments
 (0)