1 use std::borrow::Cow;
2 use std::fmt;
3 use std::net::SocketAddr;
4 use std::pin::Pin;
5 
6 use bytes::Bytes;
7 use encoding_rs::{Encoding, UTF_8};
8 use futures_util::stream::StreamExt;
9 use hyper::client::connect::HttpInfo;
10 use hyper::{HeaderMap, StatusCode, Version};
11 use mime::Mime;
12 #[cfg(feature = "json")]
13 use serde::de::DeserializeOwned;
14 #[cfg(feature = "json")]
15 use serde_json;
16 use tokio::time::Sleep;
17 use url::Url;
18 
19 use super::body::Body;
20 use super::decoder::{Accepts, Decoder};
21 #[cfg(feature = "cookies")]
22 use crate::cookie;
23 use crate::response::ResponseUrl;
24 
25 /// A Response to a submitted `Request`.
26 pub struct Response {
27     status: StatusCode,
28     headers: HeaderMap,
29     // Boxed to save space (11 words to 1 word), and it's not accessed
30     // frequently internally.
31     url: Box<Url>,
32     body: Decoder,
33     version: Version,
34     extensions: http::Extensions,
35 }
36 
37 impl Response {
new( res: hyper::Response<hyper::Body>, url: Url, accepts: Accepts, timeout: Option<Pin<Box<Sleep>>>, ) -> Response38     pub(super) fn new(
39         res: hyper::Response<hyper::Body>,
40         url: Url,
41         accepts: Accepts,
42         timeout: Option<Pin<Box<Sleep>>>,
43     ) -> Response {
44         let (parts, body) = res.into_parts();
45         let status = parts.status;
46         let version = parts.version;
47         let extensions = parts.extensions;
48 
49         let mut headers = parts.headers;
50         let decoder = Decoder::detect(&mut headers, Body::response(body, timeout), accepts);
51 
52         Response {
53             status,
54             headers,
55             url: Box::new(url),
56             body: decoder,
57             version,
58             extensions,
59         }
60     }
61 
62     /// Get the `StatusCode` of this `Response`.
63     #[inline]
status(&self) -> StatusCode64     pub fn status(&self) -> StatusCode {
65         self.status
66     }
67 
68     /// Get the HTTP `Version` of this `Response`.
69     #[inline]
version(&self) -> Version70     pub fn version(&self) -> Version {
71         self.version
72     }
73 
74     /// Get the `Headers` of this `Response`.
75     #[inline]
headers(&self) -> &HeaderMap76     pub fn headers(&self) -> &HeaderMap {
77         &self.headers
78     }
79 
80     /// Get a mutable reference to the `Headers` of this `Response`.
81     #[inline]
headers_mut(&mut self) -> &mut HeaderMap82     pub fn headers_mut(&mut self) -> &mut HeaderMap {
83         &mut self.headers
84     }
85 
86     /// Get the content-length of this response, if known.
87     ///
88     /// Reasons it may not be known:
89     ///
90     /// - The server didn't send a `content-length` header.
91     /// - The response is compressed and automatically decoded (thus changing
92     ///   the actual decoded length).
content_length(&self) -> Option<u64>93     pub fn content_length(&self) -> Option<u64> {
94         use hyper::body::HttpBody;
95 
96         HttpBody::size_hint(&self.body).exact()
97     }
98 
99     /// Retrieve the cookies contained in the response.
100     ///
101     /// Note that invalid 'Set-Cookie' headers will be ignored.
102     ///
103     /// # Optional
104     ///
105     /// This requires the optional `cookies` feature to be enabled.
106     #[cfg(feature = "cookies")]
107     #[cfg_attr(docsrs, doc(cfg(feature = "cookies")))]
cookies<'a>(&'a self) -> impl Iterator<Item = cookie::Cookie<'a>> + 'a108     pub fn cookies<'a>(&'a self) -> impl Iterator<Item = cookie::Cookie<'a>> + 'a {
109         cookie::extract_response_cookies(&self.headers).filter_map(Result::ok)
110     }
111 
112     /// Get the final `Url` of this `Response`.
113     #[inline]
url(&self) -> &Url114     pub fn url(&self) -> &Url {
115         &self.url
116     }
117 
118     /// Get the remote address used to get this `Response`.
remote_addr(&self) -> Option<SocketAddr>119     pub fn remote_addr(&self) -> Option<SocketAddr> {
120         self.extensions
121             .get::<HttpInfo>()
122             .map(|info| info.remote_addr())
123     }
124 
125     // body methods
126 
127     /// Get the full response text.
128     ///
129     /// This method decodes the response body with BOM sniffing
130     /// and with malformed sequences replaced with the REPLACEMENT CHARACTER.
131     /// Encoding is determinated from the `charset` parameter of `Content-Type` header,
132     /// and defaults to `utf-8` if not presented.
133     ///
134     /// # Example
135     ///
136     /// ```
137     /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
138     /// let content = reqwest::get("http://httpbin.org/range/26")
139     ///     .await?
140     ///     .text()
141     ///     .await?;
142     ///
143     /// println!("text: {:?}", content);
144     /// # Ok(())
145     /// # }
146     /// ```
text(self) -> crate::Result<String>147     pub async fn text(self) -> crate::Result<String> {
148         self.text_with_charset("utf-8").await
149     }
150 
151     /// Get the full response text given a specific encoding.
152     ///
153     /// This method decodes the response body with BOM sniffing
154     /// and with malformed sequences replaced with the REPLACEMENT CHARACTER.
155     /// You can provide a default encoding for decoding the raw message, while the
156     /// `charset` parameter of `Content-Type` header is still prioritized. For more information
157     /// about the possible encoding name, please go to [`encoding_rs`] docs.
158     ///
159     /// [`encoding_rs`]: https://docs.rs/encoding_rs/0.8/encoding_rs/#relationship-with-windows-code-pages
160     ///
161     /// # Example
162     ///
163     /// ```
164     /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
165     /// let content = reqwest::get("http://httpbin.org/range/26")
166     ///     .await?
167     ///     .text_with_charset("utf-8")
168     ///     .await?;
169     ///
170     /// println!("text: {:?}", content);
171     /// # Ok(())
172     /// # }
173     /// ```
text_with_charset(self, default_encoding: &str) -> crate::Result<String>174     pub async fn text_with_charset(self, default_encoding: &str) -> crate::Result<String> {
175         let content_type = self
176             .headers
177             .get(crate::header::CONTENT_TYPE)
178             .and_then(|value| value.to_str().ok())
179             .and_then(|value| value.parse::<Mime>().ok());
180         let encoding_name = content_type
181             .as_ref()
182             .and_then(|mime| mime.get_param("charset").map(|charset| charset.as_str()))
183             .unwrap_or(default_encoding);
184         let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
185 
186         let full = self.bytes().await?;
187 
188         let (text, _, _) = encoding.decode(&full);
189         if let Cow::Owned(s) = text {
190             return Ok(s);
191         }
192         unsafe {
193             // decoding returned Cow::Borrowed, meaning these bytes
194             // are already valid utf8
195             Ok(String::from_utf8_unchecked(full.to_vec()))
196         }
197     }
198 
199     /// Try to deserialize the response body as JSON.
200     ///
201     /// # Optional
202     ///
203     /// This requires the optional `json` feature enabled.
204     ///
205     /// # Examples
206     ///
207     /// ```
208     /// # extern crate reqwest;
209     /// # extern crate serde;
210     /// #
211     /// # use reqwest::Error;
212     /// # use serde::Deserialize;
213     /// #
214     /// // This `derive` requires the `serde` dependency.
215     /// #[derive(Deserialize)]
216     /// struct Ip {
217     ///     origin: String,
218     /// }
219     ///
220     /// # async fn run() -> Result<(), Error> {
221     /// let ip = reqwest::get("http://httpbin.org/ip")
222     ///     .await?
223     ///     .json::<Ip>()
224     ///     .await?;
225     ///
226     /// println!("ip: {}", ip.origin);
227     /// # Ok(())
228     /// # }
229     /// #
230     /// # fn main() { }
231     /// ```
232     ///
233     /// # Errors
234     ///
235     /// This method fails whenever the response body is not in JSON format
236     /// or it cannot be properly deserialized to target type `T`. For more
237     /// details please see [`serde_json::from_reader`].
238     ///
239     /// [`serde_json::from_reader`]: https://docs.serde.rs/serde_json/fn.from_reader.html
240     #[cfg(feature = "json")]
241     #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
json<T: DeserializeOwned>(self) -> crate::Result<T>242     pub async fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
243         let full = self.bytes().await?;
244 
245         serde_json::from_slice(&full).map_err(crate::error::decode)
246     }
247 
248     /// Get the full response body as `Bytes`.
249     ///
250     /// # Example
251     ///
252     /// ```
253     /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
254     /// let bytes = reqwest::get("http://httpbin.org/ip")
255     ///     .await?
256     ///     .bytes()
257     ///     .await?;
258     ///
259     /// println!("bytes: {:?}", bytes);
260     /// # Ok(())
261     /// # }
262     /// ```
bytes(self) -> crate::Result<Bytes>263     pub async fn bytes(self) -> crate::Result<Bytes> {
264         hyper::body::to_bytes(self.body).await
265     }
266 
267     /// Stream a chunk of the response body.
268     ///
269     /// When the response body has been exhausted, this will return `None`.
270     ///
271     /// # Example
272     ///
273     /// ```
274     /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
275     /// let mut res = reqwest::get("https://hyper.rs").await?;
276     ///
277     /// while let Some(chunk) = res.chunk().await? {
278     ///     println!("Chunk: {:?}", chunk);
279     /// }
280     /// # Ok(())
281     /// # }
282     /// ```
chunk(&mut self) -> crate::Result<Option<Bytes>>283     pub async fn chunk(&mut self) -> crate::Result<Option<Bytes>> {
284         if let Some(item) = self.body.next().await {
285             Ok(Some(item?))
286         } else {
287             Ok(None)
288         }
289     }
290 
291     /// Convert the response into a `Stream` of `Bytes` from the body.
292     ///
293     /// # Example
294     ///
295     /// ```
296     /// use futures_util::StreamExt;
297     ///
298     /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
299     /// let mut stream = reqwest::get("http://httpbin.org/ip")
300     ///     .await?
301     ///     .bytes_stream();
302     ///
303     /// while let Some(item) = stream.next().await {
304     ///     println!("Chunk: {:?}", item?);
305     /// }
306     /// # Ok(())
307     /// # }
308     /// ```
309     ///
310     /// # Optional
311     ///
312     /// This requires the optional `stream` feature to be enabled.
313     #[cfg(feature = "stream")]
314     #[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
bytes_stream(self) -> impl futures_core::Stream<Item = crate::Result<Bytes>>315     pub fn bytes_stream(self) -> impl futures_core::Stream<Item = crate::Result<Bytes>> {
316         self.body
317     }
318 
319     // util methods
320 
321     /// Turn a response into an error if the server returned an error.
322     ///
323     /// # Example
324     ///
325     /// ```
326     /// # use reqwest::Response;
327     /// fn on_response(res: Response) {
328     ///     match res.error_for_status() {
329     ///         Ok(_res) => (),
330     ///         Err(err) => {
331     ///             // asserting a 400 as an example
332     ///             // it could be any status between 400...599
333     ///             assert_eq!(
334     ///                 err.status(),
335     ///                 Some(reqwest::StatusCode::BAD_REQUEST)
336     ///             );
337     ///         }
338     ///     }
339     /// }
340     /// # fn main() {}
341     /// ```
error_for_status(self) -> crate::Result<Self>342     pub fn error_for_status(self) -> crate::Result<Self> {
343         if self.status.is_client_error() || self.status.is_server_error() {
344             Err(crate::error::status_code(*self.url, self.status))
345         } else {
346             Ok(self)
347         }
348     }
349 
350     /// Turn a reference to a response into an error if the server returned an error.
351     ///
352     /// # Example
353     ///
354     /// ```
355     /// # use reqwest::Response;
356     /// fn on_response(res: &Response) {
357     ///     match res.error_for_status_ref() {
358     ///         Ok(_res) => (),
359     ///         Err(err) => {
360     ///             // asserting a 400 as an example
361     ///             // it could be any status between 400...599
362     ///             assert_eq!(
363     ///                 err.status(),
364     ///                 Some(reqwest::StatusCode::BAD_REQUEST)
365     ///             );
366     ///         }
367     ///     }
368     /// }
369     /// # fn main() {}
370     /// ```
error_for_status_ref(&self) -> crate::Result<&Self>371     pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
372         if self.status.is_client_error() || self.status.is_server_error() {
373             Err(crate::error::status_code(*self.url.clone(), self.status))
374         } else {
375             Ok(self)
376         }
377     }
378 
379     // private
380 
381     // The Response's body is an implementation detail.
382     // You no longer need to get a reference to it, there are async methods
383     // on the `Response` itself.
384     //
385     // This method is just used by the blocking API.
386     #[cfg(feature = "blocking")]
body_mut(&mut self) -> &mut Decoder387     pub(crate) fn body_mut(&mut self) -> &mut Decoder {
388         &mut self.body
389     }
390 }
391 
392 impl fmt::Debug for Response {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result393     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394         f.debug_struct("Response")
395             .field("url", self.url())
396             .field("status", &self.status())
397             .field("headers", self.headers())
398             .finish()
399     }
400 }
401 
402 impl<T: Into<Body>> From<http::Response<T>> for Response {
from(r: http::Response<T>) -> Response403     fn from(r: http::Response<T>) -> Response {
404         let (mut parts, body) = r.into_parts();
405         let body = body.into();
406         let body = Decoder::detect(&mut parts.headers, body, Accepts::none());
407         let url = parts
408             .extensions
409             .remove::<ResponseUrl>()
410             .unwrap_or_else(|| ResponseUrl(Url::parse("http://no.url.provided.local").unwrap()));
411         let url = url.0;
412         Response {
413             status: parts.status,
414             headers: parts.headers,
415             url: Box::new(url),
416             body,
417             version: parts.version,
418             extensions: parts.extensions,
419         }
420     }
421 }
422 
423 /// A `Response` can be piped as the `Body` of another request.
424 impl From<Response> for Body {
from(r: Response) -> Body425     fn from(r: Response) -> Body {
426         Body::stream(r.body)
427     }
428 }
429 
430 #[cfg(test)]
431 mod tests {
432     use super::Response;
433     use crate::ResponseBuilderExt;
434     use http::response::Builder;
435     use url::Url;
436 
437     #[test]
test_from_http_response()438     fn test_from_http_response() {
439         let url = Url::parse("http://example.com").unwrap();
440         let response = Builder::new()
441             .status(200)
442             .url(url.clone())
443             .body("foo")
444             .unwrap();
445         let response = Response::from(response);
446 
447         assert_eq!(response.status(), 200);
448         assert_eq!(*response.url(), url);
449     }
450 }
451