From 1e5619d93a431482a06b0a610db50ea2b89d064e Mon Sep 17 00:00:00 2001 From: Khafra <42794878+KhafraDev@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:36:05 -0400 Subject: [PATCH 1/6] url: implement URL.canParse --- lib/internal/url.js | 19 +++++++++ test/fixtures/wpt/README.md | 2 +- .../wpt/url/url-statics-canparse.any.js | 42 +++++++++++++++++++ test/fixtures/wpt/versions.json | 2 +- 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/wpt/url/url-statics-canparse.any.js diff --git a/lib/internal/url.js b/lib/internal/url.js index fe4dab1224be39..b3cdea645b85a7 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -713,6 +713,16 @@ class URL { toJSON() { return this.#context.href; } + + static canParse(url, base = undefined) { + url = `${url}`; + + if (base !== undefined) { + base = `${base}`; + } + + return parse(url, base, () => {}); + } } ObjectDefineProperties(URL.prototype, { @@ -733,6 +743,15 @@ ObjectDefineProperties(URL.prototype, { toJSON: kEnumerableProperty, }); +ObjectDefineProperties(URL, { + canParse: { + __proto__: null, + configurable: true, + writable: true, + enumerable: true, + }, +}); + function installObjectURLMethods() { const { storeDataObject, diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index d767e533ec3e67..950f0cd0a966f3 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -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 diff --git a/test/fixtures/wpt/url/url-statics-canparse.any.js b/test/fixtures/wpt/url/url-statics-canparse.any.js new file mode 100644 index 00000000000000..c87fcb4f56fcdd --- /dev/null +++ b/test/fixtures/wpt/url/url-statics-canparse.any.js @@ -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})`); +}); diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index 03f6b716210f4b..583e1f75bf585f 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -68,7 +68,7 @@ "path": "streams" }, "url": { - "commit": "84caeb6fbdf45129f57c67448e6113ee1ced9fb3", + "commit": "7c5c3cc125979b4768d414471e6ab655b473aae8", "path": "url" }, "user-timing": { From 0e6aab15c3a1e27a3c78f562f3fcfd569260d34d Mon Sep 17 00:00:00 2001 From: Khafra <42794878+KhafraDev@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:22:43 -0400 Subject: [PATCH 2/6] fix: code review --- lib/internal/url.js | 3 ++- src/node_url.cc | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index b3cdea645b85a7..01d2bbbfc78dee 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -88,6 +88,7 @@ const { domainToASCII: _domainToASCII, domainToUnicode: _domainToUnicode, parse, + canParse: _canParse, updateUrl, } = internalBinding('url'); @@ -721,7 +722,7 @@ class URL { base = `${base}`; } - return parse(url, base, () => {}); + return _canParse(url, base); } } diff --git a/src/node_url.cc b/src/node_url.cc index 27e8448517a3a4..2930640ec94e5d 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -93,6 +93,30 @@ void Parse(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(true); } +void CanParse(const FunctionCallbackInfo& 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& args) { Environment* env = Environment::GetCurrent(args); CHECK_GE(args.Length(), 1); @@ -284,6 +308,7 @@ void Initialize(Local target, Local context, void* priv) { SetMethod(context, target, "parse", Parse); + SetMethod(context, target, "canParse", CanParse); SetMethod(context, target, "updateUrl", UpdateUrl); SetMethodNoSideEffect(context, target, "formatUrl", FormatUrl); @@ -294,6 +319,7 @@ void Initialize(Local target, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(Parse); + registry->Register(CanParse); registry->Register(UpdateUrl); registry->Register(FormatUrl); From ca4f625a118d5a7ad124e4b8ca0fc6a889c0b6d7 Mon Sep 17 00:00:00 2001 From: Khafra <42794878+KhafraDev@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:38:28 -0400 Subject: [PATCH 3/6] fix: add benchmark --- benchmark/url/whatwgurl-canParse.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 benchmark/url/whatwgurl-canParse.js diff --git a/benchmark/url/whatwgurl-canParse.js b/benchmark/url/whatwgurl-canParse.js new file mode 100644 index 00000000000000..bb4149c663f313 --- /dev/null +++ b/benchmark/url/whatwgurl-canParse.js @@ -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); +} From 22d7c5b6045143862b06726b07ca8c95a7f1699c Mon Sep 17 00:00:00 2001 From: Khafra <42794878+KhafraDev@users.noreply.github.com> Date: Mon, 20 Mar 2023 16:48:57 -0400 Subject: [PATCH 4/6] fix: add docs --- doc/api/url.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/api/url.md b/doc/api/url.md index ac2884e64f5533..52adf1dca72a79 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -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])` + + + +* `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`