use std::fmt; use bytes::Bytes; use http::{HeaderMap, StatusCode}; use js_sys::Uint8Array; use url::Url; #[cfg(feature = "json")] use serde::de::DeserializeOwned; /// A Response to a submitted `Request`. pub struct Response { http: http::Response, // Boxed to save space (11 words to 1 word), and it's not accessed // frequently internally. url: Box, } impl Response { pub(super) fn new(res: http::Response, url: Url) -> Response { Response { http: res, url: Box::new(url), } } /// Get the `StatusCode` of this `Response`. #[inline] pub fn status(&self) -> StatusCode { self.http.status() } /// Get the `Headers` of this `Response`. #[inline] pub fn headers(&self) -> &HeaderMap { self.http.headers() } /// Get a mutable reference to the `Headers` of this `Response`. #[inline] pub fn headers_mut(&mut self) -> &mut HeaderMap { self.http.headers_mut() } /// Get the content-length of this response, if known. /// /// Reasons it may not be known: /// /// - The server didn't send a `content-length` header. /// - The response is compressed and automatically decoded (thus changing /// the actual decoded length). pub fn content_length(&self) -> Option { self.headers() .get(http::header::CONTENT_LENGTH)? .to_str() .ok()? .parse() .ok() } /// Get the final `Url` of this `Response`. #[inline] pub fn url(&self) -> &Url { &self.url } /* It might not be possible to detect this in JS? /// Get the HTTP `Version` of this `Response`. #[inline] pub fn version(&self) -> Version { self.http.version() } */ /// Try to deserialize the response body as JSON. #[cfg(feature = "json")] #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub async fn json(self) -> crate::Result { let full = self.bytes().await?; serde_json::from_slice(&full).map_err(crate::error::decode) } /// Get the response text. pub async fn text(self) -> crate::Result { let p = self .http .body() .text() .map_err(crate::error::wasm) .map_err(crate::error::decode)?; let js_val = super::promise::(p) .await .map_err(crate::error::decode)?; if let Some(s) = js_val.as_string() { Ok(s) } else { Err(crate::error::decode("response.text isn't string")) } } /// Get the response as bytes pub async fn bytes(self) -> crate::Result { let p = self .http .body() .array_buffer() .map_err(crate::error::wasm) .map_err(crate::error::decode)?; let buf_js = super::promise::(p) .await .map_err(crate::error::decode)?; let buffer = Uint8Array::new(&buf_js); let mut bytes = vec![0; buffer.length() as usize]; buffer.copy_to(&mut bytes); Ok(bytes.into()) } // util methods /// Turn a response into an error if the server returned an error. pub fn error_for_status(self) -> crate::Result { let status = self.status(); if status.is_client_error() || status.is_server_error() { Err(crate::error::status_code(*self.url, status)) } else { Ok(self) } } /// Turn a reference to a response into an error if the server returned an error. pub fn error_for_status_ref(&self) -> crate::Result<&Self> { let status = self.status(); if status.is_client_error() || status.is_server_error() { Err(crate::error::status_code(*self.url.clone(), status)) } else { Ok(self) } } } impl fmt::Debug for Response { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Response") //.field("url", self.url()) .field("status", &self.status()) .field("headers", self.headers()) .finish() } }