| 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 | |