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, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986. | 8 * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986. |
9 */ | 9 */ |
10 class Uri { | 10 class Uri { |
| 11 final String _host; |
11 int _port; | 12 int _port; |
12 String _path; | 13 String _path; |
13 | 14 |
14 /** | 15 /** |
15 * Returns the scheme component. | 16 * Returns the scheme component. |
16 * | 17 * |
17 * Returns the empty string if there is no scheme component. | 18 * Returns the empty string if there is no scheme component. |
18 */ | 19 */ |
19 final String scheme; | 20 final String scheme; |
20 | 21 |
(...skipping 18 matching lines...) Expand all Loading... |
39 * Returns the empty string if there is no user info in the | 40 * Returns the empty string if there is no user info in the |
40 * authority component. | 41 * authority component. |
41 */ | 42 */ |
42 final String userInfo; | 43 final String userInfo; |
43 | 44 |
44 /** | 45 /** |
45 * Returns the host part of the authority component. | 46 * Returns the host part of the authority component. |
46 * | 47 * |
47 * Returns the empty string if there is no authority component and | 48 * Returns the empty string if there is no authority component and |
48 * hence no host. | 49 * hence no host. |
| 50 * |
| 51 * If the host is an IP version 6 address, the surrounding `[` and `]` is |
| 52 * removed. |
49 */ | 53 */ |
50 final String host; | 54 String get host { |
| 55 if (_host != null && _host.startsWith('[')) { |
| 56 return _host.substring(1, _host.length - 1); |
| 57 } |
| 58 return _host; |
| 59 } |
51 | 60 |
52 /** | 61 /** |
53 * Returns the port part of the authority component. | 62 * Returns the port part of the authority component. |
54 * | 63 * |
55 * Returns 0 if there is no port in the authority component. | 64 * Returns 0 if there is no port in the authority component. |
56 */ | 65 */ |
57 int get port => _port; | 66 int get port => _port; |
58 | 67 |
59 /** | 68 /** |
60 * Returns the path component. | 69 * Returns the path component. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 * default value of 0. The [path] and [query] components can be set | 125 * default value of 0. The [path] and [query] components can be set |
117 * using two different named arguments. | 126 * using two different named arguments. |
118 * | 127 * |
119 * The scheme component is set through [scheme]. The scheme is | 128 * The scheme component is set through [scheme]. The scheme is |
120 * normalized to all lowercase letters. | 129 * normalized to all lowercase letters. |
121 * | 130 * |
122 * The user info part of the authority component is set through | 131 * The user info part of the authority component is set through |
123 * [userInfo]. | 132 * [userInfo]. |
124 * | 133 * |
125 * The host part of the authority component is set through | 134 * The host part of the authority component is set through |
126 * [host]. The host can either be a hostname, a IPv4 address or an | 135 * [host]. The host can either be a hostname, an IPv4 address or an |
127 * IPv6 address, contained in '[' and ']'. If the host contains a | 136 * IPv6 address, contained in '[' and ']'. If the host contains a |
128 * ':' character, the '[' and ']' are added if not already provided. | 137 * ':' character, the '[' and ']' are added if not already provided. |
129 * | 138 * |
130 * The port part of the authority component is set through | 139 * The port part of the authority component is set through |
131 * [port]. The port is normalized for scheme http and https where | 140 * [port]. The port is normalized for scheme http and https where |
132 * port 80 and port 443 respectively is set. | 141 * port 80 and port 443 respectively is set. |
133 * | 142 * |
134 * The path component is set through either [path] or | 143 * The path component is set through either [path] or |
135 * [pathSegments]. When [path] is used, the provided string is | 144 * [pathSegments]. When [path] is used, the provided string is |
136 * expected to be fully percent-encoded, and is used in its literal | 145 * expected to be fully percent-encoded, and is used in its literal |
137 * form. When [pathSegments] is used, each of the provided segments | 146 * form. When [pathSegments] is used, each of the provided segments |
138 * is percent-encoded and joined using the forward slash | 147 * is percent-encoded and joined using the forward slash |
139 * separator. The percent-encoding of the path segments encodes all | 148 * separator. The percent-encoding of the path segments encodes all |
140 * characters except for the unreserved characters and the following | 149 * characters except for the unreserved characters and the following |
141 * list of characters: `!$&'()*+,;=:@`. If the other components | 150 * list of characters: `!$&'()*+,;=:@`. If the other components |
142 * calls for an absolute path a leading slash `/` is prepended if | 151 * calls for an absolute path a leading slash `/` is prepended if |
143 * not already there. | 152 * not already there. |
144 * | 153 * |
145 * The query component is set through either [query] or | 154 * The query component is set through either [query] or |
146 * [queryParameters]. When [query] is used the provided string is | 155 * [queryParameters]. When [query] is used the provided string is |
147 * expected to be fully percent-encoded and is used in its literal | 156 * expected to be fully percent-encoded and is used in its literal |
148 * form. When [queryParameters] is used the query is built from the | 157 * form. When [queryParameters] is used the query is built from the |
149 * provided map. Each key and value in the map is percent-encoded | 158 * provided map. Each key and value in the map is percent-encoded |
150 * and joined using equal and ampersand characters. The | 159 * and joined using equal and ampersand characters. The |
151 * percent-encoding of the keys and values encodes all characters | 160 * percent-encoding of the keys and values encodes all characters |
152 * except for the unreserved characters. | 161 * except for the unreserved characters. |
153 * | 162 * |
154 * The fragment component is set through [fragment]. | 163 * The fragment component is set through [fragment]. |
155 */ | 164 */ |
156 Uri({scheme, | 165 Uri({String scheme, |
157 this.userInfo: "", | 166 this.userInfo: "", |
158 this.host: "", | 167 String host: "", |
159 port: 0, | 168 port: 0, |
160 String path, | 169 String path, |
161 Iterable<String> pathSegments, | 170 Iterable<String> pathSegments, |
162 String query, | 171 String query, |
163 Map<String, String> queryParameters, | 172 Map<String, String> queryParameters, |
164 fragment: ""}) : | 173 fragment: ""}) : |
165 scheme = _makeScheme(scheme), | 174 scheme = _makeScheme(scheme), |
| 175 _host = _makeHost(host), |
166 query = _makeQuery(query, queryParameters), | 176 query = _makeQuery(query, queryParameters), |
167 fragment = _makeFragment(fragment) { | 177 fragment = _makeFragment(fragment) { |
168 // Perform scheme specific normalization. | 178 // Perform scheme specific normalization. |
169 if (scheme == "http" && port == 80) { | 179 if (scheme == "http" && port == 80) { |
170 _port = 0; | 180 _port = 0; |
171 } else if (scheme == "https" && port == 443) { | 181 } else if (scheme == "https" && port == 443) { |
172 _port = 0; | 182 _port = 0; |
173 } else { | 183 } else { |
174 _port = port; | 184 _port = port; |
175 } | 185 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 // Split off the user info. | 240 // Split off the user info. |
231 bool hasUserInfo = false; | 241 bool hasUserInfo = false; |
232 for (int i = 0; i < authority.length; i++) { | 242 for (int i = 0; i < authority.length; i++) { |
233 if (authority.codeUnitAt(i) == _AT_SIGN) { | 243 if (authority.codeUnitAt(i) == _AT_SIGN) { |
234 hasUserInfo = true; | 244 hasUserInfo = true; |
235 userInfo = authority.substring(0, i); | 245 userInfo = authority.substring(0, i); |
236 hostStart = i + 1; | 246 hostStart = i + 1; |
237 break; | 247 break; |
238 } | 248 } |
239 } | 249 } |
| 250 var hostEnd = hostStart; |
| 251 if (hostStart < authority.length && |
| 252 authority.codeUnitAt(hostStart) == _LEFT_BRACKET) { |
| 253 // IPv6 host. |
| 254 for (; hostEnd < authority.length; hostEnd++) { |
| 255 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; |
| 256 } |
| 257 if (hostEnd == authority.length) { |
| 258 throw new FormatException("Invalid IPv6 host entry."); |
| 259 } |
| 260 parseIPv6Address(authority.substring(hostStart + 1, hostEnd)); |
| 261 hostEnd++; // Skip the closing bracket. |
| 262 if (hostEnd != authority.length && |
| 263 authority.codeUnitAt(hostEnd) != _COLON) { |
| 264 throw new FormatException("Invalid end of authority"); |
| 265 } |
| 266 } |
240 // Split host and port. | 267 // Split host and port. |
241 bool hasPort = false; | 268 bool hasPort = false; |
242 for (int i = hostStart; i < authority.length; i++) { | 269 for (; hostEnd < authority.length; hostEnd++) { |
243 if (authority.codeUnitAt(i) == _COLON) { | 270 if (authority.codeUnitAt(hostEnd) == _COLON) { |
244 hasPort = true; | 271 var portString = authority.substring(hostEnd + 1); |
245 host = authority.substring(hostStart, i); | 272 // We allow the empty port - falling back to initial value. |
246 if (!host.isEmpty) { | 273 if (portString.isNotEmpty) port = int.parse(portString); |
247 var portString = authority.substring(i + 1); | |
248 if (portString.isNotEmpty) port = int.parse(portString); | |
249 } | |
250 break; | 274 break; |
251 } | 275 } |
252 } | 276 } |
253 if (!hasPort) { | 277 host = authority.substring(hostStart, hostEnd); |
254 host = hasUserInfo ? authority.substring(hostStart) : authority; | |
255 } | |
256 | 278 |
257 return new Uri(scheme: scheme, | 279 return new Uri(scheme: scheme, |
258 userInfo: userInfo, | 280 userInfo: userInfo, |
259 host: host, | 281 host: host, |
260 port: port, | 282 port: port, |
261 pathSegments: unencodedPath.split("/"), | 283 pathSegments: unencodedPath.split("/"), |
262 queryParameters: queryParameters); | 284 queryParameters: queryParameters); |
263 } | 285 } |
264 | 286 |
265 /** | 287 /** |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 * The returned map is unmodifiable and will throw [UnsupportedError] on any | 489 * The returned map is unmodifiable and will throw [UnsupportedError] on any |
468 * calls that would mutate it. | 490 * calls that would mutate it. |
469 */ | 491 */ |
470 Map<String, String> get queryParameters { | 492 Map<String, String> get queryParameters { |
471 if (_queryParameters == null) { | 493 if (_queryParameters == null) { |
472 _queryParameters = new _UnmodifiableMap(splitQueryString(query)); | 494 _queryParameters = new _UnmodifiableMap(splitQueryString(query)); |
473 } | 495 } |
474 return _queryParameters; | 496 return _queryParameters; |
475 } | 497 } |
476 | 498 |
| 499 static String _makeHost(String host) { |
| 500 if (host == null || host.isEmpty) return host; |
| 501 if (host.codeUnitAt(0) == _LEFT_BRACKET) { |
| 502 if (host.codeUnitAt(host.length - 1) != _RIGHT_BRACKET) { |
| 503 throw new FormatException('Missing end `]` to match `[` in host'); |
| 504 } |
| 505 parseIPv6Address(host.substring(1, host.length - 1)); |
| 506 return host; |
| 507 } |
| 508 for (int i = 0; i < host.length; i++) { |
| 509 if (host.codeUnitAt(i) == _COLON) { |
| 510 parseIPv6Address(host); |
| 511 return '[$host]'; |
| 512 } |
| 513 } |
| 514 return host; |
| 515 } |
| 516 |
477 static String _makeScheme(String scheme) { | 517 static String _makeScheme(String scheme) { |
478 bool isSchemeLowerCharacter(int ch) { | 518 bool isSchemeLowerCharacter(int ch) { |
479 return ch < 128 && | 519 return ch < 128 && |
480 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | 520 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
481 } | 521 } |
482 | 522 |
483 bool isSchemeCharacter(int ch) { | 523 bool isSchemeCharacter(int ch) { |
484 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | 524 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
485 } | 525 } |
486 | 526 |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 | 861 |
822 /** | 862 /** |
823 * Returns the origin of the URI in the form scheme://host:port for the | 863 * Returns the origin of the URI in the form scheme://host:port for the |
824 * schemes http and https. | 864 * schemes http and https. |
825 * | 865 * |
826 * It is an error if the scheme is not "http" or "https". | 866 * It is an error if the scheme is not "http" or "https". |
827 * | 867 * |
828 * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin | 868 * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin |
829 */ | 869 */ |
830 String get origin { | 870 String get origin { |
831 if (scheme == "" || host == null || host == "") { | 871 if (scheme == "" || _host == null || _host == "") { |
832 throw new StateError("Cannot use origin without a scheme: $this"); | 872 throw new StateError("Cannot use origin without a scheme: $this"); |
833 } | 873 } |
834 if (scheme != "http" && scheme != "https") { | 874 if (scheme != "http" && scheme != "https") { |
835 throw new StateError( | 875 throw new StateError( |
836 "Origin is only applicable schemes http and https: $this"); | 876 "Origin is only applicable schemes http and https: $this"); |
837 } | 877 } |
838 if (port == 0) return "$scheme://$host"; | 878 if (port == 0) return "$scheme://$_host"; |
839 return "$scheme://$host:$port"; | 879 return "$scheme://$_host:$port"; |
840 } | 880 } |
841 | 881 |
842 /** | 882 /** |
843 * Returns the file path from a file URI. | 883 * Returns the file path from a file URI. |
844 * | 884 * |
845 * The returned path has either Windows or non-Windows | 885 * The returned path has either Windows or non-Windows |
846 * semantics. | 886 * semantics. |
847 * | 887 * |
848 * For non-Windows semantics the slash ("/") is used to separate | 888 * For non-Windows semantics the slash ("/") is used to separate |
849 * path segments. | 889 * path segments. |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
955 result.write(host); | 995 result.write(host); |
956 result.write("\\"); | 996 result.write("\\"); |
957 } | 997 } |
958 result.writeAll(segments, "\\"); | 998 result.writeAll(segments, "\\"); |
959 if (hasDriveLetter && segments.length == 1) result.write("\\"); | 999 if (hasDriveLetter && segments.length == 1) result.write("\\"); |
960 return result.toString(); | 1000 return result.toString(); |
961 } | 1001 } |
962 | 1002 |
963 void _writeAuthority(StringSink ss) { | 1003 void _writeAuthority(StringSink ss) { |
964 _addIfNonEmpty(ss, userInfo, userInfo, "@"); | 1004 _addIfNonEmpty(ss, userInfo, userInfo, "@"); |
965 ss.write(host == null ? "null" : | 1005 ss.write(_host == null ? "null" : _host); |
966 host.contains(':') ? '[$host]' : host); | |
967 if (port != 0) { | 1006 if (port != 0) { |
968 ss.write(":"); | 1007 ss.write(":"); |
969 ss.write(port.toString()); | 1008 ss.write(port.toString()); |
970 } | 1009 } |
971 } | 1010 } |
972 | 1011 |
973 String toString() { | 1012 String toString() { |
974 StringBuffer sb = new StringBuffer(); | 1013 StringBuffer sb = new StringBuffer(); |
975 _addIfNonEmpty(sb, scheme, scheme, ':'); | 1014 _addIfNonEmpty(sb, scheme, scheme, ':'); |
976 if (hasAuthority || (scheme == "file")) { | 1015 if (hasAuthority || (scheme == "file")) { |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1141 } else if (index != 0) { | 1180 } else if (index != 0) { |
1142 var key = element.substring(0, index); | 1181 var key = element.substring(0, index); |
1143 var value = element.substring(index + 1); | 1182 var value = element.substring(index + 1); |
1144 map[Uri.decodeQueryComponent(key, decode: decode)] = | 1183 map[Uri.decodeQueryComponent(key, decode: decode)] = |
1145 decodeQueryComponent(value, decode: decode); | 1184 decodeQueryComponent(value, decode: decode); |
1146 } | 1185 } |
1147 return map; | 1186 return map; |
1148 }); | 1187 }); |
1149 } | 1188 } |
1150 | 1189 |
| 1190 /** |
| 1191 * Parse the [host] as an IP version 4 (IPv4) address, returning the address |
| 1192 * as a list of 4 bytes in network byte order (big endian). |
| 1193 * |
| 1194 * Throws a [FormatException] if [host] is not a valid IPv4 address |
| 1195 * representation. |
| 1196 */ |
| 1197 static List<int> parseIPv4Address(String host) { |
| 1198 void error(String msg) { |
| 1199 throw new FormatException('Illegal IPv4 address, $msg'); |
| 1200 } |
| 1201 var bytes = host.split('.'); |
| 1202 if (bytes.length != 4) { |
| 1203 error('IPv4 address should contain exactly 4 parts'); |
| 1204 } |
| 1205 // TODO(ajohnsen): Consider using Uint8List. |
| 1206 return bytes |
| 1207 .map((byteString) { |
| 1208 int byte = int.parse(byteString); |
| 1209 if (byte < 0 || byte > 255) { |
| 1210 error('each part must be in the range of `0..255`'); |
| 1211 } |
| 1212 return byte; |
| 1213 }) |
| 1214 .toList(); |
| 1215 } |
| 1216 |
| 1217 /** |
| 1218 * Parse the [host] as an IP version 6 (IPv6) address, returning the address |
| 1219 * as a list of 16 bytes in network byte order (big endian). |
| 1220 * |
| 1221 * Throws a [FormatException] if [host] is not a valid IPv6 address |
| 1222 * representation. |
| 1223 * |
| 1224 * Some examples of IPv6 addresses: |
| 1225 * * ::1 |
| 1226 * * FEDC:BA98:7654:3210:FEDC:BA98:7654:3210 |
| 1227 * * 3ffe:2a00:100:7031::1 |
| 1228 * * ::FFFF:129.144.52.38 |
| 1229 * * 2010:836B:4179::836B:4179 |
| 1230 */ |
| 1231 static List<int> parseIPv6Address(String host) { |
| 1232 // An IPv6 address consists of exactly 8 parts of 1-4 hex digits, seperated |
| 1233 // by `:`'s, with the following exceptions: |
| 1234 // |
| 1235 // - One (and only one) wildcard (`::`) may be present, representing a fill |
| 1236 // of 0's. The IPv6 `::` is thus 16 bytes of `0`. |
| 1237 // - The last two parts may be replaced by an IPv4 address. |
| 1238 void error(String msg) { |
| 1239 throw new FormatException('Illegal IPv6 address, $msg'); |
| 1240 } |
| 1241 int parseHex(int start, int end) { |
| 1242 if (end - start > 4) { |
| 1243 error('an IPv6 part can only contain a maximum of 4 hex digits'); |
| 1244 } |
| 1245 int value = int.parse(host.substring(start, end), radix: 16); |
| 1246 if (value < 0 || value > (1 << 16) - 1) { |
| 1247 error('each part must be in the range of `0x0..0xFFFF`'); |
| 1248 } |
| 1249 return value; |
| 1250 } |
| 1251 if (host.length < 2) error('address is too short'); |
| 1252 List<int> parts = []; |
| 1253 bool wildcardSeen = false; |
| 1254 int partStart = 0; |
| 1255 // Parse all parts, except a potential last one. |
| 1256 for (int i = 0; i < host.length; i++) { |
| 1257 if (host.codeUnitAt(i) == _COLON) { |
| 1258 if (i == 0) { |
| 1259 // If we see a `:` in the beginning, expect wildcard. |
| 1260 i++; |
| 1261 if (host.codeUnitAt(i) != _COLON) { |
| 1262 error('invalid start colon.'); |
| 1263 } |
| 1264 partStart = i; |
| 1265 } |
| 1266 if (i == partStart) { |
| 1267 // Wildcard. We only allow one. |
| 1268 if (wildcardSeen) { |
| 1269 error('only one wildcard `::` is allowed'); |
| 1270 } |
| 1271 wildcardSeen = true; |
| 1272 parts.add(-1); |
| 1273 } else { |
| 1274 // Found a single colon. Parse [partStart..i] as a hex entry. |
| 1275 parts.add(parseHex(partStart, i)); |
| 1276 } |
| 1277 partStart = i + 1; |
| 1278 } |
| 1279 } |
| 1280 if (parts.length == 0) error('too few parts'); |
| 1281 bool atEnd = partStart == host.length; |
| 1282 bool isLastWildcard = parts.last == -1; |
| 1283 if (atEnd && !isLastWildcard) { |
| 1284 error('expected a part after last `:`'); |
| 1285 } |
| 1286 if (!atEnd) { |
| 1287 try { |
| 1288 parts.add(parseHex(partStart, host.length)); |
| 1289 } catch (e) { |
| 1290 // Failed to parse the last chunk as hex. Try IPv4. |
| 1291 try { |
| 1292 List<int> last = parseIPv4Address(host.substring(partStart)); |
| 1293 parts.add(last[0] << 8 | last[1]); |
| 1294 parts.add(last[2] << 8 | last[3]); |
| 1295 } catch (e) { |
| 1296 error('invalid end of IPv6 address.'); |
| 1297 } |
| 1298 } |
| 1299 } |
| 1300 if (wildcardSeen) { |
| 1301 if (parts.length > 7) { |
| 1302 error('an address with a wildcard must have less than 7 parts'); |
| 1303 } |
| 1304 } else if (parts.length != 8) { |
| 1305 error('an address without a wildcard must contain exactly 8 parts'); |
| 1306 } |
| 1307 // TODO(ajohnsen): Consider using Uint8List. |
| 1308 return parts |
| 1309 .expand((value) { |
| 1310 if (value == -1) { |
| 1311 return new List.filled((9 - parts.length) * 2, 0); |
| 1312 } else { |
| 1313 return [(value >> 8) & 0xFF, value & 0xFF]; |
| 1314 } |
| 1315 }) |
| 1316 .toList(); |
| 1317 } |
| 1318 |
1151 // Frequently used character codes. | 1319 // Frequently used character codes. |
1152 static const int _DOUBLE_QUOTE = 0x22; | 1320 static const int _DOUBLE_QUOTE = 0x22; |
1153 static const int _PERCENT = 0x25; | 1321 static const int _PERCENT = 0x25; |
1154 static const int _ASTERISK = 0x2A; | 1322 static const int _ASTERISK = 0x2A; |
1155 static const int _PLUS = 0x2B; | 1323 static const int _PLUS = 0x2B; |
1156 static const int _SLASH = 0x2F; | 1324 static const int _SLASH = 0x2F; |
1157 static const int _ZERO = 0x30; | 1325 static const int _ZERO = 0x30; |
1158 static const int _NINE = 0x39; | 1326 static const int _NINE = 0x39; |
1159 static const int _COLON = 0x3A; | 1327 static const int _COLON = 0x3A; |
1160 static const int _LESS = 0x3C; | 1328 static const int _LESS = 0x3C; |
1161 static const int _GREATER = 0x3E; | 1329 static const int _GREATER = 0x3E; |
1162 static const int _QUESTION = 0x3F; | 1330 static const int _QUESTION = 0x3F; |
1163 static const int _AT_SIGN = 0x40; | 1331 static const int _AT_SIGN = 0x40; |
1164 static const int _UPPER_CASE_A = 0x41; | 1332 static const int _UPPER_CASE_A = 0x41; |
1165 static const int _UPPER_CASE_F = 0x46; | 1333 static const int _UPPER_CASE_F = 0x46; |
1166 static const int _UPPER_CASE_Z = 0x5A; | 1334 static const int _UPPER_CASE_Z = 0x5A; |
| 1335 static const int _LEFT_BRACKET = 0x5B; |
1167 static const int _BACKSLASH = 0x5C; | 1336 static const int _BACKSLASH = 0x5C; |
| 1337 static const int _RIGHT_BRACKET = 0x5D; |
1168 static const int _LOWER_CASE_A = 0x61; | 1338 static const int _LOWER_CASE_A = 0x61; |
1169 static const int _LOWER_CASE_F = 0x66; | 1339 static const int _LOWER_CASE_F = 0x66; |
1170 static const int _LOWER_CASE_Z = 0x7A; | 1340 static const int _LOWER_CASE_Z = 0x7A; |
1171 static const int _BAR = 0x7C; | 1341 static const int _BAR = 0x7C; |
1172 | 1342 |
1173 /** | 1343 /** |
1174 * This is the internal implementation of JavaScript's encodeURI function. | 1344 * This is the internal implementation of JavaScript's encodeURI function. |
1175 * It encodes all characters in the string [text] except for those | 1345 * It encodes all characters in the string [text] except for those |
1176 * that appear in [canonicalTable], and returns the escaped string. | 1346 * that appear in [canonicalTable], and returns the escaped string. |
1177 */ | 1347 */ |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1465 void clear() { | 1635 void clear() { |
1466 throw new UnsupportedError("Cannot modify an unmodifiable map"); | 1636 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
1467 } | 1637 } |
1468 void forEach(void f(K key, V value)) => _map.forEach(f); | 1638 void forEach(void f(K key, V value)) => _map.forEach(f); |
1469 Iterable<K> get keys => _map.keys; | 1639 Iterable<K> get keys => _map.keys; |
1470 Iterable<V> get values => _map.values; | 1640 Iterable<V> get values => _map.values; |
1471 int get length => _map.length; | 1641 int get length => _map.length; |
1472 bool get isEmpty => _map.isEmpty; | 1642 bool get isEmpty => _map.isEmpty; |
1473 bool get isNotEmpty => _map.isNotEmpty; | 1643 bool get isNotEmpty => _map.isNotEmpty; |
1474 } | 1644 } |
OLD | NEW |