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

Commit

Permalink
refactor($location): move file://+win path fix to $location
Browse files Browse the repository at this point in the history
The urlResolve method was fixed to automatically remove the
volume label from path names to fix issues with the file
protocol on windows where $location.path() was returning
paths where the first segment would be the volume name,
such as "/C:/mypath". See #4942 and #4928

However, the solution was specific to the $location non-
HTML5 mode, and was implemented at a lower level of
abstraction than it should have been. This refactor moves
the fix to inside of the LocationHashBangUrl $$parse method.

Closes #5041
  • Loading branch information
jeffbcross committed Nov 27, 2013
1 parent 9475622 commit 736c8fb
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 47 deletions.
40 changes: 40 additions & 0 deletions src/ng/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,47 @@ function LocationHashbangUrl(appBase, hashPrefix) {
hashPrefix);
}
parseAppUrl(withoutHashUrl, this, appBase);

this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);

this.$$compose();

/*
* In Windows, on an anchor node on documents loaded from
* the filesystem, the browser will return a pathname
* prefixed with the drive name ('/C:/path') when a
* pathname without a drive is set:
* * a.setAttribute('href', '/foo')
* * a.pathname === '/C:/foo' //true
*
* Inside of Angular, we're always using pathnames that
* do not include drive names for routing.
*/
function removeWindowsDriveName (path, url, base) {
/*
Matches paths for file protocol on windows,
such as /C:/foo/bar, and captures only /foo/bar.
*/
var windowsFilePathExp = /^\/?.*?:(\/.*)/;

var firstPathSegmentMatch;

//Get the relative path from the input URL.
if (url.indexOf(base) === 0) {
url = url.replace(base, '');
}

/*
* The input URL intentionally contains a
* first path segment that ends with a colon.
*/
if (windowsFilePathExp.exec(url)) {
return path;
}

firstPathSegmentMatch = windowsFilePathExp.exec(path);
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
}
};

/**
Expand Down
48 changes: 4 additions & 44 deletions src/ng/urlUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
// exactly the behavior needed here. There is little value is mocking these out for this
// service.
var urlParsingNode = document.createElement("a");
/*
Matches paths for file protocol on windows,
such as /C:/foo/bar, and captures only /foo/bar.
*/
var windowsFilePathExp = /^\/?.*?:(\/.*)/;
var originUrl = urlResolve(window.location.href, true);


Expand Down Expand Up @@ -68,8 +63,7 @@ var originUrl = urlResolve(window.location.href, true);
*
*/
function urlResolve(url, base) {
var href = url,
pathname;
var href = url;

if (msie) {
// Normalize before parse. Refer Implementation Notes on why this is
Expand All @@ -80,21 +74,6 @@ function urlResolve(url, base) {

urlParsingNode.setAttribute('href', href);

/*
* In Windows, on an anchor node on documents loaded from
* the filesystem, the browser will return a pathname
* prefixed with the drive name ('/C:/path') when a
* pathname without a drive is set:
* * a.setAttribute('href', '/foo')
* * a.pathname === '/C:/foo' //true
*
* Inside of Angular, we're always using pathnames that
* do not include drive names for routing.
*/

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

// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
return {
href: urlParsingNode.href,
Expand All @@ -104,11 +83,12 @@ function urlResolve(url, base) {
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
hostname: urlParsingNode.hostname,
port: urlParsingNode.port,
pathname: pathname
pathname: (urlParsingNode.pathname.charAt(0) === '/')
? urlParsingNode.pathname
: '/' + urlParsingNode.pathname
};
}


/**
* Parse a request URL and determine whether this is a same-origin request as the application document.
*
Expand All @@ -121,23 +101,3 @@ function urlIsSameOrigin(requestUrl) {
return (parsed.protocol === originUrl.protocol &&
parsed.host === originUrl.host);
}

function removeWindowsDriveName (path, url, base) {
var firstPathSegmentMatch;

//Get the relative path from the input URL.
if (url.indexOf(base) === 0) {
url = url.replace(base, '');
}

/*
* The input URL intentionally contains a
* first path segment that ends with a colon.
*/
if (windowsFilePathExp.exec(url)) {
return path;
}

firstPathSegmentMatch = windowsFilePathExp.exec(path);
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
}
3 changes: 1 addition & 2 deletions test/ng/locationSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ describe('$location', function() {
if ($sniffer.msie) return;
//reset urlParsingNode
urlParsingNode = urlParsingNodePlaceholder;
expect(urlParsingNode.pathname).not.toBe('/C:/foo');
}));


Expand Down Expand Up @@ -324,7 +323,7 @@ describe('$location', function() {
});


it('should parse hashband url into path and search', function() {
it('should parse hashbang url into path and search', function() {
expect(url.protocol()).toBe('http');
expect(url.host()).toBe('www.server.org');
expect(url.port()).toBe(1234);
Expand Down
9 changes: 8 additions & 1 deletion test/ng/urlUtilsSpec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

describe('urlUtils', function() {
describe('parse', function() {
describe('urlResolve', function() {
it('should normalize a relative url', function () {
expect(urlResolve("foo").href).toMatch(/^https?:\/\/[^/]+\/foo$/);
});
Expand All @@ -14,6 +14,13 @@ describe('urlUtils', function() {
expect(parsed.hostname).not.toBe("");
expect(parsed.pathname).not.toBe("");
});


it('should return pathname as / if empty path provided', function () {
//IE counts / as empty, necessary to use / so that pathname is not context.html
var parsed = urlResolve('/');
expect(parsed.pathname).toBe('/');
})
});

describe('isSameOrigin', function() {
Expand Down

0 comments on commit 736c8fb

Please sign in to comment.