Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: sdk/lib/core/uri.dart

Issue 16470004: Add leading slash to URI path when required. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/corelib/uri_path_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/corelib/uri_path_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698