OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.core; | 5 part of dart.core; |
6 | 6 |
7 /** | 7 /** |
8 * A parsed URI, such as a URL. | 8 * A parsed URI, such as a URL. |
9 * | 9 * |
10 * **See also:** | 10 * **See also:** |
11 * | 11 * |
12 * * [URIs][uris] in the [library tour][libtour] | 12 * * [URIs][uris] in the [library tour][libtour] |
13 * * [RFC-3986](http://tools.ietf.org/html/rfc3986) | 13 * * [RFC-3986](http://tools.ietf.org/html/rfc3986) |
14 * | 14 * |
15 * [uris]: http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#c
h03-uri | 15 * [uris]: http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#c
h03-uri |
16 * [libtour]: http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.htm
l | 16 * [libtour]: http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.htm
l |
17 */ | 17 */ |
18 class Uri { | 18 class Uri { |
19 // The host name of the URI. | |
20 // Set to `null` if there is no authority in a URI. | |
21 final String _host; | 19 final String _host; |
22 // The port. Set to null if there is no port. Normalized to null if | |
23 // the port is the default port for the scheme. | |
24 // Set to the value of the default port if an empty port was supplied. | |
25 int _port; | 20 int _port; |
26 // The path. Always non-null. | |
27 String _path; | 21 String _path; |
28 | 22 |
29 /** | 23 /** |
30 * Returns the scheme component. | 24 * Returns the scheme component. |
31 * | 25 * |
32 * Returns the empty string if there is no scheme component. | 26 * Returns the empty string if there is no scheme component. |
33 */ | 27 */ |
34 // We represent the missing scheme as an empty string. | |
35 // A valid scheme cannot be empty. | |
36 final String scheme; | 28 final String scheme; |
37 | 29 |
38 /** | 30 /** |
39 * Returns the authority component. | 31 * Returns the authority component. |
40 * | 32 * |
41 * The authority is formatted from the [userInfo], [host] and [port] | 33 * The authority is formatted from the [userInfo], [host] and [port] |
42 * parts. | 34 * parts. |
43 * | 35 * |
44 * Returns the empty string if there is no authority component. | 36 * Returns the empty string if there is no authority component. |
45 */ | 37 */ |
46 String get authority { | 38 String get authority { |
47 if (!hasAuthority) return ""; | 39 if (!hasAuthority) return ""; |
48 var sb = new StringBuffer(); | 40 var sb = new StringBuffer(); |
49 _writeAuthority(sb); | 41 _writeAuthority(sb); |
50 return sb.toString(); | 42 return sb.toString(); |
51 } | 43 } |
52 | 44 |
53 /** | 45 /** |
54 * The user-info part of the authority. | |
55 * | |
56 * Does not distinguish between an empty user-info and an absent one. | |
57 * The value is always non-null. | |
58 */ | |
59 final String _userInfo; | |
60 | |
61 /** | |
62 * Returns the user info part of the authority component. | 46 * Returns the user info part of the authority component. |
63 * | 47 * |
64 * Returns the empty string if there is no user info in the | 48 * Returns the empty string if there is no user info in the |
65 * authority component. | 49 * authority component. |
66 */ | 50 */ |
67 String get userInfo => _userInfo; | 51 final String userInfo; |
68 | 52 |
69 /** | 53 /** |
70 * Returns the host part of the authority component. | 54 * Returns the host part of the authority component. |
71 * | 55 * |
72 * Returns the empty string if there is no authority component and | 56 * Returns the empty string if there is no authority component and |
73 * hence no host. | 57 * hence no host. |
74 * | 58 * |
75 * If the host is an IP version 6 address, the surrounding `[` and `]` is | 59 * If the host is an IP version 6 address, the surrounding `[` and `]` is |
76 * removed. | 60 * removed. |
77 */ | 61 */ |
78 String get host { | 62 String get host { |
79 if (_host == null) return ""; | 63 if (_host != null && _host.startsWith('[')) { |
80 if (_host.startsWith('[')) { | |
81 return _host.substring(1, _host.length - 1); | 64 return _host.substring(1, _host.length - 1); |
82 } | 65 } |
83 return _host; | 66 return _host; |
84 } | 67 } |
85 | 68 |
86 /** | 69 /** |
87 * Returns the port part of the authority component. | 70 * Returns the port part of the authority component. |
88 * | 71 * |
89 * Returns the defualt port if there is no port number in the authority | 72 * Returns 0 if there is no port in the authority component. |
90 * component. That's 80 for http, 443 for https, and 0 for everything else. | |
91 */ | 73 */ |
92 int get port { | 74 int get port { |
93 if (_port == null) return _defaultPort(scheme); | 75 if (_port == 0) { |
| 76 if (scheme == "http") return 80; |
| 77 if (scheme == "https") return 443; |
| 78 } |
94 return _port; | 79 return _port; |
95 } | 80 } |
96 | 81 |
97 // The default port for the scheme of this Uri.. | |
98 static int _defaultPort(String scheme) { | |
99 if (scheme == "http") return 80; | |
100 if (scheme == "https") return 443; | |
101 return 0; | |
102 } | |
103 | |
104 /** | 82 /** |
105 * Returns the path component. | 83 * Returns the path component. |
106 * | 84 * |
107 * The returned path is encoded. To get direct access to the decoded | 85 * The returned path is encoded. To get direct access to the decoded |
108 * path use [pathSegments]. | 86 * path use [pathSegments]. |
109 * | 87 * |
110 * Returns the empty string if there is no path component. | 88 * Returns the empty string if there is no path component. |
111 */ | 89 */ |
112 String get path => _path; | 90 String get path => _path; |
113 | 91 |
114 // The query content, or null if there is no query. | |
115 final String _query; | |
116 | |
117 /** | 92 /** |
118 * Returns the query component. The returned query is encoded. To get | 93 * Returns the query component. The returned query is encoded. To get |
119 * direct access to the decoded query use [queryParameters]. | 94 * direct access to the decoded query use [queryParameters]. |
120 * | 95 * |
121 * Returns the empty string if there is no query component. | 96 * Returns the empty string if there is no query component. |
122 */ | 97 */ |
123 String get query => (_query == null) ? "" : _query; | 98 final String query; |
124 | |
125 // The fragment content, or null if there is no fragment. | |
126 final String _fragment; | |
127 | 99 |
128 /** | 100 /** |
129 * Returns the fragment identifier component. | 101 * Returns the fragment identifier component. |
130 * | 102 * |
131 * Returns the empty string if there is no fragment identifier | 103 * Returns the empty string if there is no fragment identifier |
132 * component. | 104 * component. |
133 */ | 105 */ |
134 String get fragment => (_fragment == null) ? "" : _fragment; | 106 final String fragment; |
135 | 107 |
136 /** | 108 /** |
137 * Cache the computed return value of [pathSegements]. | 109 * Cache the computed return value of [pathSegements]. |
138 */ | 110 */ |
139 List<String> _pathSegments; | 111 List<String> _pathSegments; |
140 | 112 |
141 /** | 113 /** |
142 * Cache the computed return value of [queryParameters]. | 114 * Cache the computed return value of [queryParameters]. |
143 */ | 115 */ |
144 Map<String, String> _queryParameters; | 116 Map<String, String> _queryParameters; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 // | 175 // |
204 // query = *( pchar / "/" / "?" ) | 176 // query = *( pchar / "/" / "?" ) |
205 // | 177 // |
206 // fragment = *( pchar / "/" / "?" ) | 178 // fragment = *( pchar / "/" / "?" ) |
207 bool isRegName(int ch) { | 179 bool isRegName(int ch) { |
208 return ch < 128 && ((_regNameTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | 180 return ch < 128 && ((_regNameTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
209 } | 181 } |
210 const int EOI = -1; | 182 const int EOI = -1; |
211 | 183 |
212 String scheme = ""; | 184 String scheme = ""; |
| 185 String path; |
213 String userinfo = ""; | 186 String userinfo = ""; |
214 String host = null; | 187 String host = ""; |
215 int port = null; | 188 int port = 0; |
216 String path = null; | 189 String query = ""; |
217 String query = null; | 190 String fragment = ""; |
218 String fragment = null; | |
219 | 191 |
220 int index = 0; | 192 int index = 0; |
221 int pathStart = 0; | 193 int pathStart = 0; |
222 // End of input-marker. | 194 // End of input-marker. |
223 int char = EOI; | 195 int char = EOI; |
224 | 196 |
225 void parseAuth() { | 197 void parseAuth() { |
226 if (index == uri.length) { | 198 if (index == uri.length) { |
227 char = EOI; | 199 char = EOI; |
228 return; | 200 return; |
(...skipping 26 matching lines...) Expand all Loading... |
255 index++; | 227 index++; |
256 char = EOI; | 228 char = EOI; |
257 } | 229 } |
258 int hostStart = authStart; | 230 int hostStart = authStart; |
259 int hostEnd = index; | 231 int hostEnd = index; |
260 if (lastAt >= 0) { | 232 if (lastAt >= 0) { |
261 userinfo = _makeUserInfo(uri, authStart, lastAt); | 233 userinfo = _makeUserInfo(uri, authStart, lastAt); |
262 hostStart = lastAt + 1; | 234 hostStart = lastAt + 1; |
263 } | 235 } |
264 if (lastColon >= 0) { | 236 if (lastColon >= 0) { |
265 int portNumber; | 237 int portNumber = 0; |
266 if (lastColon + 1 < index) { | 238 for (int i = lastColon + 1; i < index; i++) { |
267 portNumber = 0; | 239 int digit = uri.codeUnitAt(i); |
268 for (int i = lastColon + 1; i < index; i++) { | 240 if (_ZERO > digit || _NINE < digit) { |
269 int digit = uri.codeUnitAt(i); | 241 _fail(uri, i, "Invalid port number"); |
270 if (_ZERO > digit || _NINE < digit) { | |
271 _fail(uri, i, "Invalid port number"); | |
272 } | |
273 portNumber = portNumber * 10 + (digit - _ZERO); | |
274 } | 242 } |
| 243 portNumber = portNumber * 10 + (digit - _ZERO); |
275 } | 244 } |
276 port = _makePort(portNumber, scheme); | 245 port = _makePort(portNumber, scheme); |
277 hostEnd = lastColon; | 246 hostEnd = lastColon; |
278 } | 247 } |
279 host = _makeHost(uri, hostStart, hostEnd, true); | 248 host = _makeHost(uri, hostStart, hostEnd, true); |
280 if (index < uri.length) { | 249 if (index < uri.length) { |
281 char = uri.codeUnitAt(index); | 250 char = uri.codeUnitAt(index); |
282 } | 251 } |
283 } | 252 } |
284 | 253 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 char = uri.codeUnitAt(index); | 333 char = uri.codeUnitAt(index); |
365 if (char == _QUESTION || char == _NUMBER_SIGN) { | 334 if (char == _QUESTION || char == _NUMBER_SIGN) { |
366 break; | 335 break; |
367 } | 336 } |
368 char = EOI; | 337 char = EOI; |
369 } | 338 } |
370 state = NOT_IN_PATH; | 339 state = NOT_IN_PATH; |
371 } | 340 } |
372 | 341 |
373 assert(state == NOT_IN_PATH); | 342 assert(state == NOT_IN_PATH); |
374 bool ensureLeadingSlash = (host != null || scheme == "file"); | 343 bool ensureLeadingSlash = (host != "" || scheme == "file"); |
375 path = _makePath(uri, pathStart, index, null, ensureLeadingSlash); | 344 path = _makePath(uri, pathStart, index, null, ensureLeadingSlash); |
376 | 345 |
377 if (char == _QUESTION) { | 346 if (char == _QUESTION) { |
378 int numberSignIndex = uri.indexOf('#', index + 1); | 347 int numberSignIndex = uri.indexOf('#', index + 1); |
379 if (numberSignIndex < 0) { | 348 if (numberSignIndex < 0) { |
380 query = _makeQuery(uri, index + 1, uri.length, null); | 349 query = _makeQuery(uri, index + 1, uri.length, null); |
381 } else { | 350 } else { |
382 query = _makeQuery(uri, index + 1, numberSignIndex, null); | 351 query = _makeQuery(uri, index + 1, numberSignIndex, null); |
383 fragment = _makeFragment(uri, numberSignIndex + 1, uri.length); | 352 fragment = _makeFragment(uri, numberSignIndex + 1, uri.length); |
384 } | 353 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 } | 390 } |
422 // Combine message, slice and a caret pointing to the error index. | 391 // Combine message, slice and a caret pointing to the error index. |
423 message = "$message$pre${uri.substring(min, max)}$post\n" | 392 message = "$message$pre${uri.substring(min, max)}$post\n" |
424 "${' ' * (pre.length + index - min)}^"; | 393 "${' ' * (pre.length + index - min)}^"; |
425 } | 394 } |
426 throw new FormatException(message); | 395 throw new FormatException(message); |
427 } | 396 } |
428 | 397 |
429 /// Internal non-verifying constructor. Only call with validated arguments. | 398 /// Internal non-verifying constructor. Only call with validated arguments. |
430 Uri._internal(this.scheme, | 399 Uri._internal(this.scheme, |
431 this._userInfo, | 400 this.userInfo, |
432 this._host, | 401 this._host, |
433 this._port, | 402 this._port, |
434 this._path, | 403 this._path, |
435 this._query, | 404 this.query, |
436 this._fragment); | 405 this.fragment); |
437 | 406 |
438 /** | 407 /** |
439 * Creates a new URI from its components. | 408 * Creates a new URI from its components. |
440 * | 409 * |
441 * Each component is set through a named argument. Any number of | 410 * Each component is set through a named argument. Any number of |
442 * components can be provided. The [path] and [query] components can be set | 411 * components can be provided. The default value for the components |
443 * using either of two different named arguments. | 412 * not provided is the empry string, except for [port] which has a |
| 413 * default value of 0. The [path] and [query] components can be set |
| 414 * using two different named arguments. |
444 * | 415 * |
445 * The scheme component is set through [scheme]. The scheme is | 416 * The scheme component is set through [scheme]. The scheme is |
446 * normalized to all lowercase letters. If the scheme is omitted or empty, | 417 * normalized to all lowercase letters. |
447 * the URI will not have a scheme part. | |
448 * | 418 * |
449 * The user info part of the authority component is set through | 419 * The user info part of the authority component is set through |
450 * [userInfo]. It defaults to the empty string, which will be omitted | 420 * [userInfo]. |
451 * from the string representation of the URI. | |
452 * | 421 * |
453 * The host part of the authority component is set through | 422 * The host part of the authority component is set through |
454 * [host]. The host can either be a hostname, an IPv4 address or an | 423 * [host]. The host can either be a hostname, an IPv4 address or an |
455 * IPv6 address, contained in '[' and ']'. If the host contains a | 424 * IPv6 address, contained in '[' and ']'. If the host contains a |
456 * ':' character, the '[' and ']' are added if not already provided. | 425 * ':' character, the '[' and ']' are added if not already provided. |
457 * The host is normalized to all lowercase letters. | 426 * The host is normalized to all lowercase letters. |
458 * | 427 * |
459 * The port part of the authority component is set through | 428 * The port part of the authority component is set through |
460 * [port]. | 429 * [port]. The port is normalized for scheme http and https where |
461 * If [port] is omitted or `null`, it implies the default port for | 430 * port 80 and port 443 respectively is set. |
462 * the URI's scheme, and is equivalent to passing that port explicitly. | |
463 * The recognized schemes, and their default ports, are "http" (80) and | |
464 * "https" (443). All other schemes are considered as having zero as the | |
465 * default port. | |
466 * | |
467 * If any of `userInfo`, `host` or `port` are provided, | |
468 * the URI will have an autority according to [hasAuthority]. | |
469 * | 431 * |
470 * The path component is set through either [path] or | 432 * The path component is set through either [path] or |
471 * [pathSegments]. When [path] is used, it should be a valid URI path, | 433 * [pathSegments]. When [path] is used, the provided string is |
472 * but invalid characters, except the general delimiters ':/@[]?#', | 434 * expected to be fully percent-encoded, and is used in its literal |
473 * will be escaped if necessary. | 435 * form. When [pathSegments] is used, each of the provided segments |
474 * When [pathSegments] is used, each of the provided segments | 436 * is percent-encoded and joined using the forward slash |
475 * is first percent-encoded and then joined using the forward slash | |
476 * separator. The percent-encoding of the path segments encodes all | 437 * separator. The percent-encoding of the path segments encodes all |
477 * characters except for the unreserved characters and the following | 438 * characters except for the unreserved characters and the following |
478 * list of characters: `!$&'()*+,;=:@`. If the other components | 439 * list of characters: `!$&'()*+,;=:@`. If the other components |
479 * calls for an absolute path a leading slash `/` is prepended if | 440 * calls for an absolute path a leading slash `/` is prepended if |
480 * not already there. | 441 * not already there. |
481 * | 442 * |
482 * The query component is set through either [query] or | 443 * The query component is set through either [query] or |
483 * [queryParameters]. When [query] is used the provided string should | 444 * [queryParameters]. When [query] is used the provided string is |
484 * be a valid URI query, but invalid characters other than general delimiters, | 445 * expected to be fully percent-encoded and is used in its literal |
485 * will be escaped if necessary. | 446 * form. When [queryParameters] is used the query is built from the |
486 * When [queryParameters] is used the query is built from the | |
487 * provided map. Each key and value in the map is percent-encoded | 447 * provided map. Each key and value in the map is percent-encoded |
488 * and joined using equal and ampersand characters. The | 448 * and joined using equal and ampersand characters. The |
489 * percent-encoding of the keys and values encodes all characters | 449 * percent-encoding of the keys and values encodes all characters |
490 * except for the unreserved characters. | 450 * except for the unreserved characters. |
491 * If both `query` and `queryParameters` are omitted or `null`, the | |
492 * URI will have no query part. | |
493 * | 451 * |
494 * The fragment component is set through [fragment]. | 452 * The fragment component is set through [fragment]. |
495 * It should be a valid URI fragment, but invalid characters other than | |
496 * general delimiters, will be escaped if necessary. | |
497 * If `fragment` is omitted or `null`, the URI will have no fragment part. | |
498 */ | 453 */ |
499 factory Uri({String scheme : "", | 454 factory Uri({String scheme, |
500 String userInfo : "", | 455 String userInfo: "", |
501 String host, | 456 String host: "", |
502 int port, | 457 port: 0, |
503 String path, | 458 String path, |
504 Iterable<String> pathSegments, | 459 Iterable<String> pathSegments, |
505 String query, | 460 String query, |
506 Map<String, String> queryParameters, | 461 Map<String, String> queryParameters, |
507 fragment}) { | 462 fragment: ""}) { |
508 scheme = _makeScheme(scheme, _stringOrNullLength(scheme)); | 463 scheme = _makeScheme(scheme, _stringOrNullLength(scheme)); |
509 userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo)); | 464 userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo)); |
510 host = _makeHost(host, 0, _stringOrNullLength(host), false); | 465 host = _makeHost(host, 0, _stringOrNullLength(host), false); |
511 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); | 466 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); |
512 fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment)); | 467 fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment)); |
513 port = _makePort(port, scheme); | 468 port = _makePort(port, scheme); |
514 bool isFile = (scheme == "file"); | 469 bool ensureLeadingSlash = (host != "" || scheme == "file"); |
515 if (host == null && | |
516 (userInfo.isNotEmpty || port != null || isFile)) { | |
517 host = ""; | |
518 } | |
519 bool ensureLeadingSlash = (host != null || isFile); | |
520 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, | 470 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, |
521 ensureLeadingSlash); | 471 ensureLeadingSlash); |
522 | 472 |
523 return new Uri._internal(scheme, userInfo, host, port, | 473 return new Uri._internal(scheme, userInfo, host, port, |
524 path, query, fragment); | 474 path, query, fragment); |
525 } | 475 } |
526 | 476 |
527 /** | 477 /** |
528 * Creates a new `http` URI from authority, path and query. | 478 * Creates a new `http` URI from authority, path and query. |
529 * | 479 * |
530 * Examples: | 480 * Examples: |
531 * | 481 * |
532 * ``` | 482 * ``` |
533 * // http://example.org/path?q=dart. | 483 * // http://example.org/path?q=dart. |
534 * new Uri.http("google.com", "/search", { "q" : "dart" }); | 484 * new Uri.http("google.com", "/search", { "q" : "dart" }); |
535 * | 485 * |
536 * // http://user:pass@localhost:8080 | 486 * // http://user:pass@localhost:8080 |
537 * new Uri.http("user:pass@localhost:8080", ""); | 487 * new Uri.http("user:pass@localhost:8080", ""); |
538 * | 488 * |
539 * // http://example.org/a%20b | 489 * // http://example.org/a%20b |
540 * new Uri.http("example.org", "a b"); | 490 * new Uri.http("example.org", "a b"); |
541 * | 491 * |
542 * // http://example.org/a%252F | 492 * // http://example.org/a%252F |
543 * new Uri.http("example.org", "/a%2F"); | 493 * new Uri.http("example.org", "/a%2F"); |
544 * ``` | 494 * ``` |
545 * | 495 * |
546 * The `scheme` is always set to `http`. | 496 * The `scheme` is always set to `http`. |
547 * | 497 * |
548 * The `userInfo`, `host` and `port` components are set from the | 498 * The `userInfo`, `host` and `port` components are set from the |
549 * [authority] argument. If `authority` is `null` or empty, | 499 * [authority] argument. |
550 * the created `Uri` will have no authority, and will not be directly usable | |
551 * as an HTTP URL, which must have a non-empty host. | |
552 * | 500 * |
553 * The `path` component is set from the [unencodedPath] | 501 * The `path` component is set from the [unencodedPath] |
554 * argument. The path passed must not be encoded as this constructor | 502 * argument. The path passed must not be encoded as this constructor |
555 * encodes the path. | 503 * encodes the path. |
556 * | 504 * |
557 * The `query` component is set from the optional [queryParameters] | 505 * The `query` component is set from the optional [queryParameters] |
558 * argument. | 506 * argument. |
559 */ | 507 */ |
560 factory Uri.http(String authority, | 508 factory Uri.http(String authority, |
561 String unencodedPath, | 509 String unencodedPath, |
(...skipping 10 matching lines...) Expand all Loading... |
572 factory Uri.https(String authority, | 520 factory Uri.https(String authority, |
573 String unencodedPath, | 521 String unencodedPath, |
574 [Map<String, String> queryParameters]) { | 522 [Map<String, String> queryParameters]) { |
575 return _makeHttpUri("https", authority, unencodedPath, queryParameters); | 523 return _makeHttpUri("https", authority, unencodedPath, queryParameters); |
576 } | 524 } |
577 | 525 |
578 static Uri _makeHttpUri(String scheme, | 526 static Uri _makeHttpUri(String scheme, |
579 String authority, | 527 String authority, |
580 String unencodedPath, | 528 String unencodedPath, |
581 Map<String, String> queryParameters) { | 529 Map<String, String> queryParameters) { |
582 var userInfo = null; | 530 var userInfo = ""; |
583 var host = null; | 531 var host = ""; |
584 var port = null; | 532 var port = 0; |
585 | 533 |
586 if (authority != null && authority.isNotEmpty) { | 534 var hostStart = 0; |
587 var hostStart = 0; | 535 // Split off the user info. |
588 // Split off the user info. | 536 bool hasUserInfo = false; |
589 bool hasUserInfo = false; | 537 for (int i = 0; i < authority.length; i++) { |
590 for (int i = 0; i < authority.length; i++) { | 538 if (authority.codeUnitAt(i) == _AT_SIGN) { |
591 if (authority.codeUnitAt(i) == _AT_SIGN) { | 539 hasUserInfo = true; |
592 hasUserInfo = true; | 540 userInfo = authority.substring(0, i); |
593 userInfo = authority.substring(0, i); | 541 hostStart = i + 1; |
594 hostStart = i + 1; | 542 break; |
595 break; | |
596 } | |
597 } | 543 } |
598 var hostEnd = hostStart; | 544 } |
599 if (hostStart < authority.length && | 545 var hostEnd = hostStart; |
600 authority.codeUnitAt(hostStart) == _LEFT_BRACKET) { | 546 if (hostStart < authority.length && |
601 // IPv6 host. | 547 authority.codeUnitAt(hostStart) == _LEFT_BRACKET) { |
602 for (; hostEnd < authority.length; hostEnd++) { | 548 // IPv6 host. |
603 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; | 549 for (; hostEnd < authority.length; hostEnd++) { |
604 } | 550 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; |
605 if (hostEnd == authority.length) { | |
606 throw new FormatException("Invalid IPv6 host entry."); | |
607 } | |
608 parseIPv6Address(authority, hostStart + 1, hostEnd); | |
609 hostEnd++; // Skip the closing bracket. | |
610 if (hostEnd != authority.length && | |
611 authority.codeUnitAt(hostEnd) != _COLON) { | |
612 throw new FormatException("Invalid end of authority"); | |
613 } | |
614 } | 551 } |
615 // Split host and port. | 552 if (hostEnd == authority.length) { |
616 bool hasPort = false; | 553 throw new FormatException("Invalid IPv6 host entry."); |
617 for (; hostEnd < authority.length; hostEnd++) { | |
618 if (authority.codeUnitAt(hostEnd) == _COLON) { | |
619 var portString = authority.substring(hostEnd + 1); | |
620 // We allow the empty port - falling back to initial value. | |
621 if (portString.isNotEmpty) port = int.parse(portString); | |
622 break; | |
623 } | |
624 } | 554 } |
625 host = authority.substring(hostStart, hostEnd); | 555 parseIPv6Address(authority, hostStart + 1, hostEnd); |
| 556 hostEnd++; // Skip the closing bracket. |
| 557 if (hostEnd != authority.length && |
| 558 authority.codeUnitAt(hostEnd) != _COLON) { |
| 559 throw new FormatException("Invalid end of authority"); |
| 560 } |
626 } | 561 } |
| 562 // Split host and port. |
| 563 bool hasPort = false; |
| 564 for (; hostEnd < authority.length; hostEnd++) { |
| 565 if (authority.codeUnitAt(hostEnd) == _COLON) { |
| 566 var portString = authority.substring(hostEnd + 1); |
| 567 // We allow the empty port - falling back to initial value. |
| 568 if (portString.isNotEmpty) port = int.parse(portString); |
| 569 break; |
| 570 } |
| 571 } |
| 572 host = authority.substring(hostStart, hostEnd); |
| 573 |
627 return new Uri(scheme: scheme, | 574 return new Uri(scheme: scheme, |
628 userInfo: userInfo, | 575 userInfo: userInfo, |
629 host: host, | 576 host: host, |
630 port: port, | 577 port: port, |
631 pathSegments: unencodedPath.split("/"), | 578 pathSegments: unencodedPath.split("/"), |
632 queryParameters: queryParameters); | 579 queryParameters: queryParameters); |
633 } | 580 } |
634 | 581 |
635 /** | 582 /** |
636 * Creates a new file URI from an absolute or relative file path. | 583 * Creates a new file URI from an absolute or relative file path. |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
767 throw new ArgumentError("Illegal drive letter " + | 714 throw new ArgumentError("Illegal drive letter " + |
768 new String.fromCharCode(charCode)); | 715 new String.fromCharCode(charCode)); |
769 } else { | 716 } else { |
770 throw new UnsupportedError("Illegal drive letter " + | 717 throw new UnsupportedError("Illegal drive letter " + |
771 new String.fromCharCode(charCode)); | 718 new String.fromCharCode(charCode)); |
772 } | 719 } |
773 } | 720 } |
774 | 721 |
775 static _makeFileUri(String path) { | 722 static _makeFileUri(String path) { |
776 String sep = "/"; | 723 String sep = "/"; |
777 if (path.startsWith(sep)) { | 724 if (path.length > 0 && path[0] == sep) { |
778 // Absolute file:// URI. | 725 // Absolute file:// URI. |
779 return new Uri(scheme: "file", pathSegments: path.split(sep)); | 726 return new Uri(scheme: "file", pathSegments: path.split(sep)); |
780 } else { | 727 } else { |
781 // Relative URI. | 728 // Relative URI. |
782 return new Uri(pathSegments: path.split(sep)); | 729 return new Uri(pathSegments: path.split(sep)); |
783 } | 730 } |
784 } | 731 } |
785 | 732 |
786 static _makeWindowsFileUrl(String path) { | 733 static _makeWindowsFileUrl(String path) { |
787 if (path.startsWith("\\\\?\\")) { | 734 if (path.startsWith("\\\\?\\")) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
876 */ | 823 */ |
877 Map<String, String> get queryParameters { | 824 Map<String, String> get queryParameters { |
878 if (_queryParameters == null) { | 825 if (_queryParameters == null) { |
879 _queryParameters = new UnmodifiableMapView(splitQueryString(query)); | 826 _queryParameters = new UnmodifiableMapView(splitQueryString(query)); |
880 } | 827 } |
881 return _queryParameters; | 828 return _queryParameters; |
882 } | 829 } |
883 | 830 |
884 static int _makePort(int port, String scheme) { | 831 static int _makePort(int port, String scheme) { |
885 // Perform scheme specific normalization. | 832 // Perform scheme specific normalization. |
886 if (port != null && port == _defaultPort(scheme)) return null; | 833 if (port == 80 && scheme == "http") { |
| 834 return 0; |
| 835 } |
| 836 if (port == 443 && scheme == "https") { |
| 837 return 0; |
| 838 } |
887 return port; | 839 return port; |
888 } | 840 } |
889 | 841 |
890 /** | 842 /** |
891 * Check and normalize a most name. | 843 * Check and normalize a most name. |
892 * | 844 * |
893 * If the host name starts and ends with '[' and ']', it is considered an | 845 * If the host name starts and ends with '[' and ']', it is considered an |
894 * IPv6 address. If [strictIPv6] is false, the address is also considered | 846 * IPv6 address. If [strictIPv6] is false, the address is also considered |
895 * an IPv6 address if it contains any ':' character. | 847 * an IPv6 address if it contains any ':' character. |
896 * | 848 * |
897 * If it is not an IPv6 address, it is case- and escape-normalized. | 849 * If it is not an IPv6 address, it is case- and escape-normalized. |
898 * This escapes all characters not valid in a reg-name, | 850 * This escapes all characters not valid in a reg-name, |
899 * and converts all non-escape upper-case letters to lower-case. | 851 * and converts all non-escape upper-case letters to lower-case. |
900 */ | 852 */ |
901 static String _makeHost(String host, int start, int end, bool strictIPv6) { | 853 static String _makeHost(String host, int start, int end, bool strictIPv6) { |
902 // TODO(lrn): Should we normalize IPv6 addresses according to RFC 5952? | 854 // TODO(lrn): Should we normalize IPv6 addresses according to RFC 5952? |
| 855 |
903 if (host == null) return null; | 856 if (host == null) return null; |
904 if (start == end) return ""; | 857 if (start == end) return ""; |
905 // Host is an IPv6 address if it starts with '[' or contains a colon. | 858 // Host is an IPv6 address if it starts with '[' or contains a colon. |
906 if (host.codeUnitAt(start) == _LEFT_BRACKET) { | 859 if (host.codeUnitAt(start) == _LEFT_BRACKET) { |
907 if (host.codeUnitAt(end - 1) != _RIGHT_BRACKET) { | 860 if (host.codeUnitAt(end - 1) != _RIGHT_BRACKET) { |
908 _fail(host, start, 'Missing end `]` to match `[` in host'); | 861 _fail(host, start, 'Missing end `]` to match `[` in host'); |
909 } | 862 } |
910 parseIPv6Address(host, start + 1, end - 1); | 863 parseIPv6Address(host, start + 1, end - 1); |
911 // RFC 5952 requires hex digits to be lower case. | 864 // RFC 5952 requires hex digits to be lower case. |
912 return host.substring(start, end).toLowerCase(); | 865 return host.substring(start, end).toLowerCase(); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 if (_LOWER_CASE_A <= char && _LOWER_CASE_Z >= char) { | 978 if (_LOWER_CASE_A <= char && _LOWER_CASE_Z >= char) { |
1026 allLowercase = false; | 979 allLowercase = false; |
1027 } | 980 } |
1028 } | 981 } |
1029 scheme = scheme.substring(0, end); | 982 scheme = scheme.substring(0, end); |
1030 if (!allLowercase) scheme = scheme.toLowerCase(); | 983 if (!allLowercase) scheme = scheme.toLowerCase(); |
1031 return scheme; | 984 return scheme; |
1032 } | 985 } |
1033 | 986 |
1034 static String _makeUserInfo(String userInfo, int start, int end) { | 987 static String _makeUserInfo(String userInfo, int start, int end) { |
1035 if (userInfo == null) return ""; | 988 if (userInfo == null) return "null"; |
1036 return _normalize(userInfo, start, end, _userinfoTable); | 989 return _normalize(userInfo, start, end, _userinfoTable); |
1037 } | 990 } |
1038 | 991 |
1039 static String _makePath(String path, int start, int end, | 992 static String _makePath(String path, int start, int end, |
1040 Iterable<String> pathSegments, | 993 Iterable<String> pathSegments, |
1041 bool ensureLeadingSlash) { | 994 bool ensureLeadingSlash) { |
1042 if (path == null && pathSegments == null) return ""; | 995 if (path == null && pathSegments == null) return ""; |
1043 if (path != null && pathSegments != null) { | 996 if (path != null && pathSegments != null) { |
1044 throw new ArgumentError('Both path and pathSegments specified'); | 997 throw new ArgumentError('Both path and pathSegments specified'); |
1045 } | 998 } |
1046 var result; | 999 var result; |
1047 if (path != null) { | 1000 if (path != null) { |
1048 result = _normalize(path, start, end, _pathCharOrSlashTable); | 1001 result = _normalize(path, start, end, _pathCharOrSlashTable); |
1049 } else { | 1002 } else { |
1050 result = pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/"); | 1003 result = pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/"); |
1051 } | 1004 } |
1052 if (ensureLeadingSlash && result.isNotEmpty && !result.startsWith("/")) { | 1005 if (ensureLeadingSlash && result.isNotEmpty && !result.startsWith("/")) { |
1053 return "/$result"; | 1006 return "/$result"; |
1054 } | 1007 } |
1055 return result; | 1008 return result; |
1056 } | 1009 } |
1057 | 1010 |
1058 static String _makeQuery(String query, int start, int end, | 1011 static String _makeQuery(String query, int start, int end, |
1059 Map<String, String> queryParameters) { | 1012 Map<String, String> queryParameters) { |
1060 if (query == null && queryParameters == null) return null; | 1013 if (query == null && queryParameters == null) return ""; |
1061 if (query != null && queryParameters != null) { | 1014 if (query != null && queryParameters != null) { |
1062 throw new ArgumentError('Both query and queryParameters specified'); | 1015 throw new ArgumentError('Both query and queryParameters specified'); |
1063 } | 1016 } |
1064 if (query != null) return _normalize(query, start, end, _queryCharTable); | 1017 if (query != null) return _normalize(query, start, end, _queryCharTable); |
1065 | 1018 |
1066 var result = new StringBuffer(); | 1019 var result = new StringBuffer(); |
1067 var first = true; | 1020 var first = true; |
1068 queryParameters.forEach((key, value) { | 1021 queryParameters.forEach((key, value) { |
1069 if (!first) { | 1022 if (!first) { |
1070 result.write("&"); | 1023 result.write("&"); |
1071 } | 1024 } |
1072 first = false; | 1025 first = false; |
1073 result.write(Uri.encodeQueryComponent(key)); | 1026 result.write(Uri.encodeQueryComponent(key)); |
1074 if (value != null && !value.isEmpty) { | 1027 if (value != null && !value.isEmpty) { |
1075 result.write("="); | 1028 result.write("="); |
1076 result.write(Uri.encodeQueryComponent(value)); | 1029 result.write(Uri.encodeQueryComponent(value)); |
1077 } | 1030 } |
1078 }); | 1031 }); |
1079 return result.toString(); | 1032 return result.toString(); |
1080 } | 1033 } |
1081 | 1034 |
1082 static String _makeFragment(String fragment, int start, int end) { | 1035 static String _makeFragment(String fragment, int start, int end) { |
1083 if (fragment == null) return null; | 1036 if (fragment == null) return ""; |
1084 return _normalize(fragment, start, end, _queryCharTable); | 1037 return _normalize(fragment, start, end, _queryCharTable); |
1085 } | 1038 } |
1086 | 1039 |
1087 static int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; | 1040 static int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; |
1088 | 1041 |
1089 static bool _isHexDigit(int char) { | 1042 static bool _isHexDigit(int char) { |
1090 if (_NINE >= char) return _ZERO <= char; | 1043 if (_NINE >= char) return _ZERO <= char; |
1091 char |= 0x20; | 1044 char |= 0x20; |
1092 return _LOWER_CASE_A <= char && _LOWER_CASE_F >= char; | 1045 return _LOWER_CASE_A <= char && _LOWER_CASE_F >= char; |
1093 } | 1046 } |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 * (http://tools.ietf.org/html/rfc3986#section-5 "RFC-1123"). | 1271 * (http://tools.ietf.org/html/rfc3986#section-5 "RFC-1123"). |
1319 */ | 1272 */ |
1320 Uri resolveUri(Uri reference) { | 1273 Uri resolveUri(Uri reference) { |
1321 // From RFC 3986. | 1274 // From RFC 3986. |
1322 String targetScheme; | 1275 String targetScheme; |
1323 String targetUserInfo; | 1276 String targetUserInfo; |
1324 String targetHost; | 1277 String targetHost; |
1325 int targetPort; | 1278 int targetPort; |
1326 String targetPath; | 1279 String targetPath; |
1327 String targetQuery; | 1280 String targetQuery; |
1328 if (reference.scheme.isNotEmpty) { | 1281 if (reference.scheme != "") { |
1329 targetScheme = reference.scheme; | 1282 targetScheme = reference.scheme; |
| 1283 targetUserInfo = reference.userInfo; |
| 1284 targetHost = reference.host; |
| 1285 targetPort = reference.port; |
| 1286 targetPath = _removeDotSegments(reference.path); |
| 1287 targetQuery = reference.query; |
| 1288 } else { |
1330 if (reference.hasAuthority) { | 1289 if (reference.hasAuthority) { |
1331 targetUserInfo = reference.userInfo; | 1290 targetUserInfo = reference.userInfo; |
1332 targetHost = reference.host; | 1291 targetHost = reference.host; |
1333 targetPort = reference.hasPort ? reference.port : null; | 1292 targetPort = reference.port; |
1334 } | 1293 targetPath = _removeDotSegments(reference.path); |
1335 targetPath = _removeDotSegments(reference.path); | |
1336 if (reference.hasQuery) { | |
1337 targetQuery = reference.query; | 1294 targetQuery = reference.query; |
1338 } | |
1339 } else { | |
1340 targetScheme = this.scheme; | |
1341 if (reference.hasAuthority) { | |
1342 targetUserInfo = reference.userInfo; | |
1343 targetHost = reference.host; | |
1344 targetPort = _makePort(reference.hasPort ? reference.port : null, | |
1345 targetScheme); | |
1346 targetPath = _removeDotSegments(reference.path); | |
1347 if (reference.hasQuery) targetQuery = reference.query; | |
1348 } else { | 1295 } else { |
1349 if (reference.path == "") { | 1296 if (reference.path == "") { |
1350 targetPath = this._path; | 1297 targetPath = this.path; |
1351 if (reference.hasQuery) { | 1298 if (reference.query != "") { |
1352 targetQuery = reference.query; | 1299 targetQuery = reference.query; |
1353 } else { | 1300 } else { |
1354 targetQuery = this._query; | 1301 targetQuery = this.query; |
1355 } | 1302 } |
1356 } else { | 1303 } else { |
1357 if (reference.path.startsWith("/")) { | 1304 if (reference.path.startsWith("/")) { |
1358 targetPath = _removeDotSegments(reference.path); | 1305 targetPath = _removeDotSegments(reference.path); |
1359 } else { | 1306 } else { |
1360 targetPath = _removeDotSegments(_merge(this._path, reference.path)); | 1307 targetPath = _removeDotSegments(_merge(this.path, reference.path)); |
1361 } | 1308 } |
1362 if (reference.hasQuery) targetQuery = reference.query; | 1309 targetQuery = reference.query; |
1363 } | 1310 } |
1364 targetUserInfo = this._userInfo; | 1311 targetUserInfo = this.userInfo; |
1365 targetHost = this._host; | 1312 targetHost = this.host; |
1366 targetPort = this._port; | 1313 targetPort = this.port; |
1367 } | 1314 } |
| 1315 targetScheme = this.scheme; |
1368 } | 1316 } |
1369 String fragment = reference.hasFragment ? reference.fragment : null; | 1317 return new Uri(scheme: targetScheme, |
1370 return new Uri._internal(targetScheme, | 1318 userInfo: targetUserInfo, |
1371 targetUserInfo, | 1319 host: targetHost, |
1372 targetHost, | 1320 port: targetPort, |
1373 targetPort, | 1321 path: targetPath, |
1374 targetPath, | 1322 query: targetQuery, |
1375 targetQuery, | 1323 fragment: reference.fragment); |
1376 fragment); | |
1377 } | 1324 } |
1378 | 1325 |
1379 /** | 1326 /** |
1380 * Returns whether the URI has an [authority] component. | 1327 * Returns whether the URI has an [authority] component. |
1381 */ | 1328 */ |
1382 bool get hasAuthority => _host != null; | 1329 bool get hasAuthority => host != ""; |
1383 | |
1384 /** | |
1385 * Returns whether the URI has an explicit port. | |
1386 * | |
1387 * If the port number is the default port number | |
1388 * (zero for unrecognized schemes, with http (80) and https (443) being | |
1389 * recognized), | |
1390 * then the port is made implicit and omitted from the URI. | |
1391 */ | |
1392 bool get hasPort => _port != null; | |
1393 | |
1394 /** | |
1395 * Returns whether the URI has a query part. | |
1396 */ | |
1397 bool get hasQuery => _query != null; | |
1398 | |
1399 /** | |
1400 * Returns whether the URI has a fragment part. | |
1401 */ | |
1402 bool get hasFragment => _fragment != null; | |
1403 | 1330 |
1404 /** | 1331 /** |
1405 * Returns the origin of the URI in the form scheme://host:port for the | 1332 * Returns the origin of the URI in the form scheme://host:port for the |
1406 * schemes http and https. | 1333 * schemes http and https. |
1407 * | 1334 * |
1408 * It is an error if the scheme is not "http" or "https". | 1335 * It is an error if the scheme is not "http" or "https". |
1409 * | 1336 * |
1410 * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin | 1337 * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin |
1411 */ | 1338 */ |
1412 String get origin { | 1339 String get origin { |
1413 if (scheme == "" || _host == null || _host == "") { | 1340 if (scheme == "" || _host == null || _host == "") { |
1414 throw new StateError("Cannot use origin without a scheme: $this"); | 1341 throw new StateError("Cannot use origin without a scheme: $this"); |
1415 } | 1342 } |
1416 if (scheme != "http" && scheme != "https") { | 1343 if (scheme != "http" && scheme != "https") { |
1417 throw new StateError( | 1344 throw new StateError( |
1418 "Origin is only applicable schemes http and https: $this"); | 1345 "Origin is only applicable schemes http and https: $this"); |
1419 } | 1346 } |
1420 if (_port == null) return "$scheme://$_host"; | 1347 if (_port == 0) return "$scheme://$_host"; |
1421 return "$scheme://$_host:$_port"; | 1348 return "$scheme://$_host:$_port"; |
1422 } | 1349 } |
1423 | 1350 |
1424 /** | 1351 /** |
1425 * Returns the file path from a file URI. | 1352 * Returns the file path from a file URI. |
1426 * | 1353 * |
1427 * The returned path has either Windows or non-Windows | 1354 * The returned path has either Windows or non-Windows |
1428 * semantics. | 1355 * semantics. |
1429 * | 1356 * |
1430 * For non-Windows semantics the slash ("/") is used to separate | 1357 * For non-Windows semantics the slash ("/") is used to separate |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1537 if (hasDriveLetter && segments.length == 1) result.write("\\"); | 1464 if (hasDriveLetter && segments.length == 1) result.write("\\"); |
1538 return result.toString(); | 1465 return result.toString(); |
1539 } | 1466 } |
1540 | 1467 |
1541 bool get _isPathAbsolute { | 1468 bool get _isPathAbsolute { |
1542 if (path == null || path.isEmpty) return false; | 1469 if (path == null || path.isEmpty) return false; |
1543 return path.startsWith('/'); | 1470 return path.startsWith('/'); |
1544 } | 1471 } |
1545 | 1472 |
1546 void _writeAuthority(StringSink ss) { | 1473 void _writeAuthority(StringSink ss) { |
1547 if (_userInfo.isNotEmpty) { | 1474 _addIfNonEmpty(ss, userInfo, userInfo, "@"); |
1548 ss.write(_userInfo); | 1475 ss.write(_host == null ? "null" : _host); |
1549 ss.write("@"); | 1476 if (_port != 0) { |
1550 } | |
1551 if (_host != null) ss.write(_host); | |
1552 if (_port != null) { | |
1553 ss.write(":"); | 1477 ss.write(":"); |
1554 ss.write(_port); | 1478 ss.write(_port.toString()); |
1555 } | 1479 } |
1556 } | 1480 } |
1557 | 1481 |
1558 String toString() { | 1482 String toString() { |
1559 StringBuffer sb = new StringBuffer(); | 1483 StringBuffer sb = new StringBuffer(); |
1560 _addIfNonEmpty(sb, scheme, scheme, ':'); | 1484 _addIfNonEmpty(sb, scheme, scheme, ':'); |
1561 if (hasAuthority || path.startsWith("//") || (scheme == "file")) { | 1485 if (hasAuthority || path.startsWith("//") || (scheme == "file")) { |
1562 // File URIS always have the authority, even if it is empty. | 1486 // File URIS always have the authority, even if it is empty. |
1563 // The empty URI means "localhost". | 1487 // The empty URI means "localhost". |
1564 sb.write("//"); | 1488 sb.write("//"); |
1565 _writeAuthority(sb); | 1489 _writeAuthority(sb); |
1566 } | 1490 } |
1567 sb.write(path); | 1491 sb.write(path); |
1568 if (_query != null) { sb..write("?")..write(_query); } | 1492 _addIfNonEmpty(sb, query, "?", query); |
1569 if (_fragment != null) { sb..write("#")..write(_fragment); } | 1493 _addIfNonEmpty(sb, fragment, "#", fragment); |
1570 return sb.toString(); | 1494 return sb.toString(); |
1571 } | 1495 } |
1572 | 1496 |
1573 bool operator==(other) { | 1497 bool operator==(other) { |
1574 if (other is! Uri) return false; | 1498 if (other is! Uri) return false; |
1575 Uri uri = other; | 1499 Uri uri = other; |
1576 return scheme == uri.scheme && | 1500 return scheme == uri.scheme && |
1577 userInfo == uri.userInfo && | 1501 userInfo == uri.userInfo && |
1578 host == uri.host && | 1502 host == uri.host && |
1579 port == uri.port && | 1503 port == uri.port && |
(...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2271 0xafff, // 0x30 - 0x3f 1111111111110101 | 2195 0xafff, // 0x30 - 0x3f 1111111111110101 |
2272 // @ABCDEFGHIJKLMNO | 2196 // @ABCDEFGHIJKLMNO |
2273 0xffff, // 0x40 - 0x4f 1111111111111111 | 2197 0xffff, // 0x40 - 0x4f 1111111111111111 |
2274 // PQRSTUVWXYZ _ | 2198 // PQRSTUVWXYZ _ |
2275 0x87ff, // 0x50 - 0x5f 1111111111100001 | 2199 0x87ff, // 0x50 - 0x5f 1111111111100001 |
2276 // abcdefghijklmno | 2200 // abcdefghijklmno |
2277 0xfffe, // 0x60 - 0x6f 0111111111111111 | 2201 0xfffe, // 0x60 - 0x6f 0111111111111111 |
2278 // pqrstuvwxyz ~ | 2202 // pqrstuvwxyz ~ |
2279 0x47ff]; // 0x70 - 0x7f 1111111111100010 | 2203 0x47ff]; // 0x70 - 0x7f 1111111111100010 |
2280 } | 2204 } |
OLD | NEW |