worker/http/
request.rs

1use crate::http::body::Body;
2use crate::Cf;
3use crate::Result;
4use crate::{http::redirect::RequestRedirect, AbortSignal};
5use worker_sys::ext::RequestExt;
6
7use crate::http::body::BodyStream;
8use crate::http::header::{header_map_from_web_sys_headers, web_sys_headers_from_header_map};
9use bytes::Bytes;
10
11fn version_from_string(version: &str) -> http::Version {
12    match version {
13        "HTTP/0.9" => http::Version::HTTP_09,
14        "HTTP/1.0" => http::Version::HTTP_10,
15        "HTTP/1.1" => http::Version::HTTP_11,
16        "HTTP/2" => http::Version::HTTP_2,
17        "HTTP/3" => http::Version::HTTP_3,
18        _ => unreachable!("no other versions exist"),
19    }
20}
21
22/// **Requires** `http` feature. Convert [`web_sys::Request`](web_sys::Request)
23/// to [`worker::HttpRequest`](crate::HttpRequest)
24pub fn from_wasm(req: web_sys::Request) -> Result<http::Request<Body>> {
25    let mut builder = http::request::Builder::new()
26        .uri(req.url())
27        .extension(AbortSignal::from(req.signal()))
28        .extension(RequestRedirect::from(req.redirect()))
29        .method(&*req.method());
30
31    if let Some(headers) = builder.headers_mut() {
32        header_map_from_web_sys_headers(req.headers(), headers)?;
33    }
34
35    if let Some(cf) = req.cf() {
36        builder = builder
37            .version(version_from_string(&cf.http_protocol()?))
38            .extension(Cf::new(cf));
39    }
40
41    Ok(if let Some(body) = req.body() {
42        builder.body(Body::new(body))?
43    } else {
44        builder.body(Body::empty())?
45    })
46}
47
48/// **Requires** `http` feature. Convert [`http::Request`](http::Request)
49/// to [`web_sys::Request`](web_sys::Request)
50pub fn to_wasm<B: http_body::Body<Data = Bytes> + 'static>(
51    mut req: http::Request<B>,
52) -> Result<web_sys::Request> {
53    let init = web_sys::RequestInit::new();
54    init.set_method(req.method().as_str());
55    let headers = web_sys_headers_from_header_map(req.headers())?;
56    init.set_headers(headers.as_ref());
57    let uri = req.uri().to_string();
58
59    let signal = req.extensions_mut().remove::<AbortSignal>();
60    init.set_signal(signal.as_ref().map(|s| s.inner()));
61
62    if let Some(redirect) = req.extensions_mut().remove::<RequestRedirect>() {
63        init.set_redirect(redirect.into());
64    }
65
66    if let Some(cf) = req.extensions_mut().remove::<Cf>() {
67        // TODO: this should be handled in worker-sys
68        let r = ::js_sys::Reflect::set(
69            init.as_ref(),
70            &wasm_bindgen::JsValue::from("cf"),
71            &wasm_bindgen::JsValue::from(cf.inner()),
72        );
73        debug_assert!(
74            r.is_ok(),
75            "setting properties should never fail on our dictionary objects"
76        );
77        let _ = r;
78    }
79
80    let body = req.into_body();
81    if !body.is_end_stream() {
82        let readable_stream =
83            wasm_streams::ReadableStream::from_stream(BodyStream::new(body)).into_raw();
84        init.set_body(readable_stream.as_ref());
85    }
86
87    Ok(web_sys::Request::new_with_str_and_init(&uri, &init)?)
88}