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