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, 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 int _port; | 11 int _port; |
| 12 String _path; | |
| 12 | 13 |
| 13 /** | 14 /** |
| 14 * Returns the scheme component. | 15 * Returns the scheme component. |
| 15 * | 16 * |
| 16 * Returns the empty string if there is no scheme component. | 17 * Returns the empty string if there is no scheme component. |
| 17 */ | 18 */ |
| 18 final String scheme; | 19 final String scheme; |
| 19 | 20 |
| 20 /** | 21 /** |
| 21 * Returns the authority component. | 22 * Returns the authority component. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 56 int get port => _port; | 57 int get port => _port; |
| 57 | 58 |
| 58 /** | 59 /** |
| 59 * Returns the path component. | 60 * Returns the path component. |
| 60 * | 61 * |
| 61 * The returned path is encoded. To get direct access to the decoded | 62 * The returned path is encoded. To get direct access to the decoded |
| 62 * path use [pathSegments]. | 63 * path use [pathSegments]. |
| 63 * | 64 * |
| 64 * Returns the empty string if there is no path component. | 65 * Returns the empty string if there is no path component. |
| 65 */ | 66 */ |
| 66 final String path; | 67 String get path => _path; |
| 67 | 68 |
| 68 /** | 69 /** |
| 69 * Returns the query component. The returned query is encoded. To get | 70 * Returns the query component. The returned query is encoded. To get |
| 70 * direct access to the decoded query use [queryParameters]. | 71 * direct access to the decoded query use [queryParameters]. |
| 71 * | 72 * |
| 72 * Returns the empty string if there is no query component. | 73 * Returns the empty string if there is no query component. |
| 73 */ | 74 */ |
| 74 final String query; | 75 final String query; |
| 75 | 76 |
| 76 /** | 77 /** |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 * [port]. The port is normalized for scheme http and https where | 131 * [port]. The port is normalized for scheme http and https where |
| 131 * port 80 and port 443 respectively is set. | 132 * port 80 and port 443 respectively is set. |
| 132 * | 133 * |
| 133 * The path component is set through either [path] or | 134 * The path component is set through either [path] or |
| 134 * [pathSegments]. When [path] is used, the provided string is | 135 * [pathSegments]. When [path] is used, the provided string is |
| 135 * expected to be fully percent-encoded, and is used in its literal | 136 * expected to be fully percent-encoded, and is used in its literal |
| 136 * form. When [pathSegments] is used, each of the provided segments | 137 * form. When [pathSegments] is used, each of the provided segments |
| 137 * is percent-encoded and joined using the forward slash | 138 * is percent-encoded and joined using the forward slash |
| 138 * separator. The percent-encoding of the path segments encodes all | 139 * separator. The percent-encoding of the path segments encodes all |
| 139 * characters except for the unreserved characters and the following | 140 * characters except for the unreserved characters and the following |
| 140 * list of characters: `!$&'()*+,;=:@`. | 141 * list of characters: `!$&'()*+,;=:@`. If the other components |
| 142 * calls for an absolute path a leading slash `/` is prepended if | |
| 143 * not already there. | |
| 141 * | 144 * |
| 142 * The query component is set through either [query] or | 145 * The query component is set through either [query] or |
| 143 * [queryParameters]. When [query] is used the provided string is | 146 * [queryParameters]. When [query] is used the provided string is |
| 144 * expected to be fully percent-encoded and is used in its literal | 147 * expected to be fully percent-encoded and is used in its literal |
| 145 * form. When [queryParameters] is used the query is built from the | 148 * form. When [queryParameters] is used the query is built from the |
| 146 * provided map. Each key and value in the map is percent-encoded | 149 * provided map. Each key and value in the map is percent-encoded |
| 147 * and joined using equal and ampersand characters. The | 150 * and joined using equal and ampersand characters. The |
| 148 * percent-encoding of the keys and values encodes all characters | 151 * percent-encoding of the keys and values encodes all characters |
| 149 * except for the unreserved characters. | 152 * except for the unreserved characters. |
| 150 * | 153 * |
| 151 * The fragment component is set through [fragment]. | 154 * The fragment component is set through [fragment]. |
| 152 */ | 155 */ |
| 153 Uri({scheme, | 156 Uri({scheme, |
| 154 this.userInfo: "", | 157 this.userInfo: "", |
| 155 this.host: "", | 158 this.host: "", |
| 156 port: 0, | 159 port: 0, |
| 157 String path, | 160 String path, |
| 158 List<String> pathSegments, | 161 List<String> pathSegments, |
| 159 String query, | 162 String query, |
| 160 Map<String, String> queryParameters, | 163 Map<String, String> queryParameters, |
| 161 fragment: ""}) : | 164 fragment: ""}) : |
| 162 scheme = _makeScheme(scheme), | 165 scheme = _makeScheme(scheme), |
| 163 path = _makePath(path, pathSegments), | |
| 164 query = _makeQuery(query, queryParameters), | 166 query = _makeQuery(query, queryParameters), |
| 165 fragment = _makeFragment(fragment) { | 167 fragment = _makeFragment(fragment) { |
| 166 // Perform scheme specific normalization. | 168 // Perform scheme specific normalization. |
| 167 if (scheme == "http" && port == 80) { | 169 if (scheme == "http" && port == 80) { |
| 168 _port = 0; | 170 _port = 0; |
| 169 } else if (scheme == "https" && port == 443) { | 171 } else if (scheme == "https" && port == 443) { |
| 170 _port = 0; | 172 _port = 0; |
| 171 } else { | 173 } else { |
| 172 _port = port; | 174 _port = port; |
| 173 } | 175 } |
| 176 // Fill the path. | |
| 177 _path = _makePath(path, pathSegments); | |
|
Lasse Reichstein Nielsen
2013/06/06 11:50:32
But _makePath was changed to return void?
Søren Gjesse
2013/06/06 14:06:54
And that was wrong.
| |
| 174 } | 178 } |
| 175 | 179 |
| 176 /* | 180 /* |
| 177 * Returns the URI path split into its segments. Each of the | 181 * Returns the URI path split into its segments. Each of the |
| 178 * 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 |
| 179 * empty the empty list will be returned. | 183 * empty the empty list will be returned. A leading slash `/` does |
| 184 * not affect the segments returned. | |
| 180 * | 185 * |
| 181 * The returned list is immutable and will throw [StateError] on any | 186 * The returned list is unmodifiable and will throw [UnsupportedError] on any |
| 182 * calls that would mutate it. | 187 * calls that would mutate it. |
| 183 */ | 188 */ |
| 184 List<String> get pathSegments { | 189 List<String> get pathSegments { |
| 185 if (_pathSegments == null) { | 190 if (_pathSegments == null) { |
| 191 var pathToSplit = !path.isEmpty && path.codeUnitAt(0) == _SLASH | |
| 192 ? path.substring(1) | |
| 193 : path; | |
| 186 _pathSegments = new UnmodifiableListView( | 194 _pathSegments = new UnmodifiableListView( |
| 187 path == "" ? const<String>[] | 195 pathToSplit == "" ? const<String>[] |
| 188 : path.split("/") | 196 : pathToSplit.split("/") |
| 189 .map(Uri.decodeComponent) | 197 .map(Uri.decodeComponent) |
| 190 .toList(growable: false)); | 198 .toList(growable: false)); |
| 191 } | 199 } |
| 192 return _pathSegments; | 200 return _pathSegments; |
| 193 } | 201 } |
| 194 | 202 |
| 195 /* | 203 /* |
| 196 * 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 |
| 197 * specified for FORM post in the HTML 4.01 specification. Each key | 205 * specified for FORM post in the HTML 4.01 specification. Each key |
| 198 * and value in the returned map have been decoded. If there is no | 206 * and value in the returned map have been decoded. If there is no |
| 199 * query the empty map will be returned. | 207 * query the empty map will be returned. |
| 200 * | 208 * |
| 201 * The returned map is immutable and will throw [StateError] on any | 209 * The returned map is unmodifiable and will throw [UnsupportedError] on any |
| 202 * calls that would mutate it. | 210 * calls that would mutate it. |
| 203 */ | 211 */ |
| 204 Map<String, String> get queryParameters { | 212 Map<String, String> get queryParameters { |
| 205 if (_queryParameters == null) { | 213 if (_queryParameters == null) { |
| 206 var map; | 214 var map; |
| 207 map = query.split("&").fold({}, (map, element) { | 215 map = query.split("&").fold({}, (map, element) { |
| 208 int index = element.indexOf("="); | 216 int index = element.indexOf("="); |
| 209 if (index == -1) { | 217 if (index == -1) { |
| 210 if (!element.isEmpty) map[decodeQueryComponent(element)] = ""; | 218 if (!element.isEmpty) map[decodeQueryComponent(element)] = ""; |
| 211 } else if (index != 0) { | 219 } else if (index != 0) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 240 allLowercase = false; | 248 allLowercase = false; |
| 241 } else { | 249 } else { |
| 242 throw new ArgumentError('Illegal scheme: $scheme'); | 250 throw new ArgumentError('Illegal scheme: $scheme'); |
| 243 } | 251 } |
| 244 } | 252 } |
| 245 } | 253 } |
| 246 | 254 |
| 247 return allLowercase ? scheme : scheme.toLowerCase(); | 255 return allLowercase ? scheme : scheme.toLowerCase(); |
| 248 } | 256 } |
| 249 | 257 |
| 250 static String _makePath(String path, List<String> pathSegments) { | 258 void _makePath(String path, List<String> pathSegments) { |
| 251 if (path == null && pathSegments == null) return ""; | 259 if (path == null && pathSegments == null) return ""; |
| 252 if (path != null && pathSegments != null) { | 260 if (path != null && pathSegments != null) { |
| 253 throw new ArgumentError('Both path and pathSegments specified'); | 261 throw new ArgumentError('Both path and pathSegments specified'); |
| 254 } | 262 } |
| 255 if (path != null) return _normalize(path); | 263 var result; |
| 256 | 264 if (path != null) { |
| 257 return pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/"); | 265 result = _normalize(path); |
| 266 } else { | |
| 267 result = pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/"); | |
| 268 } | |
| 269 if ((hasAuthority || (scheme == "file")) && | |
| 270 !result.isEmpty && result.codeUnitAt(0) != _SLASH) { | |
|
Lasse Reichstein Nielsen
2013/06/06 11:50:32
result.startsWith("/") ?
(and remember isNotEmpty
Søren Gjesse
2013/06/06 14:06:54
Done.
| |
| 271 return "/${result}"; | |
|
Lasse Reichstein Nielsen
2013/06/06 11:50:32
No need for { and } around "result".
Søren Gjesse
2013/06/06 14:06:54
Done.
| |
| 272 } | |
| 273 return result; | |
| 258 } | 274 } |
| 259 | 275 |
| 260 static String _makeQuery(String query, Map<String, String> queryParameters) { | 276 static String _makeQuery(String query, Map<String, String> queryParameters) { |
| 261 if (query == null && queryParameters == null) return ""; | 277 if (query == null && queryParameters == null) return ""; |
| 262 if (query != null && queryParameters != null) { | 278 if (query != null && queryParameters != null) { |
| 263 throw new ArgumentError('Both query and queryParameters specified'); | 279 throw new ArgumentError('Both query and queryParameters specified'); |
| 264 } | 280 } |
| 265 if (query != null) return _normalize(query); | 281 if (query != null) return _normalize(query); |
| 266 | 282 |
| 267 var result = new StringBuffer(); | 283 var result = new StringBuffer(); |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 698 * cases an encoded URI should be parsed into components using | 714 * cases an encoded URI should be parsed into components using |
| 699 * [Uri.parse] before decoding the separate components. | 715 * [Uri.parse] before decoding the separate components. |
| 700 */ | 716 */ |
| 701 static String decodeFull(String uri) { | 717 static String decodeFull(String uri) { |
| 702 return _uriDecode(uri); | 718 return _uriDecode(uri); |
| 703 } | 719 } |
| 704 | 720 |
| 705 // Frequently used character codes. | 721 // Frequently used character codes. |
| 706 static const int _PERCENT = 0x25; | 722 static const int _PERCENT = 0x25; |
| 707 static const int _PLUS = 0x2B; | 723 static const int _PLUS = 0x2B; |
| 724 static const int _SLASH = 0x2F; | |
| 708 static const int _ZERO = 0x30; | 725 static const int _ZERO = 0x30; |
| 709 static const int _NINE = 0x39; | 726 static const int _NINE = 0x39; |
| 710 static const int _COLON = 0x3A; | 727 static const int _COLON = 0x3A; |
| 711 static const int _UPPER_CASE_A = 0x41; | 728 static const int _UPPER_CASE_A = 0x41; |
| 712 static const int _UPPER_CASE_F = 0x46; | 729 static const int _UPPER_CASE_F = 0x46; |
| 713 static const int _LOWER_CASE_A = 0x61; | 730 static const int _LOWER_CASE_A = 0x61; |
| 714 static const int _LOWER_CASE_F = 0x66; | 731 static const int _LOWER_CASE_F = 0x66; |
| 715 | 732 |
| 716 /** | 733 /** |
| 717 * This is the internal implementation of JavaScript's encodeURI function. | 734 * This is the internal implementation of JavaScript's encodeURI function. |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 993 void clear() { | 1010 void clear() { |
| 994 throw new UnsupportedError("Cannot modify an unmodifiable map"); | 1011 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 995 } | 1012 } |
| 996 void forEach(void f(K key, V value)) => _map.forEach(f); | 1013 void forEach(void f(K key, V value)) => _map.forEach(f); |
| 997 Iterable<K> get keys => _map.keys; | 1014 Iterable<K> get keys => _map.keys; |
| 998 Iterable<V> get values => _map.values; | 1015 Iterable<V> get values => _map.values; |
| 999 int get length => _map.length; | 1016 int get length => _map.length; |
| 1000 bool get isEmpty => _map.isEmpty; | 1017 bool get isEmpty => _map.isEmpty; |
| 1001 bool get isNotEmpty => _map.isNotEmpty; | 1018 bool get isNotEmpty => _map.isNotEmpty; |
| 1002 } | 1019 } |
| OLD | NEW |