mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
url: throw invalid this on detached accessors
Previously, using Reflect.get/set or calling a member method like toString() detached from the instance would result in an obscure internal error. This adds a proper brand check and throws `ERR_INVALID_THIS` when appropriate. Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/39752 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Zijian Liu <lxxyxzj@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This commit is contained in:
2 files changed
+97
No files matched your search
@@ -625,6 +625,10 @@ function onParseHashComplete(flags, protocol, username, password,
|
||||
this[context].fragment = fragment;
|
||||
}
|
||||
|
||||
function isURLThis(self) {
|
||||
return self?.[context] !== undefined;
|
||||
}
|
||||
|
||||
class URL {
|
||||
constructor(input, base) {
|
||||
// toUSVString is not needed.
|
||||
@@ -737,14 +741,20 @@ class URL {
|
||||
|
||||
// https://heycam.github.io/webidl/#es-stringifier
|
||||
toString() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[kFormat]({});
|
||||
}
|
||||
|
||||
get href() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[kFormat]({});
|
||||
}
|
||||
|
||||
set href(input) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// toUSVString is not needed.
|
||||
input = `${input}`;
|
||||
parse(input, -1, undefined, undefined,
|
||||
@@ -753,6 +763,8 @@ class URL {
|
||||
|
||||
// readonly
|
||||
get origin() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// Refs: https://url.spec.whatwg.org/#concept-url-origin
|
||||
const ctx = this[context];
|
||||
switch (ctx.scheme) {
|
||||
@@ -776,10 +788,14 @@ class URL {
|
||||
}
|
||||
|
||||
get protocol() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[context].scheme;
|
||||
}
|
||||
|
||||
set protocol(scheme) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// toUSVString is not needed.
|
||||
scheme = `${scheme}`;
|
||||
if (scheme.length === 0)
|
||||
@@ -790,10 +806,14 @@ class URL {
|
||||
}
|
||||
|
||||
get username() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[context].username;
|
||||
}
|
||||
|
||||
set username(username) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// toUSVString is not needed.
|
||||
username = `${username}`;
|
||||
if (this[cannotHaveUsernamePasswordPort])
|
||||
@@ -809,10 +829,14 @@ class URL {
|
||||
}
|
||||
|
||||
get password() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[context].password;
|
||||
}
|
||||
|
||||
set password(password) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// toUSVString is not needed.
|
||||
password = `${password}`;
|
||||
if (this[cannotHaveUsernamePasswordPort])
|
||||
@@ -828,6 +852,8 @@ class URL {
|
||||
}
|
||||
|
||||
get host() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const ctx = this[context];
|
||||
let ret = ctx.host || '';
|
||||
if (ctx.port !== null)
|
||||
@@ -836,6 +862,8 @@ class URL {
|
||||
}
|
||||
|
||||
set host(host) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const ctx = this[context];
|
||||
// toUSVString is not needed.
|
||||
host = `${host}`;
|
||||
@@ -848,10 +876,14 @@ class URL {
|
||||
}
|
||||
|
||||
get hostname() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[context].host || '';
|
||||
}
|
||||
|
||||
set hostname(host) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const ctx = this[context];
|
||||
// toUSVString is not needed.
|
||||
host = `${host}`;
|
||||
@@ -863,11 +895,15 @@ class URL {
|
||||
}
|
||||
|
||||
get port() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const port = this[context].port;
|
||||
return port === null ? '' : String(port);
|
||||
}
|
||||
|
||||
set port(port) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// toUSVString is not needed.
|
||||
port = `${port}`;
|
||||
if (this[cannotHaveUsernamePasswordPort])
|
||||
@@ -882,6 +918,8 @@ class URL {
|
||||
}
|
||||
|
||||
get pathname() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const ctx = this[context];
|
||||
if (this[cannotBeBase])
|
||||
return ctx.path[0];
|
||||
@@ -891,6 +929,8 @@ class URL {
|
||||
}
|
||||
|
||||
set pathname(path) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
// toUSVString is not needed.
|
||||
path = `${path}`;
|
||||
if (this[cannotBeBase])
|
||||
@@ -900,6 +940,8 @@ class URL {
|
||||
}
|
||||
|
||||
get search() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const { query } = this[context];
|
||||
if (query === null || query === '')
|
||||
return '';
|
||||
@@ -907,6 +949,8 @@ class URL {
|
||||
}
|
||||
|
||||
set search(search) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const ctx = this[context];
|
||||
search = toUSVString(search);
|
||||
if (search === '') {
|
||||
@@ -926,10 +970,14 @@ class URL {
|
||||
|
||||
// readonly
|
||||
get searchParams() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[searchParams];
|
||||
}
|
||||
|
||||
get hash() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const { fragment } = this[context];
|
||||
if (fragment === null || fragment === '')
|
||||
return '';
|
||||
@@ -937,6 +985,8 @@ class URL {
|
||||
}
|
||||
|
||||
set hash(hash) {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
const ctx = this[context];
|
||||
// toUSVString is not needed.
|
||||
hash = `${hash}`;
|
||||
@@ -953,6 +1003,8 @@ class URL {
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
if (!isURLThis(this))
|
||||
throw new ERR_INVALID_THIS('URL');
|
||||
return this[kFormat]({});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
|
||||
const { URL } = require('url');
|
||||
const assert = require('assert');
|
||||
|
||||
[
|
||||
'toString',
|
||||
'toJSON',
|
||||
].forEach((i) => {
|
||||
assert.throws(() => Reflect.apply(URL.prototype[i], [], {}), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
});
|
||||
|
||||
[
|
||||
'href',
|
||||
'protocol',
|
||||
'username',
|
||||
'password',
|
||||
'host',
|
||||
'hostname',
|
||||
'port',
|
||||
'pathname',
|
||||
'search',
|
||||
'hash',
|
||||
].forEach((i) => {
|
||||
assert.throws(() => Reflect.get(URL.prototype, i, {}), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
|
||||
assert.throws(() => Reflect.set(URL.prototype, i, null, {}), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
});
|
||||
|
||||
[
|
||||
'origin',
|
||||
'searchParams',
|
||||
].forEach((i) => {
|
||||
assert.throws(() => Reflect.get(URL.prototype, i, {}), {
|
||||
code: 'ERR_INVALID_THIS',
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user