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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 111 List<String> _pathSegments; | 111 List<String> _pathSegments; |
| 112 | 112 |
| 113 /** | 113 /** |
| 114 * Cache the computed return value of [queryParameters]. | 114 * Cache the computed return value of [queryParameters]. |
| 115 */ | 115 */ |
| 116 Map<String, String> _queryParameters; | 116 Map<String, String> _queryParameters; |
| 117 | 117 |
| 118 /** | 118 /** |
| 119 * Creates a new URI object by parsing a URI string. | 119 * Creates a new URI object by parsing a URI string. |
| 120 */ | 120 */ |
| 121 static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri)); | 121 static Uri parse(String uri) { |
|
Søren Gjesse
2014/02/24 09:12:41
I think it could be a good idea to include the reg
Anders Johnsen
2014/02/24 12:44:33
Done.
| |
| 122 // This parsing will not validate percent-encoding, IPv6, etc. When done | |
| 123 // it'll call `new Uri(...)` that will perform these validations. This is | |
|
Lasse Reichstein Nielsen
2014/02/24 13:02:27
it'll -> it will
that -> which
Anders Johnsen
2014/02/24 14:26:49
Done.
| |
| 124 // purely splitting up the uri string into components. | |
|
Lasse Reichstein Nielsen
2014/02/24 13:02:27
uri -> URI.
Anders Johnsen
2014/02/24 14:26:49
Done.
| |
| 125 bool isSchemeCharacter(int ch) { | |
|
Lasse Reichstein Nielsen
2014/02/24 13:02:27
Consider making this a static private method inste
Anders Johnsen
2014/02/24 14:26:49
Done.
| |
| 126 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
| 127 } | |
| 122 | 128 |
| 123 Uri._fromMatch(Match m) : | 129 bool isRegName(int ch) { |
| 124 this(scheme: _makeScheme(_emptyIfNull(m[_COMPONENT_SCHEME])), | 130 return ch < 128 && ((_regNameTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
| 125 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]), | 131 } |
| 126 host: _eitherOf( | 132 |
| 127 m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]), | 133 List<int> codeUnits = uri.codeUnits; |
| 128 port: _parseIntOrZero(m[_COMPONENT_PORT]), | 134 int length = codeUnits.length; |
| 129 path: _emptyIfNull(m[_COMPONENT_PATH]), | 135 int index = 0; |
| 130 query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]), | 136 |
| 131 fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT])); | 137 int schemeEndIndex = 0; |
| 138 | |
| 139 if (length == 0) { | |
| 140 return new Uri(); | |
| 141 } | |
| 142 | |
| 143 if (codeUnits[0] != '/'.codeUnitAt(0)) { | |
|
Søren Gjesse
2014/02/24 09:12:41
Use _SLASH (see frequently used character codes at
Anders Johnsen
2014/02/24 12:44:33
Done.
Lasse Reichstein Nielsen
2014/02/24 13:02:27
Unless you *know* that this is optimized away by a
Anders Johnsen
2014/02/24 14:26:49
Any const static members should be compiled away?
| |
| 144 // Can be scheme. | |
| 145 while (index < length) { | |
|
Søren Gjesse
2014/02/24 09:12:41
Please provide some more comments, e.g. "Look for
Anders Johnsen
2014/02/24 12:44:33
Done.
| |
| 146 | |
| 147 int codeUnit = codeUnits[index++]; | |
| 148 if (!isSchemeCharacter(codeUnit)) { | |
| 149 if (codeUnit == ':'.codeUnitAt(0)) { | |
|
Søren Gjesse
2014/02/24 09:12:41
_COLON, and more below.
Anders Johnsen
2014/02/24 12:44:33
Done.
| |
| 150 schemeEndIndex = index; | |
| 151 } else { | |
| 152 // Back up one char, as we meet a special char. | |
|
Søren Gjesse
2014/02/24 09:12:41
meet -> met?
Anders Johnsen
2014/02/24 12:44:33
Done.
Lasse Reichstein Nielsen
2014/02/24 13:02:27
as -> since
Anders Johnsen
2014/02/24 14:26:49
Done.
| |
| 153 index--; | |
| 154 } | |
| 155 break; | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 int userInfoEndIndex = -1; | |
| 161 int portIndex = -1; | |
| 162 int authorityEndIndex = schemeEndIndex; | |
| 163 // If we see '//', it must be a authority. | |
|
Søren Gjesse
2014/02/24 09:12:41
it must -> there must
a -> an
Anders Johnsen
2014/02/24 12:44:33
Done.
| |
| 164 if (authorityEndIndex == index && | |
| 165 authorityEndIndex + 1 < length && | |
| 166 codeUnits[authorityEndIndex] == '/'.codeUnitAt(0) && | |
| 167 codeUnits[authorityEndIndex + 1] == '/'.codeUnitAt(0)) { | |
| 168 // Skip '//'. | |
| 169 authorityEndIndex += 2; | |
| 170 // It can both be host and userInfo. | |
| 171 while (authorityEndIndex < length) { | |
| 172 int codeUnit = codeUnits[authorityEndIndex++]; | |
| 173 if (!isRegName(codeUnit)) { | |
| 174 if (codeUnit == '['.codeUnitAt(0)) { | |
| 175 // IPv6. Skip to '['. | |
|
Søren Gjesse
2014/02/24 09:12:41
'[' -> ']'
Anders Johnsen
2014/02/24 12:44:33
Done.
| |
| 176 authorityEndIndex = codeUnits.indexOf(']'.codeUnitAt(0), | |
| 177 authorityEndIndex) + 1; | |
| 178 if (authorityEndIndex == 0) { | |
| 179 throw new FormatException("Bad end of IPv6 host"); | |
| 180 } | |
| 181 } else if (portIndex == -1 && codeUnit == ':'.codeUnitAt(0)) { | |
| 182 // First time ':'. | |
| 183 portIndex = authorityEndIndex; | |
| 184 } else if (codeUnit == '@'.codeUnitAt(0) || | |
| 185 codeUnit == ':'.codeUnitAt(0)) { | |
| 186 // Second time ':' or first '@'. Must be userInfo. | |
| 187 userInfoEndIndex = codeUnits.indexOf('@'.codeUnitAt(0), | |
| 188 authorityEndIndex - 1); | |
| 189 // Not found. Must be path then. | |
| 190 if (userInfoEndIndex == -1) { | |
| 191 authorityEndIndex = index; | |
| 192 break; | |
| 193 } | |
| 194 portIndex = -1; | |
| 195 authorityEndIndex = userInfoEndIndex + 1; | |
| 196 // Now it can only be host:port. | |
| 197 while (authorityEndIndex < length) { | |
| 198 int codeUnit = codeUnits[authorityEndIndex++]; | |
| 199 if (!isRegName(codeUnit)) { | |
| 200 if (codeUnit == '['.codeUnitAt(0)) { | |
|
Søren Gjesse
2014/02/24 09:12:41
Refactor next 5 lines to a local function
authori
Anders Johnsen
2014/02/24 12:44:33
Done.
| |
| 201 authorityEndIndex = codeUnits.indexOf(']'.codeUnitAt(0), | |
| 202 authorityEndIndex) + 1; | |
| 203 if (authorityEndIndex == 0) { | |
| 204 throw new FormatException("Bad end of IPv6 host"); | |
| 205 } | |
| 206 } else if (codeUnit == ':'.codeUnitAt(0)) { | |
| 207 if (portIndex != -1) { | |
| 208 throw new FormatException("Double port in host"); | |
| 209 } | |
| 210 portIndex = authorityEndIndex; | |
| 211 } else { | |
| 212 authorityEndIndex--; | |
| 213 break; | |
| 214 } | |
| 215 } | |
| 216 } | |
| 217 break; | |
| 218 } else { | |
| 219 authorityEndIndex--; | |
| 220 break; | |
| 221 } | |
| 222 } | |
| 223 } | |
| 224 } else { | |
| 225 authorityEndIndex = schemeEndIndex; | |
| 226 } | |
| 227 | |
| 228 // At path now. | |
| 229 int pathEndIndex = authorityEndIndex; | |
| 230 while (pathEndIndex < length) { | |
| 231 int codeUnit = codeUnits[pathEndIndex++]; | |
| 232 if (codeUnit == '?'.codeUnitAt(0) || | |
| 233 codeUnit == '#'.codeUnitAt(0)) { | |
| 234 pathEndIndex--; | |
| 235 break; | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 // Maybe query. | |
| 240 int queryEndIndex = pathEndIndex; | |
| 241 if (queryEndIndex < length && | |
| 242 codeUnits[queryEndIndex] == '?'.codeUnitAt(0)) { | |
| 243 while (queryEndIndex < length) { | |
| 244 int codeUnit = codeUnits[queryEndIndex++]; | |
| 245 if (codeUnit == '#'.codeUnitAt(0)) { | |
| 246 queryEndIndex--; | |
| 247 break; | |
| 248 } | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 var scheme = null; | |
| 253 if (schemeEndIndex > 0) { | |
| 254 scheme = uri.substring(0, schemeEndIndex - 1); | |
| 255 } | |
| 256 | |
| 257 var host = ""; | |
| 258 var userInfo = ""; | |
| 259 var port = 0; | |
| 260 if (schemeEndIndex != authorityEndIndex) { | |
| 261 int startIndex = schemeEndIndex + 2; | |
| 262 if (userInfoEndIndex > 0) { | |
| 263 userInfo = uri.substring(startIndex, userInfoEndIndex); | |
| 264 startIndex = userInfoEndIndex + 1; | |
| 265 } | |
| 266 if (portIndex > 0) { | |
| 267 var portStr = uri.substring(portIndex, authorityEndIndex); | |
| 268 try { | |
| 269 port = int.parse(portStr); | |
| 270 } catch (_) { | |
| 271 throw new FormatException("Invalid port: '$portStr'"); | |
| 272 } | |
| 273 host = uri.substring(startIndex, portIndex - 1); | |
| 274 } else { | |
| 275 host = uri.substring(startIndex, authorityEndIndex); | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 var path = uri.substring(authorityEndIndex, pathEndIndex); | |
| 280 var query = ""; | |
| 281 if (pathEndIndex < queryEndIndex) { | |
| 282 query = uri.substring(pathEndIndex + 1, queryEndIndex); | |
| 283 } | |
| 284 var fragment = ""; | |
| 285 // If queryEndIndex is not at end (length), there is a fragment. | |
| 286 if (queryEndIndex < length) { | |
| 287 fragment = uri.substring(queryEndIndex + 1, length); | |
| 288 } | |
| 289 | |
| 290 return new Uri(scheme: scheme, | |
| 291 userInfo: userInfo, | |
| 292 host: host, | |
| 293 port: port, | |
| 294 path: path, | |
| 295 query: query, | |
| 296 fragment: fragment); | |
| 297 } | |
| 132 | 298 |
| 133 /** | 299 /** |
| 134 * Creates a new URI from its components. | 300 * Creates a new URI from its components. |
| 135 * | 301 * |
| 136 * Each component is set through a named argument. Any number of | 302 * Each component is set through a named argument. Any number of |
| 137 * components can be provided. The default value for the components | 303 * components can be provided. The default value for the components |
| 138 * not provided is the empry string, except for [port] which has a | 304 * not provided is the empry string, except for [port] which has a |
| 139 * default value of 0. The [path] and [query] components can be set | 305 * default value of 0. The [path] and [query] components can be set |
| 140 * using two different named arguments. | 306 * using two different named arguments. |
| 141 * | 307 * |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 712 index++; | 878 index++; |
| 713 } | 879 } |
| 714 } | 880 } |
| 715 if (result != null && prevIndex != index) fillResult(); | 881 if (result != null && prevIndex != index) fillResult(); |
| 716 assert(index == length); | 882 assert(index == length); |
| 717 | 883 |
| 718 if (result == null) return component; | 884 if (result == null) return component; |
| 719 return result.toString(); | 885 return result.toString(); |
| 720 } | 886 } |
| 721 | 887 |
| 722 static String _emptyIfNull(String val) => val != null ? val : ''; | |
| 723 | |
| 724 static int _parseIntOrZero(String val) { | |
| 725 if (val != null && val != '') { | |
| 726 return int.parse(val); | |
| 727 } else { | |
| 728 return 0; | |
| 729 } | |
| 730 } | |
| 731 | |
| 732 static String _eitherOf(String val1, String val2) { | |
| 733 if (val1 != null) return val1; | |
| 734 if (val2 != null) return val2; | |
| 735 return ''; | |
| 736 } | |
| 737 | |
| 738 // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js | |
| 739 static final RegExp _splitRe = new RegExp( | |
| 740 '^' | |
| 741 '(?:' | |
| 742 '([^:/?#]+)' // scheme - ignore special characters | |
| 743 // used by other URL parts such as :, | |
| 744 // ?, /, #, and . | |
| 745 ':)?' | |
| 746 '(?://' | |
| 747 '(?:([^/?#]*)@)?' // userInfo | |
| 748 '(?:' | |
| 749 r'([\w\d\-\u0100-\uffff.%]*)' | |
| 750 // host - restrict to letters, | |
| 751 // digits, dashes, dots, percent | |
| 752 // escapes, and unicode characters. | |
| 753 '|' | |
| 754 // TODO(ajohnsen): Only allow a max number of parts? | |
| 755 r'\[([A-Fa-f0-9:.]*)\])' | |
| 756 // IPv6 host - restrict to hex, | |
| 757 // dot and colon. | |
| 758 '(?::([0-9]+))?' // port | |
| 759 ')?' | |
| 760 r'([^?#[]+)?' // path | |
| 761 r'(?:\?([^#]*))?' // query | |
| 762 '(?:#(.*))?' // fragment | |
| 763 r'$'); | |
| 764 | |
| 765 static const _COMPONENT_SCHEME = 1; | |
| 766 static const _COMPONENT_USER_INFO = 2; | |
| 767 static const _COMPONENT_HOST = 3; | |
| 768 static const _COMPONENT_HOST_IPV6 = 4; | |
| 769 static const _COMPONENT_PORT = 5; | |
| 770 static const _COMPONENT_PATH = 6; | |
| 771 static const _COMPONENT_QUERY_DATA = 7; | |
| 772 static const _COMPONENT_FRAGMENT = 8; | |
| 773 | |
| 774 /** | 888 /** |
| 775 * Returns whether the URI is absolute. | 889 * Returns whether the URI is absolute. |
| 776 */ | 890 */ |
| 777 bool get isAbsolute => scheme != "" && fragment == ""; | 891 bool get isAbsolute => scheme != "" && fragment == ""; |
| 778 | 892 |
| 779 String _merge(String base, String reference) { | 893 String _merge(String base, String reference) { |
| 780 if (base == "") return "/$reference"; | 894 if (base == "") return "/$reference"; |
| 781 return "${base.substring(0, base.lastIndexOf("/") + 1)}$reference"; | 895 return "${base.substring(0, base.lastIndexOf("/") + 1)}$reference"; |
| 782 } | 896 } |
| 783 | 897 |
| (...skipping 834 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1618 0x2bff, // 0x30 - 0x3f 1111111111010100 | 1732 0x2bff, // 0x30 - 0x3f 1111111111010100 |
| 1619 // ABCDEFGHIJKLMNO | 1733 // ABCDEFGHIJKLMNO |
| 1620 0xfffe, // 0x40 - 0x4f 0111111111111111 | 1734 0xfffe, // 0x40 - 0x4f 0111111111111111 |
| 1621 // PQRSTUVWXYZ _ | 1735 // PQRSTUVWXYZ _ |
| 1622 0x87ff, // 0x50 - 0x5f 1111111111100001 | 1736 0x87ff, // 0x50 - 0x5f 1111111111100001 |
| 1623 // abcdefghijklmno | 1737 // abcdefghijklmno |
| 1624 0xfffe, // 0x60 - 0x6f 0111111111111111 | 1738 0xfffe, // 0x60 - 0x6f 0111111111111111 |
| 1625 // pqrstuvwxyz ~ | 1739 // pqrstuvwxyz ~ |
| 1626 0x47ff]; // 0x70 - 0x7f 1111111111100010 | 1740 0x47ff]; // 0x70 - 0x7f 1111111111100010 |
| 1627 | 1741 |
| 1742 // Characters allowed in the reg-name as of RFC 3986. | |
| 1743 // RFC 3986 Apendix A | |
| 1744 // reg-name = *( unreserved / pct-encoded / sub-delims ) | |
| 1745 static const _regNameTable = const [ | |
| 1746 // LSB MSB | |
| 1747 // | | | |
| 1748 0x0000, // 0x00 - 0x0f 0000000000000000 | |
| 1749 0x0000, // 0x10 - 0x1f 0000000000000000 | |
| 1750 // ! $%&'()*+,-. | |
| 1751 0x7ff2, // 0x20 - 0x2f 0100111111111110 | |
| 1752 // 0123456789 ; = | |
| 1753 0x2bff, // 0x30 - 0x3f 1111111111010100 | |
| 1754 // ABCDEFGHIJKLMNO | |
| 1755 0xfffe, // 0x40 - 0x4f 0111111111111111 | |
| 1756 // PQRSTUVWXYZ _ | |
| 1757 0x87ff, // 0x50 - 0x5f 1111111111100001 | |
| 1758 // abcdefghijklmno | |
| 1759 0xfffe, // 0x60 - 0x6f 0111111111111111 | |
| 1760 // pqrstuvwxyz ~ | |
| 1761 0x47ff]; // 0x70 - 0x7f 1111111111100010 | |
| 1762 | |
| 1628 // Characters allowed in the path as of RFC 3986. | 1763 // Characters allowed in the path as of RFC 3986. |
| 1629 // RFC 3986 section 3.3. | 1764 // RFC 3986 section 3.3. |
| 1630 // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" | 1765 // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" |
| 1631 static const _pathCharTable = const [ | 1766 static const _pathCharTable = const [ |
| 1632 // LSB MSB | 1767 // LSB MSB |
| 1633 // | | | 1768 // | | |
| 1634 0x0000, // 0x00 - 0x0f 0000000000000000 | 1769 0x0000, // 0x00 - 0x0f 0000000000000000 |
| 1635 0x0000, // 0x10 - 0x1f 0000000000000000 | 1770 0x0000, // 0x10 - 0x1f 0000000000000000 |
| 1636 // ! $ &'()*+,-. | 1771 // ! $ &'()*+,-. |
| 1637 0x7fd2, // 0x20 - 0x2f 0100101111111110 | 1772 0x7fd2, // 0x20 - 0x2f 0100101111111110 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1690 void clear() { | 1825 void clear() { |
| 1691 throw new UnsupportedError("Cannot modify an unmodifiable map"); | 1826 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 1692 } | 1827 } |
| 1693 void forEach(void f(K key, V value)) => _map.forEach(f); | 1828 void forEach(void f(K key, V value)) => _map.forEach(f); |
| 1694 Iterable<K> get keys => _map.keys; | 1829 Iterable<K> get keys => _map.keys; |
| 1695 Iterable<V> get values => _map.values; | 1830 Iterable<V> get values => _map.values; |
| 1696 int get length => _map.length; | 1831 int get length => _map.length; |
| 1697 bool get isEmpty => _map.isEmpty; | 1832 bool get isEmpty => _map.isEmpty; |
| 1698 bool get isNotEmpty => _map.isNotEmpty; | 1833 bool get isNotEmpty => _map.isNotEmpty; |
| 1699 } | 1834 } |
| OLD | NEW |