Skip to content

Commit 71d71f1

Browse files
committed
fix(server): improve detection of when a Response can have a body
By knowing if the incoming Request was a HEAD, or checking for 204 or 304 status codes, the server will do a better job of either adding or removing `Content-Length` and `Transfer-Encoding` headers. Closes #1257
1 parent 14cbd40 commit 71d71f1

File tree

6 files changed

+433
-297
lines changed

6 files changed

+433
-297
lines changed

src/http/conn.rs

+13-18
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use futures::task::Task;
77
use tokio_io::{AsyncRead, AsyncWrite};
88
use tokio_proto::streaming::pipeline::{Frame, Transport};
99

10-
use header::{ContentLength, TransferEncoding};
1110
use http::{self, Http1Transaction, DebugTruncate};
1211
use http::io::{Cursor, Buffered};
1312
use http::h1::{Encoder, Decoder};
13+
use method::Method;
1414
use version::HttpVersion;
1515

1616

@@ -37,10 +37,11 @@ where I: AsyncRead + AsyncWrite,
3737
Conn {
3838
io: Buffered::new(io),
3939
state: State {
40+
keep_alive: keep_alive,
41+
method: None,
42+
read_task: None,
4043
reading: Reading::Init,
4144
writing: Writing::Init,
42-
read_task: None,
43-
keep_alive: keep_alive,
4445
},
4546
_marker: PhantomData,
4647
}
@@ -103,7 +104,7 @@ where I: AsyncRead + AsyncWrite,
103104

104105
match version {
105106
HttpVersion::Http10 | HttpVersion::Http11 => {
106-
let decoder = match T::decoder(&head) {
107+
let decoder = match T::decoder(&head, &mut self.state.method) {
107108
Ok(d) => d,
108109
Err(e) => {
109110
debug!("decoder error = {:?}", e);
@@ -234,17 +235,8 @@ where I: AsyncRead + AsyncWrite,
234235
}
235236
}
236237

237-
fn write_head(&mut self, mut head: http::MessageHead<T::Outgoing>, body: bool) {
238+
fn write_head(&mut self, head: http::MessageHead<T::Outgoing>, body: bool) {
238239
debug_assert!(self.can_write_head());
239-
if !body {
240-
head.headers.remove::<TransferEncoding>();
241-
//TODO: check that this isn't a response to a HEAD
242-
//request, which could include the content-length
243-
//even if no body is to be written
244-
if T::should_set_length(&head) {
245-
head.headers.set(ContentLength(0));
246-
}
247-
}
248240

249241
let wants_keep_alive = head.should_keep_alive();
250242
self.state.keep_alive &= wants_keep_alive;
@@ -256,8 +248,8 @@ where I: AsyncRead + AsyncWrite,
256248
buf.extend_from_slice(pending.buf());
257249
}
258250
}
259-
let encoder = T::encode(head, buf);
260-
self.state.writing = if body {
251+
let encoder = T::encode(head, body, &mut self.state.method, buf);
252+
self.state.writing = if !encoder.is_eof() {
261253
Writing::Body(encoder, None)
262254
} else {
263255
Writing::KeepAlive
@@ -493,10 +485,11 @@ impl<I, B: AsRef<[u8]>, T, K: fmt::Debug> fmt::Debug for Conn<I, B, T, K> {
493485
}
494486

495487
struct State<B, K> {
488+
keep_alive: K,
489+
method: Option<Method>,
490+
read_task: Option<Task>,
496491
reading: Reading,
497492
writing: Writing<B>,
498-
read_task: Option<Task>,
499-
keep_alive: K,
500493
}
501494

502495
#[derive(Debug)]
@@ -522,6 +515,7 @@ impl<B: AsRef<[u8]>, K: fmt::Debug> fmt::Debug for State<B, K> {
522515
.field("reading", &self.reading)
523516
.field("writing", &self.writing)
524517
.field("keep_alive", &self.keep_alive)
518+
.field("method", &self.method)
525519
.field("read_task", &self.read_task)
526520
.finish()
527521
}
@@ -641,6 +635,7 @@ impl<B, K: KeepAlive> State<B, K> {
641635
}
642636

643637
fn idle(&mut self) {
638+
self.method = None;
644639
self.reading = Reading::Init;
645640
self.writing = Writing::Init;
646641
self.keep_alive.idle();

0 commit comments

Comments
 (0)