perf(body): reduce memory size of Body by a u64 (#2118)
Replaces the `Option<u64>` content-length with a `DecodedLength`, which stores its unknown-ness as `u64::MAX`.
This commit is contained in:
@@ -239,7 +239,7 @@ where
|
||||
let mut body = match body_len {
|
||||
DecodedLength::ZERO => Body::empty(),
|
||||
other => {
|
||||
let (tx, rx) = Body::new_channel(other.into_opt());
|
||||
let (tx, rx) = Body::new_channel(other);
|
||||
self.body_tx = Some(tx);
|
||||
rx
|
||||
}
|
||||
|
||||
@@ -4,11 +4,10 @@ use futures_util::stream::StreamExt as _;
|
||||
use h2::client::{Builder, SendRequest};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use super::{PipeToSendStream, SendBuf};
|
||||
use super::{decode_content_length, PipeToSendStream, SendBuf};
|
||||
use crate::body::Payload;
|
||||
use crate::common::{task, Exec, Future, Never, Pin, Poll};
|
||||
use crate::headers;
|
||||
use crate::headers::content_length_parse_all;
|
||||
use crate::proto::Dispatched;
|
||||
use crate::{Body, Request, Response};
|
||||
|
||||
@@ -159,7 +158,7 @@ where
|
||||
|
||||
let fut = fut.map(move |result| match result {
|
||||
Ok(res) => {
|
||||
let content_length = content_length_parse_all(res.headers());
|
||||
let content_length = decode_content_length(res.headers());
|
||||
let res = res.map(|stream| crate::Body::h2(stream, content_length));
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@ use http::header::{
|
||||
use http::HeaderMap;
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::DecodedLength;
|
||||
use crate::body::Payload;
|
||||
use crate::common::{task, Future, Pin, Poll};
|
||||
use crate::headers::content_length_parse_all;
|
||||
|
||||
pub(crate) mod client;
|
||||
pub(crate) mod server;
|
||||
@@ -71,6 +73,15 @@ fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_content_length(headers: &HeaderMap) -> DecodedLength {
|
||||
if let Some(len) = content_length_parse_all(headers) {
|
||||
// If the length is u64::MAX, oh well, just reported chunked.
|
||||
DecodedLength::checked_new(len).unwrap_or_else(|_| DecodedLength::CHUNKED)
|
||||
} else {
|
||||
DecodedLength::CHUNKED
|
||||
}
|
||||
}
|
||||
|
||||
// body adapters used by both Client and Server
|
||||
|
||||
#[pin_project]
|
||||
|
||||
@@ -6,12 +6,11 @@ use h2::Reason;
|
||||
use pin_project::{pin_project, project};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use super::{PipeToSendStream, SendBuf};
|
||||
use super::{decode_content_length, PipeToSendStream, SendBuf};
|
||||
use crate::body::Payload;
|
||||
use crate::common::exec::H2Exec;
|
||||
use crate::common::{task, Future, Pin, Poll};
|
||||
use crate::headers;
|
||||
use crate::headers::content_length_parse_all;
|
||||
use crate::proto::Dispatched;
|
||||
use crate::service::HttpService;
|
||||
|
||||
@@ -168,7 +167,7 @@ where
|
||||
match ready!(self.conn.poll_accept(cx)) {
|
||||
Some(Ok((req, respond))) => {
|
||||
trace!("incoming request");
|
||||
let content_length = content_length_parse_all(req.headers());
|
||||
let content_length = decode_content_length(req.headers());
|
||||
let req = req.map(|stream| crate::Body::h2(stream, content_length));
|
||||
let fut = H2Stream::new(service.call(req), respond);
|
||||
exec.execute_h2stream(fut);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Pieces pertaining to the HTTP message protocol.
|
||||
use http::{HeaderMap, Method, StatusCode, Uri, Version};
|
||||
|
||||
use self::body_length::DecodedLength;
|
||||
pub(crate) use self::body_length::DecodedLength;
|
||||
pub(crate) use self::h1::{dispatch, Conn, ServerTransaction};
|
||||
|
||||
pub(crate) mod h1;
|
||||
@@ -90,6 +90,15 @@ mod body_length {
|
||||
Err(crate::error::Parse::TooLarge)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn sub_if(&mut self, amt: u64) {
|
||||
match *self {
|
||||
DecodedLength::CHUNKED | DecodedLength::CLOSE_DELIMITED => (),
|
||||
DecodedLength(ref mut known) => {
|
||||
*known -= amt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DecodedLength {
|
||||
@@ -112,4 +121,25 @@ mod body_length {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sub_if_known() {
|
||||
let mut len = DecodedLength::new(30);
|
||||
len.sub_if(20);
|
||||
|
||||
assert_eq!(len.0, 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_if_chunked() {
|
||||
let mut len = DecodedLength::CHUNKED;
|
||||
len.sub_if(20);
|
||||
|
||||
assert_eq!(len, DecodedLength::CHUNKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user