H2 headers must be lower case

This commit is contained in:
Carl Lerche
2017-08-25 11:44:19 -07:00
parent 91aa1db2ff
commit 9d45255c75
8 changed files with 41 additions and 28 deletions

View File

@@ -8,7 +8,7 @@ futures = "0.1"
tokio-io = "0.1.3" tokio-io = "0.1.3"
tokio-timer = "0.1" tokio-timer = "0.1"
bytes = "0.4" bytes = "0.4"
http = { git = "https://github.com/carllerche/http", branch = "uri-try-from-parts" } http = { git = "https://github.com/carllerche/http", branch = "lower-case-header-name-parsing" }
byteorder = "1.0" byteorder = "1.0"
log = "0.3.8" log = "0.3.8"
fnv = "1.0.5" fnv = "1.0.5"

View File

@@ -2,7 +2,6 @@ use {frame, HeaderMap, ConnectionError};
use Body; use Body;
use frame::StreamId; use frame::StreamId;
use proto::{self, Connection, WindowSize}; use proto::{self, Connection, WindowSize};
use error::Reason::*;
use http::{Request, Response}; use http::{Request, Response};
use futures::{Future, Poll, Sink, Async, AsyncSink}; use futures::{Future, Poll, Sink, Async, AsyncSink};
@@ -224,7 +223,5 @@ impl proto::Peer for Peer {
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError> { fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError> {
headers.into_response() headers.into_response()
// TODO: Is this always a protocol error?
.map_err(|_| ProtocolError.into())
} }
} }

View File

@@ -1,3 +1,4 @@
use http;
use std::{error, fmt, io}; use std::{error, fmt, io};
/// The error type for HTTP/2 operations /// The error type for HTTP/2 operations
@@ -162,6 +163,13 @@ impl From<ConnectionError> for io::Error {
} }
} }
impl From<http::Error> for ConnectionError {
fn from(_: http::Error) -> Self {
// TODO: Should this always be a protocol error?
Reason::ProtocolError.into()
}
}
impl fmt::Display for ConnectionError { impl fmt::Display for ConnectionError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use self::ConnectionError::*; use self::ConnectionError::*;

View File

@@ -1,9 +1,11 @@
use super::{StreamId, StreamDependency}; use super::{StreamId, StreamDependency};
use ConnectionError;
use hpack; use hpack;
use frame::{self, Frame, Head, Kind, Error}; use frame::{self, Frame, Head, Kind, Error};
use HeaderMap; use HeaderMap;
use error::Reason::*;
use http::{self, version, uri, Request, Response, Method, StatusCode, Uri}; use http::{version, uri, Request, Response, Method, StatusCode, Uri};
use http::header::{self, HeaderName, HeaderValue}; use http::header::{self, HeaderName, HeaderValue};
use bytes::{BytesMut, Bytes}; use bytes::{BytesMut, Bytes};
@@ -183,11 +185,14 @@ impl Headers {
decoder: &mut hpack::Decoder) decoder: &mut hpack::Decoder)
-> Result<(), Error> -> Result<(), Error>
{ {
let mut reg = false;
let mut err = false; let mut err = false;
macro_rules! set_pseudo { macro_rules! set_pseudo {
($field:ident, $val:expr) => {{ ($field:ident, $val:expr) => {{
if self.pseudo.$field.is_some() { if reg {
err = true;
} else if self.pseudo.$field.is_some() {
err = true; err = true;
} else { } else {
self.pseudo.$field = Some($val); self.pseudo.$field = Some($val);
@@ -207,6 +212,7 @@ impl Headers {
match header { match header {
Field { name, value } => { Field { name, value } => {
reg = true;
self.fields.append(name, value); self.fields.append(name, value);
} }
Authority(v) => set_pseudo!(authority, v), Authority(v) => set_pseudo!(authority, v),
@@ -254,7 +260,7 @@ impl Headers {
self.flags.set_end_stream() self.flags.set_end_stream()
} }
pub fn into_response(self) -> http::Result<Response<()>> { pub fn into_response(self) -> Result<Response<()>, ConnectionError> {
let mut b = Response::builder(); let mut b = Response::builder();
if let Some(status) = self.pseudo.status { if let Some(status) = self.pseudo.status {
@@ -267,33 +273,36 @@ impl Headers {
Ok(response) Ok(response)
} }
pub fn into_request(self) -> http::Result<Request<()>> { pub fn into_request(self) -> Result<Request<()>, ConnectionError> {
let mut b = Request::builder(); let mut b = Request::builder();
// TODO: should we distinguish between HTTP_2 and HTTP_2C?
// carllerche/http#42
b.version(version::HTTP_2); b.version(version::HTTP_2);
if let Some(method) = self.pseudo.method { if let Some(method) = self.pseudo.method {
b.method(method); b.method(method);
} }
// Specifying :status for a request is a protocol error
if self.pseudo.status.is_some() {
return Err(ProtocolError.into());
}
// Convert the URI // Convert the URI
let mut parts = uri::Parts::default(); let mut parts = uri::Parts::default();
if let Some(scheme) = self.pseudo.scheme { if let Some(scheme) = self.pseudo.scheme {
// TODO: Don't unwrap // TODO: Don't unwrap
parts.scheme = Some(uri::Scheme::try_from_shared(scheme.into_inner()).unwrap()); parts.scheme = Some(uri::Scheme::from_shared(scheme.into_inner()).unwrap());
} }
if let Some(authority) = self.pseudo.authority { if let Some(authority) = self.pseudo.authority {
// TODO: Don't unwrap // TODO: Don't unwrap
parts.authority = Some(uri::Authority::try_from_shared(authority.into_inner()).unwrap()); parts.authority = Some(uri::Authority::from_shared(authority.into_inner()).unwrap());
} }
if let Some(path) = self.pseudo.path { if let Some(path) = self.pseudo.path {
// TODO: Don't unwrap // TODO: Don't unwrap
parts.origin_form = Some(uri::OriginForm::try_from_shared(path.into_inner()).unwrap()); parts.path_and_query = Some(uri::PathAndQuery::from_shared(path.into_inner()).unwrap());
} }
b.uri(parts); b.uri(parts);
@@ -400,7 +409,7 @@ impl Pseudo {
unsafe { String::from_utf8_unchecked(src) } unsafe { String::from_utf8_unchecked(src) }
} }
let path = parts.origin_form let path = parts.path_and_query
.map(|v| v.into()) .map(|v| v.into())
.unwrap_or_else(|| Bytes::from_static(b"/")); .unwrap_or_else(|| Bytes::from_static(b"/"));

View File

@@ -544,7 +544,7 @@ mod test {
use http::header::HeaderValue; use http::header::HeaderValue;
let name = "my-password".parse().unwrap(); let name = "my-password".parse().unwrap();
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap(); let mut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true); value.set_sensitive(true);
let header = Header::Field { name: Some(name), value: value }; let header = Header::Field { name: Some(name), value: value };
@@ -561,7 +561,7 @@ mod test {
// Now, try to encode a sensitive header w/ a name in the static table // Now, try to encode a sensitive header w/ a name in the static table
let name = "authorization".parse().unwrap(); let name = "authorization".parse().unwrap();
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap(); let mut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true); value.set_sensitive(true);
let header = Header::Field { name: Some(name), value: value }; let header = Header::Field { name: Some(name), value: value };
@@ -579,7 +579,7 @@ mod test {
let _ = encode(&mut encoder, vec![self::header("my-password", "not-so-secret")]); let _ = encode(&mut encoder, vec![self::header("my-password", "not-so-secret")]);
let name = "my-password".parse().unwrap(); let name = "my-password".parse().unwrap();
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap(); let mut value = HeaderValue::from_bytes(b"12345").unwrap();
value.set_sensitive(true); value.set_sensitive(true);
let header = Header::Field { name: Some(name), value: value }; let header = Header::Field { name: Some(name), value: value };
@@ -746,11 +746,11 @@ mod test {
let res = encode(&mut encoder, vec![ let res = encode(&mut encoder, vec![
Header::Field { Header::Field {
name: Some("hello".parse().unwrap()), name: Some("hello".parse().unwrap()),
value: HeaderValue::try_from_bytes(b"world").unwrap(), value: HeaderValue::from_bytes(b"world").unwrap(),
}, },
Header::Field { Header::Field {
name: None, name: None,
value: HeaderValue::try_from_bytes(b"zomg").unwrap(), value: HeaderValue::from_bytes(b"zomg").unwrap(),
}, },
]); ]);
@@ -772,11 +772,11 @@ mod test {
let mut input = vec![ let mut input = vec![
Header::Field { Header::Field {
name: Some("hello".parse().unwrap()), name: Some("hello".parse().unwrap()),
value: HeaderValue::try_from_bytes(b"world").unwrap(), value: HeaderValue::from_bytes(b"world").unwrap(),
}, },
Header::Field { Header::Field {
name: None, name: None,
value: HeaderValue::try_from_bytes(b"zomg").unwrap(), value: HeaderValue::from_bytes(b"zomg").unwrap(),
}, },
].into_iter(); ].into_iter();
@@ -822,7 +822,7 @@ mod test {
use http::header::{HeaderName, HeaderValue}; use http::header::{HeaderName, HeaderValue};
let name = HeaderName::from_bytes(name.as_bytes()).unwrap(); let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
let value = HeaderValue::try_from_bytes(val.as_bytes()).unwrap(); let value = HeaderValue::from_bytes(val.as_bytes()).unwrap();
Header::Field { name: Some(name), value: value } Header::Field { name: Some(name), value: value }
} }

View File

@@ -81,8 +81,9 @@ impl Header {
} }
} }
} else { } else {
let name = try!(HeaderName::from_bytes(&name)); // HTTP/2 requires lower case header names
let value = try!(HeaderValue::try_from_bytes(&value)); let name = try!(HeaderName::from_lowercase(&name));
let value = try!(HeaderValue::from_bytes(&value));
Ok(Header::Field { name: name, value: value }) Ok(Header::Field { name: name, value: value })
} }
@@ -228,7 +229,7 @@ impl<'a> Name<'a> {
Name::Field(name) => { Name::Field(name) => {
Ok(Header::Field { Ok(Header::Field {
name: name.clone(), name: name.clone(),
value: try!(HeaderValue::try_from_bytes(&*value)), value: try!(HeaderValue::from_bytes(&*value)),
}) })
} }
Name::Authority => { Name::Authority => {

View File

@@ -330,7 +330,7 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
fn gen_header_value(g: &mut StdRng) -> HeaderValue { fn gen_header_value(g: &mut StdRng) -> HeaderValue {
let value = gen_string(g, 0, 70); let value = gen_string(g, 0, 70);
HeaderValue::try_from_bytes(value.as_bytes()).unwrap() HeaderValue::from_bytes(value.as_bytes()).unwrap()
} }
fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String { fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {

View File

@@ -370,7 +370,5 @@ impl proto::Peer for Peer {
-> Result<Self::Poll, ConnectionError> -> Result<Self::Poll, ConnectionError>
{ {
headers.into_request() headers.into_request()
// TODO: Is this always a protocol error?
.map_err(|_| ProtocolError.into())
} }
} }