reqwest_h3/wasm/
response.rs1use std::fmt;
2
3use bytes::Bytes;
4use http::{HeaderMap, StatusCode};
5use js_sys::Uint8Array;
6use url::Url;
7
8use crate::wasm::AbortGuard;
9
10#[cfg(feature = "stream")]
11use wasm_bindgen::JsCast;
12
13#[cfg(feature = "stream")]
14use futures_util::stream::StreamExt;
15
16#[cfg(feature = "json")]
17use serde::de::DeserializeOwned;
18
19pub struct Response {
21 http: http::Response<web_sys::Response>,
22 _abort: AbortGuard,
23 url: Box<Url>,
26}
27
28impl Response {
29 pub(super) fn new(
30 res: http::Response<web_sys::Response>,
31 url: Url,
32 abort: AbortGuard,
33 ) -> Response {
34 Response {
35 http: res,
36 url: Box::new(url),
37 _abort: abort,
38 }
39 }
40
41 #[inline]
43 pub fn status(&self) -> StatusCode {
44 self.http.status()
45 }
46
47 #[inline]
49 pub fn headers(&self) -> &HeaderMap {
50 self.http.headers()
51 }
52
53 #[inline]
55 pub fn headers_mut(&mut self) -> &mut HeaderMap {
56 self.http.headers_mut()
57 }
58
59 pub fn content_length(&self) -> Option<u64> {
67 self.headers()
68 .get(http::header::CONTENT_LENGTH)?
69 .to_str()
70 .ok()?
71 .parse()
72 .ok()
73 }
74
75 #[inline]
77 pub fn url(&self) -> &Url {
78 &self.url
79 }
80
81 #[cfg(feature = "json")]
91 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
92 pub async fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
93 let full = self.bytes().await?;
94
95 serde_json::from_slice(&full).map_err(crate::error::decode)
96 }
97
98 pub async fn text(self) -> crate::Result<String> {
100 let p = self
101 .http
102 .body()
103 .text()
104 .map_err(crate::error::wasm)
105 .map_err(crate::error::decode)?;
106 let js_val = super::promise::<wasm_bindgen::JsValue>(p)
107 .await
108 .map_err(crate::error::decode)?;
109 if let Some(s) = js_val.as_string() {
110 Ok(s)
111 } else {
112 Err(crate::error::decode("response.text isn't string"))
113 }
114 }
115
116 pub async fn bytes(self) -> crate::Result<Bytes> {
118 let p = self
119 .http
120 .body()
121 .array_buffer()
122 .map_err(crate::error::wasm)
123 .map_err(crate::error::decode)?;
124
125 let buf_js = super::promise::<wasm_bindgen::JsValue>(p)
126 .await
127 .map_err(crate::error::decode)?;
128
129 let buffer = Uint8Array::new(&buf_js);
130 let mut bytes = vec![0; buffer.length() as usize];
131 buffer.copy_to(&mut bytes);
132 Ok(bytes.into())
133 }
134
135 #[cfg(feature = "stream")]
137 pub fn bytes_stream(self) -> impl futures_core::Stream<Item = crate::Result<Bytes>> {
138 let web_response = self.http.into_body();
139 let abort = self._abort;
140 let body = web_response
141 .body()
142 .expect("could not create wasm byte stream");
143 let body = wasm_streams::ReadableStream::from_raw(body.unchecked_into());
144 Box::pin(body.into_stream().map(move |buf_js| {
145 let _abort = &abort;
147 let buffer = Uint8Array::new(
148 &buf_js
149 .map_err(crate::error::wasm)
150 .map_err(crate::error::decode)?,
151 );
152 let mut bytes = vec![0; buffer.length() as usize];
153 buffer.copy_to(&mut bytes);
154 Ok(bytes.into())
155 }))
156 }
157
158 pub fn error_for_status(self) -> crate::Result<Self> {
162 let status = self.status();
163 if status.is_client_error() || status.is_server_error() {
164 Err(crate::error::status_code(*self.url, status))
165 } else {
166 Ok(self)
167 }
168 }
169
170 pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
172 let status = self.status();
173 if status.is_client_error() || status.is_server_error() {
174 Err(crate::error::status_code(*self.url.clone(), status))
175 } else {
176 Ok(self)
177 }
178 }
179}
180
181impl fmt::Debug for Response {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 f.debug_struct("Response")
184 .field("status", &self.status())
186 .field("headers", self.headers())
187 .finish()
188 }
189}