Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: unshiftio/url-parse
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1.4.7
Choose a base ref
...
head repository: unshiftio/url-parse
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1.5.1
Choose a head ref
  • 15 commits
  • 9 files changed
  • 4 contributors

Commits on Jun 4, 2019

  1. Copy the full SHA
    ed3f534 View commit details

Commits on Dec 24, 2019

  1. Copy the full SHA
    3ce7824 View commit details

Commits on Feb 10, 2020

  1. Copy the full SHA
    08fd2cc View commit details

Commits on May 24, 2020

  1. [travis] Test on node 14

    lpinca committed May 24, 2020
    Copy the full SHA
    673c3a7 View commit details

Commits on Jun 17, 2020

  1. Copy the full SHA
    77c1184 View commit details
  2. [test] Do not test on all available versions of Edge and Safari

    Use only the oldest and latest version.
    lpinca committed Jun 17, 2020
    Copy the full SHA
    ce3783f View commit details
  3. [pkg] Add .npmrc

    lpinca committed Jun 17, 2020
    Copy the full SHA
    190b216 View commit details

Commits on Sep 9, 2020

  1. Copy the full SHA
    933809d View commit details

Commits on Oct 6, 2020

  1. [pkg] Replace nyc with c8

    lpinca committed Oct 6, 2020
    Copy the full SHA
    422c8b5 View commit details
  2. Copy the full SHA
    d99bf4c View commit details

Commits on Feb 17, 2021

  1. 1

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    d1e7e88 View commit details
  2. [dist] 1.5.0

    3rd-Eden committed Feb 17, 2021
    1
    Copy the full SHA
    267a0c6 View commit details
  3. 1
    Copy the full SHA
    3ac7774 View commit details

Commits on Feb 18, 2021

  1. [fix] Fixes relative path resolving #199 #200 (#201)

    * [fix] Fixes relative path resolving #199 #200
    * [test] Additional extractProtocol tests
    3rd-Eden authored Feb 18, 2021
    1

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    750d8e8 View commit details
  2. [dist] 1.5.1

    3rd-Eden committed Feb 18, 2021
    1
    Copy the full SHA
    eb6d9f5 View commit details
Showing with 128 additions and 41 deletions.
  1. +0 −2 .gitignore
  2. +1 −0 .npmrc
  3. +5 −6 .travis.yml
  4. +10 −1 SECURITY.md
  5. +18 −6 index.js
  6. +5 −4 package.json
  7. +2 −2 test/browser.js
  8. +2 −0 test/fuzzy.js
  9. +85 −20 test/test.js
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
node_modules/
.nyc_output/
coverage/
dist/
npm-debug.log
.tern-port
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package-lock=false
11 changes: 5 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
sudo: false
language: node_js
matrix:
fast_finish: true
include:
- node_js: "10"
- node_js: "14"
env: SCRIPT=test
- node_js: "8"
- node_js: "12"
env: SCRIPT=test
- node_js: "6"
- node_js: "10"
env: SCRIPT=test
- node_js: "8"
- node_js: "12"
env:
- secure: IF01oyIKSs0C5dARdYRTilKnU1TG4zenjjEPClkQxAWIpUOxl9xcNJWDVEOPxJ/4pVt+pozyT80Rp7efh6ZiREJIQI1tUboBKSqZzSbnD5uViQNSbQ90PaDP0FIUc0IQ5o07W36rijBB0DTmtU1VofzN9PKkJO7XiSSXevI8RcM=
- SAUCE_USERNAME=url-parse
- SCRIPT=test-browser
script:
- "npm run ${SCRIPT}"
after_script:
- 'if [ "${SCRIPT}" == "test" ]; then npm i coveralls@3 && cat coverage/lcov.info | coveralls; fi'
- 'if [ "${SCRIPT}" == "test" ]; then c8 report --reporter=text-lcov | coveralls; fi'
notifications:
irc:
channels:
11 changes: 10 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
@@ -33,13 +33,22 @@ acknowledge your responsible disclosure, if you wish.

## History

> Using backslash in the protocol is valid in the browser, while url-parse
> thinks it’s a relative path. An application that validates a url using
> url-parse might pass a malicious link.
- **Reporter credits**
- CxSCA AppSec team at Checkmarx.
- Twitter: [Yaniv Nizry](https://twitter.com/ynizry)
- Fixed in: 1.5.0

> The `extractProtocol` method does not return the correct protocol when
> provided with unsanitized content which could lead to false positives.
- **Reporter credits**
- Reported through our security email & Twitter interaction.
- Twitter: [@ronperris](https://twitter.com/ronperris)
- Fixed in: 1.4.5
- Fixed in: 1.4.5

---

24 changes: 18 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@

var required = require('requires-port')
, qs = require('querystringify')
, slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//
, protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i
, slashes = /^[A-Za-z][A-Za-z0-9+-.]*:[\\/]+/
, protocolre = /^([a-z][a-z0-9.+-]*:)?([\\/]{1,})?([\S\s]*)/i
, whitespace = '[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]'
, left = new RegExp('^'+ whitespace +'+');

@@ -115,12 +115,16 @@ function lolcation(loc) {
*/
function extractProtocol(address) {
address = trimLeft(address);
var match = protocolre.exec(address);

var match = protocolre.exec(address)
, protocol = match[1] ? match[1].toLowerCase() : ''
, slashes = !!(match[2] && match[2].length >= 2)
, rest = match[2] && match[2].length === 1 ? '/' + match[3] : match[3];

return {
protocol: match[1] ? match[1].toLowerCase() : '',
slashes: !!match[2],
rest: match[3]
protocol: protocol,
slashes: slashes,
rest: rest
};
}

@@ -280,6 +284,14 @@ function Url(address, location, parser) {
url.pathname = resolve(url.pathname, location.pathname);
}

//
// Default to a / for pathname if none exists. This normalizes the URL
// to always have a /
//
if (url.pathname.charAt(0) !== '/' && url.hostname) {
url.pathname = '/' + url.pathname;
}

//
// We should not add port numbers if they are already the default port number
// for a given protocol. As the host also contains the port number we're going
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "url-parse",
"version": "1.4.7",
"version": "1.5.1",
"description": "Small footprint URL parser that works seamlessly across Node.js and browser environments",
"main": "index.js",
"scripts": {
"browserify": "rm -rf dist && mkdir -p dist && browserify index.js -s URLParse -o dist/url-parse.js",
"minify": "uglifyjs dist/url-parse.js --source-map -cm -o dist/url-parse.min.js",
"test": "nyc --reporter=html --reporter=text mocha test/test.js",
"test": "c8 --reporter=html --reporter=text mocha test/test.js",
"test-browser": "node test/browser.js",
"prepublishOnly": "npm run browserify && npm run minify",
"watch": "mocha --watch test/test.js"
@@ -39,8 +39,9 @@
"devDependencies": {
"assume": "^2.2.0",
"browserify": "^16.2.3",
"mocha": "^6.1.4",
"nyc": "^14.0.0",
"c8": "^7.3.1",
"coveralls": "^3.1.0",
"mocha": "^8.0.1",
"pre-commit": "^1.2.2",
"sauce-browsers": "^2.0.0",
"sauce-test": "^1.3.3",
4 changes: 2 additions & 2 deletions test/browser.js
Original file line number Diff line number Diff line change
@@ -12,8 +12,8 @@ const platforms = sauceBrowsers([
{ name: 'firefox', version: ['oldest', 'latest'] },
{ name: 'internet explorer', version: 'oldest..latest' },
{ name: 'iphone', version: ['oldest', 'latest'] },
{ name: 'safari', version: 'oldest..latest' },
{ name: 'microsoftedge', version: 'oldest..latest' }
{ name: 'safari', version: ['oldest', 'latest'] },
{ name: 'microsoftedge', version: ['oldest', 'latest'] }
]).then((platforms) => {
return platforms.map((platform) => {
const ret = {
2 changes: 2 additions & 0 deletions test/fuzzy.js
Original file line number Diff line number Diff line change
@@ -103,6 +103,8 @@ module.exports = function generate() {
, key;

spec.protocol = get('protocol');
spec.slashes = true;

spec.hostname = get('hostname');
spec.pathname = get('pathname');

105 changes: 85 additions & 20 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -83,6 +83,20 @@ describe('url-parse', function () {
});
});

it('correctly resolves paths', function () {
assume(parse.extractProtocol('/foo')).eql({
slashes: false,
protocol: '',
rest: '/foo'
});

assume(parse.extractProtocol('//foo/bar')).eql({
slashes: true,
protocol: '',
rest: 'foo/bar'
});
});

it('does not truncate the input string', function () {
var input = 'foo\nbar\rbaz\u2028qux\u2029';

@@ -190,9 +204,10 @@ describe('url-parse', function () {
, parsed = parse(url);

assume(parsed.port).equals('');
assume(parsed.pathname).equals('/');
assume(parsed.host).equals('example.com');
assume(parsed.hostname).equals('example.com');
assume(parsed.href).equals('http://example.com');
assume(parsed.href).equals('http://example.com/');
});

it('understands an / as pathname', function () {
@@ -208,6 +223,20 @@ describe('url-parse', function () {
assume(parsed.href).equals('http://example.com/');
});

it('correctly parses pathnames for relative paths', function () {
var url = '/dataApi/PROD/ws'
, parsed = parse(url, 'http://localhost:3000/PROD/trends');

assume(parsed.pathname).equals('/dataApi/PROD/ws');

url = '/sections/?project=default'
parsed = parse(url, 'http://example.com/foo/bar');

assume(parsed.pathname).equals('/sections/');
assume(parsed.hostname).equals('example.com');
assume(parsed.href).equals('http://example.com/sections/?project=default');
});

it('does not care about spaces', function () {
var url = 'http://x.com/path?that\'s#all, folks'
, parsed = parse(url);
@@ -242,16 +271,30 @@ describe('url-parse', function () {
assume(parsed.hostname).equals('google.com');
assume(parsed.hash).equals('#what\\is going on');

parsed = parse('//\\what-is-up.com');
parsed = parse('http://yolo.com\\what-is-up.com');
assume(parsed.pathname).equals('/what-is-up.com');
});

it('correctly ignores multiple slashes //', function () {
var url = '////what-is-up.com'
, parsed = parse(url, parse('http://google.com'));

assume(parsed.host).equals('what-is-up.com');
assume(parsed.href).equals('http://what-is-up.com/');
});

it('does not see a slash after the protocol as path', function () {
var url = 'https:\\/github.com/foo/bar'
, parsed = parse(url);

assume(parsed.host).equals('');
assume(parsed.hostname).equals('');
assume(parsed.host).equals('github.com');
assume(parsed.hostname).equals('github.com');
assume(parsed.pathname).equals('/foo/bar');

url = 'https:/\/\/\github.com/foo/bar';
assume(parsed.host).equals('github.com');
assume(parsed.hostname).equals('github.com');
assume(parsed.pathname).equals('/foo/bar');
});

describe('origin', function () {
@@ -327,32 +370,52 @@ describe('url-parse', function () {
it('extracts the right protocol from a url', function () {
var testData = [
{
href: 'http://example.com',
href: 'http://example.com/',
protocol: 'http:',
pathname: ''
pathname: '/',
slashes: true
},
{
href: 'ws://example.com/',
protocol: 'ws:',
pathname: '/',
slashes: true
},
{
href: 'wss://example.com/',
protocol: 'wss:',
pathname: '/',
slashes: true
},
{
href: 'mailto:test@example.com',
pathname: 'test@example.com',
protocol: 'mailto:'
protocol: 'mailto:',
slashes: false
},
{
href: 'data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E',
pathname: 'text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E',
protocol: 'data:'
protocol: 'data:',
slashes: false,
},
{
href: 'sip:alice@atlanta.com',
pathname: 'alice@atlanta.com',
protocol: 'sip:'
protocol: 'sip:',
slashes: false,
}
];

var data;
var data, test;
for (var i = 0, len = testData.length; i < len; ++i) {
data = parse(testData[i].href);
assume(data.protocol).equals(testData[i].protocol);
assume(data.pathname).equals(testData[i].pathname);
test = testData[i];
data = parse(test.href);

assume(data.protocol).equals(test.protocol);
assume(data.pathname).equals(test.pathname);
assume(data.slashes).equals(test.slashes);
assume(data.href).equals(test.href);
}
});

@@ -391,13 +454,14 @@ describe('url-parse', function () {
});

it('parses ipv6 with auth', function () {
var url = 'http://user:password@[3ffe:2a00:100:7031::1]:8080'
var url = 'http://user:password@[3ffe:2a00:100:7031::1]:8080/'
, parsed = parse(url);

assume(parsed.username).equals('user');
assume(parsed.password).equals('password');
assume(parsed.host).equals('[3ffe:2a00:100:7031::1]:8080');
assume(parsed.hostname).equals('[3ffe:2a00:100:7031::1]');
assume(parsed.pathname).equals('/');
assume(parsed.href).equals(url);
});

@@ -467,7 +531,7 @@ describe('url-parse', function () {

assume(data.port).equals('');
assume(data.host).equals('localhost');
assume(data.href).equals('http://localhost');
assume(data.href).equals('http://localhost/');
});

it('inherits port numbers for relative urls', function () {
@@ -516,7 +580,8 @@ describe('url-parse', function () {
});

it('inherits protocol for relative protocols', function () {
var data = parse('//foo.com/foo', parse('http://sub.example.com:808/'));
var lolcation = parse('http://sub.example.com:808/')
, data = parse('//foo.com/foo', lolcation);

assume(data.port).equals('');
assume(data.host).equals('foo.com');
@@ -529,13 +594,13 @@ describe('url-parse', function () {

assume(data.port).equals('');
assume(data.host).equals('localhost');
assume(data.href).equals('http://localhost');
assume(data.href).equals('http://localhost/');
});

it('resolves pathname for relative urls', function () {
var data, i = 0;
var tests = [
['', 'http://foo.com', ''],
['', 'http://foo.com', '/'],
['', 'http://foo.com/', '/'],
['', 'http://foo.com/a', '/a'],
['a', 'http://foo.com', '/a'],
@@ -722,12 +787,12 @@ describe('url-parse', function () {
data.set('hash', 'usage');

assume(data.hash).equals('#usage');
assume(data.href).equals('http://example.com#usage');
assume(data.href).equals('http://example.com/#usage');

data.set('hash', '#license');

assume(data.hash).equals('#license');
assume(data.href).equals('http://example.com#license');
assume(data.href).equals('http://example.com/#license');
});

it('updates the port when updating host', function () {