leptos_spin/
request.rs

1use bytes::Bytes;
2use futures::{Stream, StreamExt};
3use leptos::server_fn::{error::ServerFnError, request::Req};
4use spin_sdk::http::IncomingRequest;
5use std::borrow::Cow;
6
7/// This is here because the orphan rule does not allow us to implement it on IncomingRequest with
8/// the generic error. So we have to wrap it to make it happy
9#[derive(Debug)]
10pub struct SpinRequest {
11    pub req: IncomingRequest,
12    pub path_with_query: Option<String>,
13}
14impl SpinRequest {
15    pub fn new_from_req(req: IncomingRequest) -> Self {
16        SpinRequest {
17            path_with_query: req.path_with_query(),
18            req,
19        }
20    }
21}
22
23impl<CustErr> Req<CustErr> for SpinRequest
24where
25    CustErr: 'static,
26{
27    fn as_query(&self) -> Option<&str> {
28        self.path_with_query
29            .as_ref()
30            .and_then(|n| n.split_once('?').map(|(_, query)| query))
31    }
32
33    fn to_content_type(&self) -> Option<Cow<'_, str>> {
34        self.req
35            .headers()
36            .get(&"Content-Type".to_string())
37            .first()
38            .map(|h| String::from_utf8_lossy(h))
39            .map(Cow::into_owned)
40            .map(Cow::<'static, str>::Owned)
41    }
42
43    fn accepts(&self) -> Option<Cow<'_, str>> {
44        self.req
45            .headers()
46            .get(&"Accept".to_string())
47            .first()
48            .map(|h| String::from_utf8_lossy(h))
49            .map(Cow::into_owned)
50            .map(Cow::<'static, str>::Owned)
51    }
52
53    fn referer(&self) -> Option<Cow<'_, str>> {
54        self.req
55            .headers()
56            .get(&"Referer".to_string())
57            .first()
58            .map(|h| String::from_utf8_lossy(h))
59            .map(Cow::into_owned)
60            .map(Cow::<'static, str>::Owned)
61    }
62
63    async fn try_into_bytes(self) -> Result<Bytes, ServerFnError<CustErr>> {
64        let buf = self
65            .req
66            .into_body()
67            .await
68            .map_err(|e| ServerFnError::Deserialization(e.to_string()))?;
69        Ok(Bytes::copy_from_slice(&buf))
70    }
71
72    async fn try_into_string(self) -> Result<String, ServerFnError<CustErr>> {
73        let bytes = self.try_into_bytes().await?;
74        String::from_utf8(bytes.to_vec()).map_err(|e| ServerFnError::Deserialization(e.to_string()))
75    }
76
77    fn try_into_stream(
78        self,
79    ) -> Result<
80        impl Stream<Item = Result<Bytes, ServerFnError>> + Send + 'static,
81        ServerFnError<CustErr>,
82    > {
83        Ok(self.req.into_body_stream().map(|chunk| {
84            chunk
85                .map(|c| Bytes::copy_from_slice(&c))
86                .map_err(|e| ServerFnError::Deserialization(e.to_string()))
87        }))
88    }
89}