reqwest_wasm/wasm/
response.rs1use std::fmt;
2
3use bytes::Bytes;
4use http::{HeaderMap, StatusCode};
5use js_sys::Uint8Array;
6use url::Url;
7
8#[cfg(feature = "stream")]
9use futures_util::stream::StreamExt;
10#[cfg(feature = "json")]
11use serde::de::DeserializeOwned;
12#[cfg(feature = "stream")]
13use wasm_bindgen::JsCast;
14#[cfg(feature = "stream")]
15use wasm_streams::ReadableStream;
16
17pub struct Response {
19 http: http::Response<web_sys::Response>,
20 url: Box<Url>,
23}
24
25impl Response {
26 pub(super) fn new(res: http::Response<web_sys::Response>, url: Url) -> Response {
27 Response {
28 http: res,
29 url: Box::new(url),
30 }
31 }
32
33 #[inline]
35 pub fn status(&self) -> StatusCode {
36 self.http.status()
37 }
38
39 #[inline]
41 pub fn headers(&self) -> &HeaderMap {
42 self.http.headers()
43 }
44
45 #[inline]
47 pub fn headers_mut(&mut self) -> &mut HeaderMap {
48 self.http.headers_mut()
49 }
50
51 pub fn content_length(&self) -> Option<u64> {
59 self.headers()
60 .get(http::header::CONTENT_LENGTH)?
61 .to_str()
62 .ok()?
63 .parse()
64 .ok()
65 }
66
67 #[inline]
69 pub fn url(&self) -> &Url {
70 &self.url
71 }
72
73 #[cfg(feature = "json")]
83 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
84 pub async fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
85 let full = self.bytes().await?;
86
87 serde_json::from_slice(&full).map_err(crate::error::decode)
88 }
89
90 pub async fn text(self) -> crate::Result<String> {
92 let p = self
93 .http
94 .body()
95 .text()
96 .map_err(crate::error::wasm)
97 .map_err(crate::error::decode)?;
98 let js_val = super::promise::<wasm_bindgen::JsValue>(p)
99 .await
100 .map_err(crate::error::decode)?;
101 if let Some(s) = js_val.as_string() {
102 Ok(s)
103 } else {
104 Err(crate::error::decode("response.text isn't string"))
105 }
106 }
107
108 pub async fn bytes(self) -> crate::Result<Bytes> {
110 let p = self
111 .http
112 .body()
113 .array_buffer()
114 .map_err(crate::error::wasm)
115 .map_err(crate::error::decode)?;
116
117 let buf_js = super::promise::<wasm_bindgen::JsValue>(p)
118 .await
119 .map_err(crate::error::decode)?;
120
121 let buffer = Uint8Array::new(&buf_js);
122 let mut bytes = vec![0; buffer.length() as usize];
123 buffer.copy_to(&mut bytes);
124 Ok(bytes.into())
125 }
126
127 #[cfg(feature = "stream")]
129 pub fn js_stream(self) -> web_sys::ReadableStream {
130 let web_response = self.http.into_body();
131
132 web_response
133 .body()
134 .expect("could not create wasm byte stream")
135 }
136
137 #[cfg(feature = "stream")]
139 pub fn bytes_stream(self) -> impl futures_core::Stream<Item = crate::Result<Bytes>> {
140 let body = self.js_stream();
141 let body = ReadableStream::from_raw(body.unchecked_into());
142 body.into_stream().map(|buf_js| {
143 let buffer = Uint8Array::new(
144 &buf_js
145 .map_err(crate::error::wasm)
146 .map_err(crate::error::decode)?,
147 );
148 let mut bytes = vec![0; buffer.length() as usize];
149 buffer.copy_to(&mut bytes);
150 Ok(bytes.into())
151 })
152 }
153
154 pub fn error_for_status(self) -> crate::Result<Self> {
158 let status = self.status();
159 if status.is_client_error() || status.is_server_error() {
160 Err(crate::error::status_code(*self.url, status))
161 } else {
162 Ok(self)
163 }
164 }
165
166 pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
168 let status = self.status();
169 if status.is_client_error() || status.is_server_error() {
170 Err(crate::error::status_code(*self.url.clone(), status))
171 } else {
172 Ok(self)
173 }
174 }
175}
176
177impl fmt::Debug for Response {
178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179 f.debug_struct("Response")
180 .field("status", &self.status())
182 .field("headers", self.headers())
183 .finish()
184 }
185}