refactor(http1): return Parse::Internal error if there's an illegal header name or value (#2544)

This commit is contained in:
bensadiku
2021-06-05 00:17:37 +02:00
committed by GitHub
parent 6a6a24030e
commit 55d9a584b1
2 changed files with 20 additions and 27 deletions

View File

@@ -73,6 +73,8 @@ pub(super) enum Parse {
Header, Header,
TooLarge, TooLarge,
Status, Status,
#[cfg_attr(debug_assertions, allow(unused))]
Internal,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@@ -374,6 +376,9 @@ impl Error {
Kind::Parse(Parse::Header) => "invalid HTTP header parsed", Kind::Parse(Parse::Header) => "invalid HTTP header parsed",
Kind::Parse(Parse::TooLarge) => "message head is too large", Kind::Parse(Parse::TooLarge) => "message head is too large",
Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed", Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed",
Kind::Parse(Parse::Internal) => {
"internal error inside Hyper and/or its dependencies, please report"
}
Kind::IncompleteMessage => "connection closed before message completed", Kind::IncompleteMessage => "connection closed before message completed",
#[cfg(feature = "http1")] #[cfg(feature = "http1")]
Kind::UnexpectedMessage => "received unexpected message from connection", Kind::UnexpectedMessage => "received unexpected message from connection",

View File

@@ -8,9 +8,9 @@ use std::mem;
#[cfg(any(test, feature = "server", feature = "ffi"))] #[cfg(any(test, feature = "server", feature = "ffi"))]
use bytes::Bytes; use bytes::Bytes;
use bytes::BytesMut; use bytes::BytesMut;
use http::header::{self, Entry, HeaderName, HeaderValue};
#[cfg(feature = "server")] #[cfg(feature = "server")]
use http::header::ValueIter; use http::header::ValueIter;
use http::header::{self, Entry, HeaderName, HeaderValue};
use http::{HeaderMap, Method, StatusCode, Version}; use http::{HeaderMap, Method, StatusCode, Version};
use crate::body::DecodedLength; use crate::body::DecodedLength;
@@ -29,22 +29,10 @@ const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
macro_rules! header_name { macro_rules! header_name {
($bytes:expr) => {{ ($bytes:expr) => {{
#[cfg(debug_assertions)]
{ {
match HeaderName::from_bytes($bytes) { match HeaderName::from_bytes($bytes) {
Ok(name) => name, Ok(name) => name,
Err(_) => panic!( Err(e) => maybe_panic!(e),
"illegal header name from httparse: {:?}",
::bytes::Bytes::copy_from_slice($bytes)
),
}
}
#[cfg(not(debug_assertions))]
{
match HeaderName::from_bytes($bytes) {
Ok(name) => name,
Err(_) => panic!("illegal header name from httparse: {:?}", $bytes),
} }
} }
}}; }};
@@ -52,23 +40,24 @@ macro_rules! header_name {
macro_rules! header_value { macro_rules! header_value {
($bytes:expr) => {{ ($bytes:expr) => {{
#[cfg(debug_assertions)]
{ {
let __hvb: ::bytes::Bytes = $bytes;
match HeaderValue::from_maybe_shared(__hvb.clone()) {
Ok(name) => name,
Err(_) => panic!("illegal header value from httparse: {:?}", __hvb),
}
}
#[cfg(not(debug_assertions))]
{
// Unsafe: httparse already validated header value
unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) } unsafe { HeaderValue::from_maybe_shared_unchecked($bytes) }
} }
}}; }};
} }
macro_rules! maybe_panic {
($($arg:tt)*) => ({
let _err = ($($arg)*);
if cfg!(debug_assertions) {
panic!("{:?}", _err);
} else {
error!("Internal Hyper error, please report {:?}", _err);
return Err(Parse::Internal)
}
})
}
pub(super) fn parse_headers<T>( pub(super) fn parse_headers<T>(
bytes: &mut BytesMut, bytes: &mut BytesMut,
ctx: ParseContext<'_>, ctx: ParseContext<'_>,
@@ -891,8 +880,7 @@ impl Http1Transaction for Client {
); );
let mut res = httparse::Response::new(&mut headers); let mut res = httparse::Response::new(&mut headers);
let bytes = buf.as_ref(); let bytes = buf.as_ref();
match ctx.h1_parser_config.parse_response(&mut res, bytes) match ctx.h1_parser_config.parse_response(&mut res, bytes) {
{
Ok(httparse::Status::Complete(len)) => { Ok(httparse::Status::Complete(len)) => {
trace!("Response.parse Complete({})", len); trace!("Response.parse Complete({})", len);
let status = StatusCode::from_u16(res.code.unwrap())?; let status = StatusCode::from_u16(res.code.unwrap())?;