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

Commit de88cef

Browse files
committed
track changes to base URL and other refactorings
1 parent 3da906b commit de88cef

File tree

5 files changed

+95
-43
lines changed

5 files changed

+95
-43
lines changed

src/.eslintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
/* urlUtils.js */
156156
"urlResolve": false,
157157
"urlIsSameOrigin": false,
158+
"urlIsSameOriginAsBaseUrl": false,
158159

159160
/* ng/controller.js */
160161
"identifierForController": false,

src/ng/urlUtils.js

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// service.
99
var urlParsingNode = window.document.createElement('a');
1010
var originUrl = urlResolve(window.location.href);
11-
var baseUrl;
11+
var baseUrlParsingNode;
1212

1313

1414
/**
@@ -44,16 +44,16 @@ var baseUrl;
4444
* @description Normalizes and parses a URL.
4545
* @returns {object} Returns the normalized URL as a dictionary.
4646
*
47-
* | member name | Description |
48-
* |---------------|----------------|
47+
* | member name | Description |
48+
* |---------------|------------------------------------------------------------------------|
4949
* | href | A normalized version of the provided URL if it was not an absolute URL |
50-
* | protocol | The protocol including the trailing colon |
50+
* | protocol | The protocol without the trailing colon |
5151
* | host | The host and port (if the port is non-default) of the normalizedUrl |
5252
* | search | The search params, minus the question mark |
53-
* | hash | The hash string, minus the hash symbol
54-
* | hostname | The hostname
55-
* | port | The port, without ":"
56-
* | pathname | The pathname, beginning with "/"
53+
* | hash | The hash string, minus the hash symbol |
54+
* | hostname | The hostname |
55+
* | port | The port, without ":" |
56+
* | pathname | The pathname, beginning with "/" |
5757
*
5858
*/
5959
function urlResolve(url) {
@@ -68,19 +68,7 @@ function urlResolve(url) {
6868

6969
urlParsingNode.setAttribute('href', href);
7070

71-
// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
72-
return {
73-
href: urlParsingNode.href,
74-
protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
75-
host: urlParsingNode.host,
76-
search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
77-
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
78-
hostname: urlParsingNode.hostname,
79-
port: urlParsingNode.port,
80-
pathname: (urlParsingNode.pathname.charAt(0) === '/')
81-
? urlParsingNode.pathname
82-
: '/' + urlParsingNode.pathname
83-
};
71+
return anchorElementToObject(urlParsingNode);
8472
}
8573

8674
/**
@@ -92,12 +80,11 @@ function urlResolve(url) {
9280
*/
9381
function urlIsSameOrigin(requestUrl) {
9482
var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
95-
return (parsed.protocol === originUrl.protocol &&
96-
parsed.host === originUrl.host);
83+
return urlsAreSameOrigin(parsed, originUrl);
9784
}
9885

9986
/**
100-
* Parse a request URL and determine whether it is same-origin as the document base URL.
87+
* Parse a request URL and determine whether it is same-origin as the current document base URL.
10188
*
10289
* Note: The base URL is usually the same the document location (`location.href`) but can
10390
* overriden by using the `<base>` tag.
@@ -107,10 +94,55 @@ function urlIsSameOrigin(requestUrl) {
10794
* @returns {boolean} Whether the URL is same-origin as the document base URL.
10895
*/
10996
function urlIsSameOriginAsBaseUrl(requestUrl) {
110-
if (!baseUrl) {
111-
baseUrl = urlResolve('.');
97+
if (!baseUrlParsingNode) {
98+
baseUrlParsingNode = window.document.createElement('a');
99+
baseUrlParsingNode.href = '.';
100+
101+
if (msie) {
102+
// Work-around for IE bug described in Implementation Notes. The fix in urlResolve() is not
103+
// suitable here because we need to track changes to the base URL.
104+
baseUrlParsingNode = baseUrlParsingNode.cloneNode(false);
105+
}
112106
}
113107
var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
114-
return (parsed.protocol === baseUrl.protocol &&
115-
parsed.host === baseUrl.host);
108+
return urlsAreSameOrigin(parsed, anchorElementToObject(baseUrlParsingNode));
109+
}
110+
111+
/**
112+
* Determines if two URLs share the same origin.
113+
*
114+
* @param {object} url1 First URL to compare. Must be a normalized URL in the form of a
115+
* dictionary object returned by `urlResolve()`.
116+
* @param {object} url2 Second URL to compare. Must be a normalized URL in the form of a
117+
* dictionary object returned by `urlResolve()`.
118+
* @return {boolean} True if both URLs have the same origin, and false otherwise.
119+
*/
120+
function urlsAreSameOrigin(url1, url2) {
121+
// IE sometimes includes a port in the 'host' property, even if it is the default 80 port so
122+
// we check hostname and port separately.
123+
return url1.protocol === url2.protocol &&
124+
url1.hostname === url2.hostname &&
125+
url1.port === url2.port;
126+
}
127+
128+
/**
129+
* Converts properties in the given anchor element into a dictionary object as described in the
130+
* documentation for `urlResolve()`.
131+
* @param {HTMLAnchorElement} elem
132+
* @returns {object}
133+
*/
134+
function anchorElementToObject(elem) {
135+
// elem provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
136+
return {
137+
href: elem.href,
138+
protocol: elem.protocol ? elem.protocol.replace(/:$/, '') : '',
139+
host: elem.host,
140+
search: elem.search ? elem.search.replace(/^\?/, '') : '',
141+
hash: elem.hash ? elem.hash.replace(/^#/, '') : '',
142+
hostname: elem.hostname,
143+
port: elem.port,
144+
pathname: (elem.pathname.charAt(0) === '/')
145+
? elem.pathname
146+
: '/' + elem.pathname
147+
};
116148
}

test/e2e/fixtures/base_tag/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html ng-app="test">
33
<head>
4-
<base href="http://www.example.com">
4+
<base href="http://www.example.com/">
55
<script src="http://localhost:8000/build/angular.js"></script>
66
<script src="http://localhost:8000/e2e/fixtures/base_tag/script.js"></script>
77
</head>

test/e2e/fixtures/base_tag/script.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
angular
2-
.module('test', [])
3-
.run(function($sce) {
1+
'use strict';
2+
3+
angular.
4+
module('test', []).
5+
run(function($sce) {
46
window.isTrustedUrl = function(url) {
57
try {
68
$sce.getTrustedResourceUrl(url);
79
} catch (e) {
810
return false;
911
}
1012
return true;
11-
}
13+
};
1214
});

test/e2e/tests/base_tag.spec.js

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
'use strict';
22

3-
describe('base_tag', function() {
4-
it('SCE self URL policy should correctly handle base tags', function() {
5-
loadFixture('base_tag');
6-
7-
var url = browser.getLocationAbsUrl();
3+
describe('SCE URL policy when base tags are present', function() {
4+
function checkUrl(url, allowed) {
85
var urlIsTrusted = browser.executeScript('return isTrustedUrl(arguments[0])', url);
9-
expect(urlIsTrusted).toBe(true); // sanity check
6+
expect(urlIsTrusted).toBe(allowed);
7+
}
8+
loadFixture('base_tag');
9+
10+
// sanity checks
11+
it('allows the page URL (location.href)', function() {
12+
checkUrl(browser.getLocationAbsUrl(), true);
13+
});
14+
it('blocks off-origin URLs', function() {
15+
//browser.pause();
16+
checkUrl('http://evil.com', false);
17+
});
1018

11-
var urlIsTrusted = browser.executeScript('return isTrustedUrl("//evil.com/")');
12-
expect(urlIsTrusted).toBe(false); // sanity check
19+
it('allows relative URLs ("/relative")', function() {
20+
//browser.pause();
21+
checkUrl('/relative', true);
22+
});
23+
24+
it('allows absolute URLs from the base origin', function() {
25+
checkUrl('http://www.example.com/path/to/file.html', true);
26+
});
1327

14-
urlIsTrusted = browser.executeScript('return isTrustedUrl("/relative")');
15-
expect(urlIsTrusted).toBe(true);
28+
it('tracks changes to the base URL', function() {
29+
browser.executeScript(
30+
'document.getElementsByTagName("base")[0].href = "http://xxx.example.com/";');
31+
//browser.pause();
32+
checkUrl('http://xxx.example.com/path/to/file.html', true);
1633
});
1734
});

0 commit comments

Comments
 (0)