ttpkit_http/server/
request.rs

1//! Request types.
2
3use std::{borrow::Borrow, net::SocketAddr, ops::Deref};
4
5use crate::{
6    Body, Error, Scheme,
7    request::{Request, RequestHeader},
8    url::{IntoUrl, QueryDict, Url},
9};
10
11/// Request received from an HTTP client.
12pub struct IncomingRequest<B = Body> {
13    inner: Box<InnerRequest<B>>,
14}
15
16impl<B> IncomingRequest<B> {
17    /// Create a new client request.
18    pub fn new(
19        url_scheme: Scheme,
20        server_addr: SocketAddr,
21        client_addr: SocketAddr,
22        header: RequestHeader,
23        body: B,
24    ) -> Result<Self, Error> {
25        let context = RequestContext::new(url_scheme, server_addr, client_addr, &header)?;
26
27        let inner = InnerRequest {
28            inner: Request::new(header, body),
29            context,
30        };
31
32        let res = Self {
33            inner: Box::new(inner),
34        };
35
36        Ok(res)
37    }
38
39    /// Get the request URL.
40    #[inline]
41    pub fn url(&self) -> &Url {
42        &self.inner.context.url
43    }
44
45    /// Get the query parameters.
46    #[inline]
47    pub fn query_parameters(&self) -> &QueryDict {
48        &self.inner.context.query
49    }
50
51    /// Get the server address.
52    #[inline]
53    pub fn server_addr(&self) -> SocketAddr {
54        self.inner.context.server_addr
55    }
56
57    /// Get the client address.
58    #[inline]
59    pub fn client_addr(&self) -> SocketAddr {
60        self.inner.context.client_addr
61    }
62
63    /// Take the request body.
64    #[inline]
65    pub fn body(self) -> B {
66        self.inner.inner.body()
67    }
68
69    /// Split the request into the header and the body.
70    #[inline]
71    pub fn deconstruct(self) -> (RequestHeader, B) {
72        self.inner.inner.deconstruct()
73    }
74}
75
76impl<B> AsRef<Request<B>> for IncomingRequest<B> {
77    #[inline]
78    fn as_ref(&self) -> &Request<B> {
79        &self.inner.inner
80    }
81}
82
83impl<B> Borrow<Request<B>> for IncomingRequest<B> {
84    #[inline]
85    fn borrow(&self) -> &Request<B> {
86        &self.inner.inner
87    }
88}
89
90impl<B> Deref for IncomingRequest<B> {
91    type Target = Request<B>;
92
93    #[inline]
94    fn deref(&self) -> &Self::Target {
95        &self.inner.inner
96    }
97}
98
99/// Helper struct separating non-generic stuff.
100struct RequestContext {
101    url: Url,
102    query: QueryDict,
103    server_addr: SocketAddr,
104    client_addr: SocketAddr,
105}
106
107impl RequestContext {
108    /// Create a new request context.
109    fn new(
110        url_scheme: Scheme,
111        server_addr: SocketAddr,
112        client_addr: SocketAddr,
113        header: &RequestHeader,
114    ) -> Result<Self, Error> {
115        let host = header
116            .get_header_field_value("host")
117            .map(|h| h.to_str())
118            .and_then(|res| res.ok())
119            .map(|h| {
120                if let Some((host, _)) = h.split_once(':') {
121                    host
122                } else {
123                    h
124                }
125            })
126            .map(String::from)
127            .unwrap_or_else(|| format!("{}", server_addr.ip()));
128
129        let port = server_addr.port();
130
131        let path = header
132            .path()
133            .to_str()
134            .map_err(|_| Error::from_static_msg("unable to reconstruct request URL"))?;
135
136        let url = if port == url_scheme.default_port() {
137            format!("{url_scheme}://{host}{path}")
138        } else {
139            format!("{url_scheme}://{host}:{port}{path}")
140        };
141
142        let url = url
143            .into_url()
144            .map_err(|_| Error::from_static_msg("unable to reconstruct request URL"))?;
145
146        let query = url
147            .query()
148            .unwrap_or("")
149            .parse()
150            .map_err(|_| Error::from_static_msg("unable to parse request query parameters"))?;
151
152        let res = Self {
153            url,
154            query,
155            server_addr,
156            client_addr,
157        };
158
159        Ok(res)
160    }
161}
162
163/// Inner struct for the incoming request.
164///
165/// NOTE: The `IncomingRequest` contains only a boxed struct (this one) to
166/// avoid passing around big objects.
167struct InnerRequest<B> {
168    inner: Request<B>,
169    context: RequestContext,
170}