diff --git a/src/error.rs b/src/error.rs index db0c536b..3eb62437 100644 --- a/src/error.rs +++ b/src/error.rs @@ -72,13 +72,24 @@ pub(super) enum Parse { #[cfg(feature = "http1")] VersionH2, Uri, - Header, + Header(Header), TooLarge, Status, #[cfg_attr(debug_assertions, allow(unused))] Internal, } +#[derive(Debug)] +pub(super) enum Header { + Token, + #[cfg(feature = "http1")] + ContentLengthInvalid, + #[cfg(feature = "http1")] + TransferEncodingInvalid, + #[cfg(feature = "http1")] + TransferEncodingUnexpected, +} + #[derive(Debug)] pub(super) enum User { /// Error calling user's HttpBody::poll_data(). @@ -375,7 +386,19 @@ impl Error { #[cfg(feature = "http1")] Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)", Kind::Parse(Parse::Uri) => "invalid URI", - Kind::Parse(Parse::Header) => "invalid HTTP header parsed", + Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed", + #[cfg(feature = "http1")] + Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => { + "invalid content-length parsed" + } + #[cfg(feature = "http1")] + Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => { + "invalid transfer-encoding parsed" + } + #[cfg(feature = "http1")] + Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => { + "unexpected transfer-encoding parsed" + } Kind::Parse(Parse::TooLarge) => "message head is too large", Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed", Kind::Parse(Parse::Internal) => { @@ -475,13 +498,28 @@ impl From for Error { } } +#[cfg(feature = "http1")] +impl Parse { + pub(crate) fn content_length_invalid() -> Self { + Parse::Header(Header::ContentLengthInvalid) + } + + pub(crate) fn transfer_encoding_invalid() -> Self { + Parse::Header(Header::TransferEncodingInvalid) + } + + pub(crate) fn transfer_encoding_unexpected() -> Self { + Parse::Header(Header::TransferEncodingUnexpected) + } +} + impl From for Parse { fn from(err: httparse::Error) -> Parse { match err { httparse::Error::HeaderName | httparse::Error::HeaderValue | httparse::Error::NewLine - | httparse::Error::Token => Parse::Header, + | httparse::Error::Token => Parse::Header(Header::Token), httparse::Error::Status => Parse::Status, httparse::Error::TooManyHeaders => Parse::TooLarge, httparse::Error::Version => Parse::Version, diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 0d59edf2..f76f6cfe 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -205,7 +205,7 @@ impl Http1Transaction for Server { // malformed. A server should respond with 400 Bad Request. if !is_http_11 { debug!("HTTP/1.0 cannot have Transfer-Encoding header"); - return Err(Parse::Header); + return Err(Parse::transfer_encoding_unexpected()); } is_te = true; if headers::is_chunked_(&value) { @@ -221,15 +221,15 @@ impl Http1Transaction for Server { } let len = value .to_str() - .map_err(|_| Parse::Header) - .and_then(|s| s.parse().map_err(|_| Parse::Header))?; + .map_err(|_| Parse::content_length_invalid()) + .and_then(|s| s.parse().map_err(|_| Parse::content_length_invalid()))?; if let Some(prev) = con_len { if prev != len { debug!( "multiple Content-Length headers with different values: [{}, {}]", prev, len, ); - return Err(Parse::Header); + return Err(Parse::content_length_invalid()); } // we don't need to append this secondary length continue; @@ -267,7 +267,7 @@ impl Http1Transaction for Server { if is_te && !is_te_chunked { debug!("request with transfer-encoding header, but not chunked, bad request"); - return Err(Parse::Header); + return Err(Parse::transfer_encoding_invalid()); } let mut extensions = http::Extensions::default(); @@ -386,7 +386,7 @@ impl Http1Transaction for Server { use crate::error::Kind; let status = match *err.kind() { Kind::Parse(Parse::Method) - | Kind::Parse(Parse::Header) + | Kind::Parse(Parse::Header(_)) | Kind::Parse(Parse::Uri) | Kind::Parse(Parse::Version) => StatusCode::BAD_REQUEST, Kind::Parse(Parse::TooLarge) => StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE, @@ -1106,7 +1106,7 @@ impl Client { // malformed. A server should respond with 400 Bad Request. if inc.version == Version::HTTP_10 { debug!("HTTP/1.0 cannot have Transfer-Encoding header"); - Err(Parse::Header) + Err(Parse::transfer_encoding_unexpected()) } else if headers::transfer_encoding_is_chunked(&inc.headers) { Ok(Some((DecodedLength::CHUNKED, false))) } else { @@ -1117,7 +1117,7 @@ impl Client { Ok(Some((DecodedLength::checked_new(len)?, false))) } else if inc.headers.contains_key(header::CONTENT_LENGTH) { debug!("illegal Content-Length header"); - Err(Parse::Header) + Err(Parse::content_length_invalid()) } else { trace!("neither Transfer-Encoding nor Content-Length"); Ok(Some((DecodedLength::CLOSE_DELIMITED, false)))