1extern crate iron;
2
3use iron::BeforeMiddleware;
4use iron::headers::ContentLength;
5use iron::prelude::*;
6use iron::status;
7use iron::url;
8
9use std::default::Default;
10use std::error::Error;
11use std::fmt;
12use std::io::Read;
13
14const MAX_BODY_DEFAULT: u64 = 5e6 as u64;
15const MAX_URL_DEFAULT: usize = 256;
16
17#[derive(Debug)]
20pub struct RequestTooLarge;
21
22pub struct RequestLimit {
24 max_body: u64,
26
27 max_url_length: usize,
29}
30
31impl fmt::Display for RequestTooLarge {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 f.write_str(self.description())
34 }
35}
36
37impl Error for RequestTooLarge {
38 fn description(&self) -> &str {
39 "Request too large"
40 }
41}
42
43impl Default for RequestLimit {
44 fn default() -> RequestLimit {
45 RequestLimit {
46 max_body: MAX_BODY_DEFAULT,
47 max_url_length: MAX_URL_DEFAULT,
48 }
49 }
50}
51
52impl RequestLimit {
53 pub fn set_max_body_size(&mut self, max_body: u64) {
55 self.max_body = max_body;
56 }
57
58 pub fn set_max_url_length(&mut self, max_url_length: usize) {
60 self.max_url_length = max_url_length;
61 }
62
63 fn check_payload(&self, total: u64) -> IronResult<()> {
66 if total > self.max_body {
67 Err(IronError::new(RequestTooLarge, status::PayloadTooLarge))
68 } else {
69 Ok(())
70 }
71 }
72
73 fn check_url_length(&self, u: iron::Url) -> bool {
75 let real_url: url::Url = u.into();
76
77 real_url.as_str().len() <= self.max_url_length
78 }
79}
80
81impl BeforeMiddleware for RequestLimit {
82 fn before(&self, req: &mut Request) -> IronResult<()> {
85 if !self.check_url_length(req.url.clone()) {
86 return Err(IronError::new(RequestTooLarge, status::PayloadTooLarge));
87 }
88
89 match req.headers.get::<ContentLength>() {
90 Some(l) => self.check_payload(l.0),
91 None => self.check_payload(req.body.by_ref().bytes().count() as u64),
92 }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::RequestLimit;
99
100 static GOOGLE: &'static str = "https://google.com";
101
102 #[test]
103 fn check_ok_response() {
104 let b = RequestLimit::default();
105 assert!(b.check_payload(5).is_ok());
106 }
107
108 #[test]
109 fn check_err_response() {
110 let mut b = RequestLimit::default();
111 b.set_max_body_size(1);
112 assert!(b.check_payload(2).is_err());
113 }
114
115 #[test]
116 fn test_lengthy_url() {
117 let mut b = RequestLimit::default();
118 b.set_max_url_length(5);
119 assert_eq!(false,
120 b.check_url_length(::iron::Url::parse(GOOGLE).unwrap()));
121 }
122
123 #[test]
124 fn test_valid_url() {
125 let b = RequestLimit::default();
126 assert!(b.check_url_length(::iron::Url::parse(GOOGLE).unwrap()));
127 }
128}