document.open while a stylesheet is pending can indefinitely block onload
Categories
(Web Compatibility :: Site Reports, defect, P1)
Tracking
(firefox136 fixed)
| Tracking | Status | |
|---|---|---|
| firefox136 | --- | fixed |
People
(Reporter: twisniewski, Assigned: vhilla)
References
(Depends on 1 open bug, )
Details
(Keywords: webcompat:needs-contact, webcompat:platform-bug)
User Story
platform:windows,mac,linux,android impact:content-missing configuration:general affects:all
Attachments
(2 files, 1 obsolete file)
There is a bunch of content "missing" on https://global.gmarket.co.kr/item?goodscode=2651997834 in Firefox, because the iframe which contains said content never fires its load event, and the page never sizes the frame to fit that content.
This is done using some React JS:
return Ot(
'iframe',
{
title: 'Description',
src: 'about:blank',
scrolling: 'no',
frameBorder: '0',
ref: function (t) {
if (t) {
var n = t.contentDocument;
n.open(),
n.write(
'<title>Description</title>',
'<style>iframe,img,embed,object,video{max-width:100%;}</style>',
'<link rel="stylesheet" href="//script.gmarket.com/ebayeditor/css/ee-contents.css"></link>',
e.html
),
n.close()
}
},
width: '860',
height: n,
onLoad: function (e) {
var t = e.currentTarget.contentDocument.body.scrollHeight;
a(t)
}
}
Just after the newly-created iframe element is attached to the document, the ref handler runs, re-writes the iframe with its intended content, and then the code waits for the onLoad handler to fire. In Chrome it fires as expected sometime after the document is closed, once readyState is completed. In Firefox it never fires.
An error event is also never fired, and if I alter the source code of the iframe to include a script logging its readyState (<script>setInterval(() => { console.log(document.readyState) }, 200)</script>) it never completes, it remains interactive.
This is of course causing its content to remain hidden, so it's a webcompat issue affecting live sites, as reported on webcompat.com.
| Reporter | ||
Updated•3 years ago
|
Comment 1•3 years ago
|
||
Bug 220055 seems to have a similar issue.
Olli, Is this something that we should fix?
Given this is a web-compat issue, I am labelling this as S2 for now.
Comment 3•3 years ago
|
||
It's been a forever behavior on our end and we don't recall we've seen many reports regarding this. Moving severity to S3 for now.
Updated•3 years ago
|
Comment 4•2 years ago
|
||
Since this seems like a near-dupe of 220055 I'm going to move this bug to be a site report, and create a kb entry for the general issue.
Updated•2 years ago
|
Updated•2 years ago
|
| Assignee | ||
Comment 5•1 year ago
|
||
(In reply to Thomas Wisniewski [:twisniewski] from comment #0)
Just after the newly-created iframe element is attached to the document, the
refhandler runs, re-writes the iframe with its intended content, and then the code waits for theonLoadhandler to fire. In Chrome it fires as expected sometime after the document is closed, once readyState is completed. In Firefox it never fires.
I created a standalone testcase based off of this description. From what I see, Firefox does fire a load event after open/write/close. Maybe this is an about:blank or timing issue?
Firefox 135.0a1 behavior
When clicking test, the console shows
start writing
finished writing
onload file:...testcase.html
Chrome 133.0.6901.0 behavior
When clicking test, the console shows
onload about:blank
start writing
onload file:...testcase.html
finished writing
| Assignee | ||
Comment 6•1 year ago
|
||
The problem with the webpage appears to be with the link element being written to the iframe.
If the ref method is changed such that the written html doesn't contain a stylesheet link, the page works. On the contrary, the page breaks if the written html contains a stylesheet link with non-empty href. The page breaks with other stylesheets, even invalid ones like href=//example.
I cannot reproduce this in a new React 16.14.0 (currently used by Gmarket) project.
| Assignee | ||
Updated•1 year ago
|
| Assignee | ||
Comment 7•1 year ago
|
||
I found the issue, the problem occurs when one synchronously open/write link/closes twice.
| Assignee | ||
Comment 8•1 year ago
|
||
What's going on here is that one script loader instance is blocking onload twice, but only unblocks once.
The sequence of events is as follows:
- We start a document load via
document.open - This leads to
ScriptLoader::BeginDeferringScripts, which callsDocument::BlockOnloadincreasing themOnloadBlockCount. document.writehappens and we start processing the stylesheet- This leads to a race condition. If the sheet completes,
nsContentSink::StyleSheetLoadedleads toScriptLoader::DeferCheckpointReached. If the seconddocument.openhappens synchronously, this race is not triggered. But if one attaches the debugger, or adds a timeout, it sometimes is.
- This leads to a race condition. If the sheet completes,
- The second
document.openoccurs and callsScriptLoader::BeginDeferringScriptsfor the sameScriptLoaderobject. It's already blocking load, but if the defer checkpoint wasn't reached, it will callDocument::BlockOnloadagain (see code).- Bug 1568171 is similar to this one and made sure that if the defer checkpoint is reached, we don't block twice.
- Another link is created, the stylesheet processed, defer checkpoint reached. This triggers
ScriptLoader::ProcessPendingRequests, which will unblock load once.- This can happen only once. We only unblock when
mDeferCheckpointReachedis toggled false. We only setmDeferCheckpointReachedwhenmDeferEnabledis toggled false. We only setmDeferEnabledduringBeginDeferringScripts.
- This can happen only once. We only unblock when
| Assignee | ||
Comment 9•1 year ago
|
||
If a document is still processing a stylesheet while document.open occurs,
the defer checkpoint might not have been reached. This causes the
ScriptLoader to block load twice, although it will only unblock once.
Related: Bug 1568171
Updated•1 year ago
|
Comment 10•1 year ago
|
||
| Assignee | ||
Updated•1 year ago
|
Comment 11•1 year ago
|
||
| bugherder | ||
Description
•