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

Commit f925e8c

Browse files
ROULjeffbcross
ROUL
authored andcommitted
fix(urlUtils): urlUtils doesn't return right path for file:// on win
Chrome and other browsers on Windows often append the drive name to the pathname, as described in #4680. This would cause the location service to browse to odd URLs, such as /C:/myfile.html, when opening apps using file://. Fixes #4680
1 parent e1254b2 commit f925e8c

File tree

2 files changed

+78
-5
lines changed

2 files changed

+78
-5
lines changed

src/ng/urlUtils.js

+35-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@
77
// exactly the behavior needed here. There is little value is mocking these out for this
88
// service.
99
var urlParsingNode = document.createElement("a");
10+
/*
11+
Matches paths for file protocol on windows,
12+
such as /C:/foo/bar, and captures only /foo/bar.
13+
*/
14+
var windowsFilePathExp = /^\/?.*?:(\/.*)/;
1015
var originUrl = urlResolve(window.location.href, true);
1116

17+
1218
/**
1319
*
1420
* Implementation Notes for non-IE browsers
@@ -27,7 +33,7 @@ var originUrl = urlResolve(window.location.href, true);
2733
* browsers. However, the parsed components will not be set if the URL assigned did not specify
2834
* them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We
2935
* work around that by performing the parsing in a 2nd step by taking a previously normalized
30-
* URL (e.g. by assining to a.href) and assigning it a.href again. This correctly populates the
36+
* URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the
3137
* properties such as protocol, hostname, port, etc.
3238
*
3339
* IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one
@@ -62,7 +68,9 @@ var originUrl = urlResolve(window.location.href, true);
6268
*
6369
*/
6470
function urlResolve(url) {
65-
var href = url;
71+
var href = url,
72+
pathname;
73+
6674
if (msie) {
6775
// Normalize before parse. Refer Implementation Notes on why this is
6876
// done in two steps on IE.
@@ -72,7 +80,23 @@ function urlResolve(url) {
7280

7381
urlParsingNode.setAttribute('href', href);
7482

75-
// $$urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
83+
/*
84+
* In Windows, on an anchor node on documents loaded from
85+
* the filesystem, the browser will return a pathname
86+
* prefixed with the drive name ('/C:/path') when a
87+
* pathname without a drive is set:
88+
* * a.setAttribute('href', '/foo')
89+
* * a.pathname === '/C:/foo' //true
90+
*
91+
* Inside of Angular, we're always using pathnames that
92+
* do not include drive names for routing.
93+
*/
94+
95+
pathname = removeWindowsDriveName(urlParsingNode.pathname);
96+
pathname = (pathname.charAt(0) === '/') ? pathname : '/' + pathname;
97+
98+
99+
// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
76100
return {
77101
href: urlParsingNode.href,
78102
protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
@@ -81,9 +105,15 @@ function urlResolve(url) {
81105
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
82106
hostname: urlParsingNode.hostname,
83107
port: urlParsingNode.port,
84-
pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ?
85-
urlParsingNode.pathname : '/' + urlParsingNode.pathname
108+
pathname: pathname
86109
};
110+
111+
function removeWindowsDriveName (path) {
112+
var firstPathSegmentMatch;
113+
114+
firstPathSegmentMatch = windowsFilePathExp.exec(path);
115+
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
116+
}
87117
}
88118

89119

test/ng/locationSpec.js

+43
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,49 @@ describe('$location', function() {
1010
jqLite(document).off('click');
1111
});
1212

13+
14+
describe('File Protocol', function () {
15+
var urlParsingNodePlaceholder;
16+
17+
beforeEach(inject(function ($sniffer) {
18+
if ($sniffer.msie) return;
19+
20+
urlParsingNodePlaceholder = urlParsingNode;
21+
22+
//temporarily overriding the DOM element
23+
//with output from IE, if not in IE
24+
urlParsingNode = {
25+
hash : "#/C:/",
26+
host : "",
27+
hostname : "",
28+
href : "file:///C:/base#!/C:/foo",
29+
pathname : "/C:/foo",
30+
port : "",
31+
protocol : "file:",
32+
search : "",
33+
setAttribute: angular.noop
34+
};
35+
}));
36+
37+
38+
afterEach(inject(function ($sniffer) {
39+
if ($sniffer.msie) return;
40+
//reset urlParsingNode
41+
urlParsingNode = urlParsingNodePlaceholder;
42+
expect(urlParsingNode.pathname).not.toBe('/C:/foo');
43+
}));
44+
45+
46+
it('should not include the drive name in path() on WIN', function (){
47+
//See issue #4680 for details
48+
url = new LocationHashbangUrl('file:///base', '#!');
49+
url.$$parse('file:///base#!/foo?a=b&c#hash');
50+
51+
expect(url.path()).toBe('/foo');
52+
});
53+
});
54+
55+
1356
describe('NewUrl', function() {
1457
beforeEach(function() {
1558
url = new LocationHtml5Url('http://www.domain.com:9877/');

0 commit comments

Comments
 (0)