Skip to content
This repository has been archived by the owner on Dec 16, 2023. It is now read-only.

Commit

Permalink
Avoid Node URL bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
jagoda committed Mar 26, 2015
1 parent de5aba9 commit 5437fa4
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const assert = require('assert');
const { isRegExp } = require('util');
const URL = require('url');
const URL = require('./url');


// Used to assert that actual matches expected value, where expected may be a function or a string.
Expand Down
2 changes: 1 addition & 1 deletion src/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const DOM = require('./dom');
const EventSource = require('eventsource');
const WebSocket = require('ws');
const XMLHttpRequest = require('./xhr');
const URL = require('url');
const URL = require('./url');


// File access, not implemented yet
Expand Down
2 changes: 1 addition & 1 deletion src/history.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
const assert = require('assert');
const loadDocument = require('./document');
const DOM = require('./dom');
const URL = require('url');
const URL = require('./url');


class Location {
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Resources = require('./resources');
const Storages = require('./storage');
const Tough = require('tough-cookie');
const { Cookie } = Tough;
const URL = require('url');
const URL = require('./url');


// Version number. We get this from package.json.
Expand Down
10 changes: 3 additions & 7 deletions src/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const iconv = require('iconv-lite');
const Path = require('path');
const QS = require('querystring');
const request = require('request');
const URL = require('url');
const URL = require('./url');
const Zlib = require('zlib');


Expand Down Expand Up @@ -269,14 +269,10 @@ Resources.addHandler = function(handler) {
// It turns relative URLs into absolute URLs based on the current document URL
// or base element, or if no document open, based on browser.site property.
//
// Also handles file: URLs and creates query string from request.params for
// Also creates query string from request.params for
// GET/HEAD/DELETE requests.
Resources.normalizeURL = function(req, next) {
if (/^file:/.test(req.url))
// File URLs are special, need to handle missing slashes and not attempt
// to parse (downcases path)
req.url = req.url.replace(/^file:\/{1,3}/, 'file:///');
else if (this.document)
if (this.document)
// Resolve URL relative to document URL/base, or for new browser, using
// Browser.site
req.url = DOM.resourceLoader.resolve(this.document, req.url);
Expand Down
22 changes: 22 additions & 0 deletions src/url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Monkey patching the Node URL module to avoid a bug with URL resolution.
// See https://github.com/joyent/node/pull/14146
const URL = require('url');


exports.parse = URL.parse;
exports.format = URL.format;

exports.resolve = function (from, to) {
const pattern = /file:?/;
const protocol = URL.parse(from).protocol;
// The `to` parameter is ofter a pre-parsed URL object. Need to make a
// defensive copy to avoid the `host` assignment bug.
const original = URL.parse(URL.format(to));
const resolved = URL.parse(URL.resolve(from, to));

if (!pattern.test(protocol) && pattern.test(original.protocol) && !original.host && resolved.host) {
return URL.format(original);
}

return URL.format(resolved);
};
2 changes: 1 addition & 1 deletion src/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


const DOM = require('./dom');
const URL = require('url');
const URL = require('./url');


class XMLHttpRequest extends DOM.EventTarget {
Expand Down
24 changes: 24 additions & 0 deletions test/history_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,30 @@ describe('History', function() {
});
});

// Node has a bug that causes the root path element to be lowercased which
// causes problems when loading files from the file system.
// See https://github.com/joyent/node/pull/14146
describe('open from file system with capitalized root', function() {
const FILE_URL = 'file:///Users/foo/index.html';

before(function (done) {
browser.visit(FILE_URL, function () {
// Ignore errors -- the file isn't real...
done();
});
});

it('should change location URL', function() {
browser.assert.url(FILE_URL);
});
it('should set window location', function() {
assert.equal(browser.window.location.href, FILE_URL);
});
it('should set document location', function() {
assert.equal(browser.document.location.href, FILE_URL);
});
});

describe('change pathname', function() {
before(()=> browser.visit('/'));
before(function(done) {
Expand Down
39 changes: 39 additions & 0 deletions test/url_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const assert = require('assert');
const NativeURL = require('url');
const ZombieURL = require('../src/url');


describe('URL', function() {
describe('resolve', function() {
const patterns = [
['http://localhost', 'foo', 'http://localhost/foo'],
['http://localhost/foo/bar', 'baz', 'http://localhost/foo/baz'],
['http://localhost/foo/bar', '/bar', 'http://localhost/bar'],
['http://localhost', 'file://foo/Users', 'file://foo/Users'],
['http://localhost', 'file:///Users/foo', 'file:///Users/foo'],
['file://foo/Users', 'file:bar', 'file://foo/bar']
];

it('is not the native resolve implementation', function() {
assert.notStrictEqual(ZombieURL.resolve, NativeURL.resolve);
});

it('resolves URLs correctly', function() {
patterns.forEach(function (pattern) {
assert.equal(ZombieURL.resolve(pattern[0], pattern[1]), pattern[2]);
});
});
});

describe('parse', function() {
it('is the native parse implementation', function() {
assert.strictEqual(ZombieURL.parse, NativeURL.parse);
});
});

describe('format', function() {
it('is the native format implementation', function() {
assert.strictEqual(ZombieURL.format, NativeURL.format);
});
});
});

0 comments on commit 5437fa4

Please sign in to comment.