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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
extern crate url;
pub use hyper::header as header;
use header::{Cookie as CookieHeader, ContentType};
pub use header::CookiePair as Cookie;
pub use hyper::status::StatusCode as Status;
use hyper::{Headers, Method};
use hyper::uri::RequestUri::{AbsolutePath, Star};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::server::Request as HttpRequest;
use std::collections::BTreeMap;
use std::io::{Error, ErrorKind, Result};
use std::result::Result as StdResult;
use std::slice::Iter;
use buffer::Buffer;
use url::{ParseError, Url};
pub struct Request {
inner: HttpRequest,
path: Vec<String>,
query: Option<String>,
fragment: Option<String>,
params: Option<BTreeMap<String, String>>,
body: Option<Buffer>
}
pub fn new(inner: HttpRequest) -> StdResult<Request, ParseError> {
let (path, query, fragment) = match *inner.uri() {
AbsolutePath(ref path) => {
let base = Url::parse("http://localhost").unwrap();
match Url::options().base_url(Some(&base)).parse(path) {
Ok(url) => (url.path_segments().unwrap().map(|s| s.to_string()).collect(),
url.query().map(|s| s.to_string()),
url.fragment().map(|s| s.to_string())),
Err(e) => return Err(e)
}
},
Star => (vec!["*".to_owned()], None, None),
_ => panic!("unsupported request URI")
};
Ok(Request {
inner: inner,
path: path,
query: query,
fragment: fragment,
params: None,
body: None})
}
pub fn set_body(request: Option<&mut Request>, body: Option<Buffer>) {
if let Some(req) = request {
req.body = body;
}
}
impl Request {
pub fn body(&self) -> Result<&[u8]> {
match self.body {
Some(ref buffer) => Ok(buffer.as_ref()),
None => Err(Error::new(ErrorKind::UnexpectedEof, "empty body"))
}
}
pub fn cookies(&self) -> Iter<Cookie> {
self.headers().get::<CookieHeader>().map_or([].iter(),
|&CookieHeader(ref cookies)| cookies.iter()
)
}
pub fn form(&mut self) -> Result<Vec<(String, String)>> {
let body = try!(self.body());
match self.headers().get::<ContentType>() {
Some(&ContentType(Mime(TopLevel::Application, SubLevel::WwwFormUrlEncoded, _))) => {
let parse = url::form_urlencoded::parse(body);
Ok(parse.into_owned().collect())
}
Some(_) => Err(Error::new(ErrorKind::InvalidInput, "invalid Content-Type, expected application/x-www-form-urlencoded")),
None => Err(Error::new(ErrorKind::InvalidInput, "missing Content-Type header"))
}
}
pub fn method(&self) -> &Method {
self.inner.method()
}
#[inline]
pub fn headers(&self) -> &Headers { self.inner.headers() }
pub fn param(&self, key: &str) -> Option<&str> {
self.params.as_ref().map_or(None, |map| map.get(key).map(String::as_str))
}
pub fn path(&self) -> &[String] {
&self.path
}
pub fn query(&self) -> Option<&str> {
self.query.as_ref().map(String::as_str)
}
pub fn fragment(&self) -> Option<&str> {
self.fragment.as_ref().map(String::as_str)
}
}
pub fn set_params(request: &mut Request, params: BTreeMap<String, String>) {
request.params = Some(params);
}