Skip to content

Commit 8be84ac

Browse files
committed
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: nodejs#24345 Refs: nodejs#24218 (comment)
1 parent 6cf1769 commit 8be84ac

3 files changed

Lines changed: 31 additions & 19 deletions

File tree

lib/internal/url.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const {
4242
domainToUnicode: _domainToUnicode,
4343
encodeAuth,
4444
toUSVString: _toUSVString,
45-
parse: _parse,
45+
parse,
4646
setURLConstructor,
4747
URL_FLAGS_CANNOT_BE_BASE,
4848
URL_FLAGS_HAS_FRAGMENT,
@@ -242,14 +242,6 @@ function onParseError(flags, input) {
242242
throw error;
243243
}
244244

245-
// Reused by URL constructor and URL#href setter.
246-
function parse(url, input, base) {
247-
const base_context = base ? base[context] : undefined;
248-
url[context] = new URLContext();
249-
_parse(input.trim(), -1, base_context, undefined,
250-
onParseComplete.bind(url), onParseError);
251-
}
252-
253245
function onParseProtocolComplete(flags, protocol, username, password,
254246
host, port, path, query, fragment) {
255247
const ctx = this[context];
@@ -318,10 +310,13 @@ class URL {
318310
constructor(input, base) {
319311
// toUSVString is not needed.
320312
input = `${input}`;
313+
let base_context;
321314
if (base !== undefined) {
322-
base = new URL(base);
315+
base_context = new URL(base)[context];
323316
}
324-
parse(this, input, base);
317+
this[context] = new URLContext();
318+
parse(input, -1, base_context, undefined, onParseComplete.bind(this),
319+
onParseError);
325320
}
326321

327322
get [special]() {
@@ -444,7 +439,8 @@ Object.defineProperties(URL.prototype, {
444439
set(input) {
445440
// toUSVString is not needed.
446441
input = `${input}`;
447-
parse(this, input);
442+
parse(input, -1, undefined, undefined, onParseComplete.bind(this),
443+
onParseError);
448444
}
449445
},
450446
origin: { // readonly
@@ -490,7 +486,7 @@ Object.defineProperties(URL.prototype, {
490486
(ctx.host === '' || ctx.host === null)) {
491487
return;
492488
}
493-
_parse(scheme, kSchemeStart, null, ctx,
489+
parse(scheme, kSchemeStart, null, ctx,
494490
onParseProtocolComplete.bind(this));
495491
}
496492
},
@@ -554,7 +550,7 @@ Object.defineProperties(URL.prototype, {
554550
// Cannot set the host if cannot-be-base is set
555551
return;
556552
}
557-
_parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
553+
parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
558554
}
559555
},
560556
hostname: {
@@ -571,7 +567,7 @@ Object.defineProperties(URL.prototype, {
571567
// Cannot set the host if cannot-be-base is set
572568
return;
573569
}
574-
_parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this));
570+
parse(host, kHostname, null, ctx, onParseHostnameComplete.bind(this));
575571
}
576572
},
577573
port: {
@@ -591,7 +587,7 @@ Object.defineProperties(URL.prototype, {
591587
ctx.port = null;
592588
return;
593589
}
594-
_parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
590+
parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
595591
}
596592
},
597593
pathname: {
@@ -610,7 +606,7 @@ Object.defineProperties(URL.prototype, {
610606
path = `${path}`;
611607
if (this[cannotBeBase])
612608
return;
613-
_parse(path, kPathStart, null, this[context],
609+
parse(path, kPathStart, null, this[context],
614610
onParsePathComplete.bind(this));
615611
}
616612
},
@@ -634,7 +630,7 @@ Object.defineProperties(URL.prototype, {
634630
ctx.query = '';
635631
ctx.flags |= URL_FLAGS_HAS_QUERY;
636632
if (search) {
637-
_parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
633+
parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
638634
}
639635
}
640636
initSearchParams(this[searchParams], search);
@@ -668,7 +664,7 @@ Object.defineProperties(URL.prototype, {
668664
if (hash[0] === '#') hash = hash.slice(1);
669665
ctx.fragment = '';
670666
ctx.flags |= URL_FLAGS_HAS_FRAGMENT;
671-
_parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
667+
parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
672668
}
673669
},
674670
toJSON: {

src/node_url.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,7 @@ void URL::Parse(const char* input,
13751375
else
13761376
break;
13771377
}
1378+
input = p;
13781379
len = end - p;
13791380
}
13801381

Lines changed: 15 additions & 0 deletions
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)