rouille_maint_in/lib.rs
1// Copyright (c) 2016 The Rouille developers
2// Licensed under the Apache License, Version 2.0
3// <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6// at your option. All files in the project carrying such
7// notice may not be copied, modified, or distributed except
8// according to those terms.
9
10//! > <hr>
11//! >
12//! > __NOTE__
13//! >
14//! > This is a maintenace release of rouille, not by its original author, and not endorsed or
15//! > supported by him. The aim of the release is to minimally update the code to the 2018 edition
16//! > of Rust, and upgrade several dependencies to avoid crate duplication. This crate should be
17//! > a drop-in replacement for `rouille-3.0.0`. To use it, update `Cargo.toml` to say:
18//! >
19//! > `rouille = { version = "3", package = "rouille-maint-in" }`
20//! > <hr>
21//!
22//! The rouille library is very easy to get started with.
23//!
24//! Listening to a port is done by calling the [`start_server`](fn.start_server.html) function:
25//!
26//! ```no_run
27//! # use rouille_maint_in as rouille;
28//! use rouille::Request;
29//! use rouille::Response;
30//!
31//! rouille::start_server("0.0.0.0:80", move |request| {
32//! Response::text("hello world")
33//! });
34//! ```
35//!
36//! Whenever an HTTP request is received on the address passed as first parameter, the closure
37//! passed as second parameter is called. This closure must then return a
38//! [`Response`](struct.Response.html) that will be sent back to the client.
39//!
40//! See the documentation of [`start_server`](fn.start_server.html) for more details.
41//!
42//! # Analyzing the request
43//!
44//! The parameter that the closure receives is a [`Request`](struct.Request.html) object that
45//! represents the request made by the client.
46//!
47//! The `Request` object itself provides some getters, but most advanced functionnalities are
48//! provided by other modules of this crate.
49//!
50//! - In order to dispatch between various code depending on the URL, you can use the
51//! [`router!`](macro.router.html) macro.
52//! - In order to analyze the body of the request, like handling JSON input, form input, etc. you
53//! can take a look at [the `input` module](input/index.html).
54//!
55//! # Returning a response
56//!
57//! Once you analyzed the request, it is time to return a response by returning a
58//! [`Response`](struct.Response.html) object.
59//!
60//! All the members of `Response` are public, so you can customize it as you want. There are also
61//! several constructors that you build a basic `Response` which can then modify.
62//!
63//! In order to serve static files, take a look at
64//! [the `match_assets` function](fn.match_assets.html).
65
66#![deny(unsafe_code)]
67
68extern crate base64;
69#[cfg(feature = "brotli2")]
70extern crate brotli2;
71extern crate chrono;
72extern crate filetime;
73#[cfg(feature = "gzip")]
74extern crate deflate;
75extern crate multipart;
76extern crate rand;
77extern crate serde;
78#[macro_use]
79extern crate serde_derive;
80extern crate serde_json;
81extern crate sha1;
82extern crate time;
83extern crate tiny_http;
84pub extern crate url;
85pub extern crate percent_encoding;
86extern crate threadpool;
87extern crate num_cpus;
88
89// https://github.com/servo/rust-url/blob/e121d8d0aafd50247de5f5310a227ecb1efe6ffe/percent_encoding/lib.rs#L126
90pub const DEFAULT_ENCODE_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
91 .add(b' ').add(b'"').add(b'#').add(b'<').add(b'>')
92 .add(b'`').add(b'?').add(b'{').add(b'}');
93
94pub use assets::extension_to_mime;
95pub use assets::match_assets;
96pub use crate::log::{log, log_custom};
97pub use response::{Response, ResponseBody};
98pub use tiny_http::ReadWrite;
99
100use std::time::Duration;
101use std::error::Error;
102use std::io::Cursor;
103use std::io::Result as IoResult;
104use std::io::Read;
105use std::marker::PhantomData;
106use std::net::SocketAddr;
107use std::net::ToSocketAddrs;
108use std::panic;
109use std::panic::AssertUnwindSafe;
110use std::slice::Iter as SliceIter;
111use std::sync::Arc;
112use std::sync::Mutex;
113use std::sync::mpsc;
114use std::thread;
115use std::fmt;
116
117
118pub mod cgi;
119pub mod content_encoding;
120pub mod input;
121pub mod proxy;
122pub mod session;
123pub mod websocket;
124
125mod assets;
126mod find_route;
127mod log;
128mod response;
129mod router;
130#[doc(hidden)]
131pub mod try_or_400;
132
133/// This macro assumes that the current function returns a `Response` and takes a `Result`.
134/// If the expression you pass to the macro is an error, then a 404 response is returned.
135#[macro_export]
136macro_rules! try_or_404 {
137 ($result:expr) => (
138 match $result {
139 Ok(r) => r,
140 Err(_) => return $crate::Response::empty_404(),
141 }
142 );
143}
144
145/// This macro assumes that the current function returns a `Response`. If the condition you pass
146/// to the macro is false, then a 400 response is returned.
147///
148/// # Example
149///
150/// ```
151/// # #[macro_use] extern crate rouille_maint_in as rouille;
152/// # fn main() {
153/// use rouille::Request;
154/// use rouille::Response;
155///
156/// fn handle_something(request: &Request) -> Response {
157/// let data = try_or_400!(post_input!(request, {
158/// field1: u32,
159/// field2: String,
160/// }));
161///
162/// assert_or_400!(data.field1 >= 2);
163/// Response::text("hello")
164/// }
165/// # }
166/// ```
167#[macro_export]
168macro_rules! assert_or_400 {
169 ($cond:expr) => (
170 if !$cond {
171 return $crate::Response::empty_400();
172 }
173 );
174}
175
176/// Calls the [panic!](std::panic!) macro from the standard library wrapped in a
177/// [Response](crate::Response)-typed expression, to avoid the compiler complaining about
178/// unreachable paths in certain styles of `router!` blocks. The macro supports exactly the
179/// same types of arguments as the one in `std`.
180///
181/// # Example
182///
183/// ```should_panic
184/// # #[macro_use] extern crate rouille_maint_in as rouille;
185/// # fn main() {
186/// # use std::net::SocketAddr;
187/// # let request = rouille::Request::fake_http_from("127.0.0.1:60400".parse().expect("socket"), "GET", "/panic", vec![], vec![]);
188/// router!(request,
189/// (GET) (/panic) => {
190/// response_panic!("Oops!");
191/// },
192/// _ => (),
193/// )
194/// # }
195/// ```
196#[macro_export]
197macro_rules! response_panic {
198 () => { $crate::Response::text(if false { "" } else { ::std::panic!(); }) };
199 ($msg:expr $(,)?) => { $crate::Response::text(if false { "" } else { ::std::panic!($msg); }) };
200 ($fmt:expr, $($arg:tt)+) => { $crate::Response::text(if false { "" } else { ::std::panic!($fmt, $($arg)+); }) };
201}
202
203/// Starts a server and uses the given requests handler.
204///
205/// The request handler takes a `&Request` and must return a `Response` to send to the user.
206///
207/// > **Note**: `start_server` is meant to be an easy-to-use function. If you want more control,
208/// > see [the `Server` struct](struct.Server.html).
209///
210/// # Common mistakes
211///
212/// The handler must capture its environment by value and not by reference (`'static`). If you
213/// use closure, don't forget to put `move` in front of the closure.
214///
215/// The handler must also be thread-safe (`Send` and `Sync`).
216/// For example this handler isn't thread-safe:
217///
218/// ```compile_fail
219/// # extern crate rouille_maint_in as rouille;
220/// let mut requests_counter = 0;
221///
222/// rouille::start_server("localhost:80", move |request| {
223/// requests_counter += 1;
224///
225/// // ... rest of the handler ...
226/// # panic!()
227/// })
228/// ```
229///
230/// Multiple requests can be processed simultaneously, therefore you can't mutably access
231/// variables from the outside.
232///
233/// Instead you must use a `Mutex`:
234///
235/// ```no_run
236/// # use rouille_maint_in as rouille;
237/// use std::sync::Mutex;
238/// let requests_counter = Mutex::new(0);
239///
240/// rouille::start_server("localhost:80", move |request| {
241/// *requests_counter.lock().unwrap() += 1;
242///
243/// // rest of the handler
244/// # panic!()
245/// })
246/// ```
247///
248/// # Panic handling in the handler
249///
250/// If your request handler panicks, a 500 error will automatically be sent to the client.
251///
252/// # Panic
253///
254/// This function will panic if the server starts to fail (for example if you use a port that is
255/// already occupied) or if the socket is force-closed by the operating system.
256///
257/// If you need to handle these situations, please see `Server`.
258pub fn start_server<A, F>(addr: A, handler: F) -> !
259 where A: ToSocketAddrs,
260 F: Send + Sync + 'static + Fn(&Request) -> Response
261{
262 Server::new(addr, handler).expect("Failed to start server").run();
263 panic!("The server socket closed unexpectedly")
264}
265
266
267/// Identical to `start_server` but uses a `ThreadPool` of the given size.
268///
269/// When `pool_size` is `None`, the thread pool size will default to `8 * num-cpus`.
270/// `pool_size` must be greater than zero or this function will panic.
271pub fn start_server_with_pool<A, F>(addr: A, pool_size: Option<usize>, handler: F) -> !
272 where A: ToSocketAddrs,
273 F: Send + Sync + 'static + Fn(&Request) -> Response
274{
275 Server::new(addr, handler).expect("Failed to start server")
276 .pool_size(pool_size.unwrap_or_else(|| 8 * num_cpus::get()))
277 .run();
278 panic!("The server socket closed unexpectedly")
279}
280
281
282/// Executes a function in either a thread of a thread pool
283enum Executor {
284 Threaded,
285 Pooled {
286 pool: threadpool::ThreadPool,
287 }
288}
289impl Executor {
290 /// `size` must be greater than zero or the call to `ThreadPool::new` will panic.
291 fn with_size(size: usize) -> Self {
292 let pool = threadpool::ThreadPool::new(size);
293 Executor::Pooled { pool }
294 }
295
296 #[inline]
297 fn execute<F: FnOnce() + Send + 'static>(&self, f: F) {
298 match *self {
299 Executor::Threaded => { thread::spawn(f); }
300 Executor::Pooled { ref pool } => { pool.execute(f); }
301 }
302 }
303}
304
305
306/// A listening server.
307///
308/// This struct is the more manual server creation API of rouille and can be used as an alternative
309/// to the `start_server` function.
310///
311/// The `start_server` function is just a shortcut for `Server::new` followed with `run`. See the
312/// documentation of the `start_server` function for more details about the handler.
313///
314/// # Example
315///
316/// ```no_run
317/// # use rouille_maint_in as rouille;
318/// use rouille::Server;
319/// use rouille::Response;
320///
321/// let server = Server::new("localhost:0", |request| {
322/// Response::text("hello world")
323/// }).unwrap();
324/// println!("Listening on {:?}", server.server_addr());
325/// server.run();
326/// ```
327pub struct Server<F> {
328 server: tiny_http::Server,
329 handler: Arc<AssertUnwindSafe<F>>,
330 executor: Executor,
331}
332
333
334impl<F> Server<F> where F: Send + Sync + 'static + Fn(&Request) -> Response {
335 /// Builds a new `Server` object.
336 ///
337 /// After this function returns, the HTTP server is listening.
338 ///
339 /// Returns an error if there was an error while creating the listening socket, for example if
340 /// the port is already in use.
341 pub fn new<A>(addr: A, handler: F) -> Result<Server<F>, Box<dyn Error + Send + Sync>>
342 where A: ToSocketAddrs
343 {
344 let server = tiny_http::Server::http(addr)?;
345 Ok(Server {
346 server,
347 executor: Executor::Threaded,
348 handler: Arc::new(AssertUnwindSafe(handler)), // TODO: using AssertUnwindSafe here is wrong, but unwind safety has some usability problems in Rust in general
349 })
350 }
351
352 /// Builds a new `Server` object with SSL support.
353 ///
354 /// After this function returns, the HTTPS server is listening.
355 ///
356 /// Returns an error if there was an error while creating the listening socket, for example if
357 /// the port is already in use.
358 #[cfg(feature = "ssl")]
359 pub fn new_ssl<A>(
360 addr: A,
361 handler: F,
362 certificate: Vec<u8>,
363 private_key: Vec<u8>,
364 ) -> Result<Server<F>, Box<dyn Error + Send + Sync>> where A: ToSocketAddrs {
365 let ssl_config = tiny_http::SslConfig {
366 certificate,
367 private_key,
368 };
369 let server = tiny_http::Server::https(addr, ssl_config)?;
370 Ok(Server {
371 server,
372 executor: Executor::Threaded,
373 handler: Arc::new(AssertUnwindSafe(handler)), // TODO: using AssertUnwindSafe here is wrong, but unwind safety has some usability problems in Rust in general
374 })
375 }
376
377 /// Use a `ThreadPool` of the given size to process requests
378 ///
379 /// `pool_size` must be greater than zero or this function will panic.
380 pub fn pool_size(mut self, pool_size: usize) -> Self {
381 self.executor = Executor::with_size(pool_size);
382 self
383 }
384
385 /// Returns the address of the listening socket.
386 #[inline]
387 pub fn server_addr(&self) -> SocketAddr {
388 self.server.server_addr()
389 }
390
391 /// Runs the server forever, or until the listening socket is somehow force-closed by the
392 /// operating system.
393 #[inline]
394 pub fn run(self) {
395 for request in self.server.incoming_requests() {
396 self.process(request);
397 }
398 }
399
400 /// Processes all the client requests waiting to be processed, then returns.
401 ///
402 /// This function executes very quickly, as each client requests that needs to be processed
403 /// is processed in a separate thread.
404 #[inline]
405 pub fn poll(&self) {
406 while let Ok(Some(request)) = self.server.try_recv() {
407 self.process(request);
408 }
409 }
410
411 /// Creates a new thread for the server that can be gracefully stopped later.
412 ///
413 /// This function returns a tuple of a `JoinHandle` and a `Sender`.
414 /// You must call `JoinHandle::join()` otherwise the server will not run until completion.
415 /// The server can be stopped at will by sending it an empty `()` message from another thread.
416 /// There may be a maximum of a 1 second delay between sending the stop message and the server
417 /// stopping. This delay may be shortened in future.
418 ///
419 /// ```no_run
420 /// # use rouille_maint_in as rouille;
421 /// use std::thread;
422 /// use std::time::Duration;
423 /// use rouille::Server;
424 /// use rouille::Response;
425 ///
426 /// let server = Server::new("localhost:0", |request| {
427 /// Response::text("hello world")
428 /// }).unwrap();
429 /// println!("Listening on {:?}", server.server_addr());
430 /// let (handle, sender) = server.stoppable();
431 ///
432 /// // Stop the server in 3 seconds
433 /// thread::spawn(move || {
434 /// thread::sleep(Duration::from_secs(3));
435 /// sender.send(()).unwrap();
436 /// });
437 ///
438 /// // Block the main thread until the server is stopped
439 /// handle.join().unwrap();
440 /// ```
441 #[inline]
442 pub fn stoppable(self) -> (thread::JoinHandle<()>, mpsc::Sender<()>) {
443 let (tx, rx) = mpsc::channel();
444 let handle = thread::spawn(move || {
445 while let Err(_) = rx.try_recv() {
446 // In order to reduce CPU load wait 1s for a recv before looping again
447 while let Ok(Some(request)) = self.server.recv_timeout(Duration::from_secs(1)) {
448 self.process(request);
449 }
450 }
451 });
452
453 (handle, tx)
454 }
455
456 /// Same as `poll()` but blocks for at most `duration` before returning.
457 ///
458 /// This function can be used implement a custom server loop in a more CPU-efficient manner
459 /// than calling `poll`.
460 ///
461 /// # Example
462 ///
463 /// ```no_run
464 /// # use rouille_maint_in as rouille;
465 /// use rouille::Server;
466 /// use rouille::Response;
467 ///
468 /// let server = Server::new("localhost:0", |request| {
469 /// Response::text("hello world")
470 /// }).unwrap();
471 /// println!("Listening on {:?}", server.server_addr());
472 ///
473 /// loop {
474 /// server.poll_timeout(std::time::Duration::from_millis(100));
475 /// }
476 /// ```
477 #[inline]
478 pub fn poll_timeout(&self, dur: std::time::Duration) {
479 while let Ok(Some(request)) = self.server.recv_timeout(dur) {
480 self.process(request);
481 }
482 }
483
484 // Internal function, called when we got a request from tiny-http that needs to be processed.
485 fn process(&self, request: tiny_http::Request) {
486 // We spawn a thread so that requests are processed in parallel.
487 let handler = self.handler.clone();
488 self.executor.execute(|| {
489 // Small helper struct that makes it possible to put
490 // a `tiny_http::Request` inside a `Box<Read>`.
491 struct RequestRead(Arc<Mutex<Option<tiny_http::Request>>>);
492 impl Read for RequestRead {
493 #[inline]
494 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
495 self.0.lock().unwrap().as_mut().unwrap().as_reader().read(buf)
496 }
497 }
498
499 // Building the `Request` object.
500 let tiny_http_request;
501 let rouille_request = {
502 let url = request.url().to_owned();
503 let method = request.method().as_str().to_owned();
504 let headers = request.headers().iter().map(|h| (h.field.to_string(), h.value.clone().into())).collect();
505 let remote_addr = *request.remote_addr();
506
507 tiny_http_request = Arc::new(Mutex::new(Some(request)));
508 let data = Arc::new(Mutex::new(Some(Box::new(RequestRead(tiny_http_request.clone())) as Box<_>)));
509
510 Request {
511 url,
512 method,
513 headers,
514 https: false,
515 data,
516 remote_addr,
517 }
518 };
519
520 // Calling the handler ; this most likely takes a lot of time.
521 // If the handler panics, we build a dummy response.
522 let mut rouille_response = {
523 // We don't use the `rouille_request` anymore after the panic, so it's ok to assert
524 // it's unwind safe.
525 let rouille_request = AssertUnwindSafe(rouille_request);
526 let res = panic::catch_unwind(move || {
527 let rouille_request = rouille_request;
528 handler(&rouille_request)
529 });
530
531 match res {
532 Ok(r) => r,
533 Err(_) => {
534 Response::html("<h1>Internal Server Error</h1>\
535 <p>An internal error has occurred on the server.</p>")
536 .with_status_code(500)
537 }
538 }
539 };
540
541 // writing the response
542 let (res_data, res_len) = rouille_response.data.into_reader_and_size();
543 let mut response = tiny_http::Response::empty(rouille_response.status_code)
544 .with_data(res_data, res_len);
545
546 let mut upgrade_header = "".into();
547
548 for (key, value) in rouille_response.headers {
549 if key.eq_ignore_ascii_case("Content-Length") {
550 continue;
551 }
552
553 if key.eq_ignore_ascii_case("Upgrade") {
554 upgrade_header = value;
555 continue;
556 }
557
558 if let Ok(header) = tiny_http::Header::from_bytes(key.as_bytes(), value.as_bytes()) {
559 response.add_header(header);
560 } else {
561 // TODO: ?
562 }
563 }
564
565 if let Some(ref mut upgrade) = rouille_response.upgrade {
566 let trq = tiny_http_request.lock().unwrap().take().unwrap();
567 let socket = trq.upgrade(&upgrade_header, response);
568 upgrade.build(socket);
569
570 } else {
571 // We don't really care if we fail to send the response to the client, as there's
572 // nothing we can do anyway.
573 let _ = tiny_http_request.lock().unwrap().take().unwrap().respond(response);
574 }
575 });
576 }
577}
578
579/// Trait for objects that can take ownership of a raw connection to the client data.
580///
581/// The purpose of this trait is to be used with the `Connection: Upgrade` header, hence its name.
582pub trait Upgrade {
583 /// Initializes the object with the given socket.
584 fn build(&mut self, socket: Box<dyn ReadWrite + Send>);
585}
586
587/// Represents a request that your handler must answer to.
588///
589/// This can be either a real request (received by the HTTP server) or a mock object created with
590/// one of the `fake_*` constructors.
591pub struct Request {
592 method: String,
593 url: String,
594 headers: Vec<(String, String)>,
595 https: bool,
596 data: Arc<Mutex<Option<Box<dyn Read + Send>>>>,
597 remote_addr: SocketAddr,
598}
599
600impl fmt::Debug for Request {
601 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
602 f.debug_struct("Request")
603 .field("method", &self.method)
604 .field("url", &self.url)
605 .field("headers", &self.headers)
606 .field("https", &self.https)
607 .field("remote_addr", &self.remote_addr)
608 .finish()
609 }
610}
611
612impl Request {
613 /// Builds a fake HTTP request to be used during tests.
614 ///
615 /// The remote address of the client will be `127.0.0.1:12345`. Use `fake_http_from` to
616 /// specify what the client's address should be.
617 pub fn fake_http<U, M>(method: M, url: U, headers: Vec<(String, String)>, data: Vec<u8>)
618 -> Request where U: Into<String>, M: Into<String>
619 {
620 let data = Arc::new(Mutex::new(Some(Box::new(Cursor::new(data)) as Box<_>)));
621 let remote_addr = "127.0.0.1:12345".parse().unwrap();
622
623 Request {
624 url: url.into(),
625 method: method.into(),
626 https: false,
627 data,
628 headers,
629 remote_addr,
630 }
631 }
632
633 /// Builds a fake HTTP request to be used during tests.
634 pub fn fake_http_from<U, M>(from: SocketAddr, method: M, url: U,
635 headers: Vec<(String, String)>, data: Vec<u8>)
636 -> Request where U: Into<String>, M: Into<String>
637 {
638 let data = Arc::new(Mutex::new(Some(Box::new(Cursor::new(data)) as Box<_>)));
639
640 Request {
641 url: url.into(),
642 method: method.into(),
643 https: false,
644 data,
645 headers,
646 remote_addr: from,
647 }
648 }
649
650 /// Builds a fake HTTPS request to be used during tests.
651 ///
652 /// The remote address of the client will be `127.0.0.1:12345`. Use `fake_https_from` to
653 /// specify what the client's address should be.
654 pub fn fake_https<U, M>(method: M, url: U, headers: Vec<(String, String)>, data: Vec<u8>)
655 -> Request where U: Into<String>, M: Into<String>
656 {
657 let data = Arc::new(Mutex::new(Some(Box::new(Cursor::new(data)) as Box<_>)));
658 let remote_addr = "127.0.0.1:12345".parse().unwrap();
659
660 Request {
661 url: url.into(),
662 method: method.into(),
663 https: true,
664 data,
665 headers,
666 remote_addr,
667 }
668 }
669
670 /// Builds a fake HTTPS request to be used during tests.
671 pub fn fake_https_from<U, M>(from: SocketAddr, method: M, url: U,
672 headers: Vec<(String, String)>, data: Vec<u8>)
673 -> Request where U: Into<String>, M: Into<String>
674 {
675 let data = Arc::new(Mutex::new(Some(Box::new(Cursor::new(data)) as Box<_>)));
676
677 Request {
678 url: url.into(),
679 method: method.into(),
680 https: true,
681 data,
682 headers,
683 remote_addr: from,
684 }
685 }
686
687 /// If the decoded URL of the request starts with `prefix`, builds a new `Request` that is
688 /// the same as the original but without that prefix.
689 ///
690 /// # Example
691 ///
692 /// ```
693 /// # use rouille_maint_in as rouille;
694 /// # use rouille::Request;
695 /// # use rouille::Response;
696 /// fn handle(request: &Request) -> Response {
697 /// if let Some(request) = request.remove_prefix("/static") {
698 /// return rouille::match_assets(&request, "/static");
699 /// }
700 ///
701 /// // ...
702 /// # panic!()
703 /// }
704 /// ```
705 pub fn remove_prefix(&self, prefix: &str) -> Option<Request> {
706 if !self.url().starts_with(prefix) {
707 return None;
708 }
709
710 // TODO: url-encoded characters in the prefix are not implemented
711 assert!(self.url.starts_with(prefix));
712 Some(Request {
713 method: self.method.clone(),
714 url: self.url[prefix.len() ..].to_owned(),
715 headers: self.headers.clone(), // TODO: expensive
716 https: self.https,
717 data: self.data.clone(),
718 remote_addr: self.remote_addr,
719 })
720 }
721
722 /// Returns `true` if the request uses HTTPS, and `false` if it uses HTTP.
723 ///
724 /// # Example
725 ///
726 /// ```
727 /// # use rouille_maint_in as rouille;
728 /// use rouille::{Request, Response};
729 ///
730 /// fn handle(request: &Request) -> Response {
731 /// if !request.is_secure() {
732 /// return Response::redirect_303(format!("https://example.com"));
733 /// }
734 ///
735 /// // ...
736 /// # panic!()
737 /// }
738 /// ```
739 #[inline]
740 pub fn is_secure(&self) -> bool {
741 self.https
742 }
743
744 /// Returns the method of the request (`GET`, `POST`, etc.).
745 #[inline]
746 pub fn method(&self) -> &str {
747 &self.method
748 }
749
750 /// Returns the raw URL requested by the client. It is not decoded and thus can contain strings
751 /// such as `%20`, and the query parameters such as `?p=hello`.
752 ///
753 /// See also `url()`.
754 ///
755 /// # Example
756 ///
757 /// ```
758 /// # use rouille_maint_in as rouille;
759 /// use rouille::Request;
760 ///
761 /// let request = Request::fake_http("GET", "/hello%20world?foo=bar", vec![], vec![]);
762 /// assert_eq!(request.raw_url(), "/hello%20world?foo=bar");
763 /// ```
764 #[inline]
765 pub fn raw_url(&self) -> &str {
766 &self.url
767 }
768
769 /// Returns the raw query string requested by the client. In other words, everything after the
770 /// first `?` in the raw url.
771 ///
772 /// Returns the empty string if no query string.
773 #[inline]
774 pub fn raw_query_string(&self) -> &str {
775 if let Some(pos) = self.url.bytes().position(|c| c == b'?') {
776 self.url.split_at(pos + 1).1
777 } else {
778 ""
779 }
780 }
781
782 /// Returns the URL requested by the client.
783 ///
784 /// Contrary to `raw_url`, special characters have been decoded and the query string
785 /// (eg `?p=hello`) has been removed.
786 ///
787 /// If there is any non-unicode character in the URL, it will be replaced with `U+FFFD`.
788 ///
789 /// > **Note**: This function will decode the token `%2F` will be decoded as `/`. However the
790 /// > official speficiations say that such a token must not count as a delimiter for URL paths.
791 /// > In other words, `/hello/world` is not the same as `/hello%2Fworld`.
792 ///
793 /// # Example
794 ///
795 /// ```
796 /// # use rouille_maint_in as rouille;
797 /// use rouille::Request;
798 ///
799 /// let request = Request::fake_http("GET", "/hello%20world?foo=bar", vec![], vec![]);
800 /// assert_eq!(request.url(), "/hello world");
801 /// ```
802 pub fn url(&self) -> String {
803 let url = self.url.as_bytes();
804 let url = if let Some(pos) = url.iter().position(|&c| c == b'?') {
805 &url[..pos]
806 } else {
807 url
808 };
809
810 percent_encoding::percent_decode(url).decode_utf8_lossy().into_owned()
811 }
812
813 /// Returns the value of a GET parameter.
814 /// TODO: clumbsy
815 pub fn get_param(&self, param_name: &str) -> Option<String> {
816 let get_params = self.raw_query_string();
817
818 // TODO: `hello=5` will be matched for param name `lo`
819
820 let param = match get_params.rfind(&format!("{}=", param_name)) {
821 Some(p) => p + param_name.len() + 1,
822 None => return None,
823 };
824
825 let value = match get_params.bytes().skip(param).position(|c| c == b'&') {
826 None => &get_params[param..],
827 Some(e) => &get_params[param .. e + param],
828 };
829
830 Some(percent_encoding::percent_decode(value.replace("+", " ").as_bytes()).decode_utf8_lossy().into_owned())
831 }
832
833 /// Returns the value of a header of the request.
834 ///
835 /// Returns `None` if no such header could be found.
836 #[inline]
837 pub fn header(&self, key: &str) -> Option<&str> {
838 self.headers.iter().find(|&&(ref k, _)| k.eq_ignore_ascii_case(key)).map(|&(_, ref v)| &v[..])
839 }
840
841 /// Returns a list of all the headers of the request.
842 #[inline]
843 pub fn headers(&self) -> HeadersIter {
844 HeadersIter { iter: self.headers.iter() }
845 }
846
847 /// Returns the state of the `DNT` (Do Not Track) header.
848 ///
849 /// If the header is missing or is malformed, `None` is returned. If the header exists,
850 /// `Some(true)` is returned if `DNT` is `1` and `Some(false)` is returned if `DNT` is `0`.
851 ///
852 /// # Example
853 ///
854 /// ```
855 /// # use rouille_maint_in as rouille;
856 /// use rouille::{Request, Response};
857 ///
858 /// # fn track_user(request: &Request) {}
859 /// fn handle(request: &Request) -> Response {
860 /// if !request.do_not_track().unwrap_or(false) {
861 /// track_user(&request);
862 /// }
863 ///
864 /// // ...
865 /// # panic!()
866 /// }
867 /// ```
868 pub fn do_not_track(&self) -> Option<bool> {
869 match self.header("DNT") {
870 Some(h) if h == "1" => Some(true),
871 Some(h) if h == "0" => Some(false),
872 _ => None
873 }
874 }
875
876 /// Returns the body of the request.
877 ///
878 /// The body can only be retrieved once. Returns `None` is the body has already been retreived
879 /// before.
880 ///
881 /// # Example
882 ///
883 /// ```
884 /// # use rouille_maint_in as rouille;
885 /// use std::io::Read;
886 /// use rouille::{Request, Response, ResponseBody};
887 ///
888 /// fn echo(request: &Request) -> Response {
889 /// let mut data = request.data().expect("Oops, body already retrieved, problem \
890 /// in the server");
891 ///
892 /// let mut buf = Vec::new();
893 /// match data.read_to_end(&mut buf) {
894 /// Ok(_) => (),
895 /// Err(_) => return Response::text("Failed to read body")
896 /// };
897 ///
898 /// Response {
899 /// data: ResponseBody::from_data(buf),
900 /// .. Response::text("")
901 /// }
902 /// }
903 /// ```
904 pub fn data(&self) -> Option<RequestBody> {
905 let reader = self.data.lock().unwrap().take();
906 reader.map(|r| RequestBody { body: r, marker: PhantomData })
907 }
908
909 /// Returns the address of the client that made this request.
910 ///
911 /// # Example
912 ///
913 /// ```
914 /// # use rouille_maint_in as rouille;
915 /// use rouille::{Request, Response};
916 ///
917 /// fn handle(request: &Request) -> Response {
918 /// Response::text(format!("Your IP is: {:?}", request.remote_addr()))
919 /// }
920 /// ```
921 #[inline]
922 pub fn remote_addr(&self) -> &SocketAddr {
923 &self.remote_addr
924 }
925}
926
927/// Iterator to the list of headers in a request.
928#[derive(Debug, Clone)]
929pub struct HeadersIter<'a> {
930 iter: SliceIter<'a, (String, String)>
931}
932
933impl<'a> Iterator for HeadersIter<'a> {
934 type Item = (&'a str, &'a str);
935
936 #[inline]
937 fn next(&mut self) -> Option<Self::Item> {
938 self.iter.next().map(|&(ref k, ref v)| (&k[..], &v[..]))
939 }
940
941 #[inline]
942 fn size_hint(&self) -> (usize, Option<usize>) {
943 self.iter.size_hint()
944 }
945}
946
947impl<'a> ExactSizeIterator for HeadersIter<'a> {
948}
949
950/// Gives access to the body of a request.
951///
952/// In order to obtain this object, call `request.data()`.
953pub struct RequestBody<'a> {
954 body: Box<dyn Read + Send>,
955 marker: PhantomData<&'a ()>,
956}
957
958impl<'a> Read for RequestBody<'a> {
959 #[inline]
960 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
961 self.body.read(buf)
962 }
963}
964
965#[cfg(test)]
966mod tests {
967 use crate::Request;
968
969 #[test]
970 fn header() {
971 let request = Request::fake_http("GET", "/", vec![("Host".to_owned(), "localhost".to_owned())], vec![]);
972 assert_eq!(request.header("Host"), Some("localhost"));
973 assert_eq!(request.header("host"), Some("localhost"));
974 }
975
976 #[test]
977 fn get_param() {
978 let request = Request::fake_http("GET", "/?p=hello", vec![], vec![]);
979 assert_eq!(request.get_param("p"), Some("hello".to_owned()));
980 }
981
982 #[test]
983 fn body_twice() {
984 let request = Request::fake_http("GET", "/", vec![], vec![62, 62, 62]);
985 assert!(request.data().is_some());
986 assert!(request.data().is_none());
987 }
988
989 #[test]
990 fn url_strips_get_query() {
991 let request = Request::fake_http("GET", "/?p=hello", vec![], vec![]);
992 assert_eq!(request.url(), "/");
993 }
994
995 #[test]
996 fn urlencode_query_string() {
997 let request = Request::fake_http("GET", "/?p=hello%20world", vec![], vec![]);
998 assert_eq!(request.get_param("p"), Some("hello world".to_owned()));
999 }
1000
1001 #[test]
1002 fn plus_in_query_string() {
1003 let request = Request::fake_http("GET", "/?p=hello+world", vec![], vec![]);
1004 assert_eq!(request.get_param("p"), Some("hello world".to_owned()));
1005 }
1006
1007 #[test]
1008 fn encoded_plus_in_query_string() {
1009 let request = Request::fake_http("GET", "/?p=hello%2Bworld", vec![], vec![]);
1010 assert_eq!(request.get_param("p"), Some("hello+world".to_owned()));
1011 }
1012
1013 #[test]
1014 fn url_encode() {
1015 let request = Request::fake_http("GET", "/hello%20world", vec![], vec![]);
1016 assert_eq!(request.url(), "/hello world");
1017 }
1018
1019 #[test]
1020 fn plus_in_url() {
1021 let request = Request::fake_http("GET", "/hello+world", vec![], vec![]);
1022 assert_eq!(request.url(), "/hello+world");
1023 }
1024
1025 #[test]
1026 fn dnt() {
1027 let request = Request::fake_http("GET", "/", vec![("DNT".to_owned(), "1".to_owned())], vec![]);
1028 assert_eq!(request.do_not_track(), Some(true));
1029
1030 let request = Request::fake_http("GET", "/", vec![("DNT".to_owned(), "0".to_owned())], vec![]);
1031 assert_eq!(request.do_not_track(), Some(false));
1032
1033 let request = Request::fake_http("GET", "/", vec![], vec![]);
1034 assert_eq!(request.do_not_track(), None);
1035
1036 let request = Request::fake_http("GET", "/", vec![("DNT".to_owned(), "malformed".to_owned())], vec![]);
1037 assert_eq!(request.do_not_track(), None);
1038 }
1039}