fix(http2): allow TE "trailers" request headers

The HTTP/2 spec allows TE headers in requests if the value is
"trailers". Other TE headers are still stripped.

Closes #1642
This commit is contained in:
Theodore Cipicchio
2018-08-25 00:55:53 -07:00
committed by Sean McArthur
parent e3dc6c5511
commit 24f11a421d
4 changed files with 41 additions and 4 deletions

View File

@@ -108,7 +108,7 @@ 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(), true);
if let Some(len) = body.content_length() { if let Some(len) = body.content_length() {
headers::set_content_length_if_missing(req.headers_mut(), len); headers::set_content_length_if_missing(req.headers_mut(), len);
} }

View File

@@ -15,15 +15,17 @@ mod server;
pub(crate) use self::client::Client; pub(crate) use self::client::Client;
pub(crate) use self::server::Server; pub(crate) use self::server::Server;
fn strip_connection_headers(headers: &mut HeaderMap) { fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
// List of connection headers from: // List of connection headers from:
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection
//
// TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're
// tested separately.
let connection_headers = [ let connection_headers = [
HeaderName::from_lowercase(b"keep-alive").unwrap(), HeaderName::from_lowercase(b"keep-alive").unwrap(),
HeaderName::from_lowercase(b"proxy-connection").unwrap(), HeaderName::from_lowercase(b"proxy-connection").unwrap(),
PROXY_AUTHENTICATE, PROXY_AUTHENTICATE,
PROXY_AUTHORIZATION, PROXY_AUTHORIZATION,
TE,
TRAILER, TRAILER,
TRANSFER_ENCODING, TRANSFER_ENCODING,
UPGRADE, UPGRADE,
@@ -35,6 +37,17 @@ fn strip_connection_headers(headers: &mut HeaderMap) {
} }
} }
if is_request {
if headers.get(TE).map(|te_header| te_header != "trailers").unwrap_or(false) {
warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
headers.remove(TE);
}
} else {
if headers.remove(TE).is_some() {
warn!("TE headers illegal in HTTP/2 responses");
}
}
if let Some(header) = headers.remove(CONNECTION) { if let Some(header) = headers.remove(CONNECTION) {
warn!( warn!(
"Connection header illegal in HTTP/2: {}", "Connection header illegal in HTTP/2: {}",

View File

@@ -192,7 +192,7 @@ 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(), false);
if let Some(len) = body.content_length() { if let Some(len) = body.content_length() {
headers::set_content_length_if_missing(res.headers_mut(), len); headers::set_content_length_if_missing(res.headers_mut(), len);
} }

View File

@@ -184,6 +184,30 @@ t! {
; ;
} }
t! {
get_allow_te_trailers_header,
client:
request:
uri: "/",
headers: {
// http2 strips connection headers other than TE "trailers"
"te" => "trailers",
},
;
response:
status: 200,
;
server:
request:
uri: "/",
headers: {
"te" => "trailers",
},
;
response:
;
}
t! { t! {
get_body_chunked, get_body_chunked,
client: client: