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

Unified Diff: sdk/lib/core/uri.dart

Issue 1520943002: Support the same parameter key more than once in Uri query parameters. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/core/uri.dart
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index e4a31aa575fd0f40d23012d7b8f1382cf17d279c..660c8c87a592a248494cfa93cde8c3244b6b5146 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -136,14 +136,16 @@ class Uri {
* will be escaped if necessary.
* When [queryParameters] is used the query is built from the
* provided map. Each key and value in the map is percent-encoded
- * and joined using equal and ampersand characters. The
- * percent-encoding of the keys and values encodes all characters
- * except for the unreserved characters.
+ * and joined using equal and ampersand characters.
+ * A value in the map must be either a string, or a an [Iterable] of strings,
+ * where the latter corresponds to multiple values for the same key.
+ * The percent-encoding of the keys and values encodes all characters
+ * except for the unreserved characters, and replaces spaces with `+`.
* If `query` is the empty string, it is equivalent to omitting it.
* To have an actual empty query part,
* use an empty list for `queryParameters`.
- * If both `query` and `queryParameters` are omitted or `null`, the
- * URI will have no query part.
+ * If both `query` and `queryParameters` are omitted or `null`,
+ * the URI will have no query part.
*
* The fragment component is set through [fragment].
* It should be a valid URI fragment, but invalid characters other than
@@ -157,7 +159,7 @@ class Uri {
String path,
Iterable<String> pathSegments,
String query,
- Map<String, String> queryParameters,
+ Map<String, dynamic> queryParameters,
String fragment}) {
scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
@@ -1104,23 +1106,54 @@ class Uri {
* Returns the URI query split into a map according to the rules
* specified for FORM post in the [HTML 4.01 specification section
* 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
- * Each key and value in the returned map has been decoded. If there is no
- * query the empty map is returned.
+ * Each key and value in the returned map has been decoded.
+ * If there is no query the empty map is returned.
*
* Keys in the query string that have no value are mapped to the
* empty string.
+ * If a key occurs more than once in the query string, it is mapped to
+ * one of the values. The [queryParameterValues] getter can provide a
floitsch 2015/12/11 19:00:58 which one?
Lasse Reichstein Nielsen 2016/01/12 13:34:11 I really don't want to promise that. It's likely g
+ * map that maps to all the values.
*
* The returned map is unmodifiable and will throw [UnsupportedError] on any
* calls that would mutate it.
*/
Map<String, String> get queryParameters {
if (_queryParameters == null) {
- _queryParameters = new UnmodifiableMapView(splitQueryString(query));
+ _queryParameters =
+ new UnmodifiableMapView<String, String>(splitQueryString(query));
}
return _queryParameters;
}
/**
+ * Returns the URI query split into a map according to the rules
+ * specified for FORM post in the [HTML 4.01 specification section
+ * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+ * Each key and value in the returned map has been decoded. If there is no
+ * query the empty map is returned.
+ *
+ * Keys are mapped to lists of their values. If a key occurs only once,
+ * its value is a singleton list. If a key occurs with no value, the
+ * empty string is used as the value for that occurrence.
+ *
+ * The returned map and the lists it contains are unmodifiable
+ * and will throw [UnsupportedError] on any calls that would mutate them.
+ */
+ Map<String, List<String>> get queryParameterLists {
+ if (_queryParameterLists == null) {
+ Map queryParameterLists = _splitQueryStringAll(query);
+ for (var key in queryParameterLists.keys) {
+ queryParameterLists[key] =
+ new List<String>.unmodifiable(queryParameterLists[key]);
+ }
+ _queryParameterLists = new Map<String, List<String>>.unmodifiable(
+ queryParameterLists);
+ }
+ return _queryParameterLists;
+ }
+
+ /**
* Returns a URI where the path has been normalized.
*
* A normalized path does not contain `.` segments or non-leading `..`
@@ -1350,10 +1383,23 @@ class Uri {
result.write("&");
}
first = false;
- result.write(Uri.encodeQueryComponent(key));
- if (value != null && !value.isEmpty) {
- result.write("=");
- result.write(Uri.encodeQueryComponent(value));
+ if (value == null) {
Søren Gjesse 2015/12/14 07:41:00 Maybe this is OK, but if value is null or the empt
Lasse Reichstein Nielsen 2015/12/14 13:13:12 I think a "foo":[] entry should not introduce a "f
+ result.write(Uri.encodeQueryComponent(key));
+ } else if (value is String) {
+ result.write(Uri.encodeQueryComponent(key));
+ if (value.isNotEmpty) {
+ result.write("=");
+ result.write(Uri.encodeQueryComponent(value));
+ }
+ } else {
+ Iterable values = value;
+ for (String value in values) {
+ result.write(Uri.encodeQueryComponent(key));
+ if (value != null && value.isNotEmpty) {
+ result.write("=");
+ result.write(Uri.encodeQueryComponent(value));
+ }
+ }
}
});
return result.toString();
@@ -2156,6 +2202,43 @@ class Uri {
});
}
+ static List _createList() => [];
+
+ static Map _splitQueryStringAll(
+ String query, {Encoding encoding: UTF8}) {
+ Map result = {};
+ int i = 0;
+ int start = 0;
+ int equalsIndex = -1;
+ void parsePair(int start, int equalsIndex, int end) {
floitsch 2015/12/11 19:00:58 new line before and after nested functions.
Lasse Reichstein Nielsen 2016/01/12 13:34:11 Done.
+ String key;
+ String value;
+ if (equalsIndex < 0) {
+ key = _uriDecode(encodedComponent, start, end, encoding, true);
+ value = "";
+ } else {
+ key =
+ _uriDecode(encodedComponent, start, equalsIndex, encoding, true);
floitsch 2015/12/11 19:00:58 nit: it looks like this would fit on the previous
Lasse Reichstein Nielsen 2016/01/12 13:34:11 It does. Incredible!
+ value =
+ _uriDecode(encodedComponent, equalsIndex + 1, end, encoding, true);
+ }
+ result.putIfAbsent(key, _createList).add(value);
+ }
+ while (i < query.length) {
+ int char = query.codeUnitAt(i);
+ if (char == _equals && equalsIndex < 0) {
+ equalsIndex = i;
+ } else if (i == _ampersand) {
+ parsePair(start, equalsIndex, i);
+ start = i + 1;
+ equalsIndex = -1;
+ }
+ i++;
+ }
+ parsePair(start, equalsIndex, i);
+ return result;
+ }
+
/**
* Parse the [host] as an IP version 4 (IPv4) address, returning the address
* as a list of 4 bytes in network byte order (big endian).
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698