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