Skip to content

Commit 1073967

Browse files
author
Sebastien Armand - sa250111
committed
feat($location): parse query parameters delimited by ; or & angular#6167
According to RFC (http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2) location should match either ';' OR '&', but not both at the same time. Closes angular#6140
1 parent 1933802 commit 1073967

File tree

3 files changed

+34
-13
lines changed

3 files changed

+34
-13
lines changed

src/Angular.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,10 @@ function tryDecodeURIComponent(value) {
10551055
* Parses an escaped url query string into key-value pairs.
10561056
* @returns Object.<(string|boolean)>
10571057
*/
1058-
function parseKeyValue(/**string*/keyValue) {
1058+
function parseKeyValue(/**string*/keyValue, delimiter) {
1059+
delimiter = delimiter === ';' ? delimiter : '&';
10591060
var obj = {}, key_value, key;
1060-
forEach((keyValue || "").split(/[&;]/), function(keyValue){
1061+
forEach((keyValue || "").split(delimiter), function(keyValue){
10611062
if ( keyValue ) {
10621063
key_value = keyValue.split('=');
10631064
key = tryDecodeURIComponent(key_value[0]);

src/ng/location.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function parseAppUrl(relativeUrl, locationObj, appBase) {
3939
var match = urlResolve(relativeUrl, appBase);
4040
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
4141
match.pathname.substring(1) : match.pathname);
42-
locationObj.$$search = parseKeyValue(match.search);
42+
locationObj.$$search = parseKeyValue(match.search, locationObj.$$queryDelimiter);
4343
locationObj.$$hash = decodeURIComponent(match.hash);
4444

4545
// make sure path starts with '/';
@@ -90,6 +90,7 @@ function serverBase(url) {
9090
function LocationHtml5Url(appBase, basePrefix, queryDelimiter) {
9191
this.$$html5 = true;
9292
basePrefix = basePrefix || '';
93+
this.$$queryDelimiter = queryDelimiter;
9394
var appBaseNoFile = stripFile(appBase);
9495
parseAbsoluteUrl(appBase, this, appBase);
9596

@@ -120,7 +121,7 @@ function LocationHtml5Url(appBase, basePrefix, queryDelimiter) {
120121
* @private
121122
*/
122123
this.$$compose = function() {
123-
var search = toKeyValue(this.$$search, queryDelimiter),
124+
var search = toKeyValue(this.$$search, this.$$queryDelimiter),
124125
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
125126

126127
this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
@@ -157,6 +158,7 @@ function LocationHtml5Url(appBase, basePrefix, queryDelimiter) {
157158
*/
158159
function LocationHashbangUrl(appBase, hashPrefix, queryDelimiter) {
159160
var appBaseNoFile = stripFile(appBase);
161+
this.$$queryDelimiter = queryDelimiter;
160162

161163
parseAbsoluteUrl(appBase, this, appBase);
162164

@@ -227,7 +229,7 @@ function LocationHashbangUrl(appBase, hashPrefix, queryDelimiter) {
227229
* @private
228230
*/
229231
this.$$compose = function() {
230-
var search = toKeyValue(this.$$search, queryDelimiter),
232+
var search = toKeyValue(this.$$search, this.$$queryDelimiter),
231233
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
232234

233235
this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
@@ -287,6 +289,12 @@ LocationHashbangInHtml5Url.prototype =
287289
*/
288290
$$replace: false,
289291

292+
/**
293+
* Allows using ";" instead of "&" to separate query string arguments
294+
* @private
295+
*/
296+
$$queryDelimiter: '&',
297+
290298
/**
291299
* @ngdoc method
292300
* @name $location#absUrl
@@ -415,7 +423,7 @@ LocationHashbangInHtml5Url.prototype =
415423
return this.$$search;
416424
case 1:
417425
if (isString(search)) {
418-
this.$$search = parseKeyValue(search);
426+
this.$$search = parseKeyValue(search, this.$$queryDelimiter);
419427
} else if (isObject(search)) {
420428
this.$$search = search;
421429
} else {

test/ng/locationSpec.js

+19-7
Original file line numberDiff line numberDiff line change
@@ -316,12 +316,18 @@ describe('$location', function() {
316316

317317

318318
it('should decode query params delimited interchangeably by & and ;', function() {
319-
var url = new LocationHtml5Url('http://host.com/');
320-
url.$$parse('http://host.com/?foo=1&bar=2;baz=3');
319+
var url = new LocationHashbangUrl('http://host.com/', '#');
320+
url.$$parse('http://host.com/#?foo=1&bar=2;baz');
321321
expect(url.search()).toEqual({
322322
'foo': '1',
323-
'bar': '2',
324-
'baz': '3'
323+
'bar': '2;baz'
324+
});
325+
326+
url = new LocationHashbangUrl('http://host.com/', '#', ';');
327+
url.$$parse('http://host.com/#?foo=1&bar=2;baz');
328+
expect(url.search()).toEqual({
329+
'foo': '1&bar',
330+
'baz': true
325331
});
326332
});
327333

@@ -469,11 +475,17 @@ describe('$location', function() {
469475

470476
it('should decode query params delimited interchangeably by & and ;', function() {
471477
var url = new LocationHashbangUrl('http://host.com/', '#');
472-
url.$$parse('http://host.com/#?foo=1&bar=2;baz=3');
478+
url.$$parse('http://host.com/#?foo=1&bar=2;baz');
473479
expect(url.search()).toEqual({
474480
'foo': '1',
475-
'bar': '2',
476-
'baz': '3'
481+
'bar': '2;baz'
482+
});
483+
484+
url = new LocationHashbangUrl('http://host.com/', '#', ';');
485+
url.$$parse('http://host.com/#?foo=1&bar=2;baz');
486+
expect(url.search()).toEqual({
487+
'foo': '1&bar',
488+
'baz': true
477489
});
478490
});
479491

0 commit comments

Comments
 (0)