Skip to content

Commit 0d7ee19

Browse files
TimothyGuBridgeAR
authored andcommitted
url: reuse existing context in href setter
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: #24345 Refs: #24218 (comment) PR-URL: #24495 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 0e88f44 commit 0d7ee19

File tree

3 files changed

+33
-21
lines changed

3 files changed

+33
-21
lines changed

lib/internal/url.js

+17-21
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const {
4343
domainToUnicode: _domainToUnicode,
4444
encodeAuth,
4545
toUSVString: _toUSVString,
46-
parse: _parse,
46+
parse,
4747
setURLConstructor,
4848
URL_FLAGS_CANNOT_BE_BASE,
4949
URL_FLAGS_HAS_FRAGMENT,
@@ -243,14 +243,6 @@ function onParseError(flags, input) {
243243
throw error;
244244
}
245245

246-
// Reused by URL constructor and URL#href setter.
247-
function parse(url, input, base) {
248-
const base_context = base ? base[context] : undefined;
249-
url[context] = new URLContext();
250-
_parse(input.trim(), -1, base_context, undefined,
251-
onParseComplete.bind(url), onParseError);
252-
}
253-
254246
function onParseProtocolComplete(flags, protocol, username, password,
255247
host, port, path, query, fragment) {
256248
const ctx = this[context];
@@ -319,10 +311,13 @@ class URL {
319311
constructor(input, base) {
320312
// toUSVString is not needed.
321313
input = `${input}`;
314+
let base_context;
322315
if (base !== undefined) {
323-
base = new URL(base);
316+
base_context = new URL(base)[context];
324317
}
325-
parse(this, input, base);
318+
this[context] = new URLContext();
319+
parse(input, -1, base_context, undefined, onParseComplete.bind(this),
320+
onParseError);
326321
}
327322

328323
get [special]() {
@@ -445,7 +440,8 @@ Object.defineProperties(URL.prototype, {
445440
set(input) {
446441
// toUSVString is not needed.
447442
input = `${input}`;
448-
parse(this, input);
443+
parse(input, -1, undefined, undefined, onParseComplete.bind(this),
444+
onParseError);
449445
}
450446
},
451447
origin: { // readonly
@@ -491,8 +487,8 @@ Object.defineProperties(URL.prototype, {
491487
(ctx.host === '' || ctx.host === null)) {
492488
return;
493489
}
494-
_parse(scheme, kSchemeStart, null, ctx,
495-
onParseProtocolComplete.bind(this));
490+
parse(scheme, kSchemeStart, null, ctx,
491+
onParseProtocolComplete.bind(this));
496492
}
497493
},
498494
username: {
@@ -555,7 +551,7 @@ Object.defineProperties(URL.prototype, {
555551
// Cannot set the host if cannot-be-base is set
556552
return;
557553
}
558-
_parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
554+
parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
559555
}
560556
},
561557
hostname: {
@@ -572,7 +568,7 @@ Object.defineProperties(URL.prototype, {
572568
// Cannot set the host if cannot-be-base is set
573569
return;
574570
}
575-
_parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this));
571+
parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this));
576572
}
577573
},
578574
port: {
@@ -592,7 +588,7 @@ Object.defineProperties(URL.prototype, {
592588
ctx.port = null;
593589
return;
594590
}
595-
_parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
591+
parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
596592
}
597593
},
598594
pathname: {
@@ -611,8 +607,8 @@ Object.defineProperties(URL.prototype, {
611607
path = `${path}`;
612608
if (this[cannotBeBase])
613609
return;
614-
_parse(path, kPathStart, null, this[context],
615-
onParsePathComplete.bind(this));
610+
parse(path, kPathStart, null, this[context],
611+
onParsePathComplete.bind(this));
616612
}
617613
},
618614
search: {
@@ -635,7 +631,7 @@ Object.defineProperties(URL.prototype, {
635631
ctx.query = '';
636632
ctx.flags |= URL_FLAGS_HAS_QUERY;
637633
if (search) {
638-
_parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
634+
parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
639635
}
640636
}
641637
initSearchParams(this[searchParams], search);
@@ -669,7 +665,7 @@ Object.defineProperties(URL.prototype, {
669665
if (hash[0] === '#') hash = hash.slice(1);
670666
ctx.fragment = '';
671667
ctx.flags |= URL_FLAGS_HAS_FRAGMENT;
672-
_parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
668+
parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
673669
}
674670
},
675671
toJSON: {

src/node_url.cc

+1
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,7 @@ void URL::Parse(const char* input,
13761376
else
13771377
break;
13781378
}
1379+
input = p;
13791380
len = end - p;
13801381
}
13811382

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
// Tests below are not from WPT.
4+
const common = require('../common');
5+
const assert = require('assert');
6+
7+
const ref = new URL('http://example.com/path');
8+
const url = new URL('http://example.com/path');
9+
common.expectsError(() => {
10+
url.href = '';
11+
}, {
12+
type: TypeError
13+
});
14+
15+
assert.deepStrictEqual(url, ref);

0 commit comments

Comments
 (0)