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; #[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 pub method: Method,
70
71 pub uri: Uri,
73
74 pub version: Version,
76
77 pub headers: HeaderMap<HeaderValue>,
79
80 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("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}