worker/http/
response.rs

1use super::header::{header_map_from_web_sys_headers, web_sys_headers_from_header_map};
2use crate::http::body::Body;
3use crate::HttpResponse;
4use crate::Result;
5use crate::WebSocket;
6use bytes::Bytes;
7
8use crate::http::body::BodyStream;
9use crate::response::EncodeBody;
10use crate::CfResponseProperties;
11use crate::Headers;
12use crate::ResponseBuilder;
13use worker_sys::ext::ResponseExt;
14
15/// **Requires** `http` feature. Convert generic [`http::Response<B>`](crate::HttpResponse)
16/// to [`web_sys::Response`](web_sys::Response) where `B` can be any [`http_body::Body`](http_body::Body)
17pub fn to_wasm<B>(mut res: http::Response<B>) -> Result<web_sys::Response>
18where
19    B: http_body::Body<Data = Bytes> + 'static,
20{
21    let headers = web_sys_headers_from_header_map(res.headers())?;
22    let mut init = ResponseBuilder::new()
23        .with_status(res.status().as_u16())
24        .with_headers(Headers(headers));
25
26    if let Some(ws) = res.extensions_mut().remove::<WebSocket>() {
27        init = init.with_websocket(ws);
28    }
29    if let Some(encode_body) = res.extensions_mut().remove::<EncodeBody>() {
30        init = init.with_encode_body(encode_body);
31    }
32    if let Some(CfResponseProperties(obj)) = res.extensions_mut().remove::<CfResponseProperties>() {
33        init = init.with_cf_raw(obj);
34    }
35
36    let body = res.into_body();
37    // I'm not sure how we are supposed to determine if there is no
38    // body for an `http::Response`, seems like this may be the only
39    // option given the trait? This appears to work for things like
40    // `hyper::Empty`.
41    let readable_stream = if body.is_end_stream() {
42        None
43    } else {
44        let stream = BodyStream::new(body);
45        Some(wasm_streams::ReadableStream::from_stream(stream).into_raw())
46    };
47
48    Ok(web_sys::Response::new_with_opt_readable_stream_and_init(
49        readable_stream.as_ref(),
50        &init.into(),
51    )?)
52}
53
54/// **Requires** `http` feature. Convert [`web_sys::Response`](web_sys::Response)
55/// to [`worker::HttpResponse`](crate::HttpResponse)
56pub fn from_wasm(res: web_sys::Response) -> Result<HttpResponse> {
57    let mut builder =
58        http::response::Builder::new().status(http::StatusCode::from_u16(res.status())?);
59    if let Some(headers) = builder.headers_mut() {
60        header_map_from_web_sys_headers(res.headers(), headers)?;
61    }
62    if let Some(ws) = res.websocket() {
63        builder = builder.extension(WebSocket::from(ws));
64    }
65    if let Some(cf) = res.cf() {
66        builder = builder.extension(CfResponseProperties(cf));
67    }
68    Ok(if let Some(body) = res.body() {
69        builder.body(Body::new(body))?
70    } else {
71        builder.body(Body::empty())?
72    })
73}
74
75#[cfg(feature = "axum")]
76impl From<crate::Response> for http::Response<axum::body::Body> {
77    fn from(resp: crate::Response) -> http::Response<axum::body::Body> {
78        let res: web_sys::Response = resp.into();
79        let mut builder = http::response::Builder::new()
80            .status(http::StatusCode::from_u16(res.status()).unwrap());
81        if let Some(headers) = builder.headers_mut() {
82            crate::http::header::header_map_from_web_sys_headers(res.headers(), headers).unwrap();
83        }
84        if let Some(ws) = res.websocket() {
85            builder = builder.extension(WebSocket::from(ws));
86        }
87        if let Some(cf) = res.cf() {
88            builder = builder.extension(CfResponseProperties(cf));
89        }
90        if let Some(body) = res.body() {
91            builder
92                .body(axum::body::Body::new(crate::Body::new(body)))
93                .unwrap()
94        } else {
95            builder
96                .body(axum::body::Body::new(crate::Body::empty()))
97                .unwrap()
98        }
99    }
100}