Skip to content

Commit

Permalink
Keep hyper Response struct while mapping hyper::Body to Decoder.
Browse files Browse the repository at this point in the history
  • Loading branch information
luqmana committed Oct 30, 2021
1 parent ab49de8 commit f1383d5
Showing 1 changed file with 28 additions and 40 deletions.
68 changes: 28 additions & 40 deletions src/async_impl/response.rs
Expand Up @@ -24,14 +24,10 @@ use crate::response::ResponseUrl;

/// A Response to a submitted `Request`.
pub struct Response {
status: StatusCode,
headers: HeaderMap,
res: hyper::Response<Decoder>,
// Boxed to save space (11 words to 1 word), and it's not accessed
// frequently internally.
url: Box<Url>,
body: Decoder,
version: Version,
extensions: http::Extensions,
}

impl Response {
Expand All @@ -41,46 +37,38 @@ impl Response {
accepts: Accepts,
timeout: Option<Pin<Box<Sleep>>>,
) -> Response {
let (parts, body) = res.into_parts();
let status = parts.status;
let version = parts.version;
let extensions = parts.extensions;

let mut headers = parts.headers;
let decoder = Decoder::detect(&mut headers, Body::response(body, timeout), accepts);
let (mut parts, body) = res.into_parts();
let decoder = Decoder::detect(&mut parts.headers, Body::response(body, timeout), accepts);
let res = hyper::Response::from_parts(parts, decoder);

Response {
status,
headers,
res,
url: Box::new(url),
body: decoder,
version,
extensions,
}
}

/// Get the `StatusCode` of this `Response`.
#[inline]
pub fn status(&self) -> StatusCode {
self.status
self.res.status()
}

/// Get the HTTP `Version` of this `Response`.
#[inline]
pub fn version(&self) -> Version {
self.version
self.res.version()
}

/// Get the `Headers` of this `Response`.
#[inline]
pub fn headers(&self) -> &HeaderMap {
&self.headers
self.res.headers()
}

/// Get a mutable reference to the `Headers` of this `Response`.
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers
self.res.headers_mut()
}

/// Get the content-length of this response, if known.
Expand All @@ -93,7 +81,7 @@ impl Response {
pub fn content_length(&self) -> Option<u64> {
use hyper::body::HttpBody;

HttpBody::size_hint(&self.body).exact()
HttpBody::size_hint(self.res.body()).exact()
}

/// Retrieve the cookies contained in the response.
Expand All @@ -106,7 +94,7 @@ impl Response {
#[cfg(feature = "cookies")]
#[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
pub fn cookies<'a>(&'a self) -> impl Iterator<Item = cookie::Cookie<'a>> + 'a {
cookie::extract_response_cookies(&self.headers).filter_map(Result::ok)
cookie::extract_response_cookies(self.res.headers()).filter_map(Result::ok)
}

/// Get the final `Url` of this `Response`.
Expand All @@ -117,7 +105,8 @@ impl Response {

/// Get the remote address used to get this `Response`.
pub fn remote_addr(&self) -> Option<SocketAddr> {
self.extensions
self.res
.extensions()
.get::<HttpInfo>()
.map(|info| info.remote_addr())
}
Expand Down Expand Up @@ -173,7 +162,7 @@ impl Response {
/// ```
pub async fn text_with_charset(self, default_encoding: &str) -> crate::Result<String> {
let content_type = self
.headers
.headers()
.get(crate::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse::<Mime>().ok());
Expand Down Expand Up @@ -261,7 +250,7 @@ impl Response {
/// # }
/// ```
pub async fn bytes(self) -> crate::Result<Bytes> {
hyper::body::to_bytes(self.body).await
hyper::body::to_bytes(self.res.into_body()).await
}

/// Stream a chunk of the response body.
Expand All @@ -281,7 +270,7 @@ impl Response {
/// # }
/// ```
pub async fn chunk(&mut self) -> crate::Result<Option<Bytes>> {
if let Some(item) = self.body.next().await {
if let Some(item) = self.res.body_mut().next().await {
Ok(Some(item?))
} else {
Ok(None)
Expand Down Expand Up @@ -313,7 +302,7 @@ impl Response {
#[cfg(feature = "stream")]
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
pub fn bytes_stream(self) -> impl futures_core::Stream<Item = crate::Result<Bytes>> {
self.body
self.res.into_body()
}

// util methods
Expand All @@ -340,8 +329,9 @@ impl Response {
/// # fn main() {}
/// ```
pub fn error_for_status(self) -> crate::Result<Self> {
if self.status.is_client_error() || self.status.is_server_error() {
Err(crate::error::status_code(*self.url, self.status))
let status = self.status();
if status.is_client_error() || status.is_server_error() {
Err(crate::error::status_code(*self.url, status))
} else {
Ok(self)
}
Expand Down Expand Up @@ -369,8 +359,9 @@ impl Response {
/// # fn main() {}
/// ```
pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
if self.status.is_client_error() || self.status.is_server_error() {
Err(crate::error::status_code(*self.url.clone(), self.status))
let status = self.status();
if status.is_client_error() || status.is_server_error() {
Err(crate::error::status_code(*self.url.clone(), status))
} else {
Ok(self)
}
Expand All @@ -385,7 +376,7 @@ impl Response {
// This method is just used by the blocking API.
#[cfg(feature = "blocking")]
pub(crate) fn body_mut(&mut self) -> &mut Decoder {
&mut self.body
self.res.body_mut()
}
}

Expand All @@ -403,27 +394,24 @@ impl<T: Into<Body>> From<http::Response<T>> for Response {
fn from(r: http::Response<T>) -> Response {
let (mut parts, body) = r.into_parts();
let body = body.into();
let body = Decoder::detect(&mut parts.headers, body, Accepts::none());
let decoder = Decoder::detect(&mut parts.headers, body, Accepts::none());
let url = parts
.extensions
.remove::<ResponseUrl>()
.unwrap_or_else(|| ResponseUrl(Url::parse("http://no.url.provided.local").unwrap()));
let url = url.0;
let res = hyper::Response::from_parts(parts, decoder);
Response {
status: parts.status,
headers: parts.headers,
res,
url: Box::new(url),
body,
version: parts.version,
extensions: parts.extensions,
}
}
}

/// A `Response` can be piped as the `Body` of another request.
impl From<Response> for Body {
fn from(r: Response) -> Body {
Body::stream(r.body)
Body::stream(r.res.into_body())
}
}

Expand Down

0 comments on commit f1383d5

Please sign in to comment.