Skip to content

Commit

Permalink
url: implement URL.canParse
Browse files Browse the repository at this point in the history
PR-URL: nodejs#47179
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
  • Loading branch information
KhafraDev authored and anonrig committed Jun 24, 2023
1 parent b2fd203 commit ccdfb69
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 19 deletions.
14 changes: 14 additions & 0 deletions benchmark/url/whatwgurl-canParse.js
Original file line number Diff line number Diff line change
@@ -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);
}
21 changes: 21 additions & 0 deletions doc/api/url.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const {
domainToASCII: _domainToASCII,
domainToUnicode: _domainToUnicode,
parse,
canParse: _canParse,
updateUrl,
} = internalBinding('url');

Expand Down Expand Up @@ -720,6 +721,16 @@ class URL {
return this.#context.href;
}

static canParse(url, base = undefined) {
url = `${url}`;

if (base !== undefined) {
base = `${base}`;
}

return _canParse(url, base);
}

static createObjectURL(obj) {
const cryptoRandom = lazyCryptoRandom();
if (cryptoRandom === undefined)
Expand Down Expand Up @@ -768,6 +779,15 @@ ObjectDefineProperties(URL.prototype, {
toJSON: kEnumerableProperty,
});

ObjectDefineProperties(URL, {
canParse: {
__proto__: null,
configurable: true,
writable: true,
enumerable: true,
},
});

ObjectDefineProperties(URL, {
createObjectURL: kEnumerableProperty,
revokeObjectURL: kEnumerableProperty,
Expand Down
26 changes: 26 additions & 0 deletions src/node_url.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down
17 changes: 9 additions & 8 deletions test/fixtures/wpt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,30 @@ See [test/wpt](../../wpt/README.md) for information on how these tests are run.

Last update:

- common: https://github.com/web-platform-tests/wpt/tree/03c5072aff/common
- common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common
- console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console
- dom/abort: https://github.com/web-platform-tests/wpt/tree/8fadb38120/dom/abort
- dom/events: https://github.com/web-platform-tests/wpt/tree/ab8999891c/dom/events
- encoding: https://github.com/web-platform-tests/wpt/tree/0c1b9d1622/encoding
- fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources
- FileAPI: https://github.com/web-platform-tests/wpt/tree/3b279420d4/FileAPI
- FileAPI/file: https://github.com/web-platform-tests/wpt/tree/c01f637cca/FileAPI/file
- FileAPI: https://github.com/web-platform-tests/wpt/tree/1e432c4550/FileAPI
- hr-time: https://github.com/web-platform-tests/wpt/tree/34cafd797e/hr-time
- html/webappapis/atob: https://github.com/web-platform-tests/wpt/tree/f267e1dca6/html/webappapis/atob
- html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/2c5c3c4c27/html/webappapis/microtask-queuing
- html/webappapis/structured-clone: https://github.com/web-platform-tests/wpt/tree/47d3fb280c/html/webappapis/structured-clone
- html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/5873f2d8f1/html/webappapis/timers
- interfaces: https://github.com/web-platform-tests/wpt/tree/fc086c82d5/interfaces
- interfaces: https://github.com/web-platform-tests/wpt/tree/df731dab88/interfaces
- performance-timeline: https://github.com/web-platform-tests/wpt/tree/17ebc3aea0/performance-timeline
- resources: https://github.com/web-platform-tests/wpt/tree/fbf1e7d247/resources
- streams: https://github.com/web-platform-tests/wpt/tree/9e5ef42bd3/streams
- url: https://github.com/web-platform-tests/wpt/tree/f1ade799d0/url
- 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/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
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/ee30029d47/WebCryptoAPI
- WebCryptoAPI: https://github.com/web-platform-tests/wpt/tree/1406b5c0d0/WebCryptoAPI
- webidl/ecmascript-binding/es-exceptions: https://github.com/web-platform-tests/wpt/tree/a370aad338/webidl/ecmascript-binding/es-exceptions
- webmessaging/broadcastchannel: https://github.com/web-platform-tests/wpt/tree/e97fac4791/webmessaging/broadcastchannel

[Web Platform Tests]: https://github.com/web-platform-tests/wpt
[`git node wpt`]: https://github.com/nodejs/node-core-utils/blob/main/docs/git-node.md#git-node-wpt
42 changes: 42 additions & 0 deletions test/fixtures/wpt/url/url-statics-canparse.any.js
Original file line number Diff line number Diff line change
@@ -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})`);
});
26 changes: 15 additions & 11 deletions test/fixtures/wpt/versions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"common": {
"commit": "03c5072affa496c5fd2a506e5c40d23e36b5e3aa",
"commit": "dbd648158d337580885e70a54f929daf215211a0",
"path": "common"
},
"console": {
Expand All @@ -24,13 +24,9 @@
"path": "fetch/data-urls/resources"
},
"FileAPI": {
"commit": "3b279420d40afea32506e823f9ac005448f4f3d8",
"commit": "1e432c4550a1595888d7c9eb26d90895e9e7e022",
"path": "FileAPI"
},
"FileAPI/file": {
"commit": "c01f637cca43f0e08ce8e4269121dcd89ccbdd82",
"path": "FileAPI/file"
},
"hr-time": {
"commit": "34cafd797e58dad280d20040eee012d49ccfa91f",
"path": "hr-time"
Expand All @@ -52,23 +48,27 @@
"path": "html/webappapis/timers"
},
"interfaces": {
"commit": "fc086c82d5a7e9b01a684a23336d6d1f9e79e303",
"commit": "df731dab88a1a25c04eb7e6238c11dc28fda0801",
"path": "interfaces"
},
"performance-timeline": {
"commit": "17ebc3aea0d6321e69554067c39ab5855e6fb67e",
"path": "performance-timeline"
},
"resource-timing": {
"commit": "22d38586d04c1d22b64db36f439c6bb84f03db7d",
"path": "resource-timing"
},
"resources": {
"commit": "fbf1e7d24776b6da144dbca45c22d39dc0512d2d",
"commit": "919874f84ff3703365063e749161a34af38c3d2a",
"path": "resources"
},
"streams": {
"commit": "9e5ef42bd34b5b19b76d0d4cb19012e52c222664",
"commit": "51750bc8d749bd80930506f603940a6bafda459f",
"path": "streams"
},
"url": {
"commit": "f1ade799d04b72b0ff75c13e988744c2cd873741",
"commit": "7c5c3cc125979b4768d414471e6ab655b473aae8",
"path": "url"
},
"user-timing": {
Expand All @@ -84,11 +84,15 @@
"path": "wasm/webapi"
},
"WebCryptoAPI": {
"commit": "ee30029d47cf9f7cf8f71fe851b4c29903edf851",
"commit": "1406b5c0d07b5e8dd08e328c451e42c23f3b96c8",
"path": "WebCryptoAPI"
},
"webidl/ecmascript-binding/es-exceptions": {
"commit": "a370aad338d6ed743abb4d2c6ae84a7f1058558c",
"path": "webidl/ecmascript-binding/es-exceptions"
},
"webmessaging/broadcastchannel": {
"commit": "e97fac4791931fb7455ba3fad759d362c7108b09",
"path": "webmessaging/broadcastchannel"
}
}

0 comments on commit ccdfb69

Please sign in to comment.