1 use std::fmt;
2 
3 use bytes::Bytes;
4 use http::{HeaderMap, StatusCode};
5 use js_sys::Uint8Array;
6 use url::Url;
7 
8 #[cfg(feature = "json")]
9 use serde::de::DeserializeOwned;
10 
11 /// A Response to a submitted `Request`.
12 pub struct Response {
13     http: http::Response<web_sys::Response>,
14     // Boxed to save space (11 words to 1 word), and it's not accessed
15     // frequently internally.
16     url: Box<Url>,
17 }
18 
19 impl Response {
new(res: http::Response<web_sys::Response>, url: Url) -> Response20     pub(super) fn new(res: http::Response<web_sys::Response>, url: Url) -> Response {
21         Response {
22             http: res,
23             url: Box::new(url),
24         }
25     }
26 
27     /// Get the `StatusCode` of this `Response`.
28     #[inline]
status(&self) -> StatusCode29     pub fn status(&self) -> StatusCode {
30         self.http.status()
31     }
32 
33     /// Get the `Headers` of this `Response`.
34     #[inline]
headers(&self) -> &HeaderMap35     pub fn headers(&self) -> &HeaderMap {
36         self.http.headers()
37     }
38 
39     /// Get a mutable reference to the `Headers` of this `Response`.
40     #[inline]
headers_mut(&mut self) -> &mut HeaderMap41     pub fn headers_mut(&mut self) -> &mut HeaderMap {
42         self.http.headers_mut()
43     }
44 
45     /// Get the content-length of this response, if known.
46     ///
47     /// Reasons it may not be known:
48     ///
49     /// - The server didn't send a `content-length` header.
50     /// - The response is compressed and automatically decoded (thus changing
51     ///  the actual decoded length).
content_length(&self) -> Option<u64>52     pub fn content_length(&self) -> Option<u64> {
53         self.headers()
54             .get(http::header::CONTENT_LENGTH)?
55             .to_str()
56             .ok()?
57             .parse()
58             .ok()
59     }
60 
61     /// Get the final `Url` of this `Response`.
62     #[inline]
url(&self) -> &Url63     pub fn url(&self) -> &Url {
64         &self.url
65     }
66 
67     /* It might not be possible to detect this in JS?
68     /// Get the HTTP `Version` of this `Response`.
69     #[inline]
70     pub fn version(&self) -> Version {
71         self.http.version()
72     }
73     */
74 
75     /// Try to deserialize the response body as JSON.
76     #[cfg(feature = "json")]
77     #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
json<T: DeserializeOwned>(self) -> crate::Result<T>78     pub async fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
79         let full = self.bytes().await?;
80 
81         serde_json::from_slice(&full).map_err(crate::error::decode)
82     }
83 
84     /// Get the response text.
text(self) -> crate::Result<String>85     pub async fn text(self) -> crate::Result<String> {
86         let p = self
87             .http
88             .body()
89             .text()
90             .map_err(crate::error::wasm)
91             .map_err(crate::error::decode)?;
92         let js_val = super::promise::<wasm_bindgen::JsValue>(p)
93             .await
94             .map_err(crate::error::decode)?;
95         if let Some(s) = js_val.as_string() {
96             Ok(s)
97         } else {
98             Err(crate::error::decode("response.text isn't string"))
99         }
100     }
101 
102     /// Get the response as bytes
bytes(self) -> crate::Result<Bytes>103     pub async fn bytes(self) -> crate::Result<Bytes> {
104         let p = self
105             .http
106             .body()
107             .array_buffer()
108             .map_err(crate::error::wasm)
109             .map_err(crate::error::decode)?;
110 
111         let buf_js = super::promise::<wasm_bindgen::JsValue>(p)
112             .await
113             .map_err(crate::error::decode)?;
114 
115         let buffer = Uint8Array::new(&buf_js);
116         let mut bytes = vec![0; buffer.length() as usize];
117         buffer.copy_to(&mut bytes);
118         Ok(bytes.into())
119     }
120 
121     // util methods
122 
123     /// Turn a response into an error if the server returned an error.
error_for_status(self) -> crate::Result<Self>124     pub fn error_for_status(self) -> crate::Result<Self> {
125         let status = self.status();
126         if status.is_client_error() || status.is_server_error() {
127             Err(crate::error::status_code(*self.url, status))
128         } else {
129             Ok(self)
130         }
131     }
132 
133     /// Turn a reference to a response into an error if the server returned an error.
error_for_status_ref(&self) -> crate::Result<&Self>134     pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
135         let status = self.status();
136         if status.is_client_error() || status.is_server_error() {
137             Err(crate::error::status_code(*self.url.clone(), status))
138         } else {
139             Ok(self)
140         }
141     }
142 }
143 
144 impl fmt::Debug for Response {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result145     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146         f.debug_struct("Response")
147             //.field("url", self.url())
148             .field("status", &self.status())
149             .field("headers", self.headers())
150             .finish()
151     }
152 }
153