Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit c117089

Browse files
committed
fix($browser): normalize inputted URLs
Fixes #16100
1 parent 37d9230 commit c117089

File tree

2 files changed

+105
-5
lines changed

2 files changed

+105
-5
lines changed

src/ng/browser.js

+3
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ function Browser(window, document, $log, $sniffer, $$taskTrackerFactory) {
108108
if (url) {
109109
var sameState = lastHistoryState === state;
110110

111+
// Normalize the inputted URL
112+
url = urlResolve(url).href;
113+
111114
// Don't change anything if previous and current URLs and states match. This also prevents
112115
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
113116
// See https://github.com/angular/angular.js/commit/ffb2701

test/ng/browserSpecs.js

+102-5
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ describe('browser', function() {
418418
browser.url('http://new.org');
419419

420420
expect(pushState).toHaveBeenCalledOnce();
421-
expect(pushState.calls.argsFor(0)[2]).toEqual('http://new.org');
421+
expect(pushState.calls.argsFor(0)[2]).toEqual('http://new.org/');
422422

423423
expect(replaceState).not.toHaveBeenCalled();
424424
expect(locationReplace).not.toHaveBeenCalled();
@@ -430,7 +430,7 @@ describe('browser', function() {
430430
browser.url('http://new.org', true);
431431

432432
expect(replaceState).toHaveBeenCalledOnce();
433-
expect(replaceState.calls.argsFor(0)[2]).toEqual('http://new.org');
433+
expect(replaceState.calls.argsFor(0)[2]).toEqual('http://new.org/');
434434

435435
expect(pushState).not.toHaveBeenCalled();
436436
expect(locationReplace).not.toHaveBeenCalled();
@@ -474,7 +474,7 @@ describe('browser', function() {
474474
sniffer.history = false;
475475
browser.url('http://new.org', true);
476476

477-
expect(locationReplace).toHaveBeenCalledWith('http://new.org');
477+
expect(locationReplace).toHaveBeenCalledWith('http://new.org/');
478478

479479
expect(pushState).not.toHaveBeenCalled();
480480
expect(replaceState).not.toHaveBeenCalled();
@@ -689,6 +689,103 @@ describe('browser', function() {
689689
expect(replaceState).not.toHaveBeenCalled();
690690
expect(locationReplace).not.toHaveBeenCalled();
691691
});
692+
693+
it('should not detect changes on $$checkUrlChange() due to input vs actual encoding', function() {
694+
var callback = jasmine.createSpy('onUrlChange');
695+
browser.onUrlChange(callback);
696+
697+
browser.url('http://server/abc?q=\'');
698+
browser.$$checkUrlChange();
699+
expect(callback).not.toHaveBeenCalled();
700+
701+
browser.url('http://server/abc?q=%27');
702+
browser.$$checkUrlChange();
703+
expect(callback).not.toHaveBeenCalled();
704+
});
705+
706+
it('should not do pushState with a URL only different in encoding (less)', function() {
707+
// A URL from something such as window.location.href
708+
browser.url('http://server/abc?q=%27');
709+
710+
pushState.calls.reset();
711+
replaceState.calls.reset();
712+
locationReplace.calls.reset();
713+
714+
// A prettier URL from something such as $location
715+
browser.url('http://server/abc?q=\'');
716+
expect(pushState).not.toHaveBeenCalled();
717+
expect(replaceState).not.toHaveBeenCalled();
718+
expect(locationReplace).not.toHaveBeenCalled();
719+
});
720+
721+
it('should not do pushState with a URL only different in encoding (more)', function() {
722+
// A prettier URL from something such as $location
723+
browser.url('http://server/abc?q=\'');
724+
725+
pushState.calls.reset();
726+
replaceState.calls.reset();
727+
locationReplace.calls.reset();
728+
729+
// A URL from something such as window.location.href
730+
browser.url('http://server/abc?q=%27');
731+
expect(pushState).not.toHaveBeenCalled();
732+
expect(replaceState).not.toHaveBeenCalled();
733+
expect(locationReplace).not.toHaveBeenCalled();
734+
});
735+
736+
it('should not do pushState with a URL only adding a trailing slash after domain', function() {
737+
// A domain without a trailing /
738+
browser.url('http://server');
739+
740+
pushState.calls.reset();
741+
replaceState.calls.reset();
742+
locationReplace.calls.reset();
743+
744+
// A domain from something such as window.location.href with a trailing slash
745+
browser.url('http://server/');
746+
expect(pushState).not.toHaveBeenCalled();
747+
expect(replaceState).not.toHaveBeenCalled();
748+
expect(locationReplace).not.toHaveBeenCalled();
749+
});
750+
751+
it('should not do pushState with a URL only removing a trailing slash after domain', function() {
752+
// A domain from something such as window.location.href with a trailing slash
753+
browser.url('http://server/');
754+
755+
pushState.calls.reset();
756+
replaceState.calls.reset();
757+
locationReplace.calls.reset();
758+
759+
// A domain without a trailing /
760+
browser.url('http://server');
761+
expect(pushState).not.toHaveBeenCalled();
762+
expect(replaceState).not.toHaveBeenCalled();
763+
expect(locationReplace).not.toHaveBeenCalled();
764+
});
765+
766+
it('should do pushState with a URL only adding a trailing slash after the path', function() {
767+
browser.url('http://server/foo');
768+
769+
pushState.calls.reset();
770+
replaceState.calls.reset();
771+
locationReplace.calls.reset();
772+
773+
browser.url('http://server/foo/');
774+
expect(pushState).toHaveBeenCalledOnce();
775+
expect(fakeWindow.location.href).toEqual('http://server/foo/');
776+
});
777+
778+
it('should do pushState with a URL only removing a trailing slash after the path', function() {
779+
browser.url('http://server/foo/');
780+
781+
pushState.calls.reset();
782+
replaceState.calls.reset();
783+
locationReplace.calls.reset();
784+
785+
browser.url('http://server/foo');
786+
expect(pushState).toHaveBeenCalledOnce();
787+
expect(fakeWindow.location.href).toEqual('http://server/foo');
788+
});
692789
};
693790
}
694791
});
@@ -813,7 +910,7 @@ describe('browser', function() {
813910
it('should not fire urlChange if changed by browser.url method', function() {
814911
sniffer.history = false;
815912
browser.onUrlChange(callback);
816-
browser.url('http://new.com/');
913+
browser.url('http://new.com');
817914

818915
fakeWindow.fire('hashchange');
819916
expect(callback).not.toHaveBeenCalled();
@@ -1161,7 +1258,7 @@ describe('browser', function() {
11611258
it('should not interfere with legacy browser url replace behavior', function() {
11621259
inject(function($rootScope) {
11631260
var current = fakeWindow.location.href;
1164-
var newUrl = 'notyet';
1261+
var newUrl = 'http://notyet/';
11651262
sniffer.history = false;
11661263
expect(historyEntriesLength).toBe(1);
11671264
browser.url(newUrl, true);

0 commit comments

Comments
 (0)