url: implement URL.canParse

PR-URL: https://github.com/nodejs/node/pull/47179
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
This commit is contained in:
Khafra 2023-03-22 15:44:44 -04:00 committed by GitHub
parent 7bc0e6a4e7
commit f2651a0812
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 2 deletions

View File

@ -0,0 +1,14 @@
'use strict';
const common = require('../common.js');
const bench = common.createBenchmark(main, {
type: Object.keys(common.urls),
n: [25e6],
});
function main({ type, n }) {
bench.start();
for (let i = 0; i < n; i += 1)
URL.canParse(common.urls[type]);
bench.end(n);
}

View File

@ -662,6 +662,27 @@ added: v16.7.0
Removes the stored {Blob} identified by the given ID. Attempting to revoke a
ID that isn't registered will silently fail.
#### `URL.canParse(input[, base])`
<!-- YAML
added: REPLACEME
-->
* `input` {string} The absolute or relative input URL to parse. If `input`
is relative, then `base` is required. If `input` is absolute, the `base`
is ignored. If `input` is not a string, it is [converted to a string][] first.
* `base` {string} The base URL to resolve against if the `input` is not
absolute. If `base` is not a string, it is [converted to a string][] first.
* Returns: {boolean}
Checks if an `input` relative to the `base` can be parsed to a `URL`.
```js
const isValid = URL.canParse('/foo', 'https://example.org/'); // true
const isNotValid = URL.canParse('/foo'); // false
```
### Class: `URLSearchParams`
<!-- YAML

View File

@ -88,6 +88,7 @@ const {
domainToASCII: _domainToASCII,
domainToUnicode: _domainToUnicode,
parse,
canParse: _canParse,
updateUrl,
} = internalBinding('url');
@ -713,6 +714,16 @@ class URL {
toJSON() {
return this.#context.href;
}
static canParse(url, base = undefined) {
url = `${url}`;
if (base !== undefined) {
base = `${base}`;
}
return _canParse(url, base);
}
}
ObjectDefineProperties(URL.prototype, {
@ -733,6 +744,15 @@ ObjectDefineProperties(URL.prototype, {
toJSON: kEnumerableProperty,
});
ObjectDefineProperties(URL, {
canParse: {
__proto__: null,
configurable: true,
writable: true,
enumerable: true,
},
});
function installObjectURLMethods() {
const {
storeDataObject,

View File

@ -93,6 +93,30 @@ void Parse(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(true);
}
void CanParse(const FunctionCallbackInfo<Value>& args) {
CHECK_GE(args.Length(), 2);
CHECK(args[0]->IsString()); // input
// args[1] // base url
Environment* env = Environment::GetCurrent(args);
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
Utf8Value input(env->isolate(), args[0]);
ada::result base;
ada::url* base_pointer = nullptr;
if (args[1]->IsString()) {
base = ada::parse(Utf8Value(env->isolate(), args[1]).ToString());
if (!base) {
return args.GetReturnValue().Set(false);
}
base_pointer = &base.value();
}
ada::result out = ada::parse(input.ToStringView(), base_pointer);
args.GetReturnValue().Set(out.has_value());
}
void DomainToASCII(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_GE(args.Length(), 1);
@ -285,6 +309,7 @@ void Initialize(Local<Object> target,
void* priv) {
SetMethod(context, target, "parse", Parse);
SetMethod(context, target, "updateUrl", UpdateUrl);
SetMethodNoSideEffect(context, target, "canParse", CanParse);
SetMethodNoSideEffect(context, target, "formatUrl", FormatUrl);
SetMethodNoSideEffect(context, target, "domainToASCII", DomainToASCII);
@ -294,6 +319,7 @@ void Initialize(Local<Object> target,
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(Parse);
registry->Register(CanParse);
registry->Register(UpdateUrl);
registry->Register(FormatUrl);

View File

@ -27,7 +27,7 @@ Last update:
- resource-timing: https://github.com/web-platform-tests/wpt/tree/22d38586d0/resource-timing
- resources: https://github.com/web-platform-tests/wpt/tree/919874f84f/resources
- streams: https://github.com/web-platform-tests/wpt/tree/51750bc8d7/streams
- url: https://github.com/web-platform-tests/wpt/tree/84caeb6fbd/url
- url: https://github.com/web-platform-tests/wpt/tree/7c5c3cc125/url
- user-timing: https://github.com/web-platform-tests/wpt/tree/df24fb604e/user-timing
- wasm/jsapi: https://github.com/web-platform-tests/wpt/tree/d8dbe6990b/wasm/jsapi
- wasm/webapi: https://github.com/web-platform-tests/wpt/tree/fd1b23eeaa/wasm/webapi

View File

@ -0,0 +1,42 @@
// This intentionally does not use resources/urltestdata.json to preserve resources.
[
{
"url": undefined,
"base": undefined,
"expected": false
},
{
"url": "a:b",
"base": undefined,
"expected": true
},
{
"url": undefined,
"base": "a:b",
"expected": false
},
{
"url": "a:/b",
"base": undefined,
"expected": true
},
{
"url": undefined,
"base": "a:/b",
"expected": true
},
{
"url": "https://test:test",
"base": undefined,
"expected": false
},
{
"url": "a",
"base": "https://b/",
"expected": true
}
].forEach(({ url, base, expected }) => {
test(() => {
assert_equals(URL.canParse(url, base), expected);
}, `URL.canParse(${url}, ${base})`);
});

View File

@ -68,7 +68,7 @@
"path": "streams"
},
"url": {
"commit": "84caeb6fbdf45129f57c67448e6113ee1ced9fb3",
"commit": "7c5c3cc125979b4768d414471e6ab655b473aae8",
"path": "url"
},
"user-timing": {