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&mut DebugStruct<'_, '_>.debug_struct("Response")
392 .field("url", self.url())
393 .field("status", &self.status())
394 .field(name:"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: Parts, body: T) = r.into_parts();
402 let body: Body = body.into();
403 let decoder: Decoder = Decoder::detect(&mut parts.headers, body, Accepts::none());
404 let url: ResponseUrl = partsOption
405 .extensions
406 .remove::<ResponseUrl>()
407 .unwrap_or_else(|| ResponseUrl(Url::parse(input:"http://no.url.provided.local").unwrap()));
408 let url: Url = url.0;
409 let res: Response = hyper::Response::from_parts(parts, body: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}
445