1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
extern crate iron;
extern crate url;

use std::io::Read;
use std::sync::Arc;
use iron::prelude::*;
use std::collections::HashMap;
use std::collections::hash_map::Entry::*;
use url::form_urlencoded;
use std::str::FromStr;

pub trait RequestExt {
    fn params<'c, 'd>(&'c self, name: &'d str) -> Option<&'c Vec<String>>;
    fn param<'c, 'd, F: FromStr>(&'c self, name: &'d str) -> Option<F>;
    fn body<'c, 'd>(&'c self) -> Option<&'c String>;
}

impl<'a, 'b> RequestExt for Request<'a, 'b> {
    fn params<'c, 'd>(&'c self, name: &'d str) -> Option<&'c Vec<String>> {
        if let Some(map) = self.extensions.get::<Params>() {
            return map.get(name);
        }
        None
    }
    fn param<'c, 'd, F: FromStr>(&'c self, name: &'d str) -> Option<F> {
        match self.params(name) {
            Some(vec) if vec.len() > 0 => vec[0].clone().parse().ok(),
            _ => None,
        }
    }
    fn body<'c, 'd>(&'c self) -> Option<&'c String> {
        use std::borrow::Borrow;
        self.extensions.get::<Body>().map(|v| v.borrow())
    }
}

pub struct Params;

impl iron::typemap::Key for Params {
    type Value = Arc<HashMap<String, Vec<String>>>;
}

pub struct Body;

impl iron::typemap::Key for Body {
    type Value = Arc<String>;
}


impl iron::BeforeMiddleware for Params {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        let (body, map) = combine(req);
        req.extensions.insert::<Params>(Arc::new(map));
        req.extensions.insert::<Body>(Arc::new(body));
        Ok(())
    }
}

fn combine(req: &mut Request) -> (String, HashMap<String, Vec<String>>) {
    let mut map = HashMap::<String, Vec<String>>::new();
    let url = req.url.clone();
    let query = url.query();
    if let Some(query) = query {
        combine_duplicates(form_urlencoded::parse(&String::from(query).into_bytes()), &mut map);
    }

    let mut reader = &mut req.body;
    let mut buf = vec![0;300];
    let mut vec: Vec<u8> = Vec::new();
    while let Ok(n) = reader.read(&mut buf) {
        if n <= 0 {
            break;
        }
        vec.extend_from_slice(&buf[0..n]);
    }
    let body = String::from_utf8(vec.clone()).unwrap_or("".into());
    combine_duplicates(form_urlencoded::parse(&vec), &mut map);
    (body, map)
}

fn combine_duplicates(q: url::form_urlencoded::Parse, map: &mut HashMap<String, Vec<String>>) {
    for (k, v) in q.into_iter() {
        let (k, v) = (k.into_owned(), v.into_owned());
        match map.entry(k) {
            Occupied(entry) => {
                entry.into_mut().push(v);
            }
            Vacant(entry) => {
                entry.insert(vec![v]);
            }
        };
    }
}