predawn_core/
request.rs

1use std::{fmt, net::SocketAddr};
2
3use http::{
4    header::{CONTENT_LENGTH, CONTENT_TYPE},
5    request::Parts,
6    Extensions, HeaderMap, HeaderValue, Method, Uri, Version,
7};
8use http_body_util::Limited;
9use hyper::body::Incoming;
10use snafu::{OptionExt, Snafu};
11
12use crate::{body::RequestBody, impl_deref, impl_display, location::Location};
13
14pub const DEFAULT_BODY_LIMIT: usize = 2 * 1024 * 1024; // 2 mb
15
16#[derive(Debug)]
17pub struct Request {
18    pub head: Head,
19    pub body: Incoming,
20}
21
22impl Request {
23    pub fn new(
24        request: http::Request<Incoming>,
25        local_addr: SocketAddr,
26        remote_addr: SocketAddr,
27    ) -> Self {
28        let (
29            Parts {
30                method,
31                uri,
32                version,
33                headers,
34                extensions,
35                ..
36            },
37            body,
38        ) = request.into_parts();
39
40        Self {
41            head: Head {
42                method,
43                uri: uri.clone(),
44                version,
45                headers,
46                extensions,
47                body_limit: BodyLimit(DEFAULT_BODY_LIMIT),
48                local_addr: LocalAddr(local_addr),
49                remote_addr: RemoteAddr(remote_addr),
50                original_uri: OriginalUri(uri),
51            },
52            body,
53        }
54    }
55
56    pub fn split(self) -> (Head, RequestBody) {
57        let Self { head, body } = self;
58
59        let limit = head.body_limit.0;
60
61        (head, Limited::new(body, limit))
62    }
63}
64
65#[derive(Clone)]
66#[non_exhaustive]
67pub struct Head {
68    /// The request's method
69    pub method: Method,
70
71    /// The request's URI
72    pub uri: Uri,
73
74    /// The request's version
75    pub version: Version,
76
77    /// The request's headers
78    pub headers: HeaderMap<HeaderValue>,
79
80    /// The request's extensions
81    pub extensions: Extensions,
82
83    pub body_limit: BodyLimit,
84
85    pub(crate) local_addr: LocalAddr,
86
87    pub(crate) remote_addr: RemoteAddr,
88
89    pub(crate) original_uri: OriginalUri,
90}
91
92impl fmt::Debug for Head {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        f.debug_struct("Head")
95            .field("method", &self.method)
96            .field("uri", &self.uri)
97            .field("version", &self.version)
98            .field("headers", &self.headers)
99            // .field("extensions", &self.extensions)
100            .field("body_limit", &self.body_limit)
101            .field("local_addr", &self.local_addr)
102            .field("remote_addr", &self.remote_addr)
103            .field("original_uri", &self.original_uri)
104            .finish()
105    }
106}
107
108impl Head {
109    pub fn content_type(&self) -> Option<&str> {
110        self.headers
111            .get(CONTENT_TYPE)
112            .and_then(|value| value.to_str().ok())
113    }
114
115    pub fn content_length(&self) -> Option<usize> {
116        self.headers
117            .get(CONTENT_LENGTH)
118            .and_then(|value| value.to_str().ok()?.parse::<usize>().ok())
119    }
120
121    pub fn local_addr(&self) -> LocalAddr {
122        self.local_addr
123    }
124
125    pub fn remote_addr(&self) -> RemoteAddr {
126        self.remote_addr
127    }
128
129    pub fn original_uri(&self) -> &OriginalUri {
130        &self.original_uri
131    }
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
135pub struct BodyLimit(pub usize);
136
137impl_deref!(BodyLimit : usize);
138impl_display!(BodyLimit);
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
141pub struct LocalAddr(pub SocketAddr);
142
143impl_deref!(LocalAddr : SocketAddr);
144impl_display!(LocalAddr);
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
147pub struct RemoteAddr(pub SocketAddr);
148
149impl_deref!(RemoteAddr : SocketAddr);
150impl_display!(RemoteAddr);
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct OriginalUri(pub Uri);
154
155impl_deref!(OriginalUri : Uri);
156impl_display!(OriginalUri);
157
158impl From<Request> for http::Request<Incoming> {
159    fn from(request: Request) -> Self {
160        let Request {
161            head:
162                Head {
163                    method,
164                    uri,
165                    version,
166                    headers,
167                    extensions,
168                    body_limit,
169                    local_addr,
170                    remote_addr,
171                    original_uri,
172                },
173            body,
174        } = request;
175
176        let mut req = http::Request::new(body);
177
178        *req.method_mut() = method;
179        *req.uri_mut() = uri;
180        *req.version_mut() = version;
181        *req.headers_mut() = headers;
182        *req.extensions_mut() = extensions;
183
184        req.extensions_mut().insert(body_limit);
185        req.extensions_mut().insert(local_addr);
186        req.extensions_mut().insert(remote_addr);
187        req.extensions_mut().insert(original_uri);
188
189        req
190    }
191}
192
193impl TryFrom<http::Request<Incoming>> for Request {
194    type Error = ConvertRequestError;
195
196    fn try_from(request: http::Request<Incoming>) -> Result<Self, Self::Error> {
197        let (
198            Parts {
199                method,
200                uri,
201                version,
202                headers,
203                mut extensions,
204                ..
205            },
206            body,
207        ) = request.into_parts();
208
209        let body_limit = extensions
210            .remove::<BodyLimit>()
211            .context(NotFoundBodyLimitSnafu)?;
212
213        let local_addr = extensions
214            .remove::<LocalAddr>()
215            .context(NotFoundLocalAddrSnafu)?;
216
217        let remote_addr = extensions
218            .remove::<RemoteAddr>()
219            .context(NotFoundRemoteAddrSnafu)?;
220
221        let original_uri = extensions
222            .remove::<OriginalUri>()
223            .context(NotFoundOriginalUriSnafu)?;
224
225        Ok(Self {
226            head: Head {
227                method,
228                uri,
229                version,
230                headers,
231                extensions,
232                body_limit,
233                local_addr,
234                remote_addr,
235                original_uri,
236            },
237            body,
238        })
239    }
240}
241
242#[derive(Debug, Snafu)]
243pub enum ConvertRequestError {
244    #[snafu(display("not found `body limit` in request extensions"))]
245    NotFoundBodyLimit {
246        #[snafu(implicit)]
247        location: Location,
248    },
249
250    #[snafu(display("not found `local address` in request extensions"))]
251    NotFoundLocalAddr {
252        #[snafu(implicit)]
253        location: Location,
254    },
255
256    #[snafu(display("not found `remote address` in request extensions"))]
257    NotFoundRemoteAddr {
258        #[snafu(implicit)]
259        location: Location,
260    },
261
262    #[snafu(display("not found `original uri` in request extensions"))]
263    NotFoundOriginalUri {
264        #[snafu(implicit)]
265        location: Location,
266    },
267}