tiny_http/request.rs
1use std::io::Error as IoError;
2use std::io::{self, Cursor, ErrorKind, Read, Write};
3
4use std::fmt;
5use std::net::SocketAddr;
6use std::str::FromStr;
7
8use std::sync::mpsc::Sender;
9
10use crate::util::{EqualReader, FusedReader};
11use crate::{HTTPVersion, Header, Method, Response, StatusCode};
12use chunked_transfer::Decoder;
13
14/// Represents an HTTP request made by a client.
15///
16/// A `Request` object is what is produced by the server, and is your what
17/// your code must analyse and answer.
18///
19/// This object implements the `Send` trait, therefore you can dispatch your requests to
20/// worker threads.
21///
22/// # Pipelining
23///
24/// If a client sends multiple requests in a row (without waiting for the response), then you will
25/// get multiple `Request` objects simultaneously. This is called *requests pipelining*.
26/// Tiny-http automatically reorders the responses so that you don't need to worry about the order
27/// in which you call `respond` or `into_writer`.
28///
29/// This mechanic is disabled if:
30///
31/// - The body of a request is large enough (handling requires pipelining requires storing the
32/// body of the request in a buffer ; if the body is too big, tiny-http will avoid doing that)
33/// - A request sends a `Expect: 100-continue` header (which means that the client waits to
34/// know whether its body will be processed before sending it)
35/// - A request sends a `Connection: close` header or `Connection: upgrade` header (used for
36/// websockets), which indicates that this is the last request that will be received on this
37/// connection
38///
39/// # Automatic cleanup
40///
41/// If a `Request` object is destroyed without `into_writer` or `respond` being called,
42/// an empty response with a 500 status code (internal server error) will automatically be
43/// sent back to the client.
44/// This means that if your code fails during the handling of a request, this "internal server
45/// error" response will automatically be sent during the stack unwinding.
46///
47/// # Testing
48///
49/// If you want to build fake requests to test your server, use [`TestRequest`](crate::test::TestRequest).
50pub struct Request {
51 // where to read the body from
52 data_reader: Option<Box<dyn Read + Send + 'static>>,
53
54 // if this writer is empty, then the request has been answered
55 response_writer: Option<Box<dyn Write + Send + 'static>>,
56
57 remote_addr: Option<SocketAddr>,
58
59 // true if HTTPS, false if HTTP
60 secure: bool,
61
62 method: Method,
63
64 path: String,
65
66 http_version: HTTPVersion,
67
68 headers: Vec<Header>,
69
70 body_length: Option<usize>,
71
72 // true if a `100 Continue` response must be sent when `as_reader()` is called
73 must_send_continue: bool,
74
75 // If Some, a message must be sent after responding
76 notify_when_responded: Option<Sender<()>>,
77}
78
79struct NotifyOnDrop<R> {
80 sender: Sender<()>,
81 inner: R,
82}
83
84impl<R: Read> Read for NotifyOnDrop<R> {
85 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
86 self.inner.read(buf)
87 }
88}
89impl<R: Write> Write for NotifyOnDrop<R> {
90 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
91 self.inner.write(buf)
92 }
93 fn flush(&mut self) -> io::Result<()> {
94 self.inner.flush()
95 }
96}
97impl<R> Drop for NotifyOnDrop<R> {
98 fn drop(&mut self) {
99 self.sender.send(()).unwrap();
100 }
101}
102
103/// Error that can happen when building a `Request` object.
104#[derive(Debug)]
105pub enum RequestCreationError {
106 /// The client sent an `Expect` header that was not recognized by tiny-http.
107 ExpectationFailed,
108
109 /// Error while reading data from the socket during the creation of the `Request`.
110 CreationIoError(IoError),
111}
112
113impl From<IoError> for RequestCreationError {
114 fn from(err: IoError) -> RequestCreationError {
115 RequestCreationError::CreationIoError(err)
116 }
117}
118
119/// Builds a new request.
120///
121/// After the request line and headers have been read from the socket, a new `Request` object
122/// is built.
123///
124/// You must pass a `Read` that will allow the `Request` object to read from the incoming data.
125/// It is the responsibility of the `Request` to read only the data of the request and not further.
126///
127/// The `Write` object will be used by the `Request` to write the response.
128#[allow(clippy::too_many_arguments)]
129pub fn new_request<R, W>(
130 secure: bool,
131 method: Method,
132 path: String,
133 version: HTTPVersion,
134 headers: Vec<Header>,
135 remote_addr: Option<SocketAddr>,
136 mut source_data: R,
137 writer: W,
138) -> Result<Request, RequestCreationError>
139where
140 R: Read + Send + 'static,
141 W: Write + Send + 'static,
142{
143 // finding the transfer-encoding header
144 let transfer_encoding = headers
145 .iter()
146 .find(|h: &&Header| h.field.equiv("Transfer-Encoding"))
147 .map(|h| h.value.clone());
148
149 // finding the content-length header
150 let content_length = if transfer_encoding.is_some() {
151 // if transfer-encoding is specified, the Content-Length
152 // header must be ignored (RFC2616 #4.4)
153 None
154 } else {
155 headers
156 .iter()
157 .find(|h: &&Header| h.field.equiv("Content-Length"))
158 .and_then(|h| FromStr::from_str(h.value.as_str()).ok())
159 };
160
161 // true if the client sent a `Expect: 100-continue` header
162 let expects_continue = {
163 match headers
164 .iter()
165 .find(|h: &&Header| h.field.equiv("Expect"))
166 .map(|h| h.value.as_str())
167 {
168 None => false,
169 Some(v) if v.eq_ignore_ascii_case("100-continue") => true,
170 _ => return Err(RequestCreationError::ExpectationFailed),
171 }
172 };
173
174 // true if the client sent a `Connection: upgrade` header
175 let connection_upgrade = {
176 match headers
177 .iter()
178 .find(|h: &&Header| h.field.equiv("Connection"))
179 .map(|h| h.value.as_str())
180 {
181 Some(v) if v.to_ascii_lowercase().contains("upgrade") => true,
182 _ => false,
183 }
184 };
185
186 // we wrap `source_data` around a reading whose nature depends on the transfer-encoding and
187 // content-length headers
188 let reader = if connection_upgrade {
189 // if we have a `Connection: upgrade`, always keeping the whole reader
190 Box::new(source_data) as Box<dyn Read + Send + 'static>
191 } else if let Some(content_length) = content_length {
192 if content_length == 0 {
193 Box::new(io::empty()) as Box<dyn Read + Send + 'static>
194 } else if content_length <= 1024 && !expects_continue {
195 // if the content-length is small enough, we just read everything into a buffer
196
197 let mut buffer = vec![0; content_length];
198 let mut offset = 0;
199
200 while offset != content_length {
201 let read = source_data.read(&mut buffer[offset..])?;
202 if read == 0 {
203 // the socket returned EOF, but we were before the expected content-length
204 // aborting
205 let info = "Connection has been closed before we received enough data";
206 let err = IoError::new(ErrorKind::ConnectionAborted, info);
207 return Err(RequestCreationError::CreationIoError(err));
208 }
209
210 offset += read;
211 }
212
213 Box::new(Cursor::new(buffer)) as Box<dyn Read + Send + 'static>
214 } else {
215 let (data_reader, _) = EqualReader::new(source_data, content_length); // TODO:
216 Box::new(FusedReader::new(data_reader)) as Box<dyn Read + Send + 'static>
217 }
218 } else if transfer_encoding.is_some() {
219 // if a transfer-encoding was specified, then "chunked" is ALWAYS applied
220 // over the message (RFC2616 #3.6)
221 Box::new(FusedReader::new(Decoder::new(source_data))) as Box<dyn Read + Send + 'static>
222 } else {
223 // if we have neither a Content-Length nor a Transfer-Encoding,
224 // assuming that we have no data
225 // TODO: could also be multipart/byteranges
226 Box::new(io::empty()) as Box<dyn Read + Send + 'static>
227 };
228
229 Ok(Request {
230 data_reader: Some(reader),
231 response_writer: Some(Box::new(writer) as Box<dyn Write + Send + 'static>),
232 remote_addr,
233 secure,
234 method,
235 path,
236 http_version: version,
237 headers,
238 body_length: content_length,
239 must_send_continue: expects_continue,
240 notify_when_responded: None,
241 })
242}
243
244impl Request {
245 /// Returns true if the request was made through HTTPS.
246 #[inline]
247 pub fn secure(&self) -> bool {
248 self.secure
249 }
250
251 /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
252 #[inline]
253 pub fn method(&self) -> &Method {
254 &self.method
255 }
256
257 /// Returns the resource requested by the client.
258 #[inline]
259 pub fn url(&self) -> &str {
260 &self.path
261 }
262
263 /// Returns a list of all headers sent by the client.
264 #[inline]
265 pub fn headers(&self) -> &[Header] {
266 &self.headers
267 }
268
269 /// Returns the HTTP version of the request.
270 #[inline]
271 pub fn http_version(&self) -> &HTTPVersion {
272 &self.http_version
273 }
274
275 /// Returns the length of the body in bytes.
276 ///
277 /// Returns `None` if the length is unknown.
278 #[inline]
279 pub fn body_length(&self) -> Option<usize> {
280 self.body_length
281 }
282
283 /// Returns the address of the client that sent this request.
284 ///
285 /// The address is always `Some` for TCP listeners, but always `None` for UNIX listeners
286 /// (as the remote address of a UNIX client is almost always unnamed).
287 ///
288 /// Note that this is gathered from the socket. If you receive the request from a proxy,
289 /// this function will return the address of the proxy and not the address of the actual
290 /// user.
291 #[inline]
292 pub fn remote_addr(&self) -> Option<&SocketAddr> {
293 self.remote_addr.as_ref()
294 }
295
296 /// Sends a response with a `Connection: upgrade` header, then turns the `Request` into a `Stream`.
297 ///
298 /// The main purpose of this function is to support websockets.
299 /// If you detect that the request wants to use some kind of protocol upgrade, you can
300 /// call this function to obtain full control of the socket stream.
301 ///
302 /// If you call this on a non-websocket request, tiny-http will wait until this `Stream` object
303 /// is destroyed before continuing to read or write on the socket. Therefore you should always
304 /// destroy it as soon as possible.
305 pub fn upgrade<R: Read>(
306 mut self,
307 protocol: &str,
308 response: Response<R>,
309 ) -> Box<dyn ReadWrite + Send> {
310 use crate::util::CustomStream;
311
312 response
313 .raw_print(
314 self.response_writer.as_mut().unwrap().by_ref(),
315 self.http_version.clone(),
316 &self.headers,
317 false,
318 Some(protocol),
319 )
320 .ok(); // TODO: unused result
321
322 self.response_writer.as_mut().unwrap().flush().ok(); // TODO: unused result
323
324 let stream = CustomStream::new(self.extract_reader_impl(), self.extract_writer_impl());
325 if let Some(sender) = self.notify_when_responded.take() {
326 let stream = NotifyOnDrop {
327 sender,
328 inner: stream,
329 };
330 Box::new(stream) as Box<dyn ReadWrite + Send>
331 } else {
332 Box::new(stream) as Box<dyn ReadWrite + Send>
333 }
334 }
335
336 /// Allows to read the body of the request.
337 ///
338 /// # Example
339 ///
340 /// ```no_run
341 /// # extern crate rustc_serialize;
342 /// # extern crate tiny_http;
343 /// # use rustc_serialize::json::Json;
344 /// # use std::io::Read;
345 /// # fn get_content_type(_: &tiny_http::Request) -> &'static str { "" }
346 /// # fn main() {
347 /// # let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
348 /// let mut request = server.recv().unwrap();
349 ///
350 /// if get_content_type(&request) == "application/json" {
351 /// let mut content = String::new();
352 /// request.as_reader().read_to_string(&mut content).unwrap();
353 /// let json: Json = content.parse().unwrap();
354 /// }
355 /// # }
356 /// ```
357 ///
358 /// If the client sent a `Expect: 100-continue` header with the request, calling this
359 /// function will send back a `100 Continue` response.
360 #[inline]
361 pub fn as_reader(&mut self) -> &mut dyn Read {
362 if self.must_send_continue {
363 let msg = Response::new_empty(StatusCode(100));
364 msg.raw_print(
365 self.response_writer.as_mut().unwrap().by_ref(),
366 self.http_version.clone(),
367 &self.headers,
368 true,
369 None,
370 )
371 .ok();
372 self.response_writer.as_mut().unwrap().flush().ok();
373 self.must_send_continue = false;
374 }
375
376 self.data_reader.as_mut().unwrap()
377 }
378
379 /// Turns the `Request` into a writer.
380 ///
381 /// The writer has a raw access to the stream to the user.
382 /// This function is useful for things like CGI.
383 ///
384 /// Note that the destruction of the `Writer` object may trigger
385 /// some events. For exemple if a client has sent multiple requests and the requests
386 /// have been processed in parallel, the destruction of a writer will trigger
387 /// the writing of the next response.
388 /// Therefore you should always destroy the `Writer` as soon as possible.
389 #[inline]
390 pub fn into_writer(mut self) -> Box<dyn Write + Send + 'static> {
391 let writer = self.extract_writer_impl();
392 if let Some(sender) = self.notify_when_responded.take() {
393 let writer = NotifyOnDrop {
394 sender,
395 inner: writer,
396 };
397 Box::new(writer) as Box<dyn Write + Send + 'static>
398 } else {
399 writer
400 }
401 }
402
403 /// Extract the response `Writer` object from the Request, dropping this `Writer` has the same side effects
404 /// as the object returned by `into_writer` above.
405 ///
406 /// This may only be called once on a single request.
407 fn extract_writer_impl(&mut self) -> Box<dyn Write + Send + 'static> {
408 use std::mem;
409
410 assert!(self.response_writer.is_some());
411
412 let mut writer = None;
413 mem::swap(&mut self.response_writer, &mut writer);
414 writer.unwrap()
415 }
416
417 /// Extract the body `Reader` object from the Request.
418 ///
419 /// This may only be called once on a single request.
420 fn extract_reader_impl(&mut self) -> Box<dyn Read + Send + 'static> {
421 use std::mem;
422
423 assert!(self.data_reader.is_some());
424
425 let mut reader = None;
426 mem::swap(&mut self.data_reader, &mut reader);
427 reader.unwrap()
428 }
429
430 /// Sends a response to this request.
431 #[inline]
432 pub fn respond<R>(mut self, response: Response<R>) -> Result<(), IoError>
433 where
434 R: Read,
435 {
436 let res = self.respond_impl(response);
437 if let Some(sender) = self.notify_when_responded.take() {
438 sender.send(()).unwrap();
439 }
440 res
441 }
442
443 fn respond_impl<R>(&mut self, response: Response<R>) -> Result<(), IoError>
444 where
445 R: Read,
446 {
447 let mut writer = self.extract_writer_impl();
448
449 let do_not_send_body = self.method == Method::Head;
450
451 Self::ignore_client_closing_errors(response.raw_print(
452 writer.by_ref(),
453 self.http_version.clone(),
454 &self.headers,
455 do_not_send_body,
456 None,
457 ))?;
458
459 Self::ignore_client_closing_errors(writer.flush())
460 }
461
462 fn ignore_client_closing_errors(result: io::Result<()>) -> io::Result<()> {
463 result.or_else(|err| match err.kind() {
464 ErrorKind::BrokenPipe => Ok(()),
465 ErrorKind::ConnectionAborted => Ok(()),
466 ErrorKind::ConnectionRefused => Ok(()),
467 ErrorKind::ConnectionReset => Ok(()),
468 _ => Err(err),
469 })
470 }
471
472 pub(crate) fn with_notify_sender(mut self, sender: Sender<()>) -> Self {
473 self.notify_when_responded = Some(sender);
474 self
475 }
476}
477
478impl fmt::Debug for Request {
479 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
480 write!(
481 formatter,
482 "Request({} {} from {:?})",
483 self.method, self.path, self.remote_addr
484 )
485 }
486}
487
488impl Drop for Request {
489 fn drop(&mut self) {
490 if self.response_writer.is_some() {
491 let response = Response::empty(500);
492 let _ = self.respond_impl(response); // ignoring any potential error
493 if let Some(sender) = self.notify_when_responded.take() {
494 sender.send(()).unwrap();
495 }
496 }
497 }
498}
499
500/// Dummy trait that regroups the `Read` and `Write` traits.
501///
502/// Automatically implemented on all types that implement both `Read` and `Write`.
503pub trait ReadWrite: Read + Write {}
504impl<T> ReadWrite for T where T: Read + Write {}
505
506#[cfg(test)]
507mod tests {
508 use super::Request;
509
510 #[test]
511 fn must_be_send() {
512 #![allow(dead_code)]
513 fn f<T: Send>(_: &T) {}
514 fn bar(rq: &Request) {
515 f(rq);
516 }
517 }
518}