xitca_http/
http.rs

1//! re-export of [http] crate types.
2
3pub use ::http::*;
4
5use core::{
6    borrow::{Borrow, BorrowMut},
7    mem,
8    net::SocketAddr,
9    pin::Pin,
10    task::{Context, Poll},
11};
12
13use futures_core::stream::Stream;
14use pin_project_lite::pin_project;
15
16/// Some often used header value.
17#[allow(clippy::declare_interior_mutable_const)]
18pub mod const_header_value {
19    use ::http::header::HeaderValue;
20
21    macro_rules! const_value {
22            ($(($ident: ident, $expr: expr)), *) => {
23                $(
24                   pub const $ident: HeaderValue = HeaderValue::from_static($expr);
25                )*
26            }
27        }
28
29    const_value!(
30        (TEXT, "text/plain"),
31        (TEXT_UTF8, "text/plain; charset=utf-8"),
32        (JSON, "application/json"),
33        (APPLICATION_WWW_FORM_URLENCODED, "application/x-www-form-urlencoded"),
34        (TEXT_HTML_UTF8, "text/html; charset=utf-8"),
35        (GRPC, "application/grpc"),
36        (WEBSOCKET, "websocket")
37    );
38}
39
40/// Some often used header name.
41#[allow(clippy::declare_interior_mutable_const)]
42pub mod const_header_name {
43    use ::http::header::HeaderName;
44
45    macro_rules! const_name {
46            ($(($ident: ident, $expr: expr)), *) => {
47                $(
48                   pub const $ident: HeaderName = HeaderName::from_static($expr);
49                )*
50            }
51        }
52
53    const_name!((PROTOCOL, "protocol"));
54}
55
56/// helper trait for converting a [Request] to [Response].
57/// This is a memory optimization for re-use heap allocation and pass down the context data
58/// inside [Extensions] from request to response.
59///
60/// # Example
61/// ```rust
62/// # use xitca_http::http::{Request, Response};
63/// // arbitrary typed state inserted into request type.
64/// #[derive(Clone)]
65/// struct Foo;
66///
67/// fn into_response(mut req: Request<()>) -> Response<()> {
68///     req.extensions_mut().insert(Foo); // insert Foo to request's extensions type map.
69///     
70///     // convert request into response in place with the same memory allocation.
71///     use xitca_http::http::IntoResponse;
72///     let res = req.into_response(());
73///     
74///     // the memory is re-used so Foo type is accessible from response's extensions type map.
75///     assert!(res.extensions().get::<Foo>().is_some());
76///
77///     res
78/// }
79///
80/// ```
81pub trait IntoResponse<B, ResB> {
82    fn into_response(self, body: B) -> Response<ResB>;
83
84    fn as_response(&mut self, body: B) -> Response<ResB>
85    where
86        Self: Default,
87    {
88        mem::take(self).into_response(body)
89    }
90}
91
92impl<ReqB, B, ResB> IntoResponse<B, ResB> for Request<ReqB>
93where
94    B: Into<ResB>,
95{
96    fn into_response(self, body: B) -> Response<ResB> {
97        let (
98            request::Parts {
99                mut headers,
100                extensions,
101                ..
102            },
103            _,
104        ) = self.into_parts();
105        headers.clear();
106
107        let mut res = Response::new(body.into());
108        *res.headers_mut() = headers;
109        *res.extensions_mut() = extensions;
110
111        res
112    }
113}
114
115#[cfg(feature = "router")]
116use super::util::service::router::Params;
117
118pin_project! {
119    /// extension types for [Request]
120    #[derive(Debug)]
121    pub struct RequestExt<B> {
122        #[pin]
123        body: B,
124        // http::Extensions is often brought up as an alternative for extended states but in general
125        // xitca tries to be strongly typed when possible. runtime type casting is meant for library
126        // consumer but not library itself.
127        ext: Extension,
128    }
129}
130
131impl<B> Clone for RequestExt<B>
132where
133    B: Clone,
134{
135    fn clone(&self) -> Self {
136        Self {
137            body: self.body.clone(),
138            ext: Extension(Box::new(_Extension::clone(&*self.ext.0))),
139        }
140    }
141}
142
143// a separate extension type contain information can not be carried by http::Request. the goal is
144// to keep extended info strongly typed and not depend on runtime type map of http::Extensions.
145#[derive(Debug)]
146pub(crate) struct Extension(Box<_Extension>);
147
148impl Extension {
149    pub(crate) fn new(addr: SocketAddr) -> Self {
150        Self(Box::new(_Extension {
151            addr,
152            #[cfg(feature = "router")]
153            params: Default::default(),
154        }))
155    }
156}
157
158#[derive(Clone, Debug)]
159struct _Extension {
160    addr: SocketAddr,
161    #[cfg(feature = "router")]
162    params: Params,
163}
164
165impl<B> RequestExt<B> {
166    pub(crate) fn from_parts(body: B, ext: Extension) -> Self {
167        Self { body, ext }
168    }
169
170    /// retrieve remote peer's socket address.
171    ///
172    /// # Default
173    /// [std::net::Ipv4Addr::UNSPECIFIED] is used for representing peers that can't provide it's socket address.
174    #[inline]
175    pub fn socket_addr(&self) -> &SocketAddr {
176        &self.ext.0.addr
177    }
178
179    /// exclusive version of [RequestExt::socket_addr]
180    #[inline]
181    pub fn socket_addr_mut(&mut self) -> &mut SocketAddr {
182        &mut self.ext.0.addr
183    }
184
185    /// map body type of self to another type with given function closure.
186    #[inline]
187    pub fn map_body<F, B1>(self, func: F) -> RequestExt<B1>
188    where
189        F: FnOnce(B) -> B1,
190    {
191        RequestExt {
192            body: func(self.body),
193            ext: self.ext,
194        }
195    }
196
197    /// replace body type of self with another type and return new type of Self and original body type
198    /// in tuple.
199    #[inline]
200    pub fn replace_body<B1>(self, body: B1) -> (RequestExt<B1>, B) {
201        let body_org = self.body;
202
203        (RequestExt { body, ext: self.ext }, body_org)
204    }
205}
206
207impl<B> Default for RequestExt<B>
208where
209    B: Default,
210{
211    fn default() -> Self {
212        Self::from_parts(B::default(), Extension::new(crate::unspecified_socket_addr()))
213    }
214}
215
216impl<B> Stream for RequestExt<B>
217where
218    B: Stream,
219{
220    type Item = B::Item;
221
222    #[inline]
223    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
224        self.project().body.poll_next(cx)
225    }
226
227    #[inline]
228    fn size_hint(&self) -> (usize, Option<usize>) {
229        self.body.size_hint()
230    }
231}
232
233impl<B> Borrow<SocketAddr> for RequestExt<B> {
234    #[inline]
235    fn borrow(&self) -> &SocketAddr {
236        self.socket_addr()
237    }
238}
239
240#[cfg(feature = "router")]
241mod router {
242    use super::*;
243
244    impl<B> RequestExt<B> {
245        /// retrieve shared reference of route [Params].
246        #[inline]
247        pub fn params(&self) -> &Params {
248            &self.ext.0.params
249        }
250
251        /// retrieve exclusive reference of route [Params].
252        #[inline]
253        pub fn params_mut(&mut self) -> &mut Params {
254            &mut self.ext.0.params
255        }
256    }
257
258    impl<B> Borrow<Params> for RequestExt<B> {
259        #[inline]
260        fn borrow(&self) -> &Params {
261            self.params()
262        }
263    }
264
265    impl<B> BorrowMut<Params> for RequestExt<B> {
266        #[inline]
267        fn borrow_mut(&mut self) -> &mut Params {
268            self.params_mut()
269        }
270    }
271}
272
273/// trait for Borrow &T from &Self.
274/// used for foreign types (from xitca-http pov) that can be impl with [Borrow] trait.
275pub trait BorrowReq<T> {
276    fn borrow(&self) -> &T;
277}
278
279/// trait for Borrow &mut T from &mut Self.
280/// used for foreign types (from xitca-http pov) that can be impl with [BorrowMut] trait.
281pub trait BorrowReqMut<T> {
282    fn borrow_mut(&mut self) -> &mut T;
283}
284
285impl<Ext> BorrowReq<Uri> for Request<Ext> {
286    #[inline]
287    fn borrow(&self) -> &Uri {
288        self.uri()
289    }
290}
291
292impl<Ext> BorrowReq<Method> for Request<Ext> {
293    #[inline]
294    fn borrow(&self) -> &Method {
295        self.method()
296    }
297}
298
299impl<Ext> BorrowReq<HeaderMap> for Request<Ext> {
300    #[inline]
301    fn borrow(&self) -> &HeaderMap {
302        self.headers()
303    }
304}
305
306impl<Ext> BorrowReq<Extensions> for Request<Ext> {
307    #[inline]
308    fn borrow(&self) -> &Extensions {
309        self.extensions()
310    }
311}
312
313impl<Ext> BorrowReqMut<Extensions> for Request<Ext> {
314    #[inline]
315    fn borrow_mut(&mut self) -> &mut Extensions {
316        self.extensions_mut()
317    }
318}
319
320impl<T, B> BorrowReq<T> for Request<RequestExt<B>>
321where
322    RequestExt<B>: Borrow<T>,
323{
324    #[inline]
325    fn borrow(&self) -> &T {
326        self.body().borrow()
327    }
328}
329
330impl<T, B> BorrowReqMut<T> for Request<RequestExt<B>>
331where
332    RequestExt<B>: BorrowMut<T>,
333{
334    #[inline]
335    fn borrow_mut(&mut self) -> &mut T {
336        self.body_mut().borrow_mut()
337    }
338}