Skip to main content

xitca_http/
http.rs

1//! re-export of [http] crate types.
2
3pub use ::http::*;
4
5use core::{
6    borrow::{Borrow, BorrowMut},
7    convert::Infallible,
8    mem,
9    net::SocketAddr,
10    pin::Pin,
11    result::Result as StdResult,
12    str::FromStr,
13    task::{Context, Poll},
14};
15
16use pin_project_lite::pin_project;
17
18use crate::body::{Body, Frame, SizeHint};
19
20/// Extended protocol get injected to [`RequestExt`] for context awareness
21#[derive(Debug, Copy, Clone, PartialEq)]
22pub struct Protocol {
23    inner: _Protocol,
24}
25
26#[derive(Debug, Copy, Clone, PartialEq)]
27enum _Protocol {
28    WebSocket,
29    WebTransport,
30    ConnectIp,
31    ConnectUdp,
32    Unknown,
33}
34
35impl Protocol {
36    pub const WEB_SOCKET: Self = Self::new(_Protocol::WebSocket);
37    pub const WEB_TRANSPORT: Self = Self::new(_Protocol::WebTransport);
38    pub const CONNECT_IP: Self = Self::new(_Protocol::ConnectIp);
39    pub const CONNECT_UDP: Self = Self::new(_Protocol::ConnectUdp);
40
41    pub(crate) fn from_str(str: &str) -> Self {
42        let inner = match str {
43            "websocket" => _Protocol::WebSocket,
44            "webtransport" => _Protocol::WebTransport,
45            "connect-ip" => _Protocol::ConnectIp,
46            "connect-udp" => _Protocol::ConnectUdp,
47            _ => _Protocol::Unknown,
48        };
49
50        Self { inner }
51    }
52
53    /// Wire-form name of this protocol, suitable for the `:protocol`
54    /// pseudo-header value. Returns `""` for protocols parsed from an
55    /// unrecognised string (round-tripping unknown protocols is not
56    /// supported).
57    pub fn as_str(&self) -> &'static str {
58        match self.inner {
59            _Protocol::WebSocket => "websocket",
60            _Protocol::WebTransport => "webtransport",
61            _Protocol::ConnectIp => "connect-ip",
62            _Protocol::ConnectUdp => "connect-udp",
63            _Protocol::Unknown => "",
64        }
65    }
66
67    const fn new(inner: _Protocol) -> Self {
68        Self { inner }
69    }
70}
71
72impl FromStr for Protocol {
73    type Err = Infallible;
74
75    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
76        Ok(Self::from_str(s))
77    }
78}
79
80/// Some often used header value.
81#[allow(clippy::declare_interior_mutable_const)]
82pub mod const_header_value {
83    use ::http::header::HeaderValue;
84
85    macro_rules! const_value {
86            ($(($ident: ident, $expr: expr)), *) => {
87                $(
88                   pub const $ident: HeaderValue = HeaderValue::from_static($expr);
89                )*
90            }
91        }
92
93    const_value!(
94        (TEXT, "text/plain"),
95        (TEXT_UTF8, "text/plain; charset=utf-8"),
96        (JSON, "application/json"),
97        (APPLICATION_WWW_FORM_URLENCODED, "application/x-www-form-urlencoded"),
98        (TEXT_HTML_UTF8, "text/html; charset=utf-8"),
99        (GRPC, "application/grpc"),
100        (WEBSOCKET, "websocket")
101    );
102}
103
104/// Some often used header name.
105#[allow(clippy::declare_interior_mutable_const)]
106pub mod const_header_name {
107    use ::http::header::HeaderName;
108
109    macro_rules! const_name {
110            ($(($ident: ident, $expr: expr)), *) => {
111                $(
112                   pub const $ident: HeaderName = HeaderName::from_static($expr);
113                )*
114            }
115        }
116
117    const_name!(
118        (GRPC_STATUS, "grpc-status"),
119        (GRPC_MESSAGE, "grpc-message"),
120        (GRPC_ENCODING, "grpc-encoding"),
121        (GRPC_ACCEPT_ENCODING, "grpc-accept-encoding"),
122        (GRPC_TIMEOUT, "grpc-timeout")
123    );
124}
125
126/// helper trait for converting a [Request] to [Response].
127/// This is a memory optimization for re-use heap allocation and pass down the context data
128/// inside [Extensions] from request to response.
129///
130/// # Example
131/// ```rust
132/// # use xitca_http::http::{Request, Response};
133/// // arbitrary typed state inserted into request type.
134/// #[derive(Clone)]
135/// struct Foo;
136///
137/// fn into_response(mut req: Request<()>) -> Response<()> {
138///     req.extensions_mut().insert(Foo); // insert Foo to request's extensions type map.
139///     
140///     // convert request into response in place with the same memory allocation.
141///     use xitca_http::http::IntoResponse;
142///     let res = req.into_response(());
143///     
144///     // the memory is re-used so Foo type is accessible from response's extensions type map.
145///     assert!(res.extensions().get::<Foo>().is_some());
146///
147///     res
148/// }
149///
150/// ```
151pub trait IntoResponse<B, ResB> {
152    fn into_response(self, body: B) -> Response<ResB>;
153
154    fn as_response(&mut self, body: B) -> Response<ResB>
155    where
156        Self: Default,
157    {
158        mem::take(self).into_response(body)
159    }
160}
161
162impl<ReqB, B, ResB> IntoResponse<B, ResB> for Request<ReqB>
163where
164    B: Into<ResB>,
165{
166    fn into_response(self, body: B) -> Response<ResB> {
167        let (
168            request::Parts {
169                mut headers,
170                extensions,
171                version,
172                ..
173            },
174            _,
175        ) = self.into_parts();
176        headers.clear();
177
178        let mut res = Response::new(body.into());
179        *res.headers_mut() = headers;
180        *res.extensions_mut() = extensions;
181        *res.version_mut() = version;
182
183        res
184    }
185}
186
187#[cfg(feature = "router")]
188use super::util::service::router::Params;
189
190pin_project! {
191    /// extension types for [Request]
192    #[derive(Debug)]
193    pub struct RequestExt<B> {
194        #[pin]
195        body: B,
196        // http::Extensions is often brought up as an alternative for extended states but in general
197        // xitca tries to be strongly typed when possible. runtime type casting is meant for library
198        // consumer but not library itself.
199        ext: Extension,
200    }
201}
202
203impl<B> Clone for RequestExt<B>
204where
205    B: Clone,
206{
207    fn clone(&self) -> Self {
208        Self {
209            body: self.body.clone(),
210            ext: Extension(Box::new(_Extension::clone(&*self.ext.0))),
211        }
212    }
213}
214
215// a separate extension type contain information can not be carried by http::Request. the goal is
216// to keep extended info strongly typed and not depend on runtime type map of http::Extensions.
217#[derive(Debug)]
218pub(crate) struct Extension(Box<_Extension>);
219
220impl Extension {
221    pub(crate) fn new(addr: SocketAddr) -> Self {
222        Self::with_protocol(addr, None)
223    }
224
225    pub(crate) fn with_protocol(addr: SocketAddr, protocol: Option<Protocol>) -> Self {
226        Self(Box::new(_Extension {
227            addr,
228            protocol,
229            #[cfg(feature = "router")]
230            params: Default::default(),
231        }))
232    }
233}
234
235#[derive(Clone, Debug)]
236struct _Extension {
237    addr: SocketAddr,
238    protocol: Option<Protocol>,
239    #[cfg(feature = "router")]
240    params: Params,
241}
242
243impl<B> RequestExt<B> {
244    pub(crate) fn from_parts(body: B, ext: Extension) -> Self {
245        Self { body, ext }
246    }
247
248    /// retrieve remote peer's socket address.
249    ///
250    /// # Default
251    /// [std::net::Ipv4Addr::UNSPECIFIED] is used for representing peers that can't provide it's socket address.
252    #[inline]
253    pub fn socket_addr(&self) -> &SocketAddr {
254        &self.ext.0.addr
255    }
256
257    /// exclusive version of [RequestExt::socket_addr]
258    #[inline]
259    pub fn socket_addr_mut(&mut self) -> &mut SocketAddr {
260        &mut self.ext.0.addr
261    }
262
263    pub fn protocol(&self) -> Option<Protocol> {
264        self.ext.0.protocol
265    }
266
267    /// map body type of self to another type with given function closure.
268    #[inline]
269    pub fn map_body<F, B1>(self, func: F) -> RequestExt<B1>
270    where
271        F: FnOnce(B) -> B1,
272    {
273        RequestExt {
274            body: func(self.body),
275            ext: self.ext,
276        }
277    }
278
279    /// replace body type of self with another type and return new type of Self and original body type
280    /// in tuple.
281    #[inline]
282    pub fn replace_body<B1>(self, body: B1) -> (RequestExt<B1>, B) {
283        let body_org = self.body;
284
285        (RequestExt { body, ext: self.ext }, body_org)
286    }
287}
288
289impl<B> Default for RequestExt<B>
290where
291    B: Default,
292{
293    fn default() -> Self {
294        Self::from_parts(B::default(), Extension::new(crate::unspecified_socket_addr()))
295    }
296}
297
298impl<B> Body for RequestExt<B>
299where
300    B: Body,
301{
302    type Data = B::Data;
303    type Error = B::Error;
304
305    #[inline]
306    fn poll_frame(
307        self: Pin<&mut Self>,
308        cx: &mut Context<'_>,
309    ) -> Poll<Option<StdResult<Frame<Self::Data>, Self::Error>>> {
310        self.project().body.poll_frame(cx)
311    }
312
313    #[inline]
314    fn is_end_stream(&self) -> bool {
315        self.body.is_end_stream()
316    }
317
318    #[inline]
319    fn size_hint(&self) -> SizeHint {
320        self.body.size_hint()
321    }
322}
323
324impl<B> Borrow<SocketAddr> for RequestExt<B> {
325    #[inline]
326    fn borrow(&self) -> &SocketAddr {
327        self.socket_addr()
328    }
329}
330
331#[cfg(feature = "router")]
332mod router {
333    use super::*;
334
335    impl<B> RequestExt<B> {
336        /// retrieve shared reference of route [Params].
337        #[inline]
338        pub fn params(&self) -> &Params {
339            &self.ext.0.params
340        }
341
342        /// retrieve exclusive reference of route [Params].
343        #[inline]
344        pub fn params_mut(&mut self) -> &mut Params {
345            &mut self.ext.0.params
346        }
347    }
348
349    impl<B> Borrow<Params> for RequestExt<B> {
350        #[inline]
351        fn borrow(&self) -> &Params {
352            self.params()
353        }
354    }
355
356    impl<B> BorrowMut<Params> for RequestExt<B> {
357        #[inline]
358        fn borrow_mut(&mut self) -> &mut Params {
359            self.params_mut()
360        }
361    }
362}
363
364/// trait for Borrow &T from &Self.
365/// used for foreign types (from xitca-http pov) that can be impl with [Borrow] trait.
366pub trait BorrowReq<T> {
367    fn borrow(&self) -> &T;
368}
369
370/// trait for Borrow &mut T from &mut Self.
371/// used for foreign types (from xitca-http pov) that can be impl with [BorrowMut] trait.
372pub trait BorrowReqMut<T> {
373    fn borrow_mut(&mut self) -> &mut T;
374}
375
376impl<Ext> BorrowReq<Uri> for Request<Ext> {
377    #[inline]
378    fn borrow(&self) -> &Uri {
379        self.uri()
380    }
381}
382
383impl<Ext> BorrowReq<Method> for Request<Ext> {
384    #[inline]
385    fn borrow(&self) -> &Method {
386        self.method()
387    }
388}
389
390impl<Ext> BorrowReq<HeaderMap> for Request<Ext> {
391    #[inline]
392    fn borrow(&self) -> &HeaderMap {
393        self.headers()
394    }
395}
396
397impl<Ext> BorrowReq<Extensions> for Request<Ext> {
398    #[inline]
399    fn borrow(&self) -> &Extensions {
400        self.extensions()
401    }
402}
403
404impl<Ext> BorrowReqMut<Extensions> for Request<Ext> {
405    #[inline]
406    fn borrow_mut(&mut self) -> &mut Extensions {
407        self.extensions_mut()
408    }
409}
410
411impl<T, B> BorrowReq<T> for Request<RequestExt<B>>
412where
413    RequestExt<B>: Borrow<T>,
414{
415    #[inline]
416    fn borrow(&self) -> &T {
417        self.body().borrow()
418    }
419}
420
421impl<T, B> BorrowReqMut<T> for Request<RequestExt<B>>
422where
423    RequestExt<B>: BorrowMut<T>,
424{
425    #[inline]
426    fn borrow_mut(&mut self) -> &mut T {
427        self.body_mut().borrow_mut()
428    }
429}