optimise response decoding by using uninit header array

This commit is contained in:
Rob Ede 2022-03-08 01:09:01 +00:00
parent 3821ca1063
commit 4b3d0edc9e
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
1 changed files with 13 additions and 6 deletions

View File

@ -293,25 +293,35 @@ impl MessageType for ResponseHead {
let mut headers: [HeaderIndex; MAX_HEADERS] = EMPTY_HEADER_INDEX_ARRAY; let mut headers: [HeaderIndex; MAX_HEADERS] = EMPTY_HEADER_INDEX_ARRAY;
let (len, ver, status, h_len) = { let (len, ver, status, h_len) = {
let mut parsed: [httparse::Header<'_>; MAX_HEADERS] = EMPTY_HEADER_ARRAY; // SAFETY:
// Create an uninitialized array of `MaybeUninit`. The `assume_init` is safe because the
// type we are claiming to have initialized here is a bunch of `MaybeUninit`s, which
// do not require initialization.
let mut parsed = unsafe {
MaybeUninit::<[MaybeUninit<httparse::Header<'_>>; MAX_HEADERS]>::uninit()
.assume_init()
};
let mut res = httparse::Response::new(&mut []);
let mut config = httparse::ParserConfig::default(); let mut config = httparse::ParserConfig::default();
config.allow_spaces_after_header_name_in_responses(true); config.allow_spaces_after_header_name_in_responses(true);
let mut res = httparse::Response::new(&mut parsed); match config.parse_response_with_uninit_headers(&mut res, src, &mut parsed)? {
match config.parse_response(&mut res, src)? {
httparse::Status::Complete(len) => { httparse::Status::Complete(len) => {
let version = if res.version.unwrap() == 1 { let version = if res.version.unwrap() == 1 {
Version::HTTP_11 Version::HTTP_11
} else { } else {
Version::HTTP_10 Version::HTTP_10
}; };
let status = StatusCode::from_u16(res.code.unwrap()) let status = StatusCode::from_u16(res.code.unwrap())
.map_err(|_| ParseError::Status)?; .map_err(|_| ParseError::Status)?;
HeaderIndex::record(src, res.headers, &mut headers); HeaderIndex::record(src, res.headers, &mut headers);
(len, version, status, res.headers.len()) (len, version, status, res.headers.len())
} }
httparse::Status::Partial => { httparse::Status::Partial => {
return if src.len() >= MAX_BUFFER_SIZE { return if src.len() >= MAX_BUFFER_SIZE {
error!("MAX_BUFFER_SIZE unprocessed data reached, closing"); error!("MAX_BUFFER_SIZE unprocessed data reached, closing");
@ -363,9 +373,6 @@ pub(crate) const EMPTY_HEADER_INDEX: HeaderIndex = HeaderIndex {
pub(crate) const EMPTY_HEADER_INDEX_ARRAY: [HeaderIndex; MAX_HEADERS] = pub(crate) const EMPTY_HEADER_INDEX_ARRAY: [HeaderIndex; MAX_HEADERS] =
[EMPTY_HEADER_INDEX; MAX_HEADERS]; [EMPTY_HEADER_INDEX; MAX_HEADERS];
pub(crate) const EMPTY_HEADER_ARRAY: [httparse::Header<'static>; MAX_HEADERS] =
[httparse::EMPTY_HEADER; MAX_HEADERS];
impl HeaderIndex { impl HeaderIndex {
pub(crate) fn record( pub(crate) fn record(
bytes: &[u8], bytes: &[u8],