Skip to content

Commit 81c0d18

Browse files
committed
fix(client): don't assume bodies on 204 and 304 Responses
Closes #1242
1 parent 7ce3121 commit 81c0d18

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

src/http/h1/decode.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use self::Kind::{Length, Chunked, Eof};
1111
///
1212
/// If a message body does not include a Transfer-Encoding, it *should*
1313
/// include a Content-Length header.
14-
#[derive(Debug, Clone)]
14+
#[derive(Debug, Clone, PartialEq)]
1515
pub struct Decoder {
1616
kind: Kind,
1717
}
@@ -30,7 +30,7 @@ impl Decoder {
3030
}
3131
}
3232

33-
#[derive(Debug, Clone)]
33+
#[derive(Debug, Clone, PartialEq)]
3434
enum Kind {
3535
/// A Reader used when a Content-Length header is passed with a positive integer.
3636
Length(u64),

src/http/h1/parse.rs

+43-6
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,21 @@ impl Http1Transaction for ClientTransaction {
191191
// According to https://tools.ietf.org/html/rfc7230#section-3.3.3
192192
// 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body.
193193
// 2. Status 2xx to a CONNECT cannot have a body.
194-
//
195-
// First two steps taken care of before this method.
196-
//
197194
// 3. Transfer-Encoding: chunked has a chunked body.
198195
// 4. If multiple differing Content-Length headers or invalid, close connection.
199196
// 5. Content-Length header has a sized body.
200197
// 6. Not Client.
201198
// 7. Read till EOF.
199+
200+
//TODO: need a way to pass the Method that caused this Response
201+
202+
match inc.subject.0 {
203+
100...199 |
204+
204 |
205+
304 => return Ok(Decoder::length(0)),
206+
_ => (),
207+
}
208+
202209
if let Some(&header::TransferEncoding(ref codings)) = inc.headers.get() {
203210
if codings.last() == Some(&header::Encoding::Chunked) {
204211
Ok(Decoder::chunked())
@@ -329,9 +336,11 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) {
329336

330337
#[cfg(test)]
331338
mod tests {
332-
use http::{ServerTransaction, ClientTransaction, Http1Transaction};
333339
use bytes::BytesMut;
334340

341+
use http::{MessageHead, ServerTransaction, ClientTransaction, Http1Transaction};
342+
use header::{ContentLength, TransferEncoding};
343+
335344
#[test]
336345
fn test_parse_request() {
337346
extern crate pretty_env_logger;
@@ -368,6 +377,7 @@ mod tests {
368377
let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
369378
ServerTransaction::parse(&mut raw).unwrap_err();
370379
}
380+
371381
#[test]
372382
fn test_parse_raw_status() {
373383
let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec());
@@ -379,6 +389,34 @@ mod tests {
379389
assert_eq!(res.subject.1, "Howdy");
380390
}
381391

392+
#[test]
393+
fn test_decoder_response() {
394+
use super::Decoder;
395+
396+
let mut head = MessageHead::<::http::RawStatus>::default();
397+
398+
head.subject.0 = 204;
399+
assert_eq!(Decoder::length(0), ClientTransaction::decoder(&head).unwrap());
400+
head.subject.0 = 304;
401+
assert_eq!(Decoder::length(0), ClientTransaction::decoder(&head).unwrap());
402+
403+
head.subject.0 = 200;
404+
assert_eq!(Decoder::eof(), ClientTransaction::decoder(&head).unwrap());
405+
406+
head.headers.set(TransferEncoding::chunked());
407+
assert_eq!(Decoder::chunked(), ClientTransaction::decoder(&head).unwrap());
408+
409+
head.headers.remove::<TransferEncoding>();
410+
head.headers.set(ContentLength(10));
411+
assert_eq!(Decoder::length(10), ClientTransaction::decoder(&head).unwrap());
412+
413+
head.headers.set_raw("Content-Length", vec![b"5".to_vec(), b"5".to_vec()]);
414+
assert_eq!(Decoder::length(5), ClientTransaction::decoder(&head).unwrap());
415+
416+
head.headers.set_raw("Content-Length", vec![b"10".to_vec(), b"11".to_vec()]);
417+
ClientTransaction::decoder(&head).unwrap_err();
418+
}
419+
382420
#[cfg(feature = "nightly")]
383421
use test::Bencher;
384422

@@ -424,8 +462,7 @@ mod tests {
424462
#[cfg(feature = "nightly")]
425463
#[bench]
426464
fn bench_server_transaction_encode(b: &mut Bencher) {
427-
use ::http::MessageHead;
428-
use ::header::{Headers, ContentLength, ContentType};
465+
use header::{Headers, ContentLength, ContentType};
429466
use ::{StatusCode, HttpVersion};
430467

431468
let len = 108;

0 commit comments

Comments
 (0)