If you think a bug might affect users in the 57 release, please set the correct tracking and status flags for Release Management.

Calling document.write in srcdoc when onload is called (which does document.open) will throw

NEW
Unassigned

Status

()

Core
DOM: Core & HTML
P2
normal
4 months ago
2 months ago

People

(Reporter: allstars, Unassigned)

Tracking

Trunk
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment, 1 obsolete attachment)

(Reporter)

Description

4 months ago
Created attachment 8871653 [details]
test_srcdoc.html

The test is 
<iframe srcdoc="<script>window.onload=function(){document.write('hello');};</script>"></iframe>

See attachment for the test HTML
Open this HTML with Firefox, only the 1st iframe has 'hello', the 2nd iframe is empty.
See below for the stack.

However Chrome could show 'hello' in both iframes, as asked by smaug in https://bugzilla.mozilla.org/show_bug.cgi?id=1365857#c14, I filed this as a seperate bug.


document.write will return NS_ERR_MALFORMED_URI, the stack is 
GECKO(26064) | #01: mozilla::net::nsAboutProtocolHandler::NewChannel2(nsIURI*, nsILoadInfo*, nsIChannel**) (/home/allstars/src/gecko-dev/netwerk/protocol/about/nsAboutProtocolHandler.cpp:187)
GECKO(26064) | #02: mozilla::net::nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI*, nsIURI*, unsigned int, nsILoadInfo*, nsIChannel**) (/home/allstars/src/gecko-dev/netwerk/base/nsIOService.cpp:829)
GECKO(26064) | #03: mozilla::net::nsIOService::NewChannelFromURIWithProxyFlags2(nsIURI*, nsIURI*, unsigned int, nsIDOMNode*, nsIPrincipal*, nsIPrincipal*, unsigned int, unsigned int, nsIChannel**) (/home/allstars/src/gecko-dev/netwerk/base/nsIOService.cpp:932)
GECKO(26064) | #04: mozilla::net::nsIOService::NewChannelFromURI2(nsIURI*, nsIDOMNode*, nsIPrincipal*, nsIPrincipal*, unsigned int, unsigned int, nsIChannel**) (/home/allstars/src/gecko-dev/netwerk/base/nsIOService.cpp:727)
GECKO(26064) | #05: NS_NewChannelInternal(nsIChannel**, nsIURI*, nsINode*, nsIPrincipal*, nsIPrincipal*, unsigned int, unsigned int, nsILoadGroup*, nsIInterfaceRequestor*, unsigned int, nsIIOService*) (/home/allstars/src/gecko-dev/netwerk/base/nsNetUtil.cpp:255 (discriminator 4))
GECKO(26064) | #06: NS_NewChannel(nsIChannel**, nsIURI*, nsINode*, unsigned int, unsigned int, nsILoadGroup*, nsIInterfaceRequestor*, unsigned int, nsIIOService*) (/home/allstars/src/gecko-dev/netwerk/base/nsNetUtil.cpp:358)
GECKO(26064) | #07: nsHTMLDocument::Open(JSContext*, nsAString const&, nsAString const&, mozilla::ErrorResult&) (/home/allstars/src/gecko-dev/dom/html/nsHTMLDocument.cpp:1617)
GECKO(26064) | #08: nsHTMLDocument::Open(nsAString const&, nsAString const&, nsAString const&, JSContext*, unsigned char, nsISupports**) (/home/allstars/src/gecko-dev/dom/html/nsHTMLDocument.cpp:1436)
GECKO(26064) | #09: nsHTMLDocument::WriteCommon(JSContext*, nsAString const&, bool) (/home/allstars/src/gecko-dev/dom/html/nsHTMLDocument.cpp:1952)
GECKO(26064) | #10: nsHTMLDocument::WriteCommon(JSContext*, mozilla::dom::Sequence<nsString> const&, bool, mozilla::ErrorResult&) (/home/allstars/src/gecko-dev/dom/html/nsHTMLDocument.cpp:1879)
GECKO(26064) | #11: nsHTMLDocument::Write(JSContext*, mozilla::dom::Sequence<nsString> const&, mozilla::ErrorResult&) (/home/allstars/src/gecko-dev/dom/html/nsHTMLDocument.cpp:2011)
GECKO(26064) | #12: mozilla::dom::HTMLDocumentBinding::write(JSContext*, JS::Handle<JSObject*>, nsHTMLDocument*, JSJitMethodCallArgs const&) (/home/allstars/src/gecko-dev/obj-x86_64-pc-linux-gnu/dom/bindings/HTMLDocumentBinding.cpp:655)
GECKO(26064) | #13: mozilla::dom::GenericBindingMethod(JSContext*, unsigned int, JS::Value*) (/home/allstars/src/gecko-dev/dom/bindings/BindingUtils.cpp:2954)
GECKO(26064) | #14: js::CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) (/home/allstars/src/gecko-dev/js/src/jscntxtinlines.h:293)
GECKO(26064) | #15: js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:470)
GECKO(26064) | #16: InternalCall(JSContext*, js::AnyInvokeArgs const&) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:516)
GECKO(26064) | #17: js::CallFromStack(JSContext*, JS::CallArgs const&) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:522)
GECKO(26064) | #18: Interpret(JSContext*, js::RunState&) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:3028)
GECKO(26064) | #19: js::RunScript(JSContext*, js::RunState&) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:410)
GECKO(26064) | #20: js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:488)
GECKO(26064) | #21: InternalCall(JSContext*, js::AnyInvokeArgs const&) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:516)
GECKO(26064) | #22: js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) (/home/allstars/src/gecko-dev/js/src/vm/Interpreter.cpp:534)
GECKO(26064) | #23: JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) (/home/allstars/src/gecko-dev/js/src/jsapi.cpp:2891)
GECKO(26064) | #24: mozilla::dom::EventHandlerNonNull::Call(JSContext*, JS::Handle<JS::Value>, mozilla::dom::Event&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&) (/home/allstars/src/gecko-dev/obj-x86_64-pc-linux-gnu/dom/bindings/EventHandlerBinding.cpp:260 (discriminator 1))
GECKO(26064) | #25: void mozilla::dom::EventHandlerNonNull::Call<nsISupports*>(nsISupports* const&, mozilla::dom::Event&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&, char const*, mozilla::dom::CallbackObject::ExceptionHandling, JSCompartment*) (/home/allstars/src/gecko-dev/obj-x86_64-pc-linux-gnu/dist/include/mozilla/dom/EventHandlerBinding.h:357)
GECKO(26064) | #26: mozilla::JSEventHandler::HandleEvent(nsIDOMEvent*) (/home/allstars/src/gecko-dev/dom/events/JSEventHandler.cpp:215)
GECKO(26064) | #27: mozilla::EventListenerManager::HandleEventSubType(mozilla::EventListenerManager::Listener*, nsIDOMEvent*, mozilla::dom::EventTarget*) (/home/allstars/src/gecko-dev/dom/events/EventListenerManager.cpp:1146)
GECKO(26064) | #28: mozilla::EventListenerManager::HandleEventInternal(nsPresContext*, mozilla::WidgetEvent*, nsIDOMEvent**, mozilla::dom::EventTarget*, nsEventStatus*) (/home/allstars/src/gecko-dev/dom/events/EventListenerManager.cpp:1320)
GECKO(26064) | #29: mozilla::EventListenerManager::HandleEvent(nsPresContext*, mozilla::WidgetEvent*, nsIDOMEvent**, mozilla::dom::EventTarget*, nsEventStatus*) (/home/allstars/src/gecko-dev/obj-x86_64-pc-linux-gnu/dist/include/mozilla/EventListenerManager.h:377)
GECKO(26064) | #30: mozilla::EventTargetChainItem::HandleEvent(mozilla::EventChainPostVisitor&, mozilla::ELMCreationDetector&) (/home/allstars/src/gecko-dev/dom/events/EventDispatcher.cpp:319)
GECKO(26064) | #31: mozilla::EventTargetChainItem::HandleEventTargetChain(nsTArray<mozilla::EventTargetChainItem>&, mozilla::EventChainPostVisitor&, mozilla::EventDispatchingCallback*, mozilla::ELMCreationDetector&) (/home/allstars/src/gecko-dev/dom/events/EventDispatcher.cpp:466)
GECKO(26064) | #32: mozilla::EventDispatcher::Dispatch(nsISupports*, nsPresContext*, mozilla::WidgetEvent*, nsIDOMEvent*, nsEventStatus*, mozilla::EventDispatchingCallback*, nsTArray<mozilla::dom::EventTarget*>*) (/home/allstars/src/gecko-dev/dom/events/EventDispatcher.cpp:828)
GECKO(26064) | #33: nsDocumentViewer::LoadComplete(nsresult) (/home/allstars/src/gecko-dev/layout/base/nsDocumentViewer.cpp:1073)
GECKO(26064) | #34: nsDocShell::EndPageLoad(nsIWebProgress*, nsIChannel*, nsresult) (/home/allstars/src/gecko-dev/docshell/base/nsDocShell.cpp:7680)
GECKO(26064) | #35: nsDocShell::OnStateChange(nsIWebProgress*, nsIRequest*, unsigned int, nsresult) (/home/allstars/src/gecko-dev/docshell/base/nsDocShell.cpp:7472)
GECKO(26064) | #36: nsDocLoader::DoFireOnStateChange(nsIWebProgress*, nsIRequest*, int&, nsresult) (/home/allstars/src/gecko-dev/uriloader/base/nsDocLoader.cpp:1276 (discriminator 6))
GECKO(26064) | #37: nsDocLoader::doStopDocumentLoad(nsIRequest*, nsresult) (/home/allstars/src/gecko-dev/uriloader/base/nsDocLoader.cpp:859 (discriminator 2))
GECKO(26064) | #38: nsDocLoader::DocLoaderIsEmpty(bool) (/home/allstars/src/gecko-dev/uriloader/base/nsDocLoader.cpp:751)
GECKO(26064) | #39: nsDocLoader::OnStopRequest(nsIRequest*, nsISupports*, nsresult) (/home/allstars/src/gecko-dev/uriloader/base/nsDocLoader.cpp:624)
GECKO(26064) | #40: mozilla::net::nsLoadGroup::RemoveRequest(nsIRequest*, nsISupports*, nsresult) (/home/allstars/src/gecko-dev/netwerk/base/nsLoadGroup.cpp:629)
GECKO(26064) | #41: nsDocument::DoUnblockOnload() (/home/allstars/src/gecko-dev/dom/base/nsDocument.cpp:8957 (discriminator 2))
GECKO(26064) | #42: nsDocument::UnblockOnload(bool) (/home/allstars/src/gecko-dev/dom/base/nsDocument.cpp:8885)
GECKO(26064) | #43: nsDocument::DispatchContentLoadedEvents() (/home/allstars/src/gecko-dev/dom/base/nsDocument.cpp:5307)

So far I noticed the difference is, in pframe2 nsHTMLDocument::Open will be called,
and this is because the mParser is null in nsHTMLDocument.cpp.
http://searchfox.org/mozilla-central/source/dom/html/nsHTMLDocument.cpp#1928
Right, the key part is doing document.open from a srcdoc document.

And the reason this fails is that document.open tries to give the new thing the URI of the "responsible document", which we do via creating a channel for it, etc.  But "about:srcdoc" is a special URI that can't have a channel created for it, hence the stack above.

What does Chrome do if an about:srcdoc document does a document.open() on some other document?  Does that other document get "about:srcdoc" as a URI?  Does it then consider it to be an "iframe srcdoc document" or no?
Flags: needinfo?(allstars.chh)
Summary: Calling document.write in srcdoc when onload is called will throw → Calling document.write in srcdoc when onload is called (which does document.open) will throw
(Reporter)

Comment 2

4 months ago
(In reply to Boris Zbarsky [:bz] (if a patch has no decent message, automatic r-) from comment #1)
> Right, the key part is doing document.open from a srcdoc document.
> 
> And the reason this fails is that document.open tries to give the new thing
> the URI of the "responsible document", which we do via creating a channel
> for it, etc.  But "about:srcdoc" is a special URI that can't have a channel
> created for it, hence the stack above.
>
Yeah, per spec https://html.spec.whatwg.org/multipage/infrastructure.html#urls about:srcdoc is unresolvable.
However the problem happens only in onload, if not calling document.open in onload handler it looks fine. That's also one of the reason I filed this bug.

> What does Chrome do if an about:srcdoc document does a document.open() on
> some other document?  Does that other document get "about:srcdoc" as a URI?

upload the test to https://allstarschh.github.io/test_srcdoc.html
See pframe4, 
Firefox, pframe 4: https://allstarschh.github.io/test.html
Chrome, pframe 4: about:srcdoc
 
> Does it then consider it to be an "iframe srcdoc document" or no?

I don't understand your question clearly, in Chrome the uri of pframe4 is about:srcdoc, it's considered as an 'iframe srcdoc doc', right? 

Thanks
Flags: needinfo?(allstars.chh)
(Reporter)

Comment 3

4 months ago
Created attachment 8872946 [details]
test_srcdoc.html
Attachment #8871653 - Attachment is obsolete: true
> However the problem happens only in onload

I would expect it happens any time you call open() or write() on a document that is not in the middle of being parsed.

> upload the test to https://allstarschh.github.io/test_srcdoc.html

That test doesn't quite test the situation I was asking about.  The situation I was asking about is an about:srcdoc document executing script that does an open() on another document which is not being parsed.

In the test, pframe4 is the thing that is trying to test that, but it's racy: it runs at some random time, likely before pframe3 is done loading.  It might be simpler to have a manual test where the user waits for the page to load, then clicks something in pframe4 that triggers the script.

That said, it does look like Chrome is treating that open() call as something that does the no-op steps in the spec.

> in Chrome the uri of pframe4 is about:srcdoc

Yes.

> it's considered as an 'iframe srcdoc doc', right? 

That's not obvious.  You'd need to test one of the spec requirements that are special for "iframe srcdoc documents" in the spec to tell whether it is or not.  (Per spec as written it shouldn't be, but that also means that per spec you can have about:srcdoc documents that are not "iframe scrdoc documents", and it's not clear to me that this was a desired behavior in the spec.)
Flags: needinfo?(annevk)

Comment 5

3 months ago
I don't have a good idea for how to handle this at the moment.
Flags: needinfo?(annevk)
Priority: -- → P2
You need to log in before you can comment on or make changes to this bug.