1use std::{cell::Ref, cell::RefMut, fmt, net};
2
3use urly::Url;
4
5use crate::http::header;
6use crate::http::{HeaderMap, HttpMessage, Method, Payload, RequestHead, Response, Version};
7use crate::io::{IoRef, types};
8use crate::router::{Path, Resource};
9use crate::util::Extensions;
10
11use super::config::WebAppConfig;
12use super::info::ConnectionInfo;
13use super::rmap::ResourceMap;
14use super::{HttpRequest, State, WebResponse, WebResponseError};
15
16pub struct WebRequest<St = ()> {
20 pub(crate) req: HttpRequest,
21 payload: Payload,
22 state: St,
23}
24
25impl<St> WebRequest<St> {
26 pub(crate) fn new(req: HttpRequest, payload: Payload, state: St) -> Self {
28 WebRequest {
29 req,
30 payload,
31 state,
32 }
33 }
34
35 #[inline]
37 pub fn error_response<AppSt, E>(self, st: &AppSt, err: &E) -> WebResponse
38 where
39 AppSt: State,
40 E: WebResponseError<AppSt, AppSt::Error>,
41 {
42 WebResponse::new(err.error_response(st), self.req)
43 }
44}
45
46impl WebRequest<()> {
47 pub fn from_request(req: HttpRequest) -> Self {
49 WebRequest {
50 req,
51 payload: Payload::None,
52 state: (),
53 }
54 }
55}
56
57impl<St> WebRequest<St> {
58 pub fn into_parts(self) -> (HttpRequest, Payload, St) {
60 (self.req, self.payload, self.state)
61 }
62
63 pub fn from_parts(req: HttpRequest, payload: Payload, state: St) -> Self {
65 WebRequest {
66 req,
67 payload,
68 state,
69 }
70 }
71
72 #[inline]
74 pub fn into_response<R: Into<Response>>(self, res: R) -> WebResponse {
75 WebResponse::new(res.into(), self.req)
76 }
77
78 #[inline]
80 pub fn io(&self) -> Option<&IoRef> {
81 self.head().io.as_ref()
82 }
83
84 #[inline]
86 pub fn head(&self) -> &RequestHead {
87 self.req.head()
88 }
89
90 #[inline]
92 pub fn head_mut(&mut self) -> &mut RequestHead {
93 self.req.head_mut()
94 }
95
96 #[inline]
98 pub fn uri(&self) -> &Url {
99 &self.head().uri
100 }
101
102 #[inline]
104 pub fn method(&self) -> &Method {
105 &self.head().method
106 }
107
108 #[inline]
110 pub fn version(&self) -> Version {
111 self.head().version
112 }
113
114 #[inline]
116 pub fn headers(&self) -> &HeaderMap {
117 &self.head().headers
118 }
119
120 pub fn headers_mut(&mut self) -> &mut HeaderMap {
122 &mut self.head_mut().headers
123 }
124
125 #[inline]
127 pub fn path(&self) -> &str {
128 self.head().uri.path().as_str()
129 }
130
131 #[inline]
135 pub fn query_string(&self) -> &str {
136 self.uri().query().map_or("", urly::Query::as_str)
137 }
138
139 #[inline]
146 pub fn peer_addr(&self) -> Option<net::SocketAddr> {
147 self.head()
148 .io
149 .as_ref()
150 .and_then(|io| io.query::<types::PeerAddr>().get().map(|addr| addr.0))
151 }
152
153 #[inline]
158 pub fn take_payload(&mut self) -> Payload {
159 self.payload.take()
160 }
161
162 pub fn set_payload(&mut self, payload: Payload) {
164 self.payload = payload;
165 }
166
167 pub fn connection_info(&self) -> Ref<'_, ConnectionInfo> {
169 ConnectionInfo::get(self.head(), self.app_config())
170 }
171
172 #[inline]
179 pub fn match_info(&self) -> &Path<Url> {
180 self.req.match_info()
181 }
182
183 #[inline]
185 pub fn match_info_mut(&mut self) -> &mut Path<Url> {
186 self.req.match_info_mut()
187 }
188
189 #[inline]
191 pub fn resource_map(&self) -> &ResourceMap {
192 self.req.resource_map()
193 }
194
195 #[inline]
197 pub fn app_config(&self) -> &WebAppConfig {
198 self.req.app_config()
199 }
200
201 #[inline]
203 pub fn app_state<T: 'static>(&self) -> Option<&T> {
204 (self.req).app_config().state()
205 }
206
207 #[inline]
209 pub fn extensions(&self) -> Ref<'_, Extensions> {
210 self.req.extensions()
211 }
212
213 #[inline]
215 pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
216 self.req.extensions_mut()
217 }
218
219 #[inline]
221 pub fn st(&self) -> &St {
222 &self.state
223 }
224
225 #[inline]
227 pub fn st_mut(&mut self) -> &mut St {
228 &mut self.state
229 }
230
231 #[inline]
256 pub fn map_state<F, NewSt>(self, f: F) -> WebRequest<NewSt>
257 where
258 F: FnOnce(St) -> NewSt,
259 {
260 let WebRequest {
261 req,
262 payload,
263 state,
264 } = self;
265
266 WebRequest {
267 req,
268 payload,
269 state: f(state),
270 }
271 }
272}
273
274impl<St> Resource<Url> for WebRequest<St> {
275 fn path(&self) -> &str {
276 self.match_info().path()
277 }
278
279 fn resource_path(&mut self) -> &mut Path<Url> {
280 self.match_info_mut()
281 }
282}
283
284impl<St> HttpMessage for WebRequest<St> {
285 #[inline]
286 fn message_headers(&self) -> &HeaderMap {
288 &self.head().headers
289 }
290
291 #[inline]
293 fn message_extensions(&self) -> Ref<'_, Extensions> {
294 self.req.extensions()
295 }
296
297 #[inline]
299 fn message_extensions_mut(&self) -> RefMut<'_, Extensions> {
300 self.req.extensions_mut()
301 }
302}
303
304impl<St> fmt::Debug for WebRequest<St> {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 writeln!(
307 f,
308 "\nWebRequest {:?} {}:{}",
309 self.head().version,
310 self.head().method,
311 self.path()
312 )?;
313 if !self.query_string().is_empty() {
314 writeln!(f, " query: ?{:?}", self.query_string())?;
315 }
316 if !self.match_info().is_empty() {
317 writeln!(f, " params: {:?}", self.match_info())?;
318 }
319 writeln!(f, " headers:")?;
320 for (key, val) in self.headers() {
321 if key == header::AUTHORIZATION {
322 writeln!(f, " {key:?}: <REDACTED>")?;
323 } else {
324 writeln!(f, " {key:?}: {val:?}")?;
325 }
326 }
327 Ok(())
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use crate::http::{self, HttpMessage, header};
334 use crate::web::{HttpResponse, test::TestRequest};
335
336 #[test]
337 fn test_request() {
338 let mut req = TestRequest::default().to_srv_request();
339 assert_eq!(req.head_mut().version, http::Version::HTTP_11);
340 assert!(req.peer_addr().is_none());
341 let err = http::error::PayloadError::Overflow;
342
343 let res: HttpResponse = req.error_response::<(), _>(&(), &err).into();
344 assert_eq!(res.status(), http::StatusCode::PAYLOAD_TOO_LARGE);
345
346 let mut req = TestRequest::default().to_srv_request();
347 req.headers_mut().insert(
348 header::CONTENT_TYPE,
349 header::HeaderValue::from_static("text"),
350 );
351 req.headers_mut().insert(
352 header::AUTHORIZATION,
353 header::HeaderValue::from_static("text"),
354 );
355 req.headers_mut().remove(header::CONTENT_TYPE);
356 assert!(!req.headers().contains_key(header::CONTENT_TYPE));
357 assert!(!req.message_headers().contains_key(header::CONTENT_TYPE));
358
359 req.extensions_mut().insert("TEXT".to_string());
360 assert_eq!(req.message_extensions().get::<String>().unwrap(), "TEXT");
361 req.message_extensions_mut().remove::<String>();
362 assert!(!req.extensions().contains::<String>());
363
364 let t = format!("{req:?}");
365 assert!(t.contains("\"authorization\": <REDACTED>"));
366 }
367
368 #[test]
369 fn test_request_parts() {
370 use crate::web::{WebRequest, types::Payload};
371
372 let (req, _, ()) = TestRequest::with_uri("/path").to_http_parts();
373 let mut wreq = WebRequest::from_request(req.clone());
374 assert_eq!(wreq.path(), "/path");
375 assert!(wreq.io().is_none());
376 assert!(
377 wreq.resource_map()
378 .url_for(&req, "unknown", [""; 0])
379 .is_err()
380 );
381
382 assert!(matches!(wreq.take_payload(), crate::http::Payload::None));
383
384 let mut preq = TestRequest::default().payload("data").to_srv_request();
385 let payload = Payload(preq.take_payload()).into_inner();
386 assert!(!matches!(payload, crate::http::Payload::None));
387 assert!(matches!(preq.take_payload(), crate::http::Payload::None));
388 wreq.set_payload(payload);
389 assert!(!matches!(wreq.take_payload(), crate::http::Payload::None));
390
391 let wreq = WebRequest::from_parts(req, crate::http::Payload::None, 10usize);
392 assert_eq!(*wreq.st(), 10);
393 }
394
395 #[test]
396 fn test_request_debug_params() {
397 let req = TestRequest::with_uri("/test")
398 .param("id", "10")
399 .to_srv_request();
400 let s = format!("{req:?}");
401 assert!(s.contains("params:"), "{s}");
402 assert!(s.contains("id"), "{s}");
403
404 let req = TestRequest::with_uri("/test")
405 .param("id", "10")
406 .to_http_request();
407 let s = format!("{req:?}");
408 assert!(s.contains("params:"), "{s}");
409 }
410}