Skip to content

Commit

Permalink
url: reuse existing context in href setter
Browse files Browse the repository at this point in the history
Correctness-wise, this removes side effects in the href setter if parsing
fails. Style-wise, this allows removing the parse() wrapper function around C++
_parse().

Also fix an existing bug with whitespace trimming in C++ that was previously
circumvented by additionally trimming the input in JavaScript.

Fixes: nodejs#24345
Refs: nodejs#24218 (comment)
  • Loading branch information
TimothyGu committed Nov 19, 2018
1 parent 6cf1769 commit 8be84ac
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 19 deletions.
34 changes: 15 additions & 19 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const {
domainToUnicode: _domainToUnicode,
encodeAuth,
toUSVString: _toUSVString,
parse: _parse,
parse,
setURLConstructor,
URL_FLAGS_CANNOT_BE_BASE,
URL_FLAGS_HAS_FRAGMENT,
Expand Down Expand Up @@ -242,14 +242,6 @@ function onParseError(flags, input) {
throw error;
}

// Reused by URL constructor and URL#href setter.
function parse(url, input, base) {
const base_context = base ? base[context] : undefined;
url[context] = new URLContext();
_parse(input.trim(), -1, base_context, undefined,
onParseComplete.bind(url), onParseError);
}

function onParseProtocolComplete(flags, protocol, username, password,
host, port, path, query, fragment) {
const ctx = this[context];
Expand Down Expand Up @@ -318,10 +310,13 @@ class URL {
constructor(input, base) {
// toUSVString is not needed.
input = `${input}`;
let base_context;
if (base !== undefined) {
base = new URL(base);
base_context = new URL(base)[context];
}
parse(this, input, base);
this[context] = new URLContext();
parse(input, -1, base_context, undefined, onParseComplete.bind(this),
onParseError);
}

get [special]() {
Expand Down Expand Up @@ -444,7 +439,8 @@ Object.defineProperties(URL.prototype, {
set(input) {
// toUSVString is not needed.
input = `${input}`;
parse(this, input);
parse(input, -1, undefined, undefined, onParseComplete.bind(this),
onParseError);
}
},
origin: { // readonly
Expand Down Expand Up @@ -490,7 +486,7 @@ Object.defineProperties(URL.prototype, {
(ctx.host === '' || ctx.host === null)) {
return;
}
_parse(scheme, kSchemeStart, null, ctx,
parse(scheme, kSchemeStart, null, ctx,
onParseProtocolComplete.bind(this));
}
},
Expand Down Expand Up @@ -554,7 +550,7 @@ Object.defineProperties(URL.prototype, {
// Cannot set the host if cannot-be-base is set
return;
}
_parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
}
},
hostname: {
Expand All @@ -571,7 +567,7 @@ Object.defineProperties(URL.prototype, {
// Cannot set the host if cannot-be-base is set
return;
}
_parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this));
parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this));
}
},
port: {
Expand All @@ -591,7 +587,7 @@ Object.defineProperties(URL.prototype, {
ctx.port = null;
return;
}
_parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
}
},
pathname: {
Expand All @@ -610,7 +606,7 @@ Object.defineProperties(URL.prototype, {
path = `${path}`;
if (this[cannotBeBase])
return;
_parse(path, kPathStart, null, this[context],
parse(path, kPathStart, null, this[context],
onParsePathComplete.bind(this));
}
},
Expand All @@ -634,7 +630,7 @@ Object.defineProperties(URL.prototype, {
ctx.query = '';
ctx.flags |= URL_FLAGS_HAS_QUERY;
if (search) {
_parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
}
}
initSearchParams(this[searchParams], search);
Expand Down Expand Up @@ -668,7 +664,7 @@ Object.defineProperties(URL.prototype, {
if (hash[0] === '#') hash = hash.slice(1);
ctx.fragment = '';
ctx.flags |= URL_FLAGS_HAS_FRAGMENT;
_parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
}
},
toJSON: {
Expand Down
1 change: 1 addition & 0 deletions src/node_url.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,7 @@ void URL::Parse(const char* input,
else
break;
}
input = p;
len = end - p;
}

Expand Down
15 changes: 15 additions & 0 deletions test/parallel/test-whatwg-url-custom-href-side-effect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

// Tests below are not from WPT.
const common = require('../common');
const assert = require('assert');

const ref = new URL('http://example.com/path');
const url = new URL('http://example.com/path');
common.expectsError(() => {
url.href = '';
}, {
type: TypeError
});

assert.deepStrictEqual(url, ref);

0 comments on commit 8be84ac

Please sign in to comment.