feat(http2): set Content-Length header on outgoing messages
Closes #1547
This commit is contained in:
committed by
Sean McArthur
parent
f20afba57d
commit
386fc0d70b
@@ -78,6 +78,13 @@ pub fn content_length_value(len: u64) -> HeaderValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) {
|
||||||
|
headers
|
||||||
|
.entry(CONTENT_LENGTH)
|
||||||
|
.unwrap()
|
||||||
|
.or_insert(content_length_value(len));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transfer_encoding_is_chunked(headers: &HeaderMap) -> bool {
|
pub fn transfer_encoding_is_chunked(headers: &HeaderMap) -> bool {
|
||||||
is_chunked(headers.get_all(TRANSFER_ENCODING).into_iter())
|
is_chunked(headers.get_all(TRANSFER_ENCODING).into_iter())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
|||||||
|
|
||||||
use body::Payload;
|
use body::Payload;
|
||||||
use ::common::{Exec, Never};
|
use ::common::{Exec, Never};
|
||||||
|
use headers;
|
||||||
use super::{PipeToSendStream, SendBuf};
|
use super::{PipeToSendStream, SendBuf};
|
||||||
use ::{Body, Request, Response};
|
use ::{Body, Request, Response};
|
||||||
|
|
||||||
@@ -106,6 +107,9 @@ where
|
|||||||
let (head, body) = req.into_parts();
|
let (head, body) = req.into_parts();
|
||||||
let mut req = ::http::Request::from_parts(head, ());
|
let mut req = ::http::Request::from_parts(head, ());
|
||||||
super::strip_connection_headers(req.headers_mut());
|
super::strip_connection_headers(req.headers_mut());
|
||||||
|
if let Some(len) = body.content_length() {
|
||||||
|
headers::set_content_length_if_missing(req.headers_mut(), len);
|
||||||
|
}
|
||||||
let eos = body.is_end_stream();
|
let eos = body.is_end_stream();
|
||||||
let (fut, body_tx) = match tx.send_request(req, eos) {
|
let (fut, body_tx) = match tx.send_request(req, eos) {
|
||||||
Ok(ok) => ok,
|
Ok(ok) => ok,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
|||||||
|
|
||||||
use ::body::Payload;
|
use ::body::Payload;
|
||||||
use ::common::Exec;
|
use ::common::Exec;
|
||||||
|
use ::headers;
|
||||||
use ::service::Service;
|
use ::service::Service;
|
||||||
use super::{PipeToSendStream, SendBuf};
|
use super::{PipeToSendStream, SendBuf};
|
||||||
|
|
||||||
@@ -171,6 +172,9 @@ where
|
|||||||
let (head, body) = res.into_parts();
|
let (head, body) = res.into_parts();
|
||||||
let mut res = ::http::Response::from_parts(head, ());
|
let mut res = ::http::Response::from_parts(head, ());
|
||||||
super::strip_connection_headers(res.headers_mut());
|
super::strip_connection_headers(res.headers_mut());
|
||||||
|
if let Some(len) = body.content_length() {
|
||||||
|
headers::set_content_length_if_missing(res.headers_mut(), len);
|
||||||
|
}
|
||||||
macro_rules! reply {
|
macro_rules! reply {
|
||||||
($eos:expr) => ({
|
($eos:expr) => ({
|
||||||
match self.reply.send_response(res, $eos) {
|
match self.reply.send_response(res, $eos) {
|
||||||
|
|||||||
@@ -166,6 +166,29 @@ t! {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t! {
|
||||||
|
post_outgoing_length,
|
||||||
|
client:
|
||||||
|
request:
|
||||||
|
method: "POST",
|
||||||
|
uri: "/hello",
|
||||||
|
body: "hello, world!",
|
||||||
|
;
|
||||||
|
response:
|
||||||
|
;
|
||||||
|
server:
|
||||||
|
request:
|
||||||
|
method: "POST",
|
||||||
|
uri: "/hello",
|
||||||
|
headers: {
|
||||||
|
"content-length" => "13",
|
||||||
|
},
|
||||||
|
body: "hello, world!",
|
||||||
|
;
|
||||||
|
response:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
t! {
|
t! {
|
||||||
post_chunked,
|
post_chunked,
|
||||||
client:
|
client:
|
||||||
|
|||||||
@@ -353,6 +353,65 @@ mod response_body_lengths {
|
|||||||
expects_con_len: false,
|
expects_con_len: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn http2_auto_response_with_known_length() {
|
||||||
|
use hyper::body::Payload;
|
||||||
|
|
||||||
|
let server = serve();
|
||||||
|
let addr_str = format!("http://{}", server.addr());
|
||||||
|
server.reply().body("Hello, World!");
|
||||||
|
|
||||||
|
hyper::rt::run(hyper::rt::lazy(move || {
|
||||||
|
let client: Client<_, hyper::Body> = Client::builder().http2_only(true).build_http();
|
||||||
|
let uri = addr_str
|
||||||
|
.parse::<hyper::Uri>()
|
||||||
|
.expect("server addr should parse");
|
||||||
|
|
||||||
|
client
|
||||||
|
.get(uri)
|
||||||
|
.and_then(|res| {
|
||||||
|
assert_eq!(res.headers().get("content-length").unwrap(), "13");
|
||||||
|
// TODO: enable this after #1546
|
||||||
|
let _ = res.body().content_length();
|
||||||
|
// assert_eq!(res.body().content_length(), Some(13));
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_e| ())
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn http2_auto_response_with_conflicting_lengths() {
|
||||||
|
use hyper::body::Payload;
|
||||||
|
|
||||||
|
let server = serve();
|
||||||
|
let addr_str = format!("http://{}", server.addr());
|
||||||
|
server
|
||||||
|
.reply()
|
||||||
|
.header("content-length", "10")
|
||||||
|
.body("Hello, World!");
|
||||||
|
|
||||||
|
hyper::rt::run(hyper::rt::lazy(move || {
|
||||||
|
let client: Client<_, hyper::Body> = Client::builder().http2_only(true).build_http();
|
||||||
|
let uri = addr_str
|
||||||
|
.parse::<hyper::Uri>()
|
||||||
|
.expect("server addr should parse");
|
||||||
|
|
||||||
|
client
|
||||||
|
.get(uri)
|
||||||
|
.and_then(|res| {
|
||||||
|
assert_eq!(res.headers().get("content-length").unwrap(), "10");
|
||||||
|
// TODO: enable or remove this after #1546
|
||||||
|
let _ = res.body().content_length();
|
||||||
|
// assert_eq!(res.body().content_length(), Some(10));
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_e| ())
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user