iron_test/
request.rs

1/// Contains convenience methods for making requests to Iron Handlers.
2use hyper;
3use hyper::buffer::BufReader;
4use hyper::net::NetworkStream;
5
6use iron;
7use iron::prelude::*;
8use iron::{Handler, headers, Headers, method, Url};
9
10use std::io::Cursor;
11
12use super::mock_stream::MockStream;
13
14/// Convenience method for making GET requests to Iron Handlers.
15pub fn get<H: Handler>(path: &str, headers: Headers, handler: &H) -> IronResult<Response> {
16    request(method::Get, path, "", headers, handler)
17}
18
19/// Convenience method for making POST requests with a body to Iron Handlers.
20pub fn post<H: Handler>(path: &str, headers: Headers, body: &str, handler: &H) -> IronResult<Response> {
21    request(method::Post, path, body, headers, handler)
22}
23
24/// Convenience method for making PATCH requests with a body to Iron Handlers.
25pub fn patch<H: Handler>(path: &str, headers: Headers, body: &str, handler: &H) -> IronResult<Response> {
26    request(method::Patch, path, body, headers, handler)
27}
28
29/// Convenience method for making PUT requests with a body to Iron Handlers.
30pub fn put<H: Handler>(path: &str, headers: Headers, body: &str, handler: &H) -> IronResult<Response> {
31    request(method::Put, path, body, headers, handler)
32}
33
34/// Convenience method for making DELETE requests to Iron Handlers.
35pub fn delete<H: Handler>(path: &str, headers: Headers, handler: &H) -> IronResult<Response> {
36    request(method::Delete, path, "", headers, handler)
37}
38
39/// Convenience method for making OPTIONS requests to Iron Handlers.
40pub fn options<H: Handler>(path: &str, headers: Headers, handler: &H) -> IronResult<Response> {
41    request(method::Options, path, "", headers, handler)
42}
43
44/// Convenience method for making HEAD requests to Iron Handlers.
45pub fn head<H: Handler>(path: &str, headers: Headers, handler: &H) -> IronResult<Response> {
46    request(method::Head, path, "", headers, handler)
47}
48
49/// Constructs an Iron::Request from the given parts and passes it to the
50/// `handle` method on the given Handler.
51pub fn request<H: Handler>(method: method::Method,
52                           path: &str,
53                           body: &str,
54                           headers: Headers,
55                           handler: &H) -> IronResult<Response> {
56    let url = Url::parse(path).unwrap();
57    // From iron 0.5.x, iron::Request contains private field. So, it is not good to
58    // create iron::Request directly. Make http request and parse it with hyper,
59    // and make iron::Request from hyper::client::Request.
60    let mut buffer = String::new();
61    buffer.push_str(&format!("{} {} HTTP/1.1\r\n", &method, url));
62    buffer.push_str(&format!("Content-Length: {}\r\n", body.len() as u64));
63    for header in headers.iter() {
64        buffer.push_str(&format!("{}: {}\r\n", header.name(), header.value_string()));
65    }
66    if !headers.has::<headers::UserAgent>() {
67        buffer.push_str(&format!("User-Agent: iron-test\r\n"));
68    }
69    buffer.push_str("\r\n");
70    buffer.push_str(body);
71
72    let addr = "127.0.0.1:3000".parse().unwrap();
73    let protocol = match url.scheme() {
74        "http" => iron::Protocol::http(),
75        "https" => iron::Protocol::https(),
76        _ => panic!("unknown protocol {}", url.scheme()),
77    };
78
79    let mut stream = MockStream::new(Cursor::new(buffer.as_bytes().to_vec()));
80    let mut buf_reader = BufReader::new(&mut stream as &mut NetworkStream);
81    let http_request = hyper::server::Request::new(&mut buf_reader, addr).unwrap();
82    let mut req = Request::from_http(http_request, addr, &protocol).unwrap();
83
84    handler.handle(&mut req)
85}
86
87#[cfg(test)]
88mod test {
89    extern crate router;
90    extern crate urlencoded;
91
92    use iron::headers::Headers;
93    use iron::mime::Mime;
94    use iron::prelude::*;
95    use iron::{Handler, headers, status};
96
97    use response::{extract_body_to_bytes, extract_body_to_string};
98
99    use self::urlencoded::UrlEncodedBody;
100
101    use super::*;
102
103    struct HelloWorldHandler;
104
105    impl Handler for HelloWorldHandler {
106        fn handle(&self, _: &mut Request) -> IronResult<Response> {
107            Ok(Response::with((status::Ok, "Hello, world!")))
108        }
109    }
110
111    struct RouterHandler;
112
113    impl Handler for RouterHandler {
114        fn handle(&self, req: &mut Request) -> IronResult<Response> {
115            let params = req.extensions
116                .get::<router::Router>()
117                .expect("Expected to get a Router from the request extensions.");
118            let id = params.find("id").unwrap();
119
120            Ok(Response::with((status::Ok, id)))
121        }
122    }
123
124    struct PostHandler;
125
126    impl Handler for PostHandler {
127        fn handle(&self, req: &mut Request) -> IronResult<Response> {
128            let body = req.get_ref::<UrlEncodedBody>()
129                .expect("Expected to extract a UrlEncodedBody from the request");
130            let first_name = body.get("first_name").unwrap()[0].to_owned();
131            let last_name = body.get("last_name").unwrap()[0].to_owned();
132
133            Ok(Response::with((status::Ok, first_name + " " + &last_name)))
134        }
135    }
136
137    struct UpdateHandler;
138
139    impl Handler for UpdateHandler {
140        fn handle(&self, req: &mut Request) -> IronResult<Response> {
141            let id = {
142                let params = req.extensions
143                    .get::<router::Router>()
144                    .expect("Expected to get a Router from request extensions.");
145                params.find("id").unwrap().parse::<String>().unwrap()
146            };
147
148            let body = req.get_ref::<UrlEncodedBody>()
149                .expect("Expected to extract a UrlEncodedBody from the request");
150            let first_name = body.get("first_name").unwrap()[0].to_owned();
151            let last_name = body.get("last_name").unwrap()[0].to_owned();
152
153            Ok(Response::with((status::Ok, [first_name, last_name, id].join(" "))))
154        }
155    }
156
157    struct OptionsHandler;
158
159    impl Handler for OptionsHandler {
160        fn handle(&self, _: &mut Request) -> IronResult<Response> {
161            Ok(Response::with((status::Ok, "ALLOW: GET,POST")))
162        }
163    }
164
165    struct HeadHandler;
166
167    impl Handler for HeadHandler {
168        fn handle(&self, _: &mut Request) -> IronResult<Response> {
169            Ok(Response::with(status::Ok))
170        }
171    }
172
173    struct UserAgentHandler;
174
175    impl Handler for UserAgentHandler {
176        fn handle(&self, req: &mut Request) -> IronResult<Response> {
177            let user_agent = req.headers.get::<headers::UserAgent>().unwrap();
178            Ok(Response::with((status::Ok, user_agent.to_string())))
179        }
180    }
181
182    #[test]
183    fn test_get() {
184        let response = get("http://localhost:3000", Headers::new(), &HelloWorldHandler);
185        let result = extract_body_to_bytes(response.unwrap());
186
187        assert_eq!(result, b"Hello, world!");
188    }
189
190    #[test]
191    fn test_post() {
192        let mut headers = Headers::new();
193        let mime: Mime = "application/x-www-form-urlencoded".parse().unwrap();
194        headers.set(headers::ContentType(mime));
195        let response = post("http://localhost:3000/users",
196                            headers,
197                            "first_name=Example&last_name=User",
198                            &PostHandler);
199        let result = extract_body_to_bytes(response.unwrap());
200
201        assert_eq!(result, b"Example User");
202    }
203
204    #[test]
205    fn test_patch() {
206        let mut router = router::Router::new();
207        router.patch("/users/:id", UpdateHandler, "update");
208
209        let mut headers = Headers::new();
210        let mime: Mime = "application/x-www-form-urlencoded".parse().unwrap();
211        headers.set(headers::ContentType(mime));
212        let response = patch("http://localhost:3000/users/1",
213                             headers,
214                             "first_name=Example&last_name=User",
215                             &router);
216        let result = extract_body_to_bytes(response.unwrap());
217
218        assert_eq!(result, b"Example User 1");
219    }
220
221    #[test]
222    fn test_put() {
223        let mut router = router::Router::new();
224        router.put("/users/:id", UpdateHandler, "update");
225
226        let mut headers = Headers::new();
227        let mime: Mime = "application/x-www-form-urlencoded".parse().unwrap();
228        headers.set(headers::ContentType(mime));
229        let response = put("http://localhost:3000/users/2",
230                           headers,
231                           "first_name=Example&last_name=User",
232                           &router);
233        let result = extract_body_to_bytes(response.unwrap());
234
235        assert_eq!(result, b"Example User 2");
236    }
237
238    #[test]
239    fn test_delete() {
240        let mut router = router::Router::new();
241        router.delete("/:id", RouterHandler, "update");
242
243        let response = delete("http://localhost:3000/1", Headers::new(), &router);
244        let result = extract_body_to_bytes(response.unwrap());
245
246        assert_eq!(result, b"1");
247    }
248
249
250    #[test]
251    fn test_options() {
252        let response = options("http://localhost:3000/users/options", Headers::new(), &OptionsHandler);
253        let result = extract_body_to_bytes(response.unwrap());
254
255        assert_eq!(result, b"ALLOW: GET,POST");
256    }
257
258    #[test]
259    fn test_head() {
260        let response = head("http://localhost:3000/users", Headers::new(), &HeadHandler);
261        let result = extract_body_to_bytes(response.unwrap());
262
263        assert_eq!(result, b"");
264    }
265
266    #[test]
267    fn test_user_agent_not_provided() {
268        let headers = Headers::new();
269        let response = get("http://localhost:3000/", headers, &UserAgentHandler);
270        let result = extract_body_to_string(response.unwrap());
271
272        assert_eq!(result, "iron-test");
273    }
274
275    #[test]
276    fn test_user_agent_provided() {
277        let mut headers = Headers::new();
278        headers.set(headers::UserAgent("CustomAgent/1.0".to_owned()));
279        let response = get("http://localhost:3000/", headers, &UserAgentHandler);
280        let result = extract_body_to_string(response.unwrap());
281
282        assert_eq!(result, "CustomAgent/1.0");
283    }
284
285    #[test]
286    fn test_percent_decoded_url() {
287        let response = head("http://localhost:3000/some path with spaces", Headers::new(), &HeadHandler);
288        let result = extract_body_to_bytes(response.unwrap());
289
290        assert_eq!(result, b"");
291    }
292}