Add test to verify that link rel=compression-dictionary fetches can be blocked via connect-src#61309
Conversation
1a5b856 to
6c8b19f
Compare
|
|
||
| // Link from HTTP headers are only loaded after page, so don't ever try to | ||
| // run the test before. | ||
| promise_setup(_ => new Promise(resolve => addEventListener("load", resolve))); |
There was a problem hiding this comment.
This could run async after the document itself has loaded (which could hang). Maybe change to:
promise_setup(() => new Promise(resolve => {
if (document.readyState === 'complete') {
resolve();
} else {
addEventListener("load", resolve);
}
}));There was a problem hiding this comment.
As I commented above, the doc says the function of the promise_setup is run synchronously, so the event listener would be registered before the load completes i.e. the document is still being parsed and we always have document.readyState === 'loading' here.
I just checked the testharness code to be sure and it's actually only called synchronously if there were no prior promise_setup or promise_tests promises pending to resolve (which is the case in that test).
I'm happy to change to a more verbose promise, but I'd like to understand why this is necessary, as this is not obvious for me from the doc and code.
There was a problem hiding this comment.
I think all that guarantees (and the documents assert) is that it runs synchronously before the tests start, not relative to the inline code and the document itself. I don't know the .then async microtask scheduling well enough to know if Gemini is wrong in it's code tracing but this is what it claims (pretty adamantly):
Why promise_setup does not run synchronously (Tracing testharness.js)
In testharness.js#L1151-L1161:
if (!tests.promise_tests) {
tests.promise_tests = Promise.resolve();
}
tests.promise_tests = tests.promise_tests
.then(function() {
tests.setup(null, properties);
result = func(); // <-- Your function executes inside this .then() callback
...-
Promise.prototype.then()is always asynchronous (Microtask):
When there is no prior pending promise,tests.promise_testsis initialized toPromise.resolve(). Calling.then(callback)on a fulfilledPromisedoes not invokecallbacksynchronously on the spot. By ECMAScript specification (PerformPromiseThen),.then()queues aPromiseReactionJobonto the microtask queue. Therefore,promise_setup(func)always executesfunc()asynchronously as a microtask after the current synchronous script execution block finishes. -
Why you don't see the hang when loading the page directly in a browser:
When you load the.htmlfile directly in a standalone browser tab, the HTML parser evaluates the inline<script>tag synchronously during document parsing. When the<script>block finishes, the JavaScript engine drains the microtask queue immediately before the parser resumes and beforewindow.onloadfires. In that pristine top-level scenario,func()runs right after the script tag whiledocument.readyState === 'loading'. -
Why it can hang across WPT Test Runners (
testharnessreport.js& automated harnesses):
In automated WPT execution (wptrunner, Chromium'srun_web_tests,testdriver.js, or multi-window/iframe test wrappers), documents do not always execute as standalone top-level pages:- Test Runner & Iframe Injection: Test runners (
testharnessreport.js) often run tests inside wrapper iframes, inject scripts, or delaytests.promise_testsexecution while setting up cross-process automation hooks or parent-frame communication. - Async Setup Hooks: If any runner script or harness utility delays the
tests.promise_testschain across the page load boundary,func()insidepromise_setupwill execute after the document has already finished loading (document.readyState === 'complete').
- Test Runner & Iframe Injection: Test runners (
-
The
loadEvent Race Condition:
Becausewindow.onloadonly dispatches once per document lifecycle and does not replay for late listeners,addEventListener("load", resolve)inside any promise callback creates a race condition against the harness. Ifdocument.readyState === 'complete'whenfunc()runs,resolveis never called,tests.promise_testsstays pending forever, and all subsequentpromise_tests hang until the harness times out.
I don't know if the non-blocking microtask is something we generally need to protect against in WPT's. If not, I'm happy to stamp it but it feels like an easy safety net to put in place just in case.
There was a problem hiding this comment.
@pmeenan Thanks. OK, I was wrongly assuming Promise.prototype.then() was called immediately for a fulfilled promise but Gemini seems right here. At least it's document on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#return_value ; will apply the suggestion then.
6c8b19f to
b1603e9
Compare
…e blocked via connect-src
b1603e9 to
493a454
Compare
No description provided.