1use std::{fmt, io, slice, str};
2
3use bytes::BytesMut;
4
5use httparse;
6
7pub struct Request {
8 method: Slice,
9 path: Slice,
10 version: u8,
11 headers: Vec<(Slice, Slice)>,
12 data: BytesMut,
13}
14
15type Slice = (usize, usize);
16
17pub struct RequestHeaders<'req> {
18 headers: slice::Iter<'req, (Slice, Slice)>,
19 req: &'req Request,
20}
21
22impl Request {
23 pub fn method(&self) -> &str {
24 str::from_utf8(self.slice(&self.method)).unwrap()
25 }
26
27 pub fn path(&self) -> &str {
28 str::from_utf8(self.slice(&self.path)).unwrap()
29 }
30
31 pub fn version(&self) -> u8 {
32 self.version
33 }
34
35 pub fn headers(&self) -> RequestHeaders {
36 RequestHeaders {
37 headers: self.headers.iter(),
38 req: self,
39 }
40 }
41
42 fn slice(&self, slice: &Slice) -> &[u8] {
43 &self.data[slice.0..slice.1]
44 }
45}
46
47impl fmt::Debug for Request {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 write!(f, "<HTTP Request {} {}>", self.method(), self.path())
50 }
51}
52
53pub fn decode(buf: &mut BytesMut) -> io::Result<Option<Request>> {
54 let (method, path, version, headers, amt) = {
55 let mut headers = [httparse::EMPTY_HEADER; 16];
56 let mut r = httparse::Request::new(&mut headers);
57 let status = try!(r.parse(buf).map_err(|e| {
58 let msg = format!("failed to parse http request: {:?}", e);
59 io::Error::new(io::ErrorKind::Other, msg)
60 }));
61
62 let amt = match status {
63 httparse::Status::Complete(amt) => amt,
64 httparse::Status::Partial => return Ok(None),
65 };
66
67 let toslice = |a: &[u8]| {
68 let start = a.as_ptr() as usize - buf.as_ptr() as usize;
69 assert!(start < buf.len());
70 (start, start + a.len())
71 };
72
73 (
74 toslice(r.method.unwrap().as_bytes()),
75 toslice(r.path.unwrap().as_bytes()),
76 r.version.unwrap(),
77 r.headers
78 .iter()
79 .map(|h| (toslice(h.name.as_bytes()), toslice(h.value)))
80 .collect(),
81 amt,
82 )
83 };
84
85 Ok(Request {
86 method: method,
87 path: path,
88 version: version,
89 headers: headers,
90 data: buf.split_to(amt),
91 }
92 .into())
93}
94
95impl<'req> Iterator for RequestHeaders<'req> {
96 type Item = (&'req str, &'req [u8]);
97
98 fn next(&mut self) -> Option<(&'req str, &'req [u8])> {
99 self.headers.next().map(|&(ref a, ref b)| {
100 let a = self.req.slice(a);
101 let b = self.req.slice(b);
102 (str::from_utf8(a).unwrap(), b)
103 })
104 }
105}