Add Response::content_length() method

This commit is contained in:
Sean McArthur
2019-01-18 11:42:27 -08:00
parent c7dc8851a3
commit 68e98d54ea
3 changed files with 123 additions and 97 deletions

View File

@@ -30,7 +30,7 @@ use bytes::{Buf, BufMut, BytesMut};
use libflate::non_blocking::gzip; use libflate::non_blocking::gzip;
use futures::{Async, Future, Poll, Stream}; use futures::{Async, Future, Poll, Stream};
use hyper::{HeaderMap}; use hyper::{HeaderMap};
use hyper::header::{CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING, HeaderValue}; use hyper::header::{CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING};
use super::{Body, Chunk}; use super::{Body, Chunk};
use error; use error;
@@ -118,17 +118,17 @@ impl Decoder {
content_encoding_gzip = headers content_encoding_gzip = headers
.get_all(CONTENT_ENCODING) .get_all(CONTENT_ENCODING)
.iter() .iter()
.fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip")); .fold(false, |acc, enc| acc || enc == "gzip");
content_encoding_gzip || content_encoding_gzip ||
headers headers
.get_all(TRANSFER_ENCODING) .get_all(TRANSFER_ENCODING)
.iter() .iter()
.fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip")) .fold(false, |acc, enc| acc || enc == "gzip")
}; };
if is_gzip { if is_gzip {
if let Some(content_length) = headers.get(CONTENT_LENGTH) { if let Some(content_length) = headers.get(CONTENT_LENGTH) {
if content_length == "0" { if content_length == "0" {
warn!("GZipped response with content-length of 0"); warn!("gzip response with content-length of 0");
is_gzip = false; is_gzip = false;
} }
} }

View File

@@ -7,6 +7,7 @@ use futures::{Async, Future, Poll, Stream};
use futures::stream::Concat2; use futures::stream::Concat2;
use hyper::{HeaderMap, StatusCode, Version}; use hyper::{HeaderMap, StatusCode, Version};
use hyper::client::connect::HttpInfo; use hyper::client::connect::HttpInfo;
use hyper::header::{CONTENT_LENGTH};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde_json; use serde_json;
use url::Url; use url::Url;
@@ -49,19 +50,6 @@ impl Response {
} }
} }
/// Get the final `Url` of this `Response`.
#[inline]
pub fn url(&self) -> &Url {
&self.url
}
/// Get the remote address used to get this `Response`.
pub fn remote_addr(&self) -> Option<SocketAddr> {
self
.extensions
.get::<HttpInfo>()
.map(|info| info.remote_addr())
}
/// Get the `StatusCode` of this `Response`. /// Get the `StatusCode` of this `Response`.
#[inline] #[inline]
@@ -81,6 +69,35 @@ impl Response {
&mut self.headers &mut self.headers
} }
/// Get the final `Url` of this `Response`.
#[inline]
pub fn url(&self) -> &Url {
&self.url
}
/// Get the remote address used to get this `Response`.
pub fn remote_addr(&self) -> Option<SocketAddr> {
self
.extensions
.get::<HttpInfo>()
.map(|info| info.remote_addr())
}
/// Get the content-length of this response, if known.
///
/// Reasons it may not be known:
///
/// - The server didn't send a `content-length` header.
/// - The response is gzipped and automatically decoded (thus changing
/// the actual decoded length).
pub fn content_length(&self) -> Option<u64> {
self
.headers()
.get(CONTENT_LENGTH)
.and_then(|ct_len| ct_len.to_str().ok())
.and_then(|ct_len| ct_len.parse().ok())
}
/// Consumes the response, returning the body /// Consumes the response, returning the body
pub fn into_body(self) -> Decoder { pub fn into_body(self) -> Decoder {
self.body self.body

View File

@@ -46,6 +46,88 @@ impl Response {
} }
} }
/// Get the `StatusCode` of this `Response`.
///
/// # Examples
///
/// Checking for general status class:
///
/// ```rust
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let resp = reqwest::get("http://httpbin.org/get")?;
/// if resp.status().is_success() {
/// println!("success!");
/// } else if resp.status().is_server_error() {
/// println!("server error!");
/// } else {
/// println!("Something else happened. Status: {:?}", resp.status());
/// }
/// # Ok(())
/// # }
/// ```
///
/// Checking for specific status codes:
///
/// ```rust
/// use reqwest::Client;
/// use reqwest::StatusCode;
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let client = Client::new();
///
/// let resp = client.post("http://httpbin.org/post")
/// .body("possibly too large")
/// .send()?;
///
/// match resp.status() {
/// StatusCode::OK => println!("success!"),
/// StatusCode::PAYLOAD_TOO_LARGE => {
/// println!("Request payload is too large!");
/// }
/// s => println!("Received response status: {:?}", s),
/// };
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn status(&self) -> StatusCode {
self.inner.status()
}
/// Get the `Headers` of this `Response`.
///
/// # Example
///
/// Saving an etag when caching a file:
///
/// ```
/// use reqwest::Client;
/// use reqwest::header::ETAG;
///
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let client = Client::new();
///
/// let mut resp = client.get("http://httpbin.org/cache").send()?;
/// if resp.status().is_success() {
/// if let Some(etag) = resp.headers().get(ETAG) {
/// std::fs::write("etag", etag.as_bytes());
/// }
/// let mut file = std::fs::File::create("file")?;
/// resp.copy_to(&mut file)?;
/// }
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn headers(&self) -> &HeaderMap {
self.inner.headers()
}
/// Get the HTTP `Version` of this `Response`.
#[inline]
pub fn version(&self) -> Version {
self.inner.version()
}
/// Get the final `Url` of this `Response`. /// Get the final `Url` of this `Response`.
/// ///
/// # Example /// # Example
@@ -75,90 +157,17 @@ impl Response {
/// ``` /// ```
pub fn remote_addr(&self) -> Option<SocketAddr> { pub fn remote_addr(&self) -> Option<SocketAddr> {
self.inner.remote_addr() self.inner.remote_addr()
} }
/// Get the `StatusCode` of this `Response`. /// Get the content-length of the response, if it is known.
/// ///
/// # Examples /// Reasons it may not be known:
/// ///
/// ```rust /// - The server didn't send a `content-length` header.
/// # fn run() -> Result<(), Box<::std::error::Error>> { /// - The response is gzipped and automatically decoded (thus changing
/// let resp = reqwest::get("http://httpbin.org/get")?; /// the actual decoded length).
/// if resp.status().is_success() { pub fn content_length(&self) -> Option<u64> {
/// println!("success!"); self.inner.content_length()
/// } else if resp.status().is_server_error() {
/// println!("server error!");
/// } else {
/// println!("Something else happened. Status: {:?}", resp.status());
/// }
/// # Ok(())
/// # }
/// ```
///
/// ```rust
/// use reqwest::Client;
/// use reqwest::StatusCode;
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let client = Client::new();
/// let resp = client.post("http://httpbin.org/post")
/// .body("possibly too large")
/// .send()?;
/// match resp.status() {
/// StatusCode::OK => println!("success!"),
/// StatusCode::PAYLOAD_TOO_LARGE => {
/// println!("Request payload is too large!");
/// }
/// s => println!("Received response status: {:?}", s),
/// };
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn status(&self) -> StatusCode {
self.inner.status()
}
/// Get the `Headers` of this `Response`.
///
/// # Example
///
/// Checking the `Content-Length` header before reading the response body.
///
/// ```rust
/// # use std::io::{Read, Write};
/// # use reqwest::Client;
/// # use reqwest::header::CONTENT_LENGTH;
/// #
/// # fn run() -> Result<(), Box<::std::error::Error>> {
/// let client = Client::new();
/// let mut resp = client.head("http://httpbin.org/bytes/3000").send()?;
/// if resp.status().is_success() {
/// let len = resp.headers().get(CONTENT_LENGTH)
/// .and_then(|ct_len| ct_len.to_str().ok())
/// .and_then(|ct_len| ct_len.parse().ok())
/// .unwrap_or(0);
/// // limit 1mb response
/// if len <= 1_000_000 {
/// let mut buf = Vec::with_capacity(len as usize);
/// let mut resp = reqwest::get("http://httpbin.org/bytes/3000")?;
/// if resp.status().is_success() {
/// ::std::io::copy(&mut resp, &mut buf)?;
/// }
/// }
/// }
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn headers(&self) -> &HeaderMap {
self.inner.headers()
}
/// Get the HTTP `Version` of this `Response`.
#[inline]
pub fn version(&self) -> Version {
self.inner.version()
} }
/// Try and deserialize the response body as JSON using `serde`. /// Try and deserialize the response body as JSON using `serde`.