1 | use std::str::FromStr; |
2 | |
3 | use super::{ErrorKind, InvalidUri, Port, Uri, URI_CHARS}; |
4 | |
5 | #[test] |
6 | fn test_char_table() { |
7 | for (i, &v) in URI_CHARS.iter().enumerate() { |
8 | if v != 0 { |
9 | assert_eq!(i, v as usize); |
10 | } |
11 | } |
12 | } |
13 | |
14 | macro_rules! part { |
15 | ($s:expr) => { |
16 | Some(&$s.parse().unwrap()) |
17 | }; |
18 | } |
19 | |
20 | macro_rules! test_parse { |
21 | ( |
22 | $test_name:ident, |
23 | $str:expr, |
24 | $alt:expr, |
25 | $($method:ident = $value:expr,)* |
26 | ) => ( |
27 | #[test] |
28 | fn $test_name() { |
29 | let orig_str = $str; |
30 | let uri = match Uri::from_str(orig_str) { |
31 | Ok(uri) => uri, |
32 | Err(err) => { |
33 | panic!("parse error {:?} from {:?}" , err, orig_str); |
34 | }, |
35 | }; |
36 | $( |
37 | assert_eq!(uri.$method(), $value, "{}: uri = {:?}" , stringify!($method), uri); |
38 | )+ |
39 | assert_eq!(uri, orig_str, "partial eq to original str" ); |
40 | assert_eq!(uri, uri.clone(), "clones are equal" ); |
41 | |
42 | let new_str = uri.to_string(); |
43 | let new_uri = Uri::from_str(&new_str).expect("to_string output parses again as a Uri" ); |
44 | assert_eq!(new_uri, orig_str, "round trip still equals original str" ); |
45 | |
46 | const ALT: &'static [&'static str] = &$alt; |
47 | |
48 | for &alt in ALT.iter() { |
49 | let other: Uri = alt.parse().unwrap(); |
50 | assert_eq!(uri, *alt); |
51 | assert_eq!(uri, other); |
52 | } |
53 | } |
54 | ); |
55 | } |
56 | |
57 | test_parse! { |
58 | test_uri_parse_path_and_query, |
59 | "/some/path/here?and=then&hello#and-bye" , |
60 | [], |
61 | |
62 | scheme = None, |
63 | authority = None, |
64 | path = "/some/path/here" , |
65 | query = Some("and=then&hello" ), |
66 | host = None, |
67 | } |
68 | |
69 | test_parse! { |
70 | test_uri_parse_absolute_form, |
71 | "http://127.0.0.1:61761/chunks" , |
72 | [], |
73 | |
74 | scheme = part!("http" ), |
75 | authority = part!("127.0.0.1:61761" ), |
76 | path = "/chunks" , |
77 | query = None, |
78 | host = Some("127.0.0.1" ), |
79 | port = Port::from_str("61761" ).ok(), |
80 | } |
81 | |
82 | test_parse! { |
83 | test_uri_parse_absolute_form_without_path, |
84 | "https://127.0.0.1:61761" , |
85 | ["https://127.0.0.1:61761/" ], |
86 | |
87 | scheme = part!("https" ), |
88 | authority = part!("127.0.0.1:61761" ), |
89 | path = "/" , |
90 | query = None, |
91 | host = Some("127.0.0.1" ), |
92 | port = Port::from_str("61761" ).ok(), |
93 | } |
94 | |
95 | test_parse! { |
96 | test_uri_parse_asterisk_form, |
97 | "*" , |
98 | [], |
99 | |
100 | scheme = None, |
101 | authority = None, |
102 | path = "*" , |
103 | query = None, |
104 | host = None, |
105 | } |
106 | |
107 | test_parse! { |
108 | test_uri_parse_authority_no_port, |
109 | "localhost" , |
110 | ["LOCALHOST" , "LocaLHOSt" ], |
111 | |
112 | scheme = None, |
113 | authority = part!("localhost" ), |
114 | path = "" , |
115 | query = None, |
116 | port = None, |
117 | host = Some("localhost" ), |
118 | } |
119 | |
120 | test_parse! { |
121 | test_uri_authority_only_one_character_issue_197, |
122 | "S" , |
123 | [], |
124 | |
125 | scheme = None, |
126 | authority = part!("S" ), |
127 | path = "" , |
128 | query = None, |
129 | port = None, |
130 | host = Some("S" ), |
131 | } |
132 | |
133 | test_parse! { |
134 | test_uri_parse_authority_form, |
135 | "localhost:3000" , |
136 | ["localhosT:3000" ], |
137 | |
138 | scheme = None, |
139 | authority = part!("localhost:3000" ), |
140 | path = "" , |
141 | query = None, |
142 | host = Some("localhost" ), |
143 | port = Port::from_str("3000" ).ok(), |
144 | } |
145 | |
146 | test_parse! { |
147 | test_uri_parse_absolute_with_default_port_http, |
148 | "http://127.0.0.1:80" , |
149 | ["http://127.0.0.1:80/" ], |
150 | |
151 | scheme = part!("http" ), |
152 | authority = part!("127.0.0.1:80" ), |
153 | host = Some("127.0.0.1" ), |
154 | path = "/" , |
155 | query = None, |
156 | port = Port::from_str("80" ).ok(), |
157 | } |
158 | |
159 | test_parse! { |
160 | test_uri_parse_absolute_with_default_port_https, |
161 | "https://127.0.0.1:443" , |
162 | ["https://127.0.0.1:443/" ], |
163 | |
164 | scheme = part!("https" ), |
165 | authority = part!("127.0.0.1:443" ), |
166 | host = Some("127.0.0.1" ), |
167 | path = "/" , |
168 | query = None, |
169 | port = Port::from_str("443" ).ok(), |
170 | } |
171 | |
172 | test_parse! { |
173 | test_uri_parse_fragment_questionmark, |
174 | "http://127.0.0.1/#?" , |
175 | [], |
176 | |
177 | scheme = part!("http" ), |
178 | authority = part!("127.0.0.1" ), |
179 | host = Some("127.0.0.1" ), |
180 | path = "/" , |
181 | query = None, |
182 | port = None, |
183 | } |
184 | |
185 | test_parse! { |
186 | test_uri_parse_path_with_terminating_questionmark, |
187 | "http://127.0.0.1/path?" , |
188 | [], |
189 | |
190 | scheme = part!("http" ), |
191 | authority = part!("127.0.0.1" ), |
192 | path = "/path" , |
193 | query = Some("" ), |
194 | port = None, |
195 | } |
196 | |
197 | test_parse! { |
198 | test_uri_parse_absolute_form_with_empty_path_and_nonempty_query, |
199 | "http://127.0.0.1?foo=bar" , |
200 | [], |
201 | |
202 | scheme = part!("http" ), |
203 | authority = part!("127.0.0.1" ), |
204 | path = "/" , |
205 | query = Some("foo=bar" ), |
206 | port = None, |
207 | } |
208 | |
209 | test_parse! { |
210 | test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash, |
211 | "http://127.0.0.1#foo/bar" , |
212 | [], |
213 | |
214 | scheme = part!("http" ), |
215 | authority = part!("127.0.0.1" ), |
216 | path = "/" , |
217 | query = None, |
218 | port = None, |
219 | } |
220 | |
221 | test_parse! { |
222 | test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark, |
223 | "http://127.0.0.1#foo?bar" , |
224 | [], |
225 | |
226 | scheme = part!("http" ), |
227 | authority = part!("127.0.0.1" ), |
228 | path = "/" , |
229 | query = None, |
230 | port = None, |
231 | } |
232 | |
233 | test_parse! { |
234 | test_uri_parse_long_host_with_no_scheme, |
235 | "thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost" , |
236 | [], |
237 | |
238 | scheme = None, |
239 | authority = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost" ), |
240 | path = "" , |
241 | query = None, |
242 | port = None, |
243 | } |
244 | |
245 | test_parse! { |
246 | test_uri_parse_long_host_with_port_and_no_scheme, |
247 | "thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234" , |
248 | [], |
249 | |
250 | scheme = None, |
251 | authority = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234" ), |
252 | path = "" , |
253 | query = None, |
254 | port = Port::from_str("1234" ).ok(), |
255 | } |
256 | |
257 | test_parse! { |
258 | test_userinfo1, |
259 | "http://a:b@127.0.0.1:1234/" , |
260 | [], |
261 | |
262 | scheme = part!("http" ), |
263 | authority = part!("a:b@127.0.0.1:1234" ), |
264 | host = Some("127.0.0.1" ), |
265 | path = "/" , |
266 | query = None, |
267 | port = Port::from_str("1234" ).ok(), |
268 | } |
269 | |
270 | test_parse! { |
271 | test_userinfo2, |
272 | "http://a:b@127.0.0.1/" , |
273 | [], |
274 | |
275 | scheme = part!("http" ), |
276 | authority = part!("a:b@127.0.0.1" ), |
277 | host = Some("127.0.0.1" ), |
278 | path = "/" , |
279 | query = None, |
280 | port = None, |
281 | } |
282 | |
283 | test_parse! { |
284 | test_userinfo3, |
285 | "http://a@127.0.0.1/" , |
286 | [], |
287 | |
288 | scheme = part!("http" ), |
289 | authority = part!("a@127.0.0.1" ), |
290 | host = Some("127.0.0.1" ), |
291 | path = "/" , |
292 | query = None, |
293 | port = None, |
294 | } |
295 | |
296 | test_parse! { |
297 | test_userinfo_with_port, |
298 | "user@localhost:3000" , |
299 | [], |
300 | |
301 | scheme = None, |
302 | authority = part!("user@localhost:3000" ), |
303 | path = "" , |
304 | query = None, |
305 | host = Some("localhost" ), |
306 | port = Port::from_str("3000" ).ok(), |
307 | } |
308 | |
309 | test_parse! { |
310 | test_userinfo_pass_with_port, |
311 | "user:pass@localhost:3000" , |
312 | [], |
313 | |
314 | scheme = None, |
315 | authority = part!("user:pass@localhost:3000" ), |
316 | path = "" , |
317 | query = None, |
318 | host = Some("localhost" ), |
319 | port = Port::from_str("3000" ).ok(), |
320 | } |
321 | |
322 | test_parse! { |
323 | test_ipv6, |
324 | "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/" , |
325 | [], |
326 | |
327 | scheme = part!("http" ), |
328 | authority = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]" ), |
329 | host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]" ), |
330 | path = "/" , |
331 | query = None, |
332 | port = None, |
333 | } |
334 | |
335 | test_parse! { |
336 | test_ipv6_shorthand, |
337 | "http://[::1]/" , |
338 | [], |
339 | |
340 | scheme = part!("http" ), |
341 | authority = part!("[::1]" ), |
342 | host = Some("[::1]" ), |
343 | path = "/" , |
344 | query = None, |
345 | port = None, |
346 | } |
347 | |
348 | test_parse! { |
349 | test_ipv6_shorthand2, |
350 | "http://[::]/" , |
351 | [], |
352 | |
353 | scheme = part!("http" ), |
354 | authority = part!("[::]" ), |
355 | host = Some("[::]" ), |
356 | path = "/" , |
357 | query = None, |
358 | port = None, |
359 | } |
360 | |
361 | test_parse! { |
362 | test_ipv6_shorthand3, |
363 | "http://[2001:db8::2:1]/" , |
364 | [], |
365 | |
366 | scheme = part!("http" ), |
367 | authority = part!("[2001:db8::2:1]" ), |
368 | host = Some("[2001:db8::2:1]" ), |
369 | path = "/" , |
370 | query = None, |
371 | port = None, |
372 | } |
373 | |
374 | test_parse! { |
375 | test_ipv6_with_port, |
376 | "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008/" , |
377 | [], |
378 | |
379 | scheme = part!("http" ), |
380 | authority = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008" ), |
381 | host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]" ), |
382 | path = "/" , |
383 | query = None, |
384 | port = Port::from_str("8008" ).ok(), |
385 | } |
386 | |
387 | test_parse! { |
388 | test_percentage_encoded_path, |
389 | "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478" , |
390 | [], |
391 | |
392 | scheme = None, |
393 | authority = None, |
394 | host = None, |
395 | path = "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478" , |
396 | query = None, |
397 | port = None, |
398 | } |
399 | |
400 | test_parse! { |
401 | test_path_permissive, |
402 | "/foo=bar|baz \\^~%" , |
403 | [], |
404 | |
405 | path = "/foo=bar|baz \\^~%" , |
406 | } |
407 | |
408 | test_parse! { |
409 | test_query_permissive, |
410 | "/?foo={bar|baz} \\^`" , |
411 | [], |
412 | |
413 | query = Some("foo={bar|baz} \\^`" ), |
414 | } |
415 | |
416 | #[test] |
417 | fn test_uri_parse_error() { |
418 | fn err(s: &str) { |
419 | Uri::from_str(s).unwrap_err(); |
420 | } |
421 | |
422 | err("http://" ); |
423 | err("htt:p//host" ); |
424 | err("hyper.rs/" ); |
425 | err("hyper.rs?key=val" ); |
426 | err("?key=val" ); |
427 | err("localhost/" ); |
428 | err("localhost?key=val" ); |
429 | err(" \0" ); |
430 | err("http://[::1" ); |
431 | err("http://::1]" ); |
432 | err("localhost:8080:3030" ); |
433 | err("@" ); |
434 | err("http://username:password@/wut" ); |
435 | |
436 | // illegal queries |
437 | err("/?foo \rbar" ); |
438 | err("/?foo \nbar" ); |
439 | err("/?<" ); |
440 | err("/?>" ); |
441 | } |
442 | |
443 | #[test] |
444 | fn test_max_uri_len() { |
445 | let mut uri = vec![]; |
446 | uri.extend(b"http://localhost/" ); |
447 | uri.extend(vec![b'a' ; 70 * 1024]); |
448 | |
449 | let uri = String::from_utf8(uri).unwrap(); |
450 | let res: Result<Uri, InvalidUri> = uri.parse(); |
451 | |
452 | assert_eq!(res.unwrap_err().0, ErrorKind::TooLong); |
453 | } |
454 | |
455 | #[test] |
456 | fn test_overflowing_scheme() { |
457 | let mut uri = vec![]; |
458 | uri.extend(vec![b'a' ; 256]); |
459 | uri.extend(b"://localhost/" ); |
460 | |
461 | let uri = String::from_utf8(uri).unwrap(); |
462 | let res: Result<Uri, InvalidUri> = uri.parse(); |
463 | |
464 | assert_eq!(res.unwrap_err().0, ErrorKind::SchemeTooLong); |
465 | } |
466 | |
467 | #[test] |
468 | fn test_max_length_scheme() { |
469 | let mut uri = vec![]; |
470 | uri.extend(vec![b'a' ; 64]); |
471 | uri.extend(b"://localhost/" ); |
472 | |
473 | let uri = String::from_utf8(uri).unwrap(); |
474 | let uri: Uri = uri.parse().unwrap(); |
475 | |
476 | assert_eq!(uri.scheme_str().unwrap().len(), 64); |
477 | } |
478 | |
479 | #[test] |
480 | fn test_uri_to_path_and_query() { |
481 | let cases = vec![ |
482 | ("/" , "/" ), |
483 | ("/foo?bar" , "/foo?bar" ), |
484 | ("/foo?bar#nope" , "/foo?bar" ), |
485 | ("http://hyper.rs" , "/" ), |
486 | ("http://hyper.rs/" , "/" ), |
487 | ("http://hyper.rs/path" , "/path" ), |
488 | ("http://hyper.rs?query" , "/?query" ), |
489 | ("*" , "*" ), |
490 | ]; |
491 | |
492 | for case in cases { |
493 | let uri = Uri::from_str(case.0).unwrap(); |
494 | let s = uri.path_and_query().unwrap().to_string(); |
495 | |
496 | assert_eq!(s, case.1); |
497 | } |
498 | } |
499 | |
500 | #[test] |
501 | fn test_authority_uri_parts_round_trip() { |
502 | let s = "hyper.rs" ; |
503 | let uri = Uri::from_str(s).expect("first parse" ); |
504 | assert_eq!(uri, s); |
505 | assert_eq!(uri.to_string(), s); |
506 | |
507 | let parts = uri.into_parts(); |
508 | let uri2 = Uri::from_parts(parts).expect("from_parts" ); |
509 | assert_eq!(uri2, s); |
510 | assert_eq!(uri2.to_string(), s); |
511 | } |
512 | |
513 | #[test] |
514 | fn test_partial_eq_path_with_terminating_questionmark() { |
515 | let a = "/path" ; |
516 | let uri = Uri::from_str("/path?" ).expect("first parse" ); |
517 | |
518 | assert_eq!(uri, a); |
519 | } |
520 | |