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 { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 Uri._fromMatch(Match m) : | 100 Uri._fromMatch(Match m) : |
101 this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]), | 101 this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]), |
102 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]), | 102 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]), |
103 host: _eitherOf( | 103 host: _eitherOf( |
104 m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]), | 104 m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]), |
105 port: _parseIntOrZero(m[_COMPONENT_PORT]), | 105 port: _parseIntOrZero(m[_COMPONENT_PORT]), |
106 path: _emptyIfNull(m[_COMPONENT_PATH]), | 106 path: _emptyIfNull(m[_COMPONENT_PATH]), |
107 query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]), | 107 query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]), |
108 fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT])); | 108 fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT])); |
109 | 109 |
110 /* | 110 /** |
111 * Create a new URI from its components. | 111 * Create a new URI from its components. |
112 * | 112 * |
113 * Each component is set through a named argument. Any number of | 113 * Each component is set through a named argument. Any number of |
114 * components can be provided. The default value for the components | 114 * components can be provided. The default value for the components |
115 * not provided is the empry string, except for [port] which has a | 115 * not provided is the empry string, except for [port] which has a |
116 * default value of 0. The [path] and [query] components can be set | 116 * default value of 0. The [path] and [query] components can be set |
117 * using two different named arguments. | 117 * using two different named arguments. |
118 * | 118 * |
119 * The scheme component is set through [scheme]. The scheme is | 119 * The scheme component is set through [scheme]. The scheme is |
120 * normalized to all lowercase letters. | 120 * normalized to all lowercase letters. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 _port = 0; | 170 _port = 0; |
171 } else if (scheme == "https" && port == 443) { | 171 } else if (scheme == "https" && port == 443) { |
172 _port = 0; | 172 _port = 0; |
173 } else { | 173 } else { |
174 _port = port; | 174 _port = port; |
175 } | 175 } |
176 // Fill the path. | 176 // Fill the path. |
177 _path = _makePath(path, pathSegments); | 177 _path = _makePath(path, pathSegments); |
178 } | 178 } |
179 | 179 |
180 /* | 180 /** |
181 * Returns the URI path split into its segments. Each of the | 181 * Returns the URI path split into its segments. Each of the |
182 * segments in the returned list have been decoded. If the path is | 182 * segments in the returned list have been decoded. If the path is |
183 * empty the empty list will be returned. A leading slash `/` does | 183 * empty the empty list will be returned. A leading slash `/` does |
184 * not affect the segments returned. | 184 * not affect the segments returned. |
185 * | 185 * |
186 * The returned list is unmodifiable and will throw [UnsupportedError] on any | 186 * The returned list is unmodifiable and will throw [UnsupportedError] on any |
187 * calls that would mutate it. | 187 * calls that would mutate it. |
188 */ | 188 */ |
189 List<String> get pathSegments { | 189 List<String> get pathSegments { |
190 if (_pathSegments == null) { | 190 if (_pathSegments == null) { |
191 var pathToSplit = !path.isEmpty && path.codeUnitAt(0) == _SLASH | 191 var pathToSplit = !path.isEmpty && path.codeUnitAt(0) == _SLASH |
192 ? path.substring(1) | 192 ? path.substring(1) |
193 : path; | 193 : path; |
194 _pathSegments = new UnmodifiableListView( | 194 _pathSegments = new UnmodifiableListView( |
195 pathToSplit == "" ? const<String>[] | 195 pathToSplit == "" ? const<String>[] |
196 : pathToSplit.split("/") | 196 : pathToSplit.split("/") |
197 .map(Uri.decodeComponent) | 197 .map(Uri.decodeComponent) |
198 .toList(growable: false)); | 198 .toList(growable: false)); |
199 } | 199 } |
200 return _pathSegments; | 200 return _pathSegments; |
201 } | 201 } |
202 | 202 |
203 /* | 203 /** |
204 * Returns the URI query split into a map according to the rules | 204 * Returns the URI query split into a map according to the rules |
205 * specified for FORM post in the HTML 4.01 specification. Each key | 205 * specified for FORM post in the [HTML 4.01 specification section 17.13.4] |
206 * and value in the returned map have been decoded. If there is no | 206 * (http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 |
207 * query the empty map will be returned. | 207 * "HTML 4.01 section 17.13.4"). Each key and value in the returned map |
| 208 * has been decoded. If there is no query the empty map is returned. |
| 209 * |
| 210 * Keys in the query string that have no value are mapped to the |
| 211 * empty string. |
208 * | 212 * |
209 * The returned map is unmodifiable and will throw [UnsupportedError] on any | 213 * The returned map is unmodifiable and will throw [UnsupportedError] on any |
210 * calls that would mutate it. | 214 * calls that would mutate it. |
211 */ | 215 */ |
212 Map<String, String> get queryParameters { | 216 Map<String, String> get queryParameters { |
213 if (_queryParameters == null) { | 217 if (_queryParameters == null) { |
214 var map; | 218 _queryParameters = new _UnmodifiableMap(splitQueryString(query)); |
215 map = query.split("&").fold({}, (map, element) { | |
216 int index = element.indexOf("="); | |
217 if (index == -1) { | |
218 if (!element.isEmpty) map[decodeQueryComponent(element)] = ""; | |
219 } else if (index != 0) { | |
220 var key = element.substring(0, index); | |
221 var value = element.substring(index + 1); | |
222 map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value); | |
223 } | |
224 return map; | |
225 }); | |
226 _queryParameters = new _UnmodifiableMap(map); | |
227 } | 219 } |
228 return _queryParameters; | 220 return _queryParameters; |
229 } | 221 } |
230 | 222 |
231 static String _makeScheme(String scheme) { | 223 static String _makeScheme(String scheme) { |
232 bool isSchemeLowerCharacter(int ch) { | 224 bool isSchemeLowerCharacter(int ch) { |
233 return ch < 128 && | 225 return ch < 128 && |
234 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | 226 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
235 } | 227 } |
236 | 228 |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 } | 534 } |
543 return new Uri(scheme: targetScheme, | 535 return new Uri(scheme: targetScheme, |
544 userInfo: targetUserInfo, | 536 userInfo: targetUserInfo, |
545 host: targetHost, | 537 host: targetHost, |
546 port: targetPort, | 538 port: targetPort, |
547 path: targetPath, | 539 path: targetPath, |
548 query: targetQuery, | 540 query: targetQuery, |
549 fragment: reference.fragment); | 541 fragment: reference.fragment); |
550 } | 542 } |
551 | 543 |
| 544 /** |
| 545 * Returns whether the URI has an [authority] component. |
| 546 */ |
552 bool get hasAuthority => host != ""; | 547 bool get hasAuthority => host != ""; |
553 | 548 |
554 /** | 549 /** |
555 * Returns the origin of the URI in the form scheme://host:port for the | 550 * Returns the origin of the URI in the form scheme://host:port for the |
556 * schemes http and https. | 551 * schemes http and https. |
557 * | 552 * |
558 * It is an error if the scheme is not "http" or "https". | 553 * It is an error if the scheme is not "http" or "https". |
559 * | 554 * |
560 * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin | 555 * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin |
561 */ | 556 */ |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 * [encodeQueryComponent]. | 635 * [encodeQueryComponent]. |
641 * | 636 * |
642 * To avoid the need for explicitly encoding use the [pathSegments] | 637 * To avoid the need for explicitly encoding use the [pathSegments] |
643 * and [queryParameters] optional named arguments when constructing | 638 * and [queryParameters] optional named arguments when constructing |
644 * a [Uri]. | 639 * a [Uri]. |
645 */ | 640 */ |
646 static String encodeComponent(String component) { | 641 static String encodeComponent(String component) { |
647 return _uriEncode(_unreserved2396Table, component); | 642 return _uriEncode(_unreserved2396Table, component); |
648 } | 643 } |
649 | 644 |
650 /* | 645 /** |
651 * Encode the string [component] according to the HTML 4.01 rules | 646 * Encode the string [component] according to the HTML 4.01 rules |
652 * for encoding the posting of a HTML form as a query string | 647 * for encoding the posting of a HTML form as a query string |
653 * component. | 648 * component. |
654 * | 649 * |
655 * Spaces will be replaced with plus and all characters except for | 650 * Spaces will be replaced with plus and all characters except for |
656 * uppercase and lowercase letters, decimal digits and the | 651 * uppercase and lowercase letters, decimal digits and the |
657 * characters `-._~`. Note that the set of characters encoded is a | 652 * characters `-._~`. Note that the set of characters encoded is a |
658 * superset of what HTML 4.01 says as it refers to RFC 1738 for | 653 * superset of what HTML 4.01 says as it refers to RFC 1738 for |
659 * reserved characters. | 654 * reserved characters. |
660 * | 655 * |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
711 * | 706 * |
712 * Note that decoding a full URI might change its meaning as some of | 707 * Note that decoding a full URI might change its meaning as some of |
713 * the decoded characters could be reserved characters. In most | 708 * the decoded characters could be reserved characters. In most |
714 * cases an encoded URI should be parsed into components using | 709 * cases an encoded URI should be parsed into components using |
715 * [Uri.parse] before decoding the separate components. | 710 * [Uri.parse] before decoding the separate components. |
716 */ | 711 */ |
717 static String decodeFull(String uri) { | 712 static String decodeFull(String uri) { |
718 return _uriDecode(uri); | 713 return _uriDecode(uri); |
719 } | 714 } |
720 | 715 |
| 716 /** |
| 717 * Returns the [query] split into a map according to the rules |
| 718 * specified for FORM post in the |
| 719 * [HTML 4.01 specification section 17.13.4] |
| 720 * (http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 |
| 721 * "HTML 4.01 section 17.13.4"). Each key and value in the returned |
| 722 * map has been decoded. If the [query] |
| 723 * is the empty string an empty map is returned. |
| 724 * |
| 725 * Keys in the query string that have no value are mapped to the |
| 726 * empty string. |
| 727 */ |
| 728 static Map<String, String> splitQueryString(String query) { |
| 729 return query.split("&").fold({}, (map, element) { |
| 730 int index = element.indexOf("="); |
| 731 if (index == -1) { |
| 732 if (element != "") map[decodeQueryComponent(element)] = ""; |
| 733 } else if (index != 0) { |
| 734 var key = element.substring(0, index); |
| 735 var value = element.substring(index + 1); |
| 736 map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value); |
| 737 } |
| 738 return map; |
| 739 }); |
| 740 } |
| 741 |
721 // Frequently used character codes. | 742 // Frequently used character codes. |
722 static const int _PERCENT = 0x25; | 743 static const int _PERCENT = 0x25; |
723 static const int _PLUS = 0x2B; | 744 static const int _PLUS = 0x2B; |
724 static const int _SLASH = 0x2F; | 745 static const int _SLASH = 0x2F; |
725 static const int _ZERO = 0x30; | 746 static const int _ZERO = 0x30; |
726 static const int _NINE = 0x39; | 747 static const int _NINE = 0x39; |
727 static const int _COLON = 0x3A; | 748 static const int _COLON = 0x3A; |
728 static const int _UPPER_CASE_A = 0x41; | 749 static const int _UPPER_CASE_A = 0x41; |
729 static const int _UPPER_CASE_F = 0x46; | 750 static const int _UPPER_CASE_F = 0x46; |
730 static const int _LOWER_CASE_A = 0x61; | 751 static const int _LOWER_CASE_A = 0x61; |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1010 void clear() { | 1031 void clear() { |
1011 throw new UnsupportedError("Cannot modify an unmodifiable map"); | 1032 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
1012 } | 1033 } |
1013 void forEach(void f(K key, V value)) => _map.forEach(f); | 1034 void forEach(void f(K key, V value)) => _map.forEach(f); |
1014 Iterable<K> get keys => _map.keys; | 1035 Iterable<K> get keys => _map.keys; |
1015 Iterable<V> get values => _map.values; | 1036 Iterable<V> get values => _map.values; |
1016 int get length => _map.length; | 1037 int get length => _map.length; |
1017 bool get isEmpty => _map.isEmpty; | 1038 bool get isEmpty => _map.isEmpty; |
1018 bool get isNotEmpty => _map.isNotEmpty; | 1039 bool get isNotEmpty => _map.isNotEmpty; |
1019 } | 1040 } |
OLD | NEW |