Open Bug 958962 Opened 11 years ago Updated 2 years ago

No way to consistently enable <NOSCRIPT> elements using Cu.blockScriptForGlobal() early (e.g. in "content-document-global-created" observer?)

Categories

(Core :: Layout, defect, P4)

defect

Tracking

()

People

(Reporter: ma1, Unassigned)

References

Details

I'm trying to use the Cu.blockScriptForGlobal() API to block inline scripts on some pages, by calling it at the earliest chance (which I believe is in a "content-document-global-created" observer callback). Unfortunately, this appear to not consistently trigger "scripts disabled" parsing mode, i.e. <NOSCRIPT> elements are kept usually hidden, probably because the change in script allowance status happens too late (even though it couldn't happen earlier, at least using this technique). Is there anything that can be done to let this approach work as expected, i.e. the page parsing/rendering being consistent with the scripting status? In order to reproduce, just run the following code in a browser-environment scratchpad: let TOPIC = "content-document-global-created"; if (window.noscriptObserver) try { Services.obs.removeObserver(window.noscriptObserver, TOPIC); } catch(e) {} Services.obs.addObserver(window.noscriptObserver = { observe: function(subject, topic, data) { Cu.blockScriptForGlobal(subject); } }, TOPIC, false); content.location = 'data:text/html,<body><style>.status:after { content: "disabled" }</style><script>document.write("<style>.status:after { content: \\"ENABLED\\" }</style>")</script><div class="status">JavaScript status: </div><noscript>&lt;noscript&gt; element shown.</noscript></body>';
OS: Windows 7 → All
Hardware: x86_64 → All
Yeah I don't know if this technique will work - the document is probably already at least somewhat parsed at this point. Boris?
Flags: needinfo?(bzbarsky)
I wouldn't think so; we fire that observer notification from OnStartRequest, essentially, before we feed any data into the parser. I'll take a look into what's going on here.
Similar to bug 662907.
See Also: → 662907
This isn't a parsing problem at all. It's a pure styling issue. In particular, we set up the preference stylesheet with a stack like so: #0 PresShell::SetPrefNoScriptRule (this=0x1499e0000) at nsPresShell.cpp:1339 #1 0x000000010668110b in PresShell::SetPreferenceStyleRules (this=0x1499e0000, aForceReflow=false) at nsPresShell.cpp:1253 #2 0x000000010667f65a in PresShell::Init (this=0x1499e0000, aDocument=0x1236d5800, aPresContext=0x1237ce000, aViewManager=0x1132b1f40, aStyleSet=0x121fe8c00, aCompatMode=eCompatibility_NavQuirks) at nsPresShell.cpp:821 #3 0x0000000105c7fd8f in nsDocument::doCreateShell (this=0x1236d5800, aContext=0x1237ce000, aViewManager=0x1132b1f40, aStyleSet=0x121fe8c00, aCompatMode=eCompatibility_NavQuirks) at nsDocument.cpp:3507 #4 0x00000001060c4275 in nsHTMLDocument::CreateShell (this=0x1236d5800, aContext=0x1237ce000, aViewManager=0x1132b1f40, aStyleSet=0x121fe8c00) at nsHTMLDocument.cpp:287 #5 0x0000000106667963 in nsDocumentViewer::InitPresentationStuff (this=0x149817370, aDoInitialReflow=false) at nsDocumentViewer.cpp:653 #6 0x0000000106667725 in nsDocumentViewer::InitInternal (this=0x149817370, aParentWidget=0x0, aState=0x0, aBounds=@0x7fff5fbfbad8, aDoCreation=true, aNeedMakeCX=true, aForceSetNewDocument=true) at nsDocumentViewer.cpp:904 but the "content-document-global-created" is dispatched via a scriptblocker that comes off the stack at the end of InitInternal, so _after_ that's happened. And when blockScriptForGlobal() does its thing, it doesn't tell the presshell to update its styles. So while the document is parsed just fine the <noscript> has display:none styles applied to it. I wonder whether we can just delay creating the preference stylesheet until after we've fired DOMWindowCreated. But of course we could have consumers of that that depend on it being set up.... :(
Flags: needinfo?(bzbarsky)
I mean, as a workaround you could apply a stylesheet to the document that changes the style on <noscript> to be display:initial or something...
Component: HTML: Parser → Layout
(In reply to Boris Zbarsky [:bz] from comment #5) > I mean, as a workaround you could apply a stylesheet to the document that > changes the style on <noscript> to be display:initial or something... Yep,I had figured this out yesterday and released a work-around with a similar approach. Can you see any problematic side effect or performance issue in the following code called synchronously from the observer callback (thus before any DOM node has been added yet)? <SNIPPET> let ss = DOMUtils.getAllStyleSheets(subject.document) // reverse loop because the preference stylesheet is almost always the last one for (let j = ss.length; j-- > 0;) { let s = ss[j]; if(s.href === "about:PreferenceStyleSheet") { let rules = s.cssRules; // skip 1st & 2nd, as they are HTML & SVG namespaces for (let j = 2, len = rules.length; j < len; j++) { let r = rules[j]; if (r.cssText === "noscript { display: none ! important; }") { s.deleteRule(j); break; } } break; } } </SNIPPET> Still, having the preference stylesheet applied after "content-document-global-created" and getting rid of this ugly hack would be nice :)
Hmm. I think that should work, yes.
Priority: -- → P4
(In reply to Giorgio Maone [:mao] from comment #0) > I'm trying to use the Cu.blockScriptForGlobal() API to block inline scripts > on some pages, by calling it at the earliest chance (which I believe is in a > "content-document-global-created" observer callback). Shouldn't docshell.allowJavascript = false before navigation have the same effect?
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.