golem_wasi_http/wasi/
response.rs1use crate::Body;
2use bytes::Bytes;
3use encoding_rs::{Encoding, UTF_8};
4use http::header::CONTENT_LENGTH;
5use http::{Extensions, HeaderMap, StatusCode, Version};
6use mime::Mime;
7#[cfg(feature = "json")]
8use serde::de::DeserializeOwned;
9#[cfg(feature = "json")]
10use serde_json;
11use std::borrow::Cow;
12use std::io;
13use std::io::Read;
14use std::net::SocketAddr;
15use url::Url;
16
17use wasi::http::types::IncomingBody;
18use wasi::http::*;
19use wasi::io::streams::InputStream;
20
21#[derive(Debug)]
23pub struct Response {
24 status: StatusCode,
25 headers: HeaderMap,
26 body: Option<Body>,
27 #[allow(dead_code)]
28 incoming_response: types::IncomingResponse,
29 url: Url,
30 extensions: Extensions,
31}
32
33impl Response {
34 pub(crate) fn new(
35 status: StatusCode,
36 headers: HeaderMap,
37 body: Body,
38 incoming_response: types::IncomingResponse,
39 url: Url,
40 ) -> Response {
41 Response {
42 status,
43 headers,
44 body: Some(body),
45 incoming_response,
46 url,
47 extensions: Extensions::default(),
48 }
49 }
50
51 #[inline]
53 pub fn status(&self) -> StatusCode {
54 self.status
55 }
56
57 #[inline]
59 pub fn headers(&self) -> &HeaderMap {
60 &self.headers
61 }
62
63 #[inline]
65 pub fn headers_mut(&mut self) -> &mut HeaderMap {
66 &mut self.headers
67 }
68
69 #[inline]
71 pub fn version(&self) -> Version {
72 Version::HTTP_11
73 }
74
75 #[inline]
77 pub fn url(&self) -> &Url {
78 &self.url
79 }
80
81 pub fn remote_addr(&self) -> Option<SocketAddr> {
83 None
84 }
85
86 pub fn extensions(&self) -> &http::Extensions {
88 &self.extensions
89 }
90
91 pub fn extensions_mut(&mut self) -> &mut http::Extensions {
93 &mut self.extensions
94 }
95
96 pub fn content_length(&self) -> Option<u64> {
104 self.headers
105 .get(CONTENT_LENGTH)
106 .and_then(|ct_len| ct_len.to_str().ok())
107 .and_then(|ct_len| ct_len.parse().ok())
108 }
109
110 #[cfg(feature = "json")]
123 #[cfg(not(feature = "async"))]
124 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
125 pub fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
126 let full = self.bytes()?;
127 serde_json::from_slice(&full).map_err(crate::error::decode)
128 }
129
130 #[cfg(feature = "json")]
143 #[cfg(feature = "async")]
144 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
145 pub async fn json<T: DeserializeOwned>(self) -> crate::Result<T> {
146 let full = self.bytes().await?;
147 serde_json::from_slice(&full).map_err(crate::error::decode)
148 }
149
150 #[cfg(not(feature = "async"))]
152 pub fn bytes(mut self) -> crate::Result<Bytes> {
153 let bytes: Bytes = Bytes::copy_from_slice(self.body.take().unwrap().buffer()?);
154 Ok(bytes)
155 }
156
157 #[cfg(feature = "async")]
159 pub async fn bytes(mut self) -> crate::Result<Bytes> {
160 let bytes: Bytes = Bytes::copy_from_slice(self.body.take().unwrap().buffer().await?);
161 Ok(bytes)
162 }
163
164 #[cfg(feature = "async")]
166 pub fn async_chunks(
167 mut self,
168 ) -> impl async_iterator::Iterator<Item = Result<Vec<u8>, crate::Error>> {
169 let sync_reader = self.body.take().unwrap().into_reader();
170 let async_reader = sync_reader.into_async();
171 async_reader
172 }
173
174 pub fn get_raw_input_stream(&mut self) -> (InputStream, IncomingBody) {
177 let body = self.body.take().unwrap();
178 body.into_raw_input_stream()
179 }
180
181 #[cfg(not(feature = "async"))]
188 pub fn text(self) -> crate::Result<String> {
189 self.text_with_charset("utf-8")
190 }
191
192 #[cfg(feature = "async")]
199 pub async fn text(self) -> crate::Result<String> {
200 self.text_with_charset("utf-8").await
201 }
202
203 #[cfg(not(feature = "async"))]
213 pub fn text_with_charset(self, default_encoding: &str) -> crate::Result<String> {
214 let content_type = self
215 .headers()
216 .get(crate::header::CONTENT_TYPE)
217 .and_then(|value| value.to_str().ok())
218 .and_then(|value| value.parse::<Mime>().ok());
219 let encoding_name = content_type
220 .as_ref()
221 .and_then(|mime| mime.get_param("charset").map(|charset| charset.as_str()))
222 .unwrap_or(default_encoding);
223 let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
224
225 let full = self.bytes()?;
226
227 let (text, _, _) = encoding.decode(&full);
228 if let Cow::Owned(s) = text {
229 return Ok(s);
230 }
231 unsafe {
232 Ok(String::from_utf8_unchecked(full.to_vec()))
235 }
236 }
237
238 #[cfg(feature = "async")]
248 pub async fn text_with_charset(self, default_encoding: &str) -> crate::Result<String> {
249 let content_type = self
250 .headers()
251 .get(crate::header::CONTENT_TYPE)
252 .and_then(|value| value.to_str().ok())
253 .and_then(|value| value.parse::<Mime>().ok());
254 let encoding_name = content_type
255 .as_ref()
256 .and_then(|mime| mime.get_param("charset").map(|charset| charset.as_str()))
257 .unwrap_or(default_encoding);
258 let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
259
260 let full = self.bytes().await?;
261
262 let (text, _, _) = encoding.decode(&full);
263 if let Cow::Owned(s) = text {
264 return Ok(s);
265 }
266 unsafe {
267 Ok(String::from_utf8_unchecked(full.to_vec()))
270 }
271 }
272
273 pub fn copy_to<W: io::Write + ?Sized>(&mut self, w: &mut W) -> crate::Result<u64> {
282 io::copy(self, w).map_err(crate::error::decode_io)
283 }
284
285 pub fn error_for_status(self) -> crate::Result<Self> {
287 let status = self.status();
288 if status.is_client_error() || status.is_server_error() {
289 Err(crate::error::status_code(self.url.clone(), status))
290 } else {
291 Ok(self)
292 }
293 }
294
295 pub fn error_for_status_ref(&self) -> crate::Result<&Self> {
297 let status = self.status();
298 if status.is_client_error() || status.is_server_error() {
299 Err(crate::error::status_code(self.url.clone(), status))
300 } else {
301 Ok(self)
302 }
303 }
304}
305
306impl Read for Response {
307 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
308 self.body.take().unwrap().into_reader().read(buf)
309 }
310}