Skip to content

Commit

Permalink
fix($location): add semicolon to whitelist of delimiters to unencode
Browse files Browse the repository at this point in the history
Some servers require characters within path segments to contain semicolons,
such as `/;jsessionid=foo` in order to work correctly. RFC-3986 includes
semicolons as acceptable sub-delimiters inside of path and query, but $location
currently encodes semicolons. This can cause an infinite digest to occur since $location
is comparing the internal semicolon-encoded url with the semicolon-unencoded url returned
from window.location.href, causing Angular to believe the url is changing with each digest
loop.

This fix adds ";" to the list of characters to unencode after encoding queries or path segments.

Closes angular#5019
  • Loading branch information
jeffbcross committed Jul 28, 2014
1 parent f684c21 commit 2699101
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/Angular.js
Expand Up @@ -1154,6 +1154,7 @@ function toKeyValue(obj) {
function encodeUriSegment(val) {
return encodeUriQuery(val, true).
replace(/%26/gi, '&').
replace(/%3B/gi, ';').
replace(/%3D/gi, '=').
replace(/%2B/gi, '+');
}
Expand All @@ -1176,6 +1177,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%3B/gi, ';').
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
}

Expand Down
10 changes: 5 additions & 5 deletions test/AngularSpec.js
Expand Up @@ -668,16 +668,16 @@ describe('angular', function() {
toEqual('asdf1234asdf');

//don't encode unreserved'
expect(encodeUriSegment("-_.!~*'() -_.!~*'()")).
toEqual("-_.!~*'()%20-_.!~*'()");
expect(encodeUriSegment("-_.!~*'(); -_.!~*'();")).
toEqual("-_.!~*'();%20-_.!~*'();");

//don't encode the rest of pchar'
expect(encodeUriSegment(':@&=+$, :@&=+$,')).
toEqual(':@&=+$,%20:@&=+$,');

//encode '/', ';' and ' ''
//encode '/' and ' ''
expect(encodeUriSegment('/; /;')).
toEqual('%2F%3B%20%2F%3B');
toEqual('%2F;%20%2F;');
});
});

Expand All @@ -699,7 +699,7 @@ describe('angular', function() {

//encode '&', ';', '=', '+', and '#'
expect(encodeUriQuery('&;=+# &;=+#')).
toEqual('%26%3B%3D%2B%23+%26%3B%3D%2B%23');
toEqual('%26;%3D%2B%23+%26;%3D%2B%23');

//encode ' ' as '+'
expect(encodeUriQuery(' ')).
Expand Down
33 changes: 33 additions & 0 deletions test/ng/locationSpec.js
Expand Up @@ -62,6 +62,39 @@ describe('$location', function() {
});


it('should not infinitely digest when using a semicolon in initial path', function() {
module(function($windowProvider, $locationProvider, $browserProvider) {
$locationProvider.html5Mode(true);
$windowProvider.$get = function() {
var win = {};
angular.extend(win, window);
win.location = {
href: 'http://localhost:9876/;jsessionid=foo'
};
return win;
};
$browserProvider.$get = function($document, $window) {
var sniffer = {history: false, hashchange: true};
var logs = {log:[], warn:[], info:[], error:[]};
var fakeLog = {log: function() { logs.log.push(slice.call(arguments)); },
warn: function() { logs.warn.push(slice.call(arguments)); },
info: function() { logs.info.push(slice.call(arguments)); },
error: function() { logs.error.push(slice.call(arguments)); }};

/* global Browser: false */
var b = new Browser($window, $document, fakeLog, sniffer);
b.pollFns = [];
return b;
};
});
var self = this;
inject(function($location, $browser, $rootScope) {
expect(function() {
$rootScope.$digest();
}).not.toThrow();
});
});

describe('NewUrl', function() {
beforeEach(function() {
url = new LocationHtml5Url('http://www.domain.com:9877/');
Expand Down

0 comments on commit 2699101

Please sign in to comment.