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 map for `queryParameters`. |
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) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1462 if (digit <= 9) return digit; | 1463 if (digit <= 9) return digit; |
1463 int lowerCase = char | 0x20; | 1464 int lowerCase = char | 0x20; |
1464 if (Uri._LOWER_CASE_A <= lowerCase && lowerCase <= _LOWER_CASE_F) { | 1465 if (Uri._LOWER_CASE_A <= lowerCase && lowerCase <= _LOWER_CASE_F) { |
1465 return lowerCase - (_LOWER_CASE_A - 10); | 1466 return lowerCase - (_LOWER_CASE_A - 10); |
1466 } | 1467 } |
1467 return -1; | 1468 return -1; |
1468 } | 1469 } |
1469 | 1470 |
1470 static String _escapeChar(int char) { | 1471 static String _escapeChar(int char) { |
1471 assert(char <= 0x10ffff); // It's a valid unicode code point. | 1472 assert(char <= 0x10ffff); // It's a valid unicode code point. |
1472 List codeUnits; | 1473 List<int> codeUnits; |
1473 if (char < 0x80) { | 1474 if (char < 0x80) { |
1474 // ASCII, a single percent encoded sequence. | 1475 // ASCII, a single percent encoded sequence. |
1475 codeUnits = new List(3); | 1476 codeUnits = new List(3); |
1476 codeUnits[0] = _PERCENT; | 1477 codeUnits[0] = _PERCENT; |
1477 codeUnits[1] = _hexDigits.codeUnitAt(char >> 4); | 1478 codeUnits[1] = _hexDigits.codeUnitAt(char >> 4); |
1478 codeUnits[2] = _hexDigits.codeUnitAt(char & 0xf); | 1479 codeUnits[2] = _hexDigits.codeUnitAt(char & 0xf); |
1479 } else { | 1480 } else { |
1480 // Do UTF-8 encoding of character, then percent encode bytes. | 1481 // 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. | 1482 int flag = 0xc0; // The high-bit markers on the first byte of UTF-8. |
1482 int encodedBytes = 2; | 1483 int encodedBytes = 2; |
(...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2358 } | 2359 } |
2359 } | 2360 } |
2360 } | 2361 } |
2361 if (wildcardSeen) { | 2362 if (wildcardSeen) { |
2362 if (parts.length > 7) { | 2363 if (parts.length > 7) { |
2363 error('an address with a wildcard must have less than 7 parts'); | 2364 error('an address with a wildcard must have less than 7 parts'); |
2364 } | 2365 } |
2365 } else if (parts.length != 8) { | 2366 } else if (parts.length != 8) { |
2366 error('an address without a wildcard must contain exactly 8 parts'); | 2367 error('an address without a wildcard must contain exactly 8 parts'); |
2367 } | 2368 } |
2368 // TODO(ajohnsen): Consider using Uint8List. | 2369 List<int> bytes = new Uint8List(16); |
2369 List bytes = new List<int>(16); | |
2370 for (int i = 0, index = 0; i < parts.length; i++) { | 2370 for (int i = 0, index = 0; i < parts.length; i++) { |
2371 int value = parts[i]; | 2371 int value = parts[i]; |
2372 if (value == -1) { | 2372 if (value == -1) { |
2373 int wildCardLength = 9 - parts.length; | 2373 int wildCardLength = 9 - parts.length; |
2374 for (int j = 0; j < wildCardLength; j++) { | 2374 for (int j = 0; j < wildCardLength; j++) { |
2375 bytes[index] = 0; | 2375 bytes[index] = 0; |
2376 bytes[index + 1] = 0; | 2376 bytes[index + 1] = 0; |
2377 index += 2; | 2377 index += 2; |
2378 } | 2378 } |
2379 } else { | 2379 } else { |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2823 * | 2823 * |
2824 * Equivalent to `new Uri.dataFromString(...).data`, but may | 2824 * Equivalent to `new Uri.dataFromString(...).data`, but may |
2825 * be more efficient if the [uri] itself isn't used. | 2825 * be more efficient if the [uri] itself isn't used. |
2826 */ | 2826 */ |
2827 factory UriData.fromString(String content, | 2827 factory UriData.fromString(String content, |
2828 {String mimeType, | 2828 {String mimeType, |
2829 Encoding encoding, | 2829 Encoding encoding, |
2830 Map<String, String> parameters, | 2830 Map<String, String> parameters, |
2831 bool base64: false}) { | 2831 bool base64: false}) { |
2832 StringBuffer buffer = new StringBuffer(); | 2832 StringBuffer buffer = new StringBuffer(); |
2833 List indices = [_noScheme]; | 2833 List<int> indices = [_noScheme]; |
2834 String charsetName; | 2834 String charsetName; |
2835 String encodingName; | 2835 String encodingName; |
2836 if (parameters != null) charsetName = parameters["charset"]; | 2836 if (parameters != null) charsetName = parameters["charset"]; |
2837 if (encoding == null) { | 2837 if (encoding == null) { |
2838 if (charsetName != null) { | 2838 if (charsetName != null) { |
2839 encoding = Encoding.getByName(charsetName); | 2839 encoding = Encoding.getByName(charsetName); |
2840 } | 2840 } |
2841 } else if (charsetName == null) { | 2841 } else if (charsetName == null) { |
2842 // Non-null only if parameters does not contain "charset". | 2842 // Non-null only if parameters does not contain "charset". |
2843 encodingName = encoding.name; | 2843 encodingName = encoding.name; |
(...skipping 16 matching lines...) Expand all Loading... |
2860 * Creates a `data:` URI containing an encoding of [bytes]. | 2860 * Creates a `data:` URI containing an encoding of [bytes]. |
2861 * | 2861 * |
2862 * Equivalent to `new Uri.dataFromBytes(...).data`, but may | 2862 * Equivalent to `new Uri.dataFromBytes(...).data`, but may |
2863 * be more efficient if the [uri] itself isn't used. | 2863 * be more efficient if the [uri] itself isn't used. |
2864 */ | 2864 */ |
2865 factory UriData.fromBytes(List<int> bytes, | 2865 factory UriData.fromBytes(List<int> bytes, |
2866 {mimeType: "application/octet-stream", | 2866 {mimeType: "application/octet-stream", |
2867 Map<String, String> parameters, | 2867 Map<String, String> parameters, |
2868 percentEncoded: false}) { | 2868 percentEncoded: false}) { |
2869 StringBuffer buffer = new StringBuffer(); | 2869 StringBuffer buffer = new StringBuffer(); |
2870 List indices = [_noScheme]; | 2870 List<int> indices = [_noScheme]; |
2871 _writeUri(mimeType, null, parameters, buffer, indices); | 2871 _writeUri(mimeType, null, parameters, buffer, indices); |
2872 indices.add(buffer.length); | 2872 indices.add(buffer.length); |
2873 if (percentEncoded) { | 2873 if (percentEncoded) { |
2874 buffer.write(','); | 2874 buffer.write(','); |
2875 _uriEncodeBytes(_uricTable, bytes, buffer); | 2875 _uriEncodeBytes(_uricTable, bytes, buffer); |
2876 } else { | 2876 } else { |
2877 buffer.write(';base64,'); | 2877 buffer.write(';base64,'); |
2878 indices.add(buffer.length - 1); | 2878 indices.add(buffer.length - 1); |
2879 BASE64.encoder | 2879 BASE64.encoder |
2880 .startChunkedConversion( | 2880 .startChunkedConversion( |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3224 | 3224 |
3225 static UriData _parse(String text, int start, Uri sourceUri) { | 3225 static UriData _parse(String text, int start, Uri sourceUri) { |
3226 assert(start == 0 || start == 5); | 3226 assert(start == 0 || start == 5); |
3227 assert((start == 5) == text.startsWith("data:")); | 3227 assert((start == 5) == text.startsWith("data:")); |
3228 | 3228 |
3229 /// Character codes. | 3229 /// Character codes. |
3230 const int comma = 0x2c; | 3230 const int comma = 0x2c; |
3231 const int slash = 0x2f; | 3231 const int slash = 0x2f; |
3232 const int semicolon = 0x3b; | 3232 const int semicolon = 0x3b; |
3233 const int equals = 0x3d; | 3233 const int equals = 0x3d; |
3234 List indices = [start - 1]; | 3234 List<int> indices = [start - 1]; |
3235 int slashIndex = -1; | 3235 int slashIndex = -1; |
3236 var char; | 3236 var char; |
3237 int i = start; | 3237 int i = start; |
3238 for (; i < text.length; i++) { | 3238 for (; i < text.length; i++) { |
3239 char = text.codeUnitAt(i); | 3239 char = text.codeUnitAt(i); |
3240 if (char == comma || char == semicolon) break; | 3240 if (char == comma || char == semicolon) break; |
3241 if (char == slash) { | 3241 if (char == slash) { |
3242 if (slashIndex < 0) { | 3242 if (slashIndex < 0) { |
3243 slashIndex = i; | 3243 slashIndex = i; |
3244 continue; | 3244 continue; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3345 // All non-escape RFC-2396 uric characters. | 3345 // All non-escape RFC-2396 uric characters. |
3346 // | 3346 // |
3347 // uric = reserved | unreserved | escaped | 3347 // uric = reserved | unreserved | escaped |
3348 // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," | 3348 // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
3349 // unreserved = alphanum | mark | 3349 // unreserved = alphanum | mark |
3350 // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" | 3350 // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" |
3351 // | 3351 // |
3352 // This is the same characters as in a URI query (which is URI pchar plus '?') | 3352 // This is the same characters as in a URI query (which is URI pchar plus '?') |
3353 static const _uricTable = Uri._queryCharTable; | 3353 static const _uricTable = Uri._queryCharTable; |
3354 } | 3354 } |
OLD | NEW |