-
Notifications
You must be signed in to change notification settings - Fork 30.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
src: implement whatwg's URLPattern spec #56452
base: main
Are you sure you want to change the base?
Conversation
Review requested:
|
Can you elaborate? libuv is a C library so I don't think exceptions exist there, and I'm pretty sure V8 is built with exceptions disabled. |
My bad UV does not enable exceptions. Referencing v8.gyp file:
|
This is not really V8. It's a build-time executable (torque) used to generate code for V8 |
|
||
MaybeLocal<Value> URLPattern::Hash() const { | ||
auto context = env()->context(); | ||
return ToV8Value(context, url_pattern_.get_hash()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the key challenge here is that this will copy the string on every call. Any chance of memoizing the string once created.
src/node_url_pattern.cc
Outdated
URLPattern::URLPattern(Environment* env, | ||
Local<Object> object, | ||
ada::url_pattern&& url_pattern) | ||
: BaseObject(env, object) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We likely should introduce this as experimental in the first release, even if it graduates from experimental quickly. There should likely be a warning emitted on the first construction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK: There is no easy way to emit an experimental warning in C++ that can be dismissed using the CLI command. For now, I have made it experimental on the nodejs doc.
Can you also include a fairly simple benchmark? |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #56452 +/- ##
==========================================
- Coverage 89.21% 89.18% -0.03%
==========================================
Files 663 665 +2
Lines 192001 192564 +563
Branches 36921 37045 +124
==========================================
+ Hits 171286 171733 +447
- Misses 13582 13642 +60
- Partials 7133 7189 +56
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think this is a good pattern to land in Node.js. Specifically, a server using this will create one per route and iterate in a loop. This will be slow, specifically if you need to match the last of the list.
(This feedback was provided when URLPattern was standardized and essentially ignored).
For this to be useful, we would need to have a Node.js-specific API to organize these URLPattern in a radix prefix trie and actually do the matching all at once.
I can possibly be persuaded that we need this for Web platform compatibility, but it’s not that popular either (unlike fetch()).
@jasnell I’ll try to build this and get a benchmark going against the ecosystem routers. |
Right now, this pull-request does not pass WPT, and not at all optimized. Any benchmarks will not be beneficial. |
ad32b4d
to
cef45f0
Compare
@targos I've removed the exception requirement of this pull-request. We no longer use std::regex and I've put it under a flag where it's not enabled for Node.js builds: ada-url/ada#853 |
cef45f0
to
72cb00f
Compare
From what I see it's all ada related. Since we have collaborators that are actively working on that project I'll leave it to them, but feel free to reach out if any assistance is needed. |
input = ada::url_pattern_init{}; | ||
} else if (args[0]->IsString()) { | ||
Utf8Value input_value(env->isolate(), args[0].As<String>()); | ||
input_base = input_value.ToString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small suggestion: We could just move the Utf8Value
into the outer scope as a std::optional<Utf8Value>
and skip the intermediate std::string
then?
Similar recommendation elsewhere :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. Thank you for the recommendation and review!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somehow the following change causes "free(): invalid pointer"
void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
URLPattern* url_pattern;
ASSIGN_OR_RETURN_UNWRAP(&url_pattern, args.This());
auto env = Environment::GetCurrent(args);
ada::url_pattern_input input;
std::optional<Utf8Value> input_base{};
std::optional<Utf8Value> base_url{};
if (args.Length() == 0) {
input = ada::url_pattern_init{};
} else if (args[0]->IsString()) {
input_base = Utf8Value(env->isolate(), args[0].As<String>());
input = input_base->ToStringView();
} else if (args[0]->IsObject()) {
input = URLPatternInit::FromJsObject(env, args[0].As<Object>());
} else {
THROW_ERR_INVALID_ARG_TYPE(
env, "URLPattern input needs to be a string or an object");
return;
}
if (args.Length() > 1) {
if (!args[1]->IsString()) {
THROW_ERR_INVALID_ARG_TYPE(env, "baseURL must be a string");
return;
}
base_url = Utf8Value(env->isolate(), args[1].As<String>());
}
std::optional<std::string_view> base_url_opt =
base_url ? std::optional(base_url->ToStringView()) : std::nullopt;
args.GetReturnValue().Set(url_pattern->Test(env, input, base_url_opt));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we should probably add = delete
for the copy/move operators/constructors to MaybeStackValue
to prevent people from running into this.
Using input_base.emplace()
instead of input_base = Utf8Value(...)
should work just fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using emplace still throws a free invalid pointer abort:
frame #9: 0x00005555563c92a4 node`node::url_pattern::URLPattern::Test(v8::FunctionCallbackInfo<v8::Value> const&) + 772
node`node::url_pattern::URLPattern::Test:
-> 0x5555563c92a4 <+772>: movzbl -0x888(%rbp), %eax
0x5555563c92ab <+779>: subl $0x1, %eax
0x5555563c92ae <+782>: cmpb $-0x3, %al
0x5555563c92b0 <+784>: ja 0x5555563c92ba ; <+794>
bool Test( | ||
Environment* env, | ||
const ada::url_pattern_input& input, | ||
std::optional<std::string_view>& baseURL); // NOLINT (runtime/references) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to prefer NOLINT over the recommendation here?
(Although I feel like in this case this maybe should be a const reference anyway?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I make it a const parameter, then it doesn't compile due to this line:
if (auto result = url_pattern_.exec(input, baseURL ? &*baseURL : nullptr)) {
exec() method in ada expects std::string_view* base_url
where ada::url has a similar API surface as well, and making it const would differentiate the signature between url_pattern and url in Ada.
I'm not sure what is the best way, other than adding NOLINT and keeping this non-const.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I make it a const parameter, then it doesn't compile due to this line:
So ... what if that line becomes
std::string_view tmp;
if (auto result = url_pattern_.exec(input, baseURL ? &(tmp = *baseURL) : nullptr)) {
? Might look a bit odd but it's perfectly fine and it is imho a bit clearer anyway about why we're passing a std::string_view*
here (notably, the fact that url_pattern_.exec()
does not perform relevant modifications on the underlying characters, which the presence of a non-const pointer could indicate)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blech... but yeah, that's better even if it looks ugly ;-)
72cb00f
to
2609e54
Compare
PR has to be semver-major since it adds a new global |
2609e54
to
333b7b3
Compare
Removing semver-major. I've removed the global assignment to make this backportable to older release lines. I'll open another PR with semver-major label once this lands. |
333b7b3
to
e81311a
Compare
@anonrig At a glance, the Windows issues have to do with predefined macros clashing with variable names... See ada-url/ada#854 which should help. |
72fe0bd
to
b4de80e
Compare
Thanks lemire. I rebased and updated Ada. Re-running tests now... |
Co-authored-by: Daniel Lemire <[email protected]>
b4de80e
to
eb005da
Compare
The
notable-change
Please suggest a text for the release notes if you'd like to include a more detailed summary, then proceed to update the PR description with the text or a link to the notable change suggested text comment. Otherwise, the commit will be placed in the Other Notable Changes section. |
Co-authored-by: Daniel Lemire (@lemire)
Blocked
This is blocked from landing due to the old macOS machines we use in our infrastructure (cc @nodejs/build)
Notes:
TODOs
cc @nodejs/cpp-reviewers
Fixes #40844