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

Commit 89f435d

Browse files
committed
fix(urlUtils): made removal of windows drive from path safer
Prior to this fix, the urlResolve method would automatically strip the first segment of a path if the segment ends in a colon. This was to correct undesired behavior in the $location service using the file protocol on windows in multiple browsers (see #4680). However, there could be cases where users intentionally have first path segments that end in a colon (although this conflicts with section 3.3 of rfc3986). The solution to this problem is an extra check to make sure the first path segment of the input url does not end with a colon, to make sure we're only removing undesired path segments. Fixes #4939
1 parent bcc6e8d commit 89f435d

File tree

3 files changed

+38
-19
lines changed

3 files changed

+38
-19
lines changed

src/ng/location.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ function encodePath(path) {
2222
return segments.join('/');
2323
}
2424

25-
function parseAbsoluteUrl(absoluteUrl, locationObj) {
26-
var parsedUrl = urlResolve(absoluteUrl);
25+
function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
26+
var parsedUrl = urlResolve(absoluteUrl, appBase);
2727

2828
locationObj.$$protocol = parsedUrl.protocol;
2929
locationObj.$$host = parsedUrl.hostname;
3030
locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
3131
}
3232

3333

34-
function parseAppUrl(relativeUrl, locationObj) {
34+
function parseAppUrl(relativeUrl, locationObj, appBase) {
3535
var prefixed = (relativeUrl.charAt(0) !== '/');
3636
if (prefixed) {
3737
relativeUrl = '/' + relativeUrl;
3838
}
39-
var match = urlResolve(relativeUrl);
39+
var match = urlResolve(relativeUrl, appBase);
4040
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
4141
match.pathname.substring(1) : match.pathname);
4242
locationObj.$$search = parseKeyValue(match.search);
@@ -91,7 +91,7 @@ function LocationHtml5Url(appBase, basePrefix) {
9191
this.$$html5 = true;
9292
basePrefix = basePrefix || '';
9393
var appBaseNoFile = stripFile(appBase);
94-
parseAbsoluteUrl(appBase, this);
94+
parseAbsoluteUrl(appBase, this, appBase);
9595

9696

9797
/**
@@ -106,7 +106,7 @@ function LocationHtml5Url(appBase, basePrefix) {
106106
appBaseNoFile);
107107
}
108108

109-
parseAppUrl(pathUrl, this);
109+
parseAppUrl(pathUrl, this, appBase);
110110

111111
if (!this.$$path) {
112112
this.$$path = '/';
@@ -158,7 +158,7 @@ function LocationHtml5Url(appBase, basePrefix) {
158158
function LocationHashbangUrl(appBase, hashPrefix) {
159159
var appBaseNoFile = stripFile(appBase);
160160

161-
parseAbsoluteUrl(appBase, this);
161+
parseAbsoluteUrl(appBase, this, appBase);
162162

163163

164164
/**
@@ -178,7 +178,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
178178
throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
179179
hashPrefix);
180180
}
181-
parseAppUrl(withoutHashUrl, this);
181+
parseAppUrl(withoutHashUrl, this, appBase);
182182
this.$$compose();
183183
};
184184

src/ng/urlUtils.js

+22-10
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ var originUrl = urlResolve(window.location.href, true);
6767
* | pathname | The pathname, beginning with "/"
6868
*
6969
*/
70-
function urlResolve(url) {
70+
function urlResolve(url, base) {
7171
var href = url,
7272
pathname;
7373

@@ -92,10 +92,9 @@ function urlResolve(url) {
9292
* do not include drive names for routing.
9393
*/
9494

95-
pathname = removeWindowsDriveName(urlParsingNode.pathname);
95+
pathname = removeWindowsDriveName(urlParsingNode.pathname, url, base);
9696
pathname = (pathname.charAt(0) === '/') ? pathname : '/' + pathname;
9797

98-
9998
// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
10099
return {
101100
href: urlParsingNode.href,
@@ -107,13 +106,6 @@ function urlResolve(url) {
107106
port: urlParsingNode.port,
108107
pathname: pathname
109108
};
110-
111-
function removeWindowsDriveName (path) {
112-
var firstPathSegmentMatch;
113-
114-
firstPathSegmentMatch = windowsFilePathExp.exec(path);
115-
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
116-
}
117109
}
118110

119111

@@ -129,3 +121,23 @@ function urlIsSameOrigin(requestUrl) {
129121
return (parsed.protocol === originUrl.protocol &&
130122
parsed.host === originUrl.host);
131123
}
124+
125+
function removeWindowsDriveName (path, url, base) {
126+
var firstPathSegmentMatch;
127+
128+
//Get the relative path from the input URL.
129+
if (url.indexOf(base) === 0) {
130+
url = url.replace(base, '');
131+
}
132+
133+
/*
134+
* The input URL intentionally contains a
135+
* first path segment that ends with a colon.
136+
*/
137+
if (windowsFilePathExp.exec(url)) {
138+
return path;
139+
}
140+
141+
firstPathSegmentMatch = windowsFilePathExp.exec(path);
142+
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
143+
}

test/ng/locationSpec.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ describe('$location', function() {
3434
};
3535
}));
3636

37-
3837
afterEach(inject(function ($sniffer) {
3938
if ($sniffer.msie) return;
4039
//reset urlParsingNode
@@ -50,6 +49,14 @@ describe('$location', function() {
5049

5150
expect(url.path()).toBe('/foo');
5251
});
52+
53+
54+
it('should include the drive name if it was provided in the input url', function () {
55+
url = new LocationHashbangUrl('file:///base', '#!');
56+
url.$$parse('file:///base#!/C:/foo?a=b&c#hash');
57+
58+
expect(url.path()).toBe('/C:/foo');
59+
});
5360
});
5461

5562

0 commit comments

Comments
 (0)