fix($location): add semicolon to whitelist of delimiters to unencode
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 #5019
This commit is contained in:
@@ -1176,6 +1176,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
replace(/%3A/gi, ':').
|
||||
replace(/%24/g, '$').
|
||||
replace(/%2C/gi, ',').
|
||||
replace(/%3B/gi, ';').
|
||||
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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;');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(' ')).
|
||||
|
||||
@@ -62,6 +62,48 @@ 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.addEventListener = angular.noop;
|
||||
win.removeEventListener = angular.noop;
|
||||
win.history = {
|
||||
replaceState: angular.noop,
|
||||
pushState: angular.noop
|
||||
};
|
||||
win.location = {
|
||||
href: 'http://localhost:9876/;jsessionid=foo',
|
||||
replace: function(val) {
|
||||
win.location.href = val;
|
||||
}
|
||||
};
|
||||
return win;
|
||||
};
|
||||
$browserProvider.$get = function($document, $window) {
|
||||
var sniffer = {history: true, hashchange: false};
|
||||
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/');
|
||||
|
||||
Reference in New Issue
Block a user