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:** |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 141 * When [queryParameters] is used the query is built from the | 141 * When [queryParameters] is used the query is built from the |
| 142 * provided map. Each key and value in the map is percent-encoded | 142 * provided map. Each key and value in the map is percent-encoded |
| 143 * and joined using equal and ampersand characters. | 143 * and joined using equal and ampersand characters. |
| 144 * A value in the map must be either a string, or an [Iterable] of strings, | 144 * A value in the map must be either a string, or an [Iterable] of strings, |
| 145 * where the latter corresponds to multiple values for the same key. | 145 * where the latter corresponds to multiple values for the same key. |
| 146 * | 146 * |
| 147 * The percent-encoding of the keys and values encodes all characters | 147 * The percent-encoding of the keys and values encodes all characters |
| 148 * except for the unreserved characters, and replaces spaces with `+`. | 148 * except for the unreserved characters, and replaces spaces with `+`. |
| 149 * If `query` is the empty string, it is equivalent to omitting it. | 149 * If `query` is the empty string, it is equivalent to omitting it. |
| 150 * To have an actual empty query part, | 150 * To have an actual empty query part, |
| 151 * use an empty list for `queryParameters`. | 151 * use an empty list for `queryParameters`. |
|
Lasse Reichstein Nielsen
2016/04/16 09:58:22
empty map?
floitsch
2016/04/19 15:36:39
Done.
| |
| 152 * | 152 * |
| 153 * If both `query` and `queryParameters` are omitted or `null`, | 153 * If both `query` and `queryParameters` are omitted or `null`, |
| 154 * the URI has no query part. | 154 * the URI has no query part. |
| 155 * | 155 * |
| 156 * The fragment component is set through [fragment]. | 156 * The fragment component is set through [fragment]. |
| 157 * It should be a valid URI fragment, but invalid characters other than | 157 * It should be a valid URI fragment, but invalid characters other than |
| 158 * general delimiters, are escaped if necessary. | 158 * general delimiters, are escaped if necessary. |
| 159 * If `fragment` is omitted or `null`, the URI has no fragment part. | 159 * If `fragment` is omitted or `null`, the URI has no fragment part. |
| 160 */ | 160 */ |
| 161 factory Uri({String scheme : "", | 161 factory Uri({String scheme : "", |
| 162 String userInfo : "", | 162 String userInfo : "", |
| 163 String host, | 163 String host, |
| 164 int port, | 164 int port, |
| 165 String path, | 165 String path, |
| 166 Iterable<String> pathSegments, | 166 Iterable<String> pathSegments, |
| 167 String query, | 167 String query, |
| 168 Map<String, dynamic> queryParameters, | 168 Map<String, dynamic/*String|Iterable<String>*/> queryParameters, |
| 169 String fragment}) { | 169 String fragment}) { |
| 170 scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme)); | 170 scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme)); |
| 171 userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo)); | 171 userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo)); |
| 172 host = _makeHost(host, 0, _stringOrNullLength(host), false); | 172 host = _makeHost(host, 0, _stringOrNullLength(host), false); |
| 173 // Special case this constructor for backwards compatibility. | 173 // Special case this constructor for backwards compatibility. |
| 174 if (query == "") query = null; | 174 if (query == "") query = null; |
| 175 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); | 175 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); |
| 176 fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment)); | 176 fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment)); |
| 177 port = _makePort(port, scheme); | 177 port = _makePort(port, scheme); |
| 178 bool isFile = (scheme == "file"); | 178 bool isFile = (scheme == "file"); |
| (...skipping 824 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1003 * call above, but may also be slightly faster because the parts taken | 1003 * call above, but may also be slightly faster because the parts taken |
| 1004 * from this `Uri` need not be checked for validity again. | 1004 * from this `Uri` need not be checked for validity again. |
| 1005 */ | 1005 */ |
| 1006 Uri replace({String scheme, | 1006 Uri replace({String scheme, |
| 1007 String userInfo, | 1007 String userInfo, |
| 1008 String host, | 1008 String host, |
| 1009 int port, | 1009 int port, |
| 1010 String path, | 1010 String path, |
| 1011 Iterable<String> pathSegments, | 1011 Iterable<String> pathSegments, |
| 1012 String query, | 1012 String query, |
| 1013 Map<String, String> queryParameters, | 1013 Map<String, dynamic/*String|Iterable<String>*/> queryParameters, |
| 1014 String fragment}) { | 1014 String fragment}) { |
| 1015 // Set to true if the scheme has (potentially) changed. | 1015 // Set to true if the scheme has (potentially) changed. |
| 1016 // In that case, the default port may also have changed and we need | 1016 // In that case, the default port may also have changed and we need |
| 1017 // to check even the existing port. | 1017 // to check even the existing port. |
| 1018 bool schemeChanged = false; | 1018 bool schemeChanged = false; |
| 1019 if (scheme != null) { | 1019 if (scheme != null) { |
| 1020 scheme = _makeScheme(scheme, 0, scheme.length); | 1020 scheme = _makeScheme(scheme, 0, scheme.length); |
| 1021 schemeChanged = true; | 1021 schemeChanged = true; |
| 1022 } else { | 1022 } else { |
| 1023 scheme = this.scheme; | 1023 scheme = this.scheme; |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1366 /// If the URI has neither scheme nor authority, it's considered a | 1366 /// If the URI has neither scheme nor authority, it's considered a |
| 1367 /// "pure path" and normalization won't remove leading ".." segments. | 1367 /// "pure path" and normalization won't remove leading ".." segments. |
| 1368 /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm. | 1368 /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm. |
| 1369 static String _normalizePath(String path, String scheme, bool hasAuthority) { | 1369 static String _normalizePath(String path, String scheme, bool hasAuthority) { |
| 1370 if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) { | 1370 if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) { |
| 1371 return _normalizeRelativePath(path); | 1371 return _normalizeRelativePath(path); |
| 1372 } | 1372 } |
| 1373 return _removeDotSegments(path); | 1373 return _removeDotSegments(path); |
| 1374 } | 1374 } |
| 1375 | 1375 |
| 1376 static String _makeQuery(String query, int start, int end, | 1376 static String _makeQuery( |
| 1377 Map<String, String> queryParameters) { | 1377 String query, int start, int end, |
| 1378 Map<String, dynamic/*String|Iterable<String>*/> queryParameters) { | |
| 1378 if (query == null && queryParameters == null) return null; | 1379 if (query == null && queryParameters == null) return null; |
| 1379 if (query != null && queryParameters != null) { | 1380 if (query != null && queryParameters != null) { |
| 1380 throw new ArgumentError('Both query and queryParameters specified'); | 1381 throw new ArgumentError('Both query and queryParameters specified'); |
| 1381 } | 1382 } |
| 1382 if (query != null) return _normalize(query, start, end, _queryCharTable); | 1383 if (query != null) return _normalize(query, start, end, _queryCharTable); |
| 1383 | 1384 |
| 1384 var result = new StringBuffer(); | 1385 var result = new StringBuffer(); |
| 1385 var separator = ""; | 1386 var separator = ""; |
| 1386 | 1387 |
| 1387 void writeParameter(String key, String value) { | 1388 void writeParameter(String key, String value) { |
| 1388 result.write(separator); | 1389 result.write(separator); |
| 1389 separator = "&"; | 1390 separator = "&"; |
| 1390 result.write(Uri.encodeQueryComponent(key)); | 1391 result.write(Uri.encodeQueryComponent(key)); |
| 1391 if (value != null && value.isNotEmpty) { | 1392 if (value != null && value.isNotEmpty) { |
| 1392 result.write("="); | 1393 result.write("="); |
| 1393 result.write(Uri.encodeQueryComponent(value)); | 1394 result.write(Uri.encodeQueryComponent(value)); |
| 1394 } | 1395 } |
| 1395 } | 1396 } |
| 1396 | 1397 |
| 1397 queryParameters.forEach((key, value) { | 1398 queryParameters.forEach( |
| 1399 (String key, dynamic/*String|Iterable<String>*/ value) { | |
| 1398 if (value == null || value is String) { | 1400 if (value == null || value is String) { |
| 1399 writeParameter(key, value); | 1401 writeParameter(key, value); |
| 1400 } else { | 1402 } else { |
| 1401 Iterable values = value; | 1403 Iterable values = value; |
| 1402 for (String value in values) { | 1404 for (String value in values) { |
| 1403 writeParameter(key, value); | 1405 writeParameter(key, value); |
| 1404 } | 1406 } |
| 1405 } | 1407 } |
| 1406 }); | 1408 }); |
| 1407 return result.toString(); | 1409 return result.toString(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1462 if (digit <= 9) return digit; | 1464 if (digit <= 9) return digit; |
| 1463 int lowerCase = char | 0x20; | 1465 int lowerCase = char | 0x20; |
| 1464 if (Uri._LOWER_CASE_A <= lowerCase && lowerCase <= _LOWER_CASE_F) { | 1466 if (Uri._LOWER_CASE_A <= lowerCase && lowerCase <= _LOWER_CASE_F) { |
| 1465 return lowerCase - (_LOWER_CASE_A - 10); | 1467 return lowerCase - (_LOWER_CASE_A - 10); |
| 1466 } | 1468 } |
| 1467 return -1; | 1469 return -1; |
| 1468 } | 1470 } |
| 1469 | 1471 |
| 1470 static String _escapeChar(int char) { | 1472 static String _escapeChar(int char) { |
| 1471 assert(char <= 0x10ffff); // It's a valid unicode code point. | 1473 assert(char <= 0x10ffff); // It's a valid unicode code point. |
| 1472 List codeUnits; | 1474 List<int> codeUnits; |
| 1473 if (char < 0x80) { | 1475 if (char < 0x80) { |
| 1474 // ASCII, a single percent encoded sequence. | 1476 // ASCII, a single percent encoded sequence. |
| 1475 codeUnits = new List(3); | 1477 codeUnits = new List(3); |
| 1476 codeUnits[0] = _PERCENT; | 1478 codeUnits[0] = _PERCENT; |
| 1477 codeUnits[1] = _hexDigits.codeUnitAt(char >> 4); | 1479 codeUnits[1] = _hexDigits.codeUnitAt(char >> 4); |
| 1478 codeUnits[2] = _hexDigits.codeUnitAt(char & 0xf); | 1480 codeUnits[2] = _hexDigits.codeUnitAt(char & 0xf); |
| 1479 } else { | 1481 } else { |
| 1480 // Do UTF-8 encoding of character, then percent encode bytes. | 1482 // Do UTF-8 encoding of character, then percent encode bytes. |
| 1481 int flag = 0xc0; // The high-bit markers on the first byte of UTF-8. | 1483 int flag = 0xc0; // The high-bit markers on the first byte of UTF-8. |
| 1482 int encodedBytes = 2; | 1484 int encodedBytes = 2; |
| (...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2358 } | 2360 } |
| 2359 } | 2361 } |
| 2360 } | 2362 } |
| 2361 if (wildcardSeen) { | 2363 if (wildcardSeen) { |
| 2362 if (parts.length > 7) { | 2364 if (parts.length > 7) { |
| 2363 error('an address with a wildcard must have less than 7 parts'); | 2365 error('an address with a wildcard must have less than 7 parts'); |
| 2364 } | 2366 } |
| 2365 } else if (parts.length != 8) { | 2367 } else if (parts.length != 8) { |
| 2366 error('an address without a wildcard must contain exactly 8 parts'); | 2368 error('an address without a wildcard must contain exactly 8 parts'); |
| 2367 } | 2369 } |
| 2368 // TODO(ajohnsen): Consider using Uint8List. | 2370 // TODO(ajohnsen): Consider using Uint8List. |
|
Lasse Reichstein Nielsen
2016/04/16 09:58:22
Do consider doing that.
floitsch
2016/04/19 15:36:39
Done.
| |
| 2369 List bytes = new List<int>(16); | 2371 List<int> bytes = new List<int>(16); |
| 2370 for (int i = 0, index = 0; i < parts.length; i++) { | 2372 for (int i = 0, index = 0; i < parts.length; i++) { |
| 2371 int value = parts[i]; | 2373 int value = parts[i]; |
| 2372 if (value == -1) { | 2374 if (value == -1) { |
| 2373 int wildCardLength = 9 - parts.length; | 2375 int wildCardLength = 9 - parts.length; |
| 2374 for (int j = 0; j < wildCardLength; j++) { | 2376 for (int j = 0; j < wildCardLength; j++) { |
| 2375 bytes[index] = 0; | 2377 bytes[index] = 0; |
| 2376 bytes[index + 1] = 0; | 2378 bytes[index + 1] = 0; |
| 2377 index += 2; | 2379 index += 2; |
| 2378 } | 2380 } |
| 2379 } else { | 2381 } else { |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2823 * | 2825 * |
| 2824 * Equivalent to `new Uri.dataFromString(...).data`, but may | 2826 * Equivalent to `new Uri.dataFromString(...).data`, but may |
| 2825 * be more efficient if the [uri] itself isn't used. | 2827 * be more efficient if the [uri] itself isn't used. |
| 2826 */ | 2828 */ |
| 2827 factory UriData.fromString(String content, | 2829 factory UriData.fromString(String content, |
| 2828 {String mimeType, | 2830 {String mimeType, |
| 2829 Encoding encoding, | 2831 Encoding encoding, |
| 2830 Map<String, String> parameters, | 2832 Map<String, String> parameters, |
| 2831 bool base64: false}) { | 2833 bool base64: false}) { |
| 2832 StringBuffer buffer = new StringBuffer(); | 2834 StringBuffer buffer = new StringBuffer(); |
| 2833 List indices = [_noScheme]; | 2835 List<int> indices = [_noScheme]; |
| 2834 String charsetName; | 2836 String charsetName; |
| 2835 String encodingName; | 2837 String encodingName; |
| 2836 if (parameters != null) charsetName = parameters["charset"]; | 2838 if (parameters != null) charsetName = parameters["charset"]; |
| 2837 if (encoding == null) { | 2839 if (encoding == null) { |
| 2838 if (charsetName != null) { | 2840 if (charsetName != null) { |
| 2839 encoding = Encoding.getByName(charsetName); | 2841 encoding = Encoding.getByName(charsetName); |
| 2840 } | 2842 } |
| 2841 } else if (charsetName == null) { | 2843 } else if (charsetName == null) { |
| 2842 // Non-null only if parameters does not contain "charset". | 2844 // Non-null only if parameters does not contain "charset". |
| 2843 encodingName = encoding.name; | 2845 encodingName = encoding.name; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2860 * Creates a `data:` URI containing an encoding of [bytes]. | 2862 * Creates a `data:` URI containing an encoding of [bytes]. |
| 2861 * | 2863 * |
| 2862 * Equivalent to `new Uri.dataFromBytes(...).data`, but may | 2864 * Equivalent to `new Uri.dataFromBytes(...).data`, but may |
| 2863 * be more efficient if the [uri] itself isn't used. | 2865 * be more efficient if the [uri] itself isn't used. |
| 2864 */ | 2866 */ |
| 2865 factory UriData.fromBytes(List<int> bytes, | 2867 factory UriData.fromBytes(List<int> bytes, |
| 2866 {mimeType: "application/octet-stream", | 2868 {mimeType: "application/octet-stream", |
| 2867 Map<String, String> parameters, | 2869 Map<String, String> parameters, |
| 2868 percentEncoded: false}) { | 2870 percentEncoded: false}) { |
| 2869 StringBuffer buffer = new StringBuffer(); | 2871 StringBuffer buffer = new StringBuffer(); |
| 2870 List indices = [_noScheme]; | 2872 List<int> indices = [_noScheme]; |
| 2871 _writeUri(mimeType, null, parameters, buffer, indices); | 2873 _writeUri(mimeType, null, parameters, buffer, indices); |
| 2872 indices.add(buffer.length); | 2874 indices.add(buffer.length); |
| 2873 if (percentEncoded) { | 2875 if (percentEncoded) { |
| 2874 buffer.write(','); | 2876 buffer.write(','); |
| 2875 _uriEncodeBytes(_uricTable, bytes, buffer); | 2877 _uriEncodeBytes(_uricTable, bytes, buffer); |
| 2876 } else { | 2878 } else { |
| 2877 buffer.write(';base64,'); | 2879 buffer.write(';base64,'); |
| 2878 indices.add(buffer.length - 1); | 2880 indices.add(buffer.length - 1); |
| 2879 BASE64.encoder | 2881 BASE64.encoder |
| 2880 .startChunkedConversion( | 2882 .startChunkedConversion( |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3224 | 3226 |
| 3225 static UriData _parse(String text, int start, Uri sourceUri) { | 3227 static UriData _parse(String text, int start, Uri sourceUri) { |
| 3226 assert(start == 0 || start == 5); | 3228 assert(start == 0 || start == 5); |
| 3227 assert((start == 5) == text.startsWith("data:")); | 3229 assert((start == 5) == text.startsWith("data:")); |
| 3228 | 3230 |
| 3229 /// Character codes. | 3231 /// Character codes. |
| 3230 const int comma = 0x2c; | 3232 const int comma = 0x2c; |
| 3231 const int slash = 0x2f; | 3233 const int slash = 0x2f; |
| 3232 const int semicolon = 0x3b; | 3234 const int semicolon = 0x3b; |
| 3233 const int equals = 0x3d; | 3235 const int equals = 0x3d; |
| 3234 List indices = [start - 1]; | 3236 List<int> indices = [start - 1]; |
| 3235 int slashIndex = -1; | 3237 int slashIndex = -1; |
| 3236 var char; | 3238 var char; |
| 3237 int i = start; | 3239 int i = start; |
| 3238 for (; i < text.length; i++) { | 3240 for (; i < text.length; i++) { |
| 3239 char = text.codeUnitAt(i); | 3241 char = text.codeUnitAt(i); |
| 3240 if (char == comma || char == semicolon) break; | 3242 if (char == comma || char == semicolon) break; |
| 3241 if (char == slash) { | 3243 if (char == slash) { |
| 3242 if (slashIndex < 0) { | 3244 if (slashIndex < 0) { |
| 3243 slashIndex = i; | 3245 slashIndex = i; |
| 3244 continue; | 3246 continue; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3345 // All non-escape RFC-2396 uric characters. | 3347 // All non-escape RFC-2396 uric characters. |
| 3346 // | 3348 // |
| 3347 // uric = reserved | unreserved | escaped | 3349 // uric = reserved | unreserved | escaped |
| 3348 // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," | 3350 // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
| 3349 // unreserved = alphanum | mark | 3351 // unreserved = alphanum | mark |
| 3350 // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" | 3352 // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" |
| 3351 // | 3353 // |
| 3352 // This is the same characters as in a URI query (which is URI pchar plus '?') | 3354 // This is the same characters as in a URI query (which is URI pchar plus '?') |
| 3353 static const _uricTable = Uri._queryCharTable; | 3355 static const _uricTable = Uri._queryCharTable; |
| 3354 } | 3356 } |
| OLD | NEW |