1#![cfg_attr(test, deny(warnings))]
2
3extern crate semver;
4extern crate conduit;
5
6use std::iter;
7use std::io::prelude::*;
8use std::net::SocketAddr;
9use std::collections::hash_map::{HashMap, Iter};
10
11use conduit::{Method, Scheme, Host, Extensions, Headers, Request};
12
13pub trait RequestDelegator {
14 fn request(&self) -> &Request;
15 fn mut_request(&mut self) -> &mut Request;
16
17 fn http_version(&self) -> semver::Version {
18 self.request().http_version()
19 }
20
21 fn conduit_version(&self) -> semver::Version {
22 self.request().conduit_version()
23 }
24
25 fn method(&self) -> Method {
26 self.request().method()
27 }
28
29 fn scheme(&self) -> Scheme {
30 self.request().scheme()
31 }
32
33 fn host(&self) -> Host {
34 self.request().host()
35 }
36
37 fn virtual_root(&self) -> Option<&str> {
38 self.request().virtual_root()
39 }
40
41 fn path(&self) -> &str {
42 self.request().path()
43 }
44
45 fn query_string(&self) -> Option<&str> {
46 self.request().query_string()
47 }
48
49 fn remote_addr(&self) -> SocketAddr {
50 self.request().remote_addr()
51 }
52
53 fn content_length(&self) -> Option<u64> {
54 self.request().content_length()
55 }
56
57 fn headers(&self) -> &Headers {
58 self.request().headers()
59 }
60
61 fn body(&mut self) -> &mut Read {
62 self.mut_request().body()
63 }
64
65 fn extensions(&self) -> &Extensions {
66 self.request().extensions()
67 }
68
69 fn mut_extensions(&mut self) -> &mut Extensions {
70 self.mut_request().mut_extensions()
71 }
72}
73
74impl<'a> Request for &'a mut (RequestDelegator + 'a) {
75 fn http_version(&self) -> semver::Version {
76 (**self).http_version()
77 }
78
79 fn conduit_version(&self) -> semver::Version {
80 (**self).conduit_version()
81 }
82
83 fn method(&self) -> Method {
84 (**self).method()
85 }
86
87 fn scheme(&self) -> Scheme {
88 (**self).scheme()
89 }
90
91 fn host(&self) -> Host {
92 (**self).host()
93 }
94
95 fn virtual_root(&self) -> Option<&str> {
96 (**self).virtual_root()
97 }
98
99 fn path(&self) -> &str {
100 (**self).path()
101 }
102
103 fn query_string(&self) -> Option<&str> {
104 (**self).query_string()
105 }
106
107 fn remote_addr(&self) -> SocketAddr {
108 (**self).remote_addr()
109 }
110
111 fn content_length(&self) -> Option<u64> {
112 (**self).content_length()
113 }
114
115 fn headers(&self) -> &Headers {
116 (**self).headers()
117 }
118
119 fn body(&mut self) -> &mut Read {
120 (**self).body()
121 }
122
123 fn extensions(&self) -> &Extensions {
124 (**self).extensions()
125 }
126
127 fn mut_extensions(&mut self) -> &mut Extensions {
128 (**self).mut_extensions()
129 }
130}
131
132type RawHeaders = HashMap<String, Vec<String>>;
133pub type InHeader<'a> = (&'a String, &'a Vec<String>);
134pub type OutHeader<'a> = (String, &'a Vec<String>);
135
136#[derive(PartialEq, Clone, Debug)]
137pub struct HeaderMap(HashMap<String, Vec<String>>);
138
139impl HeaderMap {
140 pub fn normalize(headers: HashMap<String, Vec<String>>) -> HeaderMap {
141 let headers = headers.into_iter().map(|(k,v)| (to_lower(&k), v)).collect();
142 HeaderMap(headers)
143 }
144
145 pub fn iter(&self) -> iter::Map<Iter<String, Vec<String>>,
146 for<'a> fn(InHeader<'a>) -> OutHeader<'a>> {
147 fn foo<'a>((k, v): InHeader<'a>) -> OutHeader<'a> { (to_lower(k), v) }
148 let f: for<'a> fn(InHeader<'a>) -> OutHeader<'a> = foo;
149 self.as_ref().iter().map(f)
150 }
151
152 fn as_ref(&self) -> &HashMap<String, Vec<String>> {
153 match *self {
154 HeaderMap(ref map) => map
155 }
156 }
157
158 fn as_mut(&mut self) -> &mut HashMap<String, Vec<String>> {
159 match *self {
160 HeaderMap(ref mut map) => map
161 }
162 }
163
164 pub fn len(&self) -> usize {
165 self.as_ref().len()
166 }
167 pub fn clear(&mut self) {
168 self.as_mut().clear()
169 }
170 pub fn find(&self, key: &str) -> Option<&Vec<String>> {
171 self.as_ref().get(&to_lower(key))
172 }
173 pub fn insert(&mut self, k: &str, v: Vec<String>) -> Option<Vec<String>> {
174 self.as_mut().insert(to_lower(&k), v)
175 }
176 pub fn remove(&mut self, k: &str) -> Option<Vec<String>> {
177 self.as_mut().remove(&to_lower(k))
178 }
179
180 pub fn find_mut(&mut self, k: &str) -> Option<&mut Vec<String>> {
181 self.as_mut().get_mut(&to_lower(k))
182 }
183}
184
185fn to_lower(string: &str) -> String {
186 string.chars().flat_map(|c| c.to_lowercase()).collect()
187}
188
189#[cfg(test)]
190mod tests {
191 extern crate conduit_test as test;
192
193 use {RequestDelegator, HeaderMap};
194
195 use std::collections::HashMap;
196 use conduit::{Request, Method};
197
198 struct OverrideRequest<'a> {
199 request: &'a mut (Request + 'a),
200 }
201
202 impl<'a> RequestDelegator for OverrideRequest<'a> {
203 fn request(&self) -> &Request {
204 let req: &Request = self.request; req
205 }
206
207 fn mut_request(&mut self) -> &mut Request {
208 let req: &mut Request = self.request; req
209 }
210
211 fn method(&self) -> Method {
212 Method::Get
213 }
214 }
215
216 #[test]
217 fn test_delegate() {
218 let request = &mut test::MockRequest::new(Method::Head, "/hello");
219 let new = OverrideRequest { request: request };
220
221 assert_eq!(new.method(), Method::Get);
222 assert_eq!(new.path(), "/hello");
223 }
224
225 #[test]
226 fn test_header_map() {
227 let mut map = HeaderMap(HashMap::new());
228 map.insert("Content-Type", vec!("text/html".to_string()));
229 map.insert("location", vec!("http://example.com".to_string()));
230
231 assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())));
232 assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())));
233 assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())));
234 assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())));
235 }
236
237 #[test]
238 fn test_header_map_with_static_inserts() {
239 let mut map = HeaderMap(HashMap::new());
240 map.insert("Content-Type", vec!("text/html".to_string()));
241 map.insert("location", vec!("http://example.com".to_string()));
242
243 assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())));
244 assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())));
245 assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())));
246 assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())));
247 }
248
249 #[test]
250 fn test_normalize() {
251 let mut map = HashMap::new();
252 map.insert("Content-Type".to_string(), vec!("text/html".to_string()));
253
254 let headers = HeaderMap::normalize(map);
255 assert_eq!(headers.find(&"Content-Type".to_string()), Some(&vec!("text/html".to_string())));
256 assert_eq!(headers.find(&"Content-Type"), Some(&vec!("text/html".to_string())));
257 assert_eq!(headers.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())));
258 assert_eq!(headers.find(&"content-type"), Some(&vec!("text/html".to_string())));
259 }
260
261 #[test]
262 fn test_iterate() {
263 let mut headers = HeaderMap(HashMap::new());
264 headers.insert("Content-Type", vec!("text/html".to_string()));
265 headers.insert("location", vec!("http://example.com".to_string()));
266
267 assert!(headers.iter().any(|t| {
268 t.0 == "content-type" &&
269 &t.1[..] == ["text/html".to_string()]
270 }));
271 assert!(headers.iter().any(|t| {
272 t.0 == "location" &&
273 &t.1[..] == ["http://example.com".to_string()]
274 }));
275 assert!(headers.iter().count() == 2);
276 }
277}