mco_http/server/
request.rs1use std::io::{self, Read};
6use std::net::SocketAddr;
7use std::time::Duration;
8
9use crate::buffer::BufReader;
10use crate::net::NetworkStream;
11use crate::version::{HttpVersion};
12use crate::method::Method;
13use crate::header::{Headers, ContentLength, TransferEncoding};
14use crate::http::h1::{self, Incoming, HttpReader};
15use crate::http::h1::HttpReader::{SizedReader, ChunkedReader, EmptyReader};
16use crate::server::extensions::Extensions;
17use crate::uri::RequestUri;
18
19pub struct Request<'a, 'b: 'a> {
21 pub remote_addr: SocketAddr,
23 pub method: Method,
25 pub headers: Headers,
27 pub uri: RequestUri,
29 pub version: HttpVersion,
31 pub extra: Extensions,
33 pub body: HttpReader<&'a mut BufReader<&'b mut dyn NetworkStream>>
35}
36
37
38impl<'a, 'b: 'a> Request<'a, 'b> {
39 pub fn new(stream: &'a mut BufReader<&'b mut dyn NetworkStream>, addr: SocketAddr)
42 -> crate::Result<Request<'a, 'b>> {
43
44 let Incoming { version, subject: (method, uri), headers } = h1::parse_request(stream)?;
45 debug!("Request Line: {:?} {:?} {:?}", method, uri, version);
46 debug!("{:?}", headers);
47
48 let body = if headers.has::<ContentLength>() {
49 match headers.get::<ContentLength>() {
50 Some(&ContentLength(len)) => SizedReader(stream, len),
51 None => unreachable!()
52 }
53 } else if headers.has::<TransferEncoding>() {
54 todo!("check for Transfer-Encoding: chunked");
55 ChunkedReader(stream, None)
56 } else {
57 EmptyReader(stream)
58 };
59
60 Ok(Request {
61 remote_addr: addr,
62 method: method,
63 uri: uri,
64 headers: headers,
65 version: version,
66 body: body,
67 extra: Default::default(),
68 })
69 }
70
71 #[inline]
73 pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
74 self.body.get_ref().get_ref().set_read_timeout(timeout)
75 }
76
77 #[inline]
79 pub fn downcast_ref<T: NetworkStream>(&self) -> Option<&T> {
80 self.body.get_ref().get_ref().downcast_ref()
81 }
82
83 #[inline]
88 pub fn ssl<T: NetworkStream>(&self) -> Option<&T> {
89 self.downcast_ref()
90 }
91
92 #[inline]
94 pub fn deconstruct(self) -> (SocketAddr, Method, Headers,
95 RequestUri, HttpVersion,
96 HttpReader<&'a mut BufReader<&'b mut dyn NetworkStream>>) {
97 (self.remote_addr, self.method, self.headers,
98 self.uri, self.version, self.body)
99 }
100}
101
102impl<'a, 'b> Read for Request<'a, 'b> {
103 #[inline]
104 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
105 self.body.read(buf)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::buffer::BufReader;
112 use crate::header::{Host, TransferEncoding, Encoding};
113 use crate::net::NetworkStream;
114 use crate::mock::MockStream;
115 use super::Request;
116
117 use std::io::{self, Read};
118 use std::net::SocketAddr;
119
120 fn sock(s: &str) -> SocketAddr {
121 s.parse().unwrap()
122 }
123
124 fn read_to_string(mut req: Request) -> io::Result<String> {
125 let mut s = String::new();
126 req.read_to_string(&mut s)?;
127 Ok(s)
128 }
129
130 #[test]
131 fn test_get_empty_body() {
132 let mut mock = MockStream::with_input(b"\
133 GET / HTTP/1.1\r\n\
134 Host: example.domain\r\n\
135 \r\n\
136 I'm a bad request.\r\n\
137 ");
138
139 let mock: &mut dyn NetworkStream = &mut mock;
141 let mut stream = BufReader::new(mock);
142
143 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
144 assert_eq!(read_to_string(req).unwrap(), "".to_owned());
145 }
146
147 #[test]
148 fn test_get_with_body() {
149 let mut mock = MockStream::with_input(b"\
150 GET / HTTP/1.1\r\n\
151 Host: example.domain\r\n\
152 Content-Length: 19\r\n\
153 \r\n\
154 I'm a good request.\r\n\
155 ");
156
157 let mock: &mut dyn NetworkStream = &mut mock;
159 let mut stream = BufReader::new(mock);
160
161 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
162 assert_eq!(read_to_string(req).unwrap(), "I'm a good request.".to_owned());
163 }
164
165 #[test]
166 fn test_head_empty_body() {
167 let mut mock = MockStream::with_input(b"\
168 HEAD / HTTP/1.1\r\n\
169 Host: example.domain\r\n\
170 \r\n\
171 I'm a bad request.\r\n\
172 ");
173
174 let mock: &mut dyn NetworkStream = &mut mock;
176 let mut stream = BufReader::new(mock);
177
178 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
179 assert_eq!(read_to_string(req).unwrap(), "".to_owned());
180 }
181
182 #[test]
183 fn test_post_empty_body() {
184 let mut mock = MockStream::with_input(b"\
185 POST / HTTP/1.1\r\n\
186 Host: example.domain\r\n\
187 \r\n\
188 I'm a bad request.\r\n\
189 ");
190
191 let mock: &mut dyn NetworkStream = &mut mock;
193 let mut stream = BufReader::new(mock);
194
195 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
196 assert_eq!(read_to_string(req).unwrap(), "".to_owned());
197 }
198
199 #[test]
200 fn test_parse_chunked_request() {
201 let mut mock = MockStream::with_input(b"\
202 POST / HTTP/1.1\r\n\
203 Host: example.domain\r\n\
204 Transfer-Encoding: chunked\r\n\
205 \r\n\
206 1\r\n\
207 q\r\n\
208 2\r\n\
209 we\r\n\
210 2\r\n\
211 rt\r\n\
212 0\r\n\
213 \r\n"
214 );
215
216 let mock: &mut dyn NetworkStream = &mut mock;
218 let mut stream = BufReader::new(mock);
219
220 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
221
222 match req.headers.get::<Host>() {
224 Some(host) => {
225 assert_eq!("example.domain", host.hostname);
226 },
227 None => panic!("Host header expected!"),
228 };
229 match req.headers.get::<TransferEncoding>() {
230 Some(encodings) => {
231 assert_eq!(1, encodings.len());
232 assert_eq!(Encoding::Chunked, encodings[0]);
233 }
234 None => panic!("Transfer-Encoding: chunked expected!"),
235 };
236 assert_eq!(read_to_string(req).unwrap(), "qwert".to_owned());
238 }
239
240 #[test]
243 fn test_invalid_chunk_size_not_hex_digit() {
244 let mut mock = MockStream::with_input(b"\
245 POST / HTTP/1.1\r\n\
246 Host: example.domain\r\n\
247 Transfer-Encoding: chunked\r\n\
248 \r\n\
249 X\r\n\
250 1\r\n\
251 0\r\n\
252 \r\n"
253 );
254
255 let mock: &mut dyn NetworkStream = &mut mock;
257 let mut stream = BufReader::new(mock);
258
259 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
260
261 assert!(read_to_string(req).is_err());
262 }
263
264 #[test]
267 fn test_invalid_chunk_size_extension() {
268 let mut mock = MockStream::with_input(b"\
269 POST / HTTP/1.1\r\n\
270 Host: example.domain\r\n\
271 Transfer-Encoding: chunked\r\n\
272 \r\n\
273 1 this is an invalid extension\r\n\
274 1\r\n\
275 0\r\n\
276 \r\n"
277 );
278
279 let mock: &mut dyn NetworkStream = &mut mock;
281 let mut stream = BufReader::new(mock);
282
283 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
284
285 assert!(read_to_string(req).is_err());
286 }
287
288 #[test]
291 fn test_chunk_size_with_extension() {
292 let mut mock = MockStream::with_input(b"\
293 POST / HTTP/1.1\r\n\
294 Host: example.domain\r\n\
295 Transfer-Encoding: chunked\r\n\
296 \r\n\
297 1;this is an extension with a digit 1\r\n\
298 1\r\n\
299 0\r\n\
300 \r\n"
301 );
302
303 let mock: &mut dyn NetworkStream = &mut mock;
305 let mut stream = BufReader::new(mock);
306
307 let req = Request::new(&mut stream, sock("127.0.0.1:80")).unwrap();
308
309 assert_eq!(read_to_string(req).unwrap(), "1".to_owned());
310 }
311
312}