fanta/
request.rs

1use std::{io, slice, str, fmt};
2use std::collections::HashMap;
3use serde;
4use bytes::BytesMut;
5use serde_json;
6
7use httparse;
8
9pub struct Request {
10    body: Slice,
11    method: Slice,
12    path: Slice,
13    version: u8,
14    // TODO: use a small vec to avoid this unconditional allocation
15    headers: Vec<(Slice, Slice)>,
16    data: BytesMut,
17    params: HashMap<String, String>
18}
19
20type Slice = (usize, usize);
21
22pub struct RequestHeaders<'req> {
23    headers: slice::Iter<'req, (Slice, Slice)>,
24    req: &'req Request,
25}
26
27impl Request {
28    pub fn raw_body(&self) -> &str {
29        str::from_utf8(self.slice(&self.body)).unwrap()
30    }
31
32    pub fn method(&self) -> &str {
33        str::from_utf8(self.slice(&self.method)).unwrap()
34    }
35
36    pub fn path(&self) -> &str {
37        str::from_utf8(self.slice(&self.path)).unwrap()
38    }
39
40    pub fn version(&self) -> u8 {
41        self.version
42    }
43
44    pub fn headers(&self) -> RequestHeaders {
45        RequestHeaders {
46            headers: self.headers.iter(),
47            req: self,
48        }
49    }
50
51    pub fn body_as<'a, T>(&self, body: &'a str) -> serde_json::Result<T>
52        where T: serde::de::Deserialize<'a>
53    {
54        serde_json::from_str(body)
55    }
56
57    fn slice(&self, slice: &Slice) -> &[u8] {
58        &self.data[slice.0..slice.1]
59    }
60
61    pub fn params(&self) -> &HashMap<String, String> {
62        &self.params
63    }
64
65    pub fn set_params(&mut self, params: HashMap<String, String>) {
66        self.params = params;
67    }
68}
69
70impl fmt::Debug for Request {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        write!(f, "<HTTP Request {} {}>", self.method(), self.path())
73    }
74}
75
76pub fn decode(buf: &mut BytesMut) -> io::Result<Option<Request>> {
77    // TODO: we should grow this headers array if parsing fails and asks
78    //       for more headers
79    let len = buf.len();
80    let (method, path, version, headers, body) = {
81        let mut headers = [httparse::EMPTY_HEADER; 16];
82        let mut r = httparse::Request::new(&mut headers);
83        let status = try!(r.parse(buf).map_err(|e| {
84            let msg = format!("failed to parse http request: {:?}", e);
85            io::Error::new(io::ErrorKind::Other, msg)
86        }));
87
88        let amt = match status {
89            httparse::Status::Complete(amt) => amt,
90            httparse::Status::Partial => {
91                return Ok(None)
92            },
93        };
94
95        let toslice = |a: &[u8]| {
96            let start = a.as_ptr() as usize - buf.as_ptr() as usize;
97            assert!(start < buf.len());
98            (start, start + a.len())
99        };
100
101        (toslice(r.method.unwrap().as_bytes()),
102         toslice(r.path.unwrap().as_bytes()),
103         r.version.unwrap(),
104         r.headers
105          .iter()
106          .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
107          .collect(),
108         (amt, buf.len()))
109    };
110
111    Ok(Request {
112        method: method,
113        path: path,
114        version: version,
115        headers: headers,
116        data: buf.split_to(len),
117        body: body,
118        params: HashMap::new()
119    }.into())
120}
121
122impl<'req> Iterator for RequestHeaders<'req> {
123    type Item = (&'req str, &'req [u8]);
124
125    fn next(&mut self) -> Option<(&'req str, &'req [u8])> {
126        self.headers.next().map(|&(ref a, ref b)| {
127            let a = self.req.slice(a);
128            let b = self.req.slice(b);
129            (str::from_utf8(a).unwrap(), b)
130        })
131    }
132}