Add Response::content_length() method
This commit is contained in:
		| @@ -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; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										169
									
								
								src/response.rs
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								src/response.rs
									
									
									
									
									
								
							| @@ -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`. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user