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                version,
102                ..
103            },
104            _,
105        ) = self.into_parts();
106        headers.clear();
107
108        let mut res = Response::new(body.into());
109        *res.headers_mut() = headers;
110        *res.extensions_mut() = extensions;
111        *res.version_mut() = version;
112
113        res
114    }
115}
116
117#[cfg(feature = "router")]
118use super::util::service::router::Params;
119
120pin_project! {
121    /// extension types for [Request]
122    #[derive(Debug)]
123    pub struct RequestExt<B> {
124        #[pin]
125        body: B,
126        // http::Extensions is often brought up as an alternative for extended states but in general
127        // xitca tries to be strongly typed when possible. runtime type casting is meant for library
128        // consumer but not library itself.
129        ext: Extension,
130    }
131}
132
133impl<B> Clone for RequestExt<B>
134where
135    B: Clone,
136{
137    fn clone(&self) -> Self {
138        Self {
139            body: self.body.clone(),
140            ext: Extension(Box::new(_Extension::clone(&*self.ext.0))),
141        }
142    }
143}
144
145// a separate extension type contain information can not be carried by http::Request. the goal is
146// to keep extended info strongly typed and not depend on runtime type map of http::Extensions.
147#[derive(Debug)]
148pub(crate) struct Extension(Box<_Extension>);
149
150impl Extension {
151    pub(crate) fn new(addr: SocketAddr) -> Self {
152        Self(Box::new(_Extension {
153            addr,
154            #[cfg(feature = "router")]
155            params: Default::default(),
156        }))
157    }
158}
159
160#[derive(Clone, Debug)]
161struct _Extension {
162    addr: SocketAddr,
163    #[cfg(feature = "router")]
164    params: Params,
165}
166
167impl<B> RequestExt<B> {
168    pub(crate) fn from_parts(body: B, ext: Extension) -> Self {
169        Self { body, ext }
170    }
171
172    /// retrieve remote peer's socket address.
173    ///
174    /// # Default
175    /// [std::net::Ipv4Addr::UNSPECIFIED] is used for representing peers that can't provide it's socket address.
176    #[inline]
177    pub fn socket_addr(&self) -> &SocketAddr {
178        &self.ext.0.addr
179    }
180
181    /// exclusive version of [RequestExt::socket_addr]
182    #[inline]
183    pub fn socket_addr_mut(&mut self) -> &mut SocketAddr {
184        &mut self.ext.0.addr
185    }
186
187    /// map body type of self to another type with given function closure.
188    #[inline]
189    pub fn map_body<F, B1>(self, func: F) -> RequestExt<B1>
190    where
191        F: FnOnce(B) -> B1,
192    {
193        RequestExt {
194            body: func(self.body),
195            ext: self.ext,
196        }
197    }
198
199    /// replace body type of self with another type and return new type of Self and original body type
200    /// in tuple.
201    #[inline]
202    pub fn replace_body<B1>(self, body: B1) -> (RequestExt<B1>, B) {
203        let body_org = self.body;
204
205        (RequestExt { body, ext: self.ext }, body_org)
206    }
207}
208
209impl<B> Default for RequestExt<B>
210where
211    B: Default,
212{
213    fn default() -> Self {
214        Self::from_parts(B::default(), Extension::new(crate::unspecified_socket_addr()))
215    }
216}
217
218impl<B> Stream for RequestExt<B>
219where
220    B: Stream,
221{
222    type Item = B::Item;
223
224    #[inline]
225    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
226        self.project().body.poll_next(cx)
227    }
228
229    #[inline]
230    fn size_hint(&self) -> (usize, Option<usize>) {
231        self.body.size_hint()
232    }
233}
234
235impl<B> Borrow<SocketAddr> for RequestExt<B> {
236    #[inline]
237    fn borrow(&self) -> &SocketAddr {
238        self.socket_addr()
239    }
240}
241
242#[cfg(feature = "router")]
243mod router {
244    use super::*;
245
246    impl<B> RequestExt<B> {
247        /// retrieve shared reference of route [Params].
248        #[inline]
249        pub fn params(&self) -> &Params {
250            &self.ext.0.params
251        }
252
253        /// retrieve exclusive reference of route [Params].
254        #[inline]
255        pub fn params_mut(&mut self) -> &mut Params {
256            &mut self.ext.0.params
257        }
258    }
259
260    impl<B> Borrow<Params> for RequestExt<B> {
261        #[inline]
262        fn borrow(&self) -> &Params {
263            self.params()
264        }
265    }
266
267    impl<B> BorrowMut<Params> for RequestExt<B> {
268        #[inline]
269        fn borrow_mut(&mut self) -> &mut Params {
270            self.params_mut()
271        }
272    }
273}
274
275/// trait for Borrow &T from &Self.
276/// used for foreign types (from xitca-http pov) that can be impl with [Borrow] trait.
277pub trait BorrowReq<T> {
278    fn borrow(&self) -> &T;
279}
280
281/// trait for Borrow &mut T from &mut Self.
282/// used for foreign types (from xitca-http pov) that can be impl with [BorrowMut] trait.
283pub trait BorrowReqMut<T> {
284    fn borrow_mut(&mut self) -> &mut T;
285}
286
287impl<Ext> BorrowReq<Uri> for Request<Ext> {
288    #[inline]
289    fn borrow(&self) -> &Uri {
290        self.uri()
291    }
292}
293
294impl<Ext> BorrowReq<Method> for Request<Ext> {
295    #[inline]
296    fn borrow(&self) -> &Method {
297        self.method()
298    }
299}
300
301impl<Ext> BorrowReq<HeaderMap> for Request<Ext> {
302    #[inline]
303    fn borrow(&self) -> &HeaderMap {
304        self.headers()
305    }
306}
307
308impl<Ext> BorrowReq<Extensions> for Request<Ext> {
309    #[inline]
310    fn borrow(&self) -> &Extensions {
311        self.extensions()
312    }
313}
314
315impl<Ext> BorrowReqMut<Extensions> for Request<Ext> {
316    #[inline]
317    fn borrow_mut(&mut self) -> &mut Extensions {
318        self.extensions_mut()
319    }
320}
321
322impl<T, B> BorrowReq<T> for Request<RequestExt<B>>
323where
324    RequestExt<B>: Borrow<T>,
325{
326    #[inline]
327    fn borrow(&self) -> &T {
328        self.body().borrow()
329    }
330}
331
332impl<T, B> BorrowReqMut<T> for Request<RequestExt<B>>
333where
334    RequestExt<B>: BorrowMut<T>,
335{
336    #[inline]
337    fn borrow_mut(&mut self) -> &mut T {
338        self.body_mut().borrow_mut()
339    }
340}