Skip to main content

ntex/http/
request.rs

1use std::{cell::Ref, cell::RefMut, fmt, mem, net};
2
3use urly::Url;
4
5use crate::http::header::{self, HeaderMap};
6use crate::http::httpmessage::HttpMessage;
7use crate::http::message::{Message, RequestHead};
8use crate::http::{Method, Version, payload::Payload};
9use crate::{io::IoRef, io::types, util::Extensions};
10
11/// An HTTP request.
12pub struct Request {
13    pub(crate) payload: Payload,
14    pub(crate) head: Message<RequestHead>,
15}
16
17impl HttpMessage for Request {
18    #[inline]
19    fn message_headers(&self) -> &HeaderMap {
20        &self.head().headers
21    }
22
23    /// Request extensions
24    #[inline]
25    fn message_extensions(&self) -> Ref<'_, Extensions> {
26        self.head.extensions()
27    }
28
29    /// Mutable reference to a the request's extensions
30    #[inline]
31    fn message_extensions_mut(&self) -> RefMut<'_, Extensions> {
32        self.head.extensions_mut()
33    }
34}
35
36impl From<Message<RequestHead>> for Request {
37    fn from(head: Message<RequestHead>) -> Self {
38        Request {
39            head,
40            payload: Payload::None,
41        }
42    }
43}
44
45impl Request {
46    /// Creates an empty request.
47    pub fn new() -> Request {
48        Request {
49            head: Message::new(),
50            payload: Payload::None,
51        }
52    }
53}
54
55impl Request {
56    /// Creates a request with the supplied payload.
57    pub fn with_payload(payload: Payload) -> Request {
58        Request {
59            payload,
60            head: Message::new(),
61        }
62    }
63
64    #[inline]
65    /// Returns the request head.
66    pub fn head(&self) -> &RequestHead {
67        &self.head
68    }
69
70    #[inline]
71    #[doc(hidden)]
72    /// Mutable reference to a http message part of the request
73    pub fn head_mut(&mut self) -> &mut RequestHead {
74        &mut self.head
75    }
76
77    /// Returns the request URI.
78    #[inline]
79    pub fn uri(&self) -> &Url {
80        &self.head().uri
81    }
82
83    /// Returns mutable access to the request URI.
84    #[inline]
85    pub fn uri_mut(&mut self) -> &mut Url {
86        &mut self.head_mut().uri
87    }
88
89    /// Returns the request method.
90    #[inline]
91    pub fn method(&self) -> &Method {
92        &self.head().method
93    }
94
95    /// Returns the HTTP version.
96    #[inline]
97    pub fn version(&self) -> Version {
98        self.head().version
99    }
100
101    /// Returns the path component of the request URI.
102    #[inline]
103    pub fn path(&self) -> &str {
104        self.head().uri.path().as_str()
105    }
106
107    #[inline]
108    /// Returns the request headers.
109    pub fn headers(&self) -> &HeaderMap {
110        &self.head().headers
111    }
112
113    /// Returns mutable access to the request headers.
114    pub fn headers_mut(&mut self) -> &mut HeaderMap {
115        &mut self.head_mut().headers
116    }
117
118    /// Returns whether this is an upgrade or `CONNECT` request.
119    #[inline]
120    pub fn upgrade(&self) -> bool {
121        self.head().upgrade() || self.head().method == Method::CONNECT
122    }
123
124    /// Returns the I/O object for the current connection, when available.
125    #[inline]
126    pub fn io(&self) -> Option<&IoRef> {
127        self.head().io.as_ref()
128    }
129
130    /// Returns the peer socket address.
131    ///
132    /// Peer address is actual socket address, if proxy is used in front of
133    /// ntex http server, then peer address would be address of this proxy.
134    #[inline]
135    pub fn peer_addr(&self) -> Option<net::SocketAddr> {
136        self.head().io.as_ref().and_then(|io| {
137            io.query::<types::PeerAddr>()
138                .get()
139                .map(types::PeerAddr::into_inner)
140        })
141    }
142
143    /// Returns mutable access to the request payload.
144    pub fn payload(&mut self) -> &mut Payload {
145        &mut self.payload
146    }
147
148    /// Takes the request payload, leaving an empty payload behind.
149    pub fn take_payload(&mut self) -> Payload {
150        mem::take(&mut self.payload)
151    }
152
153    /// Replaces the request payload and returns the previous value.
154    pub fn replace_payload(&mut self, payload: Payload) -> Payload {
155        mem::replace(&mut self.payload, payload)
156    }
157
158    /// Returns the request extensions.
159    #[inline]
160    pub fn extensions(&self) -> Ref<'_, Extensions> {
161        self.head.extensions()
162    }
163
164    /// Returns mutable access to the request extensions.
165    #[inline]
166    pub fn extensions_mut(&self) -> RefMut<'_, Extensions> {
167        self.head.extensions_mut()
168    }
169
170    /// Split request into request head and payload
171    pub(crate) fn into_parts(self) -> (Message<RequestHead>, Payload) {
172        (self.head, self.payload)
173    }
174}
175
176impl Default for Request {
177    fn default() -> Request {
178        Request::new()
179    }
180}
181
182impl fmt::Debug for Request {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        writeln!(
185            f,
186            "\nRequest {:?} {}:{}",
187            self.version(),
188            self.method(),
189            self.path()
190        )?;
191        if let Some(q) = self.uri().query() {
192            writeln!(f, "  query: ?{q:?}")?;
193        }
194        writeln!(f, "  headers:")?;
195        for (key, val) in self.headers() {
196            if key == header::AUTHORIZATION {
197                writeln!(f, "    {key:?}: <REDACTED>")?;
198            } else {
199                writeln!(f, "    {key:?}: {val:?}")?;
200            }
201        }
202        Ok(())
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209
210    #[test]
211    fn test_basics() {
212        let msg = Message::new();
213        let req = Request::new();
214        assert!(req.io().is_none());
215        let mut req = Request::from(msg);
216        assert!(req.io().is_none());
217
218        req.headers_mut().insert(
219            header::CONTENT_TYPE,
220            header::HeaderValue::from_static("text/plain"),
221        );
222        assert!(req.headers().contains_key(header::CONTENT_TYPE));
223
224        req.extensions_mut()
225            .insert(header::HeaderValue::from_static("text/plain"));
226        assert_eq!(
227            req.extensions().get::<header::HeaderValue>().unwrap(),
228            header::HeaderValue::from_static("text/plain")
229        );
230
231        req.head_mut().headers_mut().insert(
232            header::CONTENT_LENGTH,
233            header::HeaderValue::from_static("100"),
234        );
235        assert!(req.headers().contains_key(header::CONTENT_LENGTH));
236
237        req.head_mut().no_chunking(true);
238        assert!(!req.head().chunked());
239        req.head_mut().no_chunking(false);
240        assert!(req.head().chunked());
241
242        *req.uri_mut() = Url::try_from("/index.html?q=1").unwrap();
243        assert_eq!(req.uri().path(), "/index.html");
244        assert_eq!(req.uri().query().unwrap(), "q=1");
245
246        let s = format!("{req:?}");
247        assert!(s.contains("Request HTTP/1.1 GET:/index.html"));
248
249        let s = format!("{:?}", req.head());
250        assert!(s.contains("RequestHead { id: 0, uri:"));
251    }
252
253    #[test]
254    fn test_default() {
255        let req = Request::default();
256        assert_eq!(req.method(), Method::GET);
257        assert!(req.io().is_none());
258    }
259}