Open Bug 460460 Opened 16 years ago Updated 2 years ago

importNode() and adoptNode() fail when node comes from XHR created in a JS component

Categories

(Core :: DOM: Core & HTML, defect, P3)

defect

Tracking

()

People

(Reporter: fabrice.desre, Unassigned)

References

Details

(Keywords: regression)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b1) Gecko/20081007 Firefox/3.1b1
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b2pre) Gecko/20081015

It is not possible anymore to import or adopt nodes from an XML document retrieved using XHR into a doc created by implementation.createDocument().

The error returned is NS_UNEXPECTED_ERROR

Reproducible: Always

Steps to Reproduce:
1. Create a document using doc = CC["@mozilla.org/xml/xml-document;1"].createInstance(CI.nsIDOMDocument).implementation.createDocument("", "root", null);
2. Retrieve an XML doc using XHR
3. try node = doc.importNode(xhr.responseXML.documentElement)
Actual Results:  
Fails with NS_UNEXPECTED_ERROR

Expected Results:  
This should work, and was working before
Summary: importNode() and adoptNode() fail when node comes from XHR → importNode() and adoptNode() fail when node comes from XHR created in a JS component
Status: UNCONFIRMED → NEW
Component: General → DOM
Ever confirmed: true
Product: Firefox → Core
QA Contact: general → general
Note that this also fails in any chrome script in an extension, not only in a JS XPCOM component.
Bug 456271 prevented adopting/importing if (1) the new doc doesn't have
script handling object (which is the case here) and (2) the original document 
isn't a chrome document and (3) it does have a script handling object.

On IRC you mentioned that you create XHR using .createInstance().
That tries to get the |window| to which it is bound to from stack.
Perhaps that is the problem here. Maybe it finds non-chrome window.

What causes XHR to be created?
Does it fail if you create XHR using "new XMLHttpRequest()"?
The best thing you could do is to create document using
document.implementation.createDocument("", "", null);
and XHR using new XMLHttpRequest();

Perhaps you could pass chrome |window| to your JS component
and call |new chromeWindow.XMLHttpRequest()| and |chromeWindow.document.implementation.createDocument("", "", null)| ?
Er... why does the XHR document have a script handling object?  Or alternately, why does the createDocument()-created object not have one?  I would think they would behave identically in this respect...

I should note that this code's use of a contract to create XML documents is going to become unsupported in the very near future, but that's not really important to this bug report.
Blocks: 456271
Keywords: regression
CC["@mozilla.org/xml/xml-document;1"].createInstance(CI.nsIDOMDocument).implementation.createDocument("",
"root", null);
Doesn't set any script handling object because the original created document doesn't have one.
(I don't know why to create 2 documents, first a temporary with .createInstance and then with .createDocument)
I guess the reason the createDocument() doc doesn't have a script handling object in this case is in fact due to the use of the contract id thing, huh?

Getting the window from the stack sounds like a bad-and-frightening thing to me.... :(

Also, does DOMParser have similar issues if created via contract?

This whole script handling object thing needs to go.  It's basically incompatible with sane use in JS components, if it requires everything to have a DOMWindow... :(
(In reply to comment #5)
> Er... why does the XHR document have a script handling object? 
We could perhaps remove the Init thing, which tries to get the script object.
C++ should always call Init explicitly and JS should use new XMLHttpRequest
syntax.
(In reply to comment #7)
> This whole script handling object thing needs to go.  It's basically
> incompatible with sane use in JS components, if it requires everything to have
> a DOMWindow... :(
I know. The problem is in XPConnect.
I should note that for DOMParser we expose a JS-callable init() to be used from JS components, but the hack job of adding init() to XMLHttpRequest didn't copy that over.  I should also note that the JS-callable DOMParser init() doesn't take a script global object.  Should it?  Again, the goal is to be able to use all this stuff in a sane way in a JS component.

As for the XPConnect thing...  What that really means is that XHR and so forth need a JSContext, right?  They don't actually need a script global, as far as I can tell.
In particular, I would think that a JS component has a sane JSContext, but I'm not sure it would outlive the initial execution of the component's script.  :(
Oh, and comment 8 is a non-starter precisely because JS components can't use |new XMLHttpRequest()|.
FWIW this is a regression between firefox 3.0.x and 3.5.  TBH from the comments I can't gleam exactly what is supposed to be the correct behavior.  This is what used to work in older version of mozilla:

var xmlNode = someXHRXMLNode; // recv from a XMLHTTPRequest
var doc = Cc["@mozilla.org/xml/xml-document;1"].createInstance(Ci.nsIDOMDocument);
// more code to create document
// this line blows up with NS_UNEXPECTED_ERROR
someNodeInNewDoc.appendChild(doc.importNode(xmlNode,true));


The solution (as hinted at above) is to make sure both documents are created using the same implementation.  Luckily from any DOM node you can can get back to the implementation.  What worked for me:


var doc = xmlNode.ownerDocument.implementation.createDocument(null,"yourroottag",null);
doc.documentElement.appendChild(doc.importNode(xmlNode,true));
> FWIW this is a regression between firefox 3.0.x and 3.5.

Yes, we know.  See comment 2.
This is an issue if you use document.implementation.createHTMLDocument() to create an HTML document on the fly, then attempt to insert it into an iframe as well.
Er... what does comment 16 have to do with this bug?  You can't insert dynamically created documents into iframes.  Or do you mean that you're inserting nodes from that document?
This code works fine for me in the browser console, so I take it this has since been fixed?

>doc = Cc["@mozilla.org/xml/xml-document;1"].createInstance(Ci.nsIDOMDocument).implementation.createDocument("",
"root", null);
>xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
>xhr.responseType = "document";
>xhr.open("get", "http://google.com/", true);
>xhr.send();
>node = doc.importNode(xhr.response.documentElement);
>doc.childNodes[0].appendChild(node);
Flags: needinfo?(bzbarsky)
The link in comment 10 is dead because we kill things without creating redirects.  The code to throw NS_ERROR_UNEXPECTED if adopting from a doc with a script handling object into one without is still there in nsNodeUtils::CloneAndAdopt.

I think the big difference is that in the meantime we fixed bug 756277, which makes the failure mode described in comment 2 not happen anymore...
Depends on: 756277
Flags: needinfo?(bzbarsky)
Priority: -- → P3
Component: DOM → DOM: Core & HTML
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.