reqwest/async_impl/
response.rs

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