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