diff --git a/src/async_impl/decoder.rs b/src/async_impl/decoder.rs index ce2f6fc..25f2f16 100644 --- a/src/async_impl/decoder.rs +++ b/src/async_impl/decoder.rs @@ -30,7 +30,7 @@ use bytes::{Buf, BufMut, BytesMut}; use libflate::non_blocking::gzip; use futures::{Async, Future, Poll, Stream}; 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 error; @@ -118,17 +118,17 @@ impl Decoder { content_encoding_gzip = headers .get_all(CONTENT_ENCODING) .iter() - .fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip")); + .fold(false, |acc, enc| acc || enc == "gzip"); content_encoding_gzip || headers .get_all(TRANSFER_ENCODING) .iter() - .fold(false, |acc, enc| acc || enc == HeaderValue::from_static("gzip")) + .fold(false, |acc, enc| acc || enc == "gzip") }; if is_gzip { if let Some(content_length) = headers.get(CONTENT_LENGTH) { if content_length == "0" { - warn!("GZipped response with content-length of 0"); + warn!("gzip response with content-length of 0"); is_gzip = false; } } diff --git a/src/async_impl/response.rs b/src/async_impl/response.rs index 0522f26..3b74a94 100644 --- a/src/async_impl/response.rs +++ b/src/async_impl/response.rs @@ -7,6 +7,7 @@ use futures::{Async, Future, Poll, Stream}; use futures::stream::Concat2; use hyper::{HeaderMap, StatusCode, Version}; use hyper::client::connect::HttpInfo; +use hyper::header::{CONTENT_LENGTH}; use serde::de::DeserializeOwned; use serde_json; 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 { - self - .extensions - .get::() - .map(|info| info.remote_addr()) - } /// Get the `StatusCode` of this `Response`. #[inline] @@ -81,6 +69,35 @@ impl Response { &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 { + self + .extensions + .get::() + .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 { + 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 pub fn into_body(self) -> Decoder { self.body diff --git a/src/response.rs b/src/response.rs index 5804f78..57e9087 100644 --- a/src/response.rs +++ b/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`. /// /// # Example @@ -75,90 +157,17 @@ impl Response { /// ``` pub fn remote_addr(&self) -> Option { 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 - /// # 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(()) - /// # } - /// ``` - /// - /// ```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() + /// - 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 { + self.inner.content_length() } /// Try and deserialize the response body as JSON using `serde`.