-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
There is no active script when a user triggers an inline event handler #3295
Comments
I suspect this is also of interest to @bzbarsky. |
Hmm.... https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm calls https://heycam.github.io/webidl/#invoke-a-callback-function which calls https://tc39.github.io/ecma262/#sec-call In this case, that lands in https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist and https://tc39.github.io/ecma262/#sec-prepareforordinarycall and that will set things up with the [[ScriptOrModule]] of the function being called. That comes from https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler which does https://tc39.github.io/ecma262/#sec-functioncreate which calls https://tc39.github.io/ecma262/#sec-functioninitialize which relies on GetActiveScriptOrModule at that point. Which may well not be defined (I got a bit lost while digging)? But then I don't quite follow the assert added in #3163 which claims that jobs are only enqueued while a script is active; we can certainly enqueue jobs inside an event handler function, right? Of course there's the extra fun of what happens with I've sort of lost track of how the ES spec uses "script or module" bits and why it thinks they should always exist, but it seems like fundamentally the issue is that ES thinks the only way you can start a new execution is by "running a script or evaluating a module", while in reality you can also start by calling a (possibly built-in) function directly. This seems like a pretty bad semantic mismatch between the ES spec and the web. :( |
So, I guess the case is that if the page author has ever triggered the getter (e.g. just done
Yeah, it seems like that's broken here too, as a result of this particular case.
So, it's basically only to support I think we have two paths:
I am leaning toward the API base URL idea. This would be observably equivalent to trying to plug the hole by creating some synthetic script for event handler purposes, but would also catch any other potential places we missed, and would be import()-specific.
This is all relatively recent, so I wouldn't say this is a big fundamental problem; we can fix it. I'd be curious from an implementer point of view which solution makes the most sense, between trying to maintain the invariant via synthetic scripts, versus using a fallback. For example, I could imagine that implementers might like the synthetic script approach, because it would help things like stack traces, the |
Ah, if this is only relevant for So normally the url of the script is not used as a base url for things in the web platform. I agree that this is a little silly in various cases but especially for imports. Falling back to the current settings object API base URL makes a lot of sense to me. That will ensure that things are always defined, and in the inline event handler case definitely produce the "right" behavior (use the URL of the page as the base URL).
Gotcha. I agree that makes life simpler. In terms of implementation, I'm not sure what works best. In SpiderMonkey, a non-builtin function always has an associated "script" which has a "filename" (typically a URL, but it's just an opaque string as far as SpiderMonkey is concerned, for the most part). For inline event handlers that we compile from a an attr value string, we set that "filename" to the document URL of the element's owner document at the moment when compilation happens. |
I'm personally a fan of this. In Chrome right now (< this link is outdated) we fallback to the document base URL, which I believe in this case, is equivalent to using the current settings object's API base URL. The more I look around..could someone explain the difference between current settings object and entry settings object? Are we thinking the fix here is to make the import spec not Assert so harshly, and then in 8.1.3.8.2 just check to see if
...or do I have this wrong? |
@domfarolino see the example in https://html.spec.whatwg.org/multipage/webappapis.html#realms-settings-objects-global-objects for an illustration of the difference between entry/incumbent/current/relevant (settings objects are 1:1 with Realms). |
Yeah that's basically it. I think I would change "resolve a module specifier" to take a base URL instead of a script. Then we'd add a steps after step 1 that create baseURL and fetchOptions variables. Also, I found a bug: step 4 just says "settings object" when it should probably say "referencing script's settings object". Or, in this fixed universe, we'd also create a settingsObject variable. Are you, uh, volunteering? :) |
I haven't looked into how exactly what your fallback code looks like, but use of "the document" is a red flag, because there are multiple documents around. Most simply, if you get the event handler string compiled while the node is in one document, then you adopt it into another one, now the current settings is whatever the document was where you compiled but "the document" is probably where you adopted into. Which one does Chrome actually use? I looked into what Gecko does here. In Gecko, if you
so presumably we only allow |
The issue is that Gecko doesn't implement the |
Indeed! I'd like to take a look at this this weekend, I should have more time then.
Ahh, I'm not sure actually. I'll dig into this a bit too but can't guarantee a timely answer to that one. |
Ok @bzbarsky to answer your question, in Chrome right now we use the base URL of the document the handler was first compiled/ran in. For example, if:
...the "document's base URL" we use in subsequent evaluations of |
Hmm, doesn't it say "referencing script's settings object" right now? Also, as you mentioned in the case where there is no referencing script and we'd have to create a |
This doesn't seem quite right. Right now the spec says to "crash" (it tries to get a property of the active script, and the active script is null). After the changes proposed here it will be the base URL of the node document of the attribute's owner element, which can be different from the one that's causing the click. This follows from https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler step 9/10, which establish that the function is created in the node document of the attribute's owner element.
Yeah, this got fixed by #3700.
Yeah, that was what I was thinking.
I think we can just rename "default classic script fetch options" to "default script fetch options". The credentials mode should stay the same for both; changing that default is tracked by #3656. |
@domfarolino interestingly it looks like we'll also need to fix HostResolveImportedModule, not just HostImportModuleDynamically. https://tc39.github.io/proposal-dynamic-import/ calls both of them with the active, and potentially null, script. |
This is in preparation for #3295, which deals with cases when there is no referencing script. In that case, we'll want to derive a URL and pass it through.
Good catch, will update that too. |
I skipped over an important comment of @bzbarsky's, while working on #4181:
This is still correct. In particular the trouble case is something like button.setAttribute("onclick", `
Promise.resolve('import("./example.js").catch(e => print("caught", e))')
.then(eval);
`); plus the user actually clicking on the button. In this case there will be no active script when FunctionCreate is called in step 10 of get the current value of the event handler, which means the same is true when .then() calls EnqueueJob, which breaks the assert. I will update #4181 to remove the assert and guard the related steps. This is in line with our conclusion that it's OK for there to not be an active script in these pathological cases, and instead have import() fall back to using the document's base URL. |
Closes #3295. This also fixes a related inaccurate assert in EnqueueJob, putting in guards for a null active script there as well and adding examples explaining the various scenarios.
Closes #3295. This also fixes a related inaccurate assert in EnqueueJob, putting in guards for a null active script there as well and adding examples explaining the various scenarios.
This is in preparation for whatwg#3295, which deals with cases when there is no referencing script. In that case, we'll want to derive a URL and pass it through.
Closes whatwg#3295. This also fixes a related inaccurate assert in EnqueueJob, putting in guards for a null active script there as well and adding examples explaining the various scenarios.
Closes whatwg#3295. This also fixes a related inaccurate assert in EnqueueJob, putting in guards for a null active script there as well and adding examples explaining the various scenarios.
Consider
<div onclick="import('./foo.js')">
. Per spec this code is evaluated via https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm. There is no active script at this time, causing the import() spec to blow up (fail an assert).This is somewhat similar to what was fixed by #3163. The fix is less obvious though. I guess we'd create a synthetic script representing the page's inline event handlers??
/cc @whatwg/modules
The text was updated successfully, but these errors were encountered: