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