1use crate::cors::Cors;
2use crate::error::Error;
3use crate::headers::Headers;
4use crate::ByteStream;
5use crate::Result;
6use crate::WebSocket;
7
8#[cfg(feature = "http")]
9use bytes::Bytes;
10use futures_util::{TryStream, TryStreamExt};
11use js_sys::Uint8Array;
12use serde::{de::DeserializeOwned, Serialize};
13#[cfg(feature = "http")]
14use std::convert::TryFrom;
15use wasm_bindgen::JsCast;
16use wasm_bindgen::JsValue;
17use web_sys::ReadableStream;
18use worker_sys::ext::{ResponseExt, ResponseInitExt};
19
20#[derive(Debug, Clone)]
21pub enum ResponseBody {
22 Empty,
23 Body(Vec<u8>),
24 Stream(ReadableStream),
25}
26
27const CONTENT_TYPE: &str = "content-type";
28
29#[derive(Debug)]
32pub struct Response {
33 body: ResponseBody,
34 init: ResponseBuilder,
35}
36
37#[cfg(feature = "http")]
38impl<B: http_body::Body<Data = Bytes> + 'static> TryFrom<http::Response<B>> for Response {
39 type Error = crate::Error;
40 fn try_from(res: http::Response<B>) -> Result<Self> {
41 let resp = crate::http::response::to_wasm(res)?;
42 Ok(resp.into())
43 }
44}
45
46#[cfg(feature = "http")]
47impl TryFrom<Response> for crate::HttpResponse {
48 type Error = crate::Error;
49 fn try_from(res: Response) -> Result<crate::HttpResponse> {
50 let sys_resp: web_sys::Response = res.into();
51 crate::http::response::from_wasm(sys_resp)
52 }
53}
54
55impl Response {
56 pub fn builder() -> ResponseBuilder {
58 ResponseBuilder::new()
59 }
60
61 pub fn from_json<B: Serialize>(value: &B) -> Result<Self> {
64 ResponseBuilder::new().from_json(value)
65 }
66
67 pub fn from_html(html: impl AsRef<str>) -> Result<Self> {
70 ResponseBuilder::new().from_html(html)
71 }
72
73 pub fn from_bytes(bytes: Vec<u8>) -> Result<Self> {
76 ResponseBuilder::new().from_bytes(bytes)
77 }
78
79 pub fn from_body(body: ResponseBody) -> Result<Self> {
82 Ok(ResponseBuilder::new().body(body))
83 }
84
85 pub fn from_websocket(websocket: WebSocket) -> Result<Self> {
88 Ok(ResponseBuilder::new()
89 .with_websocket(websocket)
90 .with_status(101)
91 .empty())
92 }
93
94 pub fn from_stream<S>(stream: S) -> Result<Self>
98 where
99 S: TryStream + 'static,
100 S::Ok: Into<Vec<u8>>,
101 S::Error: Into<Error>,
102 {
103 ResponseBuilder::new().from_stream(stream)
104 }
105
106 pub fn ok(body: impl Into<String>) -> Result<Self> {
109 ResponseBuilder::new().ok(body)
110 }
111
112 pub fn empty() -> Result<Self> {
114 Ok(ResponseBuilder::new().empty())
115 }
116
117 pub fn error(msg: impl Into<String>, status: u16) -> Result<Self> {
120 if !(400..=599).contains(&status) {
121 return Err(Error::Internal(
122 "error status codes must be in the 400-599 range! see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status for more".into(),
123 ));
124 }
125
126 Ok(ResponseBuilder::new()
127 .with_status(status)
128 .fixed(msg.into().into_bytes()))
129 }
130
131 pub fn redirect(url: url::Url) -> Result<Self> {
133 match web_sys::Response::redirect(url.as_str()) {
134 Ok(edge_response) => Ok(Response::from(edge_response)),
135 Err(err) => Err(Error::from(err)),
136 }
137 }
138
139 pub fn redirect_with_status(url: url::Url, status_code: u16) -> Result<Self> {
141 if !(300..=399).contains(&status_code) {
142 return Err(Error::Internal(
143 "redirect status codes must be in the 300-399 range! Please checkout https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages for more".into(),
144 ));
145 }
146 match web_sys::Response::redirect_with_status(url.as_str(), status_code) {
147 Ok(edge_response) => Ok(Response::from(edge_response)),
148 Err(err) => Err(Error::from(err)),
149 }
150 }
151
152 pub fn status_code(&self) -> u16 {
154 self.init.status_code
155 }
156
157 pub fn body(&self) -> &ResponseBody {
159 &self.body
160 }
161
162 pub async fn text(&mut self) -> Result<String> {
164 match &self.body {
165 ResponseBody::Body(bytes) => {
166 Ok(String::from_utf8(bytes.clone()).map_err(|e| Error::from(e.to_string()))?)
167 }
168 ResponseBody::Empty => Ok(String::new()),
169 ResponseBody::Stream(_) => {
170 let bytes = self.bytes().await?;
171 String::from_utf8(bytes).map_err(|e| Error::RustError(e.to_string()))
172 }
173 }
174 }
175
176 pub async fn json<B: DeserializeOwned>(&mut self) -> Result<B> {
178 serde_json::from_str(&self.text().await?).map_err(Error::from)
179 }
180
181 pub async fn bytes(&mut self) -> Result<Vec<u8>> {
183 match &self.body {
184 ResponseBody::Body(bytes) => Ok(bytes.clone()),
185 ResponseBody::Empty => Ok(Vec::new()),
186 ResponseBody::Stream(_) => {
187 self.stream()?
188 .try_fold(Vec::new(), |mut bytes, mut chunk| async move {
189 bytes.append(&mut chunk);
190 Ok(bytes)
191 })
192 .await
193 }
194 }
195 }
196
197 pub fn stream(&mut self) -> Result<ByteStream> {
199 let stream = match &self.body {
200 ResponseBody::Stream(edge_request) => edge_request.clone(),
201 _ => return Err(Error::RustError("body is not streamable".into())),
202 };
203
204 let stream = wasm_streams::ReadableStream::from_raw(stream.dyn_into().unwrap());
205
206 Ok(ByteStream {
207 inner: stream.into_stream(),
208 })
209 }
210
211 pub fn websocket(self) -> Option<WebSocket> {
213 self.init.websocket
214 }
215
216 pub fn with_headers(mut self, headers: Headers) -> Self {
218 self.init = self.init.with_headers(headers);
219 self
220 }
221
222 pub fn with_status(mut self, status_code: u16) -> Self {
226 self.init = self.init.with_status(status_code);
227 self
228 }
229
230 pub fn with_cors(mut self, cors: &Cors) -> Result<Self> {
241 self.init = self.init.with_cors(cors)?;
242 Ok(self)
243 }
244
245 pub fn with_websocket(mut self, websocket: Option<WebSocket>) -> Self {
248 self.init.websocket = websocket;
249 self
250 }
251
252 pub fn encode_body(&self) -> &EncodeBody {
254 &self.init.encode_body
255 }
256
257 pub fn with_encode_body(mut self, encode_body: EncodeBody) -> Self {
261 self.init.encode_body = encode_body;
262 self
263 }
264
265 pub fn cf<T: serde::de::DeserializeOwned>(&self) -> Result<Option<T>> {
267 self.init
268 .cf
269 .clone()
270 .map(|cf| serde_wasm_bindgen::from_value(cf.unchecked_into()))
271 .transpose()
272 .map_err(Error::SerdeWasmBindgenError)
273 }
274
275 pub fn with_cf<T: serde::Serialize>(mut self, cf: Option<T>) -> Result<Self> {
278 match cf {
279 Some(cf) => self.init = self.init.with_cf(cf)?,
280 None => self.init.cf = None,
281 }
282 Ok(self)
283 }
284
285 pub fn headers(&self) -> &Headers {
287 &self.init.headers
288 }
289
290 pub fn headers_mut(&mut self) -> &mut Headers {
292 &mut self.init.headers
293 }
294
295 pub fn into_parts(self) -> (ResponseBuilder, ResponseBody) {
298 (self.init, self.body)
299 }
300
301 pub fn cloned(&mut self) -> Result<Self> {
303 if self.init.websocket.is_some() {
304 return Err(Error::RustError("WebSockets cannot be cloned".into()));
305 }
306
307 let edge = web_sys::Response::from(&*self);
308 let cloned = edge.clone()?;
309
310 self.body = match edge.body() {
313 Some(stream) => ResponseBody::Stream(stream),
314 None => ResponseBody::Empty,
315 };
316
317 let clone: Response = cloned.into();
318
319 Ok(clone.with_encode_body(*self.encode_body()))
320 }
321}
322
323#[test]
324fn no_using_invalid_error_status_code() {
325 assert!(Response::error("OK", 200).is_err());
326 assert!(Response::error("600", 600).is_err());
327 assert!(Response::error("399", 399).is_err());
328}
329
330#[non_exhaustive]
331#[derive(Default, Debug, Clone, Copy)]
332pub enum EncodeBody {
335 #[default]
338 Automatic,
339 Manual,
342}
343
344#[derive(Debug, Clone)]
345pub struct ResponseBuilder {
346 status_code: u16,
347 headers: Headers,
348 websocket: Option<WebSocket>,
349 encode_body: EncodeBody,
350 cf: Option<js_sys::Object>,
351}
352
353impl ResponseBuilder {
354 pub fn new() -> Self {
355 Self {
356 status_code: 200,
357 headers: Headers::new(),
358 websocket: None,
359 encode_body: EncodeBody::default(),
360 cf: None,
361 }
362 }
363
364 pub fn with_status(mut self, status: u16) -> Self {
368 self.status_code = status;
369 self
370 }
371
372 pub fn with_headers(mut self, headers: Headers) -> Self {
374 self.headers = headers;
375 self
376 }
377
378 pub fn with_header(self, key: &str, value: &str) -> Result<Self> {
380 self.headers.set(key, value)?;
381 Ok(self)
382 }
383
384 pub fn with_cors(self, cors: &Cors) -> Result<Self> {
393 let mut headers = self.headers.clone();
394 cors.apply_headers(&mut headers)?;
395 Ok(self.with_headers(headers))
396 }
397
398 pub fn with_websocket(mut self, websocket: WebSocket) -> Self {
401 self.websocket = Some(websocket);
402 self
403 }
404
405 pub fn with_encode_body(mut self, encode_body: EncodeBody) -> Self {
409 self.encode_body = encode_body;
410 self
411 }
412
413 pub fn with_cf<T: serde::Serialize>(self, cf: T) -> Result<Self> {
416 let value = serde_wasm_bindgen::to_value(&cf)?;
417 if value.is_object() {
418 let obj = value.unchecked_into::<js_sys::Object>();
419 Ok(self.with_cf_raw(obj))
420 } else {
421 Err(Error::from("cf must be an object"))
422 }
423 }
424
425 pub(crate) fn with_cf_raw(mut self, obj: js_sys::Object) -> Self {
426 self.cf = Some(obj);
427 self
428 }
429
430 pub fn fixed(self, body: Vec<u8>) -> Response {
432 Response {
433 body: ResponseBody::Body(body),
434 init: self,
435 }
436 }
437
438 pub fn stream(self, stream: ReadableStream) -> Response {
440 Response {
441 body: ResponseBody::Stream(stream),
442 init: self,
443 }
444 }
445
446 pub fn body(self, body: ResponseBody) -> Response {
448 Response { body, init: self }
449 }
450
451 pub fn empty(self) -> Response {
453 Response {
454 body: ResponseBody::Empty,
455 init: self,
456 }
457 }
458
459 pub fn from_json<B: Serialize>(self, value: &B) -> Result<Response> {
462 if let Ok(data) = serde_json::to_string(value) {
463 self.headers.set(CONTENT_TYPE, "application/json")?;
464 Ok(self.fixed(data.into_bytes()))
465 } else {
466 Err(Error::Json(("Failed to encode data to json".into(), 500)))
467 }
468 }
469
470 pub fn from_html(self, html: impl AsRef<str>) -> Result<Response> {
473 self.headers.set(CONTENT_TYPE, "text/html; charset=utf-8")?;
474 let data = html.as_ref().as_bytes().to_vec();
475 Ok(self.fixed(data))
476 }
477
478 pub fn from_bytes(self, bytes: Vec<u8>) -> Result<Response> {
481 self.headers.set(CONTENT_TYPE, "application/octet-stream")?;
482 Ok(self.fixed(bytes))
483 }
484
485 pub fn from_stream<S>(self, stream: S) -> Result<Response>
489 where
490 S: TryStream + 'static,
491 S::Ok: Into<Vec<u8>>,
492 S::Error: Into<Error>,
493 {
494 let js_stream = stream
495 .map_ok(|item| -> Vec<u8> { item.into() })
496 .map_ok(|chunk| {
497 let array = Uint8Array::new_with_length(chunk.len() as _);
498 array.copy_from(&chunk);
499
500 array.into()
501 })
502 .map_err(|err| -> crate::Error { err.into() })
503 .map_err(|e| JsValue::from(e.to_string()));
504
505 let stream = wasm_streams::ReadableStream::from_stream(js_stream);
506 let stream: ReadableStream = stream.into_raw().dyn_into().unwrap();
507
508 Ok(self.stream(stream))
509 }
510
511 pub fn ok(self, body: impl Into<String>) -> Result<Response> {
514 self.headers
515 .set(CONTENT_TYPE, "text/plain; charset=utf-8")?;
516
517 Ok(self.fixed(body.into().into_bytes()))
518 }
519
520 pub fn error(self, msg: impl Into<String>, status: u16) -> Result<Response> {
523 if !(400..=599).contains(&status) {
524 return Err(Error::Internal(
525 "error status codes must be in the 400-599 range! see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status for more".into(),
526 ));
527 }
528
529 Ok(self.with_status(status).fixed(msg.into().into_bytes()))
530 }
531}
532
533impl From<ResponseBuilder> for web_sys::ResponseInit {
534 fn from(init: ResponseBuilder) -> Self {
535 let mut edge_init = web_sys::ResponseInit::new();
536 edge_init.set_status(init.status_code);
537 edge_init.set_headers(&init.headers.0);
538 if let Some(websocket) = &init.websocket {
539 edge_init
540 .websocket(websocket.as_ref())
541 .expect("failed to set websocket");
542 }
543 if matches!(init.encode_body, EncodeBody::Manual) {
544 edge_init
545 .encode_body("manual")
546 .expect("failed to set encode_body");
547 }
548 if let Some(cf) = init.cf {
549 edge_init.cf(&cf).expect("failed to set cf");
550 }
551 edge_init
552 }
553}
554
555impl From<Response> for web_sys::Response {
556 fn from(res: Response) -> Self {
557 match res.body {
558 ResponseBody::Body(bytes) => {
559 let array = Uint8Array::new_with_length(bytes.len() as u32);
560 array.copy_from(&bytes);
561 web_sys::Response::new_with_opt_buffer_source_and_init(
562 Some(&array),
563 &res.init.into(),
564 )
565 .unwrap()
566 }
567 ResponseBody::Stream(stream) => {
568 web_sys::Response::new_with_opt_readable_stream_and_init(
569 Some(&stream),
570 &res.init.into(),
571 )
572 .unwrap()
573 }
574 ResponseBody::Empty => {
575 web_sys::Response::new_with_opt_str_and_init(None, &res.init.into()).unwrap()
576 }
577 }
578 }
579}
580
581impl From<&Response> for web_sys::Response {
582 fn from(res: &Response) -> Self {
583 let init = res.init.clone();
584 match &res.body {
585 ResponseBody::Body(bytes) => {
586 let array = Uint8Array::new_with_length(bytes.len() as u32);
587 array.copy_from(bytes);
588 web_sys::Response::new_with_opt_buffer_source_and_init(Some(&array), &init.into())
589 .unwrap()
590 }
591 ResponseBody::Stream(stream) => {
592 web_sys::Response::new_with_opt_readable_stream_and_init(Some(stream), &init.into())
593 .unwrap()
594 }
595 ResponseBody::Empty => {
596 web_sys::Response::new_with_opt_str_and_init(None, &init.into()).unwrap()
597 }
598 }
599 }
600}
601
602impl From<web_sys::Response> for Response {
603 fn from(res: web_sys::Response) -> Self {
604 let builder = ResponseBuilder {
605 headers: Headers(res.headers()),
606 status_code: res.status(),
607 websocket: res.websocket().map(|ws| ws.into()),
608 encode_body: EncodeBody::Automatic,
609 cf: res.cf(),
610 };
611 match res.body() {
612 Some(stream) => builder.stream(stream),
613 None => builder.empty(),
614 }
615 }
616}
617
618pub trait IntoResponse {
621 fn into_raw(
622 self,
623 ) -> std::result::Result<web_sys::Response, impl Into<Box<dyn std::error::Error>>>;
624}
625
626impl IntoResponse for web_sys::Response {
627 fn into_raw(
628 self,
629 ) -> std::result::Result<web_sys::Response, impl Into<Box<dyn std::error::Error>>> {
630 Ok::<web_sys::Response, Error>(self)
631 }
632}
633
634impl IntoResponse for Response {
635 fn into_raw(
636 self,
637 ) -> std::result::Result<web_sys::Response, impl Into<Box<dyn std::error::Error>>> {
638 Ok::<web_sys::Response, Error>(self.into())
639 }
640}
641
642#[cfg(feature = "http")]
643impl<B> IntoResponse for http::Response<B>
644where
645 B: http_body::Body<Data = Bytes> + 'static,
646{
647 fn into_raw(
648 self,
649 ) -> std::result::Result<web_sys::Response, impl Into<Box<dyn std::error::Error>>> {
650 crate::http::response::to_wasm(self)
651 }
652}