| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library uriTest; | |
| 6 | |
| 7 import "package:expect/expect.dart"; | |
| 8 import 'dart:convert'; | |
| 9 | |
| 10 testUri(String uriText, bool isAbsolute) { | |
| 11 var uri = Uri.parse(uriText); | |
| 12 | |
| 13 Expect.equals(isAbsolute, uri.isAbsolute); | |
| 14 Expect.stringEquals(uriText, uri.toString()); | |
| 15 | |
| 16 // Test equals and hashCode members. | |
| 17 var uri2 = Uri.parse(uriText); | |
| 18 Expect.equals(uri, uri2); | |
| 19 Expect.equals(uri.hashCode, uri2.hashCode); | |
| 20 | |
| 21 // Test that removeFragment doesn't change anything else. | |
| 22 if (uri.hasFragment) { | |
| 23 Expect.equals(Uri.parse(uriText.substring(0, uriText.indexOf('#'))), | |
| 24 uri.removeFragment()); | |
| 25 } else { | |
| 26 Expect.equals(uri, Uri.parse(uriText + "#fragment").removeFragment()); | |
| 27 } | |
| 28 } | |
| 29 | |
| 30 testEncodeDecode(String orig, String encoded) { | |
| 31 var e = Uri.encodeFull(orig); | |
| 32 Expect.stringEquals(encoded, e); | |
| 33 var d = Uri.decodeFull(encoded); | |
| 34 Expect.stringEquals(orig, d); | |
| 35 } | |
| 36 | |
| 37 testEncodeDecodeComponent(String orig, String encoded) { | |
| 38 var e = Uri.encodeComponent(orig); | |
| 39 Expect.stringEquals(encoded, e); | |
| 40 var d = Uri.decodeComponent(encoded); | |
| 41 Expect.stringEquals(orig, d); | |
| 42 } | |
| 43 | |
| 44 testEncodeDecodeQueryComponent(String orig, String encodedUTF8, | |
| 45 String encodedLatin1, String encodedAscii) { | |
| 46 var e, d; | |
| 47 e = Uri.encodeQueryComponent(orig); | |
| 48 Expect.stringEquals(encodedUTF8, e); | |
| 49 d = Uri.decodeQueryComponent(encodedUTF8); | |
| 50 Expect.stringEquals(orig, d); | |
| 51 | |
| 52 e = Uri.encodeQueryComponent(orig, encoding: UTF8); | |
| 53 Expect.stringEquals(encodedUTF8, e); | |
| 54 d = Uri.decodeQueryComponent(encodedUTF8, encoding: UTF8); | |
| 55 Expect.stringEquals(orig, d); | |
| 56 | |
| 57 e = Uri.encodeQueryComponent(orig, encoding: LATIN1); | |
| 58 Expect.stringEquals(encodedLatin1, e); | |
| 59 d = Uri.decodeQueryComponent(encodedLatin1, encoding: LATIN1); | |
| 60 Expect.stringEquals(orig, d); | |
| 61 | |
| 62 if (encodedAscii != null) { | |
| 63 e = Uri.encodeQueryComponent(orig, encoding: ASCII); | |
| 64 Expect.stringEquals(encodedAscii, e); | |
| 65 d = Uri.decodeQueryComponent(encodedAscii, encoding: ASCII); | |
| 66 Expect.stringEquals(orig, d); | |
| 67 } else { | |
| 68 Expect.throws(() => Uri.encodeQueryComponent(orig, encoding: ASCII), | |
| 69 (e) => e is ArgumentError); | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 testUriPerRFCs() { | |
| 74 final urisSample = "http://a/b/c/d;p?q"; | |
| 75 Uri base = Uri.parse(urisSample); | |
| 76 testResolve(expect, relative) { | |
| 77 Expect.stringEquals(expect, base.resolve(relative).toString()); | |
| 78 } | |
| 79 | |
| 80 // From RFC 3986. | |
| 81 testResolve("g:h", "g:h"); | |
| 82 testResolve("http://a/b/c/g", "g"); | |
| 83 testResolve("http://a/b/c/g", "./g"); | |
| 84 testResolve("http://a/b/c/g/", "g/"); | |
| 85 testResolve("http://a/g", "/g"); | |
| 86 testResolve("http://g", "//g"); | |
| 87 testResolve("http://a/b/c/d;p?y", "?y"); | |
| 88 testResolve("http://a/b/c/g?y", "g?y"); | |
| 89 testResolve("http://a/b/c/d;p?q#s", "#s"); | |
| 90 testResolve("http://a/b/c/g#s", "g#s"); | |
| 91 testResolve("http://a/b/c/g?y#s", "g?y#s"); | |
| 92 testResolve("http://a/b/c/;x", ";x"); | |
| 93 testResolve("http://a/b/c/g;x", "g;x"); | |
| 94 testResolve("http://a/b/c/g;x?y#s", "g;x?y#s"); | |
| 95 testResolve("http://a/b/c/d;p?q", ""); | |
| 96 testResolve("http://a/b/c/", "."); | |
| 97 testResolve("http://a/b/c/", "./"); | |
| 98 testResolve("http://a/b/", ".."); | |
| 99 testResolve("http://a/b/", "../"); | |
| 100 testResolve("http://a/b/g", "../g"); | |
| 101 testResolve("http://a/", "../.."); | |
| 102 testResolve("http://a/", "../../"); | |
| 103 testResolve("http://a/g", "../../g"); | |
| 104 testResolve("http://a/g", "../../../g"); | |
| 105 testResolve("http://a/g", "../../../../g"); | |
| 106 testResolve("http://a/g", "/./g"); | |
| 107 testResolve("http://a/g", "/../g"); | |
| 108 testResolve("http://a/b/c/g.", "g."); | |
| 109 testResolve("http://a/b/c/.g", ".g"); | |
| 110 testResolve("http://a/b/c/g..", "g.."); | |
| 111 testResolve("http://a/b/c/..g", "..g"); | |
| 112 testResolve("http://a/b/g", "./../g"); | |
| 113 testResolve("http://a/b/c/g/", "./g/."); | |
| 114 testResolve("http://a/b/c/g/h", "g/./h"); | |
| 115 testResolve("http://a/b/c/h", "g/../h"); | |
| 116 testResolve("http://a/b/c/g;x=1/y", "g;x=1/./y"); | |
| 117 testResolve("http://a/b/c/y", "g;x=1/../y"); | |
| 118 testResolve("http://a/b/c/g?y/./x", "g?y/./x"); | |
| 119 testResolve("http://a/b/c/g?y/../x", "g?y/../x"); | |
| 120 testResolve("http://a/b/c/g#s/./x", "g#s/./x"); | |
| 121 testResolve("http://a/b/c/g#s/../x", "g#s/../x"); | |
| 122 testResolve("http:g", "http:g"); | |
| 123 | |
| 124 // Additional tests (not from RFC 3986). | |
| 125 testResolve("http://a/b/g;p/h;s", "../g;p/h;s"); | |
| 126 | |
| 127 // Test non-URI base (no scheme, no authority, relative path). | |
| 128 base = Uri.parse("a/b/c?_#_"); | |
| 129 testResolve("a/b/g?q#f", "g?q#f"); | |
| 130 testResolve("../", "../../.."); | |
| 131 testResolve("a/b/", "."); | |
| 132 testResolve("c", "../../c"); | |
| 133 | |
| 134 base = Uri.parse("s:a/b"); | |
| 135 testResolve("s:/c", "../c"); | |
| 136 } | |
| 137 | |
| 138 void testResolvePath(String expected, String path) { | |
| 139 Expect.equals( | |
| 140 expected, new Uri(path: '/').resolveUri(new Uri(path: path)).path); | |
| 141 Expect.equals("http://localhost$expected", | |
| 142 Uri.parse("http://localhost").resolveUri(new Uri(path: path)).toString()); | |
| 143 } | |
| 144 | |
| 145 const ALPHA = r"abcdefghijklmnopqrstuvwxuzABCDEFGHIJKLMNOPQRSTUVWXUZ"; | |
| 146 const DIGIT = r"0123456789"; | |
| 147 const PERCENT_ENCODED = "%00%ff"; | |
| 148 const SUBDELIM = r"!$&'()*+,;="; | |
| 149 | |
| 150 const SCHEMECHAR = "$ALPHA$DIGIT+-."; | |
| 151 const UNRESERVED = "$ALPHA$DIGIT-._~"; | |
| 152 const REGNAMECHAR = "$UNRESERVED$SUBDELIM$PERCENT_ENCODED"; | |
| 153 const USERINFOCHAR = "$REGNAMECHAR:"; | |
| 154 | |
| 155 const PCHAR_NC = "$UNRESERVED$SUBDELIM$PERCENT_ENCODED@"; | |
| 156 const PCHAR = "$PCHAR_NC:"; | |
| 157 const QUERYCHAR = "$PCHAR/?"; | |
| 158 | |
| 159 void testValidCharacters() { | |
| 160 // test that all valid characters are accepted. | |
| 161 | |
| 162 for (var scheme in ["", "$SCHEMECHAR$SCHEMECHAR:"]) { | |
| 163 for (var userinfo in [ | |
| 164 "", | |
| 165 "@", | |
| 166 "$USERINFOCHAR$USERINFOCHAR@", | |
| 167 "$USERINFOCHAR:$DIGIT@" | |
| 168 ]) { | |
| 169 for (var host in [ | |
| 170 "", "$REGNAMECHAR$REGNAMECHAR", | |
| 171 "255.255.255.256", // valid reg-name. | |
| 172 "[ffff::ffff:ffff]", "[ffff::255.255.255.255]" | |
| 173 ]) { | |
| 174 for (var port in ["", ":", ":$DIGIT$DIGIT"]) { | |
| 175 var auth = "$userinfo$host$port"; | |
| 176 if (auth.isNotEmpty) auth = "//$auth"; | |
| 177 var paths = ["", "/", "/$PCHAR", "/$PCHAR/"]; // Absolute or empty. | |
| 178 if (auth.isNotEmpty) { | |
| 179 // Initial segment may be empty. | |
| 180 paths..add("//$PCHAR"); | |
| 181 } else { | |
| 182 // Path may begin with non-slash. | |
| 183 if (scheme.isEmpty) { | |
| 184 // Initial segment must not contain colon. | |
| 185 paths | |
| 186 ..add(PCHAR_NC) | |
| 187 ..add("$PCHAR_NC/$PCHAR") | |
| 188 ..add("$PCHAR_NC/$PCHAR/"); | |
| 189 } else { | |
| 190 paths..add(PCHAR)..add("$PCHAR/$PCHAR")..add("$PCHAR/$PCHAR/"); | |
| 191 } | |
| 192 } | |
| 193 for (var path in paths) { | |
| 194 for (var query in ["", "?", "?$QUERYCHAR"]) { | |
| 195 for (var fragment in ["", "#", "#$QUERYCHAR"]) { | |
| 196 var uri = "$scheme$auth$path$query$fragment"; | |
| 197 // Should not throw. | |
| 198 var result = Uri.parse(uri); | |
| 199 } | |
| 200 } | |
| 201 } | |
| 202 } | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 void testInvalidUrls() { | |
| 209 void checkInvalid(uri) { | |
| 210 try { | |
| 211 var result = Uri.parse(uri); | |
| 212 Expect.fail("Invalid URI `$uri` parsed to $result\n" + dump(result)); | |
| 213 } on FormatException { | |
| 214 // Success. | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 checkInvalid("s%41://x.x/"); // No escapes in scheme, | |
| 219 // and no colon before slash in path. | |
| 220 checkInvalid("1a://x.x/"); // Scheme must start with letter, | |
| 221 // and no colon before slash in path. | |
| 222 checkInvalid(".a://x.x/"); // Scheme must start with letter, | |
| 223 // and no colon before slash in path. | |
| 224 checkInvalid("_:"); // Character not valid in scheme, | |
| 225 // and no colon before slash in path. | |
| 226 checkInvalid(":"); // Scheme must start with letter, | |
| 227 // and no colon before slash in path. | |
| 228 | |
| 229 void checkInvalidReplaced(uri, invalid, replacement) { | |
| 230 var source = uri.replaceAll('{}', invalid); | |
| 231 var expected = uri.replaceAll('{}', replacement); | |
| 232 var result = Uri.parse(source); | |
| 233 Expect.equals(expected, "$result", "Source: $source\n${dump(result)}"); | |
| 234 } | |
| 235 | |
| 236 // Regression test for http://dartbug.com/16081 | |
| 237 checkInvalidReplaced( | |
| 238 "http://www.example.org/red%09ros{}#red)", "\u00e9", "%C3%A9"); | |
| 239 checkInvalidReplaced("http://r{}sum\{}.example.org", "\u00E9", "%C3%A9"); | |
| 240 | |
| 241 // Invalid characters. The characters must be rejected, even if normalizing | |
| 242 // the input would cause them to be valid (normalization happens after | |
| 243 // validation). | |
| 244 var invalidCharsAndReplacements = [ | |
| 245 "\xe7", "%C3%A7", // Arbitrary non-ASCII letter | |
| 246 " ", "%20", // Space, not allowed anywhere. | |
| 247 '"', "%22", // Quote, not allowed anywhere | |
| 248 "<>", "%3C%3E", // Less/greater-than, not allowed anywhere. | |
| 249 "\x7f", "%7F", // DEL, not allowed anywhere | |
| 250 "\xdf", "%C3%9F", // German lower-case scharf-S. | |
| 251 // Becomes ASCII when upper-cased. | |
| 252 "\u0130", "%C4%B0", // Latin capital dotted I, | |
| 253 // becomes ASCII lower-case in Turkish. | |
| 254 "%\uFB03", "%25%EF%AC%83", // % + Ligature ffi, | |
| 255 // becomes ASCII when upper-cased, | |
| 256 // should not be read as "%FFI". | |
| 257 "\u212a", "%E2%84%AA", // Kelvin sign. Becomes ASCII when lower-cased. | |
| 258 "%1g", "%251g", // Invalid escape. | |
| 259 "\u{10000}", "%F0%90%80%80", // Non-BMP character as surrogate pair. | |
| 260 ]; | |
| 261 for (int i = 0; i < invalidCharsAndReplacements.length; i += 2) { | |
| 262 var invalid = invalidCharsAndReplacements[i]; | |
| 263 var valid = invalidCharsAndReplacements[i + 1]; | |
| 264 checkInvalid("A{}b:///".replaceAll('{}', invalid)); | |
| 265 checkInvalid("{}b:///".replaceAll('{}', invalid)); | |
| 266 checkInvalidReplaced("s://user{}info@x.x/", invalid, valid); | |
| 267 checkInvalidReplaced("s://reg{}name/", invalid, valid); | |
| 268 checkInvalid("s://regname:12{}45/".replaceAll("{}", invalid)); | |
| 269 checkInvalidReplaced("s://regname/p{}ath/", invalid, valid); | |
| 270 checkInvalidReplaced("/p{}ath/", invalid, valid); | |
| 271 checkInvalidReplaced("p{}ath/", invalid, valid); | |
| 272 checkInvalidReplaced("s://regname/path/?x{}x", invalid, valid); | |
| 273 checkInvalidReplaced("s://regname/path/#x{}x", invalid, valid); | |
| 274 checkInvalidReplaced("s://regname/path/??#x{}x", invalid, valid); | |
| 275 } | |
| 276 | |
| 277 // At most one @ in userinfo. | |
| 278 checkInvalid("s://x@x@x.x/"); | |
| 279 // No colon in host except before a port. | |
| 280 checkInvalid("s://x@x:x/"); | |
| 281 // At most one port. | |
| 282 checkInvalid("s://x@x:9:9/"); | |
| 283 // At most one #. | |
| 284 checkInvalid("s://x/x#foo#bar"); | |
| 285 // @ not allowed in scheme. | |
| 286 checkInvalid("s@://x:9/x?x#x"); | |
| 287 // ] not allowed alone in host. | |
| 288 checkInvalid("s://xx]/"); | |
| 289 // ] not allowed anywhere except in host. | |
| 290 checkInvalid("s://xx/]"); | |
| 291 checkInvalid("s://xx/?]"); | |
| 292 checkInvalid("s://xx/#]"); | |
| 293 checkInvalid("s:/]"); | |
| 294 checkInvalid("s:/?]"); | |
| 295 checkInvalid("s:/#]"); | |
| 296 // IPv6 must be enclosed in [ and ] for Uri.parse. | |
| 297 // It is allowed un-enclosed as argument to `Uri(host:...)` because we don't | |
| 298 // need to delimit. | |
| 299 checkInvalid("s://ffff::ffff:1234/"); | |
| 300 } | |
| 301 | |
| 302 void testNormalization() { | |
| 303 // The Uri constructor and the Uri.parse function performs RFC-3986 | |
| 304 // syntax based normalization. | |
| 305 | |
| 306 var uri; | |
| 307 | |
| 308 // Scheme: Only case normalization. Schemes cannot contain escapes. | |
| 309 uri = Uri.parse("A:"); | |
| 310 Expect.equals("a", uri.scheme); | |
| 311 uri = Uri.parse("Z:"); | |
| 312 Expect.equals("z", uri.scheme); | |
| 313 uri = Uri.parse("$SCHEMECHAR:"); | |
| 314 Expect.equals(SCHEMECHAR.toLowerCase(), uri.scheme); | |
| 315 | |
| 316 // Percent escape normalization. | |
| 317 // Escapes of unreserved characters are converted to the character, | |
| 318 // subject to case normalization in reg-name. | |
| 319 for (var i = 0; i < UNRESERVED.length; i++) { | |
| 320 var char = UNRESERVED[i]; | |
| 321 var escape = "%" + char.codeUnitAt(0).toRadixString(16); // all > 0xf. | |
| 322 | |
| 323 uri = Uri.parse("s://xX${escape}xX@yY${escape}yY/zZ${escape}zZ" | |
| 324 "?vV${escape}vV#wW${escape}wW"); | |
| 325 Expect.equals("xX${char}xX", uri.userInfo); | |
| 326 Expect.equals("yY${char}yY".toLowerCase(), uri.host); | |
| 327 Expect.equals("/zZ${char}zZ", uri.path); | |
| 328 Expect.equals("vV${char}vV", uri.query); | |
| 329 Expect.equals("wW${char}wW", uri.fragment); | |
| 330 } | |
| 331 | |
| 332 // Escapes of reserved characters are kept, but upper-cased. | |
| 333 for (var escape in ["%00", "%1f", "%7F", "%fF"]) { | |
| 334 uri = Uri.parse("s://xX${escape}xX@yY${escape}yY/zZ${escape}zZ" | |
| 335 "?vV${escape}vV#wW${escape}wW"); | |
| 336 var normalizedEscape = escape.toUpperCase(); | |
| 337 Expect.equals("xX${normalizedEscape}xX", uri.userInfo); | |
| 338 Expect.equals("yy${normalizedEscape}yy", uri.host); | |
| 339 Expect.equals("/zZ${normalizedEscape}zZ", uri.path); | |
| 340 Expect.equals("vV${normalizedEscape}vV", uri.query); | |
| 341 Expect.equals("wW${normalizedEscape}wW", uri.fragment); | |
| 342 } | |
| 343 | |
| 344 // Some host normalization edge cases. | |
| 345 uri = Uri.parse("x://x%61X%41x%41X%61x/"); | |
| 346 Expect.equals("xaxaxaxax", uri.host); | |
| 347 | |
| 348 uri = Uri.parse("x://Xxxxxxxx/"); | |
| 349 Expect.equals("xxxxxxxx", uri.host); | |
| 350 | |
| 351 uri = Uri.parse("x://xxxxxxxX/"); | |
| 352 Expect.equals("xxxxxxxx", uri.host); | |
| 353 | |
| 354 uri = Uri.parse("x://xxxxxxxx%61/"); | |
| 355 Expect.equals("xxxxxxxxa", uri.host); | |
| 356 | |
| 357 uri = Uri.parse("x://%61xxxxxxxx/"); | |
| 358 Expect.equals("axxxxxxxx", uri.host); | |
| 359 | |
| 360 uri = Uri.parse("x://X/"); | |
| 361 Expect.equals("x", uri.host); | |
| 362 | |
| 363 uri = Uri.parse("x://%61/"); | |
| 364 Expect.equals("a", uri.host); | |
| 365 | |
| 366 uri = new Uri(scheme: "x", path: "//y"); | |
| 367 Expect.equals("//y", uri.path); | |
| 368 Expect.equals("x:////y", uri.toString()); | |
| 369 | |
| 370 uri = new Uri(scheme: "file", path: "//y"); | |
| 371 Expect.equals("//y", uri.path); | |
| 372 Expect.equals("file:////y", uri.toString()); | |
| 373 | |
| 374 // File scheme noralizes to always showing authority, even if empty. | |
| 375 uri = new Uri(scheme: "file", path: "/y"); | |
| 376 Expect.equals("file:///y", uri.toString()); | |
| 377 uri = new Uri(scheme: "file", path: "y"); | |
| 378 Expect.equals("file:///y", uri.toString()); | |
| 379 | |
| 380 // Empty host/query/fragment ensures the delimiter is there. | |
| 381 // Different from not being there. | |
| 382 Expect.equals("scheme:/", Uri.parse("scheme:/").toString()); | |
| 383 Expect.equals("scheme:/", new Uri(scheme: "scheme", path: "/").toString()); | |
| 384 | |
| 385 Expect.equals("scheme:///?#", Uri.parse("scheme:///?#").toString()); | |
| 386 Expect.equals( | |
| 387 "scheme:///#", | |
| 388 new Uri(scheme: "scheme", host: "", path: "/", query: "", fragment: "") | |
| 389 .toString()); | |
| 390 } | |
| 391 | |
| 392 void testReplace() { | |
| 393 var uris = [ | |
| 394 Uri.parse(""), | |
| 395 Uri.parse("a://@:/?#"), | |
| 396 Uri.parse("a://b@c:4/e/f?g#h"), | |
| 397 Uri.parse("$SCHEMECHAR://$USERINFOCHAR@$REGNAMECHAR:$DIGIT/$PCHAR/$PCHAR" | |
| 398 "?$QUERYCHAR#$QUERYCHAR"), | |
| 399 ]; | |
| 400 for (var uri1 in uris) { | |
| 401 for (var uri2 in uris) { | |
| 402 if (identical(uri1, uri2)) continue; | |
| 403 var scheme = uri1.scheme; | |
| 404 var userInfo = uri1.hasAuthority ? uri1.userInfo : ""; | |
| 405 var host = uri1.hasAuthority ? uri1.host : null; | |
| 406 var port = uri1.hasAuthority ? uri1.port : 0; | |
| 407 var path = uri1.path; | |
| 408 var query = uri1.hasQuery ? uri1.query : null; | |
| 409 var fragment = uri1.hasFragment ? uri1.fragment : null; | |
| 410 | |
| 411 var tmp1 = uri1; | |
| 412 | |
| 413 void test() { | |
| 414 var tmp2 = new Uri( | |
| 415 scheme: scheme, | |
| 416 userInfo: userInfo, | |
| 417 host: host, | |
| 418 port: port, | |
| 419 path: path, | |
| 420 query: query == "" ? null : query, | |
| 421 queryParameters: query == "" ? {} : null, | |
| 422 fragment: fragment); | |
| 423 Expect.equals(tmp1, tmp2); | |
| 424 } | |
| 425 | |
| 426 test(); | |
| 427 | |
| 428 scheme = uri2.scheme; | |
| 429 tmp1 = tmp1.replace(scheme: scheme); | |
| 430 test(); | |
| 431 | |
| 432 if (uri2.hasAuthority) { | |
| 433 userInfo = uri2.userInfo; | |
| 434 host = uri2.host; | |
| 435 port = uri2.port; | |
| 436 tmp1 = tmp1.replace(userInfo: userInfo, host: host, port: port); | |
| 437 test(); | |
| 438 } | |
| 439 | |
| 440 path = uri2.path; | |
| 441 tmp1 = tmp1.replace(path: path); | |
| 442 test(); | |
| 443 | |
| 444 if (uri2.hasQuery) { | |
| 445 query = uri2.query; | |
| 446 tmp1 = tmp1.replace(query: query); | |
| 447 test(); | |
| 448 } | |
| 449 | |
| 450 if (uri2.hasFragment) { | |
| 451 fragment = uri2.fragment; | |
| 452 tmp1 = tmp1.replace(fragment: fragment); | |
| 453 test(); | |
| 454 } | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 // Regression test, http://dartbug.com/20814 | |
| 459 var uri = Uri.parse("/no-authorty/"); | |
| 460 uri = uri.replace(fragment: "fragment"); | |
| 461 Expect.isFalse(uri.hasAuthority); | |
| 462 | |
| 463 uri = new Uri(scheme: "foo", path: "bar"); | |
| 464 uri = uri.replace(queryParameters: { | |
| 465 "x": ["42", "37"], | |
| 466 "y": ["43", "38"] | |
| 467 }); | |
| 468 var params = uri.queryParametersAll; | |
| 469 Expect.equals(2, params.length); | |
| 470 Expect.listEquals(["42", "37"], params["x"]); | |
| 471 Expect.listEquals(["43", "38"], params["y"]); | |
| 472 } | |
| 473 | |
| 474 main() { | |
| 475 testUri("http:", true); | |
| 476 testUri("file:///", true); | |
| 477 testUri("file", false); | |
| 478 testUri("http://user@example.com:8080/fisk?query=89&hest=silas", true); | |
| 479 testUri( | |
| 480 "http://user@example.com:8080/fisk?query=89&hest=silas#fragment", false); | |
| 481 Expect.stringEquals( | |
| 482 "http://user@example.com/a/b/c?query#fragment", | |
| 483 new Uri( | |
| 484 scheme: "http", | |
| 485 userInfo: "user", | |
| 486 host: "example.com", | |
| 487 port: 80, | |
| 488 path: "/a/b/c", | |
| 489 query: "query", | |
| 490 fragment: "fragment") | |
| 491 .toString()); | |
| 492 Expect.stringEquals( | |
| 493 "/a/b/c/", | |
| 494 new Uri( | |
| 495 scheme: null, | |
| 496 userInfo: null, | |
| 497 host: null, | |
| 498 port: 0, | |
| 499 path: "/a/b/c/", | |
| 500 query: null, | |
| 501 fragment: null) | |
| 502 .toString()); | |
| 503 Expect.stringEquals("file:///", Uri.parse("file:").toString()); | |
| 504 | |
| 505 testResolvePath("/a/g", "/a/b/c/./../../g"); | |
| 506 testResolvePath("/a/g", "/a/b/c/./../../g"); | |
| 507 testResolvePath("/mid/6", "mid/content=5/../6"); | |
| 508 testResolvePath("/a/b/e", "a/b/c/d/../../e"); | |
| 509 testResolvePath("/a/b/e", "../a/b/c/d/../../e"); | |
| 510 testResolvePath("/a/b/e", "./a/b/c/d/../../e"); | |
| 511 testResolvePath("/a/b/e", "../a/b/./c/d/../../e"); | |
| 512 testResolvePath("/a/b/e", "./a/b/./c/d/../../e"); | |
| 513 testResolvePath("/a/b/e/", "./a/b/./c/d/../../e/."); | |
| 514 testResolvePath("/a/b/e/", "./a/b/./c/d/../../e/./."); | |
| 515 testResolvePath("/a/b/e/", "./a/b/./c/d/../../e/././."); | |
| 516 | |
| 517 testUriPerRFCs(); | |
| 518 | |
| 519 Expect.stringEquals( | |
| 520 "http://example.com", Uri.parse("http://example.com/a/b/c").origin); | |
| 521 Expect.stringEquals( | |
| 522 "https://example.com", Uri.parse("https://example.com/a/b/c").origin); | |
| 523 Expect.stringEquals("http://example.com:1234", | |
| 524 Uri.parse("http://example.com:1234/a/b/c").origin); | |
| 525 Expect.stringEquals("https://example.com:1234", | |
| 526 Uri.parse("https://example.com:1234/a/b/c").origin); | |
| 527 Expect.throws(() => Uri.parse("http:").origin, (e) { | |
| 528 return e is StateError; | |
| 529 }, "origin for uri with empty host should fail"); | |
| 530 Expect.throws( | |
| 531 () => new Uri( | |
| 532 scheme: "http", | |
| 533 userInfo: null, | |
| 534 host: "", | |
| 535 port: 80, | |
| 536 path: "/a/b/c", | |
| 537 query: "query", | |
| 538 fragment: "fragment") | |
| 539 .origin, (e) { | |
| 540 return e is StateError; | |
| 541 }, "origin for uri with empty host should fail"); | |
| 542 Expect.throws( | |
| 543 () => new Uri( | |
| 544 scheme: null, | |
| 545 userInfo: null, | |
| 546 host: "", | |
| 547 port: 80, | |
| 548 path: "/a/b/c", | |
| 549 query: "query", | |
| 550 fragment: "fragment") | |
| 551 .origin, (e) { | |
| 552 return e is StateError; | |
| 553 }, "origin for uri with empty scheme should fail"); | |
| 554 Expect.throws( | |
| 555 () => new Uri( | |
| 556 scheme: "http", | |
| 557 userInfo: null, | |
| 558 host: null, | |
| 559 port: 80, | |
| 560 path: "/a/b/c", | |
| 561 query: "query", | |
| 562 fragment: "fragment") | |
| 563 .origin, (e) { | |
| 564 return e is StateError; | |
| 565 }, "origin for uri with empty host should fail"); | |
| 566 Expect.throws(() => Uri.parse("http://:80").origin, (e) { | |
| 567 return e is StateError; | |
| 568 }, "origin for uri with empty host should fail"); | |
| 569 Expect.throws(() => Uri.parse("file://localhost/test.txt").origin, (e) { | |
| 570 return e is StateError; | |
| 571 }, "origin for non-http/https uri should fail"); | |
| 572 | |
| 573 // URI encode tests | |
| 574 // Create a string with code point 0x10000 encoded as a surrogate pair. | |
| 575 var s = UTF8.decode([0xf0, 0x90, 0x80, 0x80]); | |
| 576 | |
| 577 Expect.stringEquals("\u{10000}", s); | |
| 578 | |
| 579 testEncodeDecode("A + B", "A%20+%20B"); | |
| 580 testEncodeDecode("\uFFFE", "%EF%BF%BE"); | |
| 581 testEncodeDecode("\uFFFF", "%EF%BF%BF"); | |
| 582 testEncodeDecode("\uFFFE", "%EF%BF%BE"); | |
| 583 testEncodeDecode("\uFFFF", "%EF%BF%BF"); | |
| 584 testEncodeDecode("\x7f", "%7F"); | |
| 585 testEncodeDecode("\x80", "%C2%80"); | |
| 586 testEncodeDecode("\u0800", "%E0%A0%80"); | |
| 587 // All characters not escaped by encodeFull. | |
| 588 var unescapedFull = r"abcdefghijklmnopqrstuvwxyz" | |
| 589 r"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| 590 r"0123456789!#$&'()*+,-./:;=?@_~"; | |
| 591 // ASCII characters escaped by encodeFull: | |
| 592 var escapedFull = | |
| 593 "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" | |
| 594 "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" | |
| 595 r' "%<>[\]^`{|}' | |
| 596 "\x7f"; | |
| 597 var escapedTo = "%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F" | |
| 598 "%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F" | |
| 599 "%20%22%25%3C%3E%5B%5C%5D%5E%60%7B%7C%7D%7F"; | |
| 600 testEncodeDecode(unescapedFull, unescapedFull); | |
| 601 testEncodeDecode(escapedFull, escapedTo); | |
| 602 var nonAscii = | |
| 603 "\x80-\xff-\u{100}-\u{7ff}-\u{800}-\u{ffff}-\u{10000}-\u{10ffff}"; | |
| 604 var nonAsciiEncoding = "%C2%80-%C3%BF-%C4%80-%DF%BF-%E0%A0%80-%EF%BF%BF-" | |
| 605 "%F0%90%80%80-%F4%8F%BF%BF"; | |
| 606 testEncodeDecode(nonAscii, nonAsciiEncoding); | |
| 607 testEncodeDecode(s, "%F0%90%80%80"); | |
| 608 testEncodeDecodeComponent("A + B", "A%20%2B%20B"); | |
| 609 testEncodeDecodeComponent("\uFFFE", "%EF%BF%BE"); | |
| 610 testEncodeDecodeComponent("\uFFFF", "%EF%BF%BF"); | |
| 611 testEncodeDecodeComponent("\uFFFE", "%EF%BF%BE"); | |
| 612 testEncodeDecodeComponent("\uFFFF", "%EF%BF%BF"); | |
| 613 testEncodeDecodeComponent("\x7f", "%7F"); | |
| 614 testEncodeDecodeComponent("\x80", "%C2%80"); | |
| 615 testEncodeDecodeComponent("\u0800", "%E0%A0%80"); | |
| 616 testEncodeDecodeComponent(":/@',;?&=+\$", "%3A%2F%40'%2C%3B%3F%26%3D%2B%24"); | |
| 617 testEncodeDecodeComponent(s, "%F0%90%80%80"); | |
| 618 testEncodeDecodeQueryComponent("A + B", "A+%2B+B", "A+%2B+B", "A+%2B+B"); | |
| 619 testEncodeDecodeQueryComponent( | |
| 620 "æ ø å", "%C3%A6+%C3%B8+%C3%A5", "%E6+%F8+%E5", null); | |
| 621 testEncodeDecodeComponent(nonAscii, nonAsciiEncoding); | |
| 622 | |
| 623 // Invalid URI - : and @ is swapped, port ("host") should be numeric. | |
| 624 Expect.throws(() => Uri.parse("file://user@password:host/path"), | |
| 625 (e) => e is FormatException); | |
| 626 | |
| 627 testValidCharacters(); | |
| 628 testInvalidUrls(); | |
| 629 testNormalization(); | |
| 630 testReplace(); | |
| 631 } | |
| 632 | |
| 633 String dump(Uri uri) { | |
| 634 return "URI: $uri\n" | |
| 635 " Scheme: ${uri.scheme} #${uri.scheme.length}\n" | |
| 636 " User-info: ${uri.userInfo} #${uri.userInfo.length}\n" | |
| 637 " Host: ${uri.host} #${uri.host.length}\n" | |
| 638 " Port: ${uri.port}\n" | |
| 639 " Path: ${uri.path} #${uri.path.length}\n" | |
| 640 " Query: ${uri.query} #${uri.query.length}\n" | |
| 641 " Fragment: ${uri.fragment} #${uri.fragment.length}\n"; | |
| 642 } | |
| OLD | NEW |