polyfills icon indicating copy to clipboard operation
polyfills copied to clipboard

document.domain and <node>.innerHTML on IE11

Open kurtinatlanta opened this issue 6 years ago • 13 comments

Description

When using the polyfills in IE11, if document.domain is set, .innerHTML throws a SCRIPT5022: WrongDocumentError at line 84 of template/template.js.

I'm not finding any information in my various searches that shed any light on why this is happening or how to eliminate it.

Setting document.domain AFTER loading the polyfill does not change the results.

Using .textContent and .appendChild(document.createTextNode('New node') both work, but we are using a 3rd party web component that sets innerHTML that we may not be able to change.

This appears to be a bug in the polyfill more than an issue with the component.

Steps to Reproduce

Using this HTML:

<!DOCTYPE html>
<head>
  <title>Web component test</title>
  <script>
    document.domain = '<somedomain>.com';
  </script>
  <script src="https://unpkg.com/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
</head>
<body>
  Web components test.
  <div id="wc1">Initial content.</div>
  <button onclick="document.getElementById('wc1').innerHTML = 'Updated content ' + Date.now();">Update</button>
  <button onclick="addNode('div');">Add node</button>
  <script>
    function addNode(nodeName) {
      var node = document.createElement(nodeName);
      node.innerHTML = 'New node';
      document.body.appendChild(node);
    }
  </script>
</body>
  1. Create an HTML file on your local web server using the above HTML.
  2. Set document.domain to your domain.
  3. Load the file from your web server into IE11.
  4. Open the developer tools (press F12).
  5. Click the 'Add node' button.

Expected Results

A new node at the end of the document with the text 'New node'

Actual Results

In the Javascript console: SCRIPT5022: WrongDocumentError template.js (84,11)

Browsers Affected

  • [ ] Chrome
  • [ ] Firefox
  • [ ] Edge
  • [ ] Safari
  • [x] IE 11

kurtinatlanta avatar Jul 30 '19 03:07 kurtinatlanta

What versions of Windows and IE 11 are you running? I tried publishing the above test case to a publicly accessible server, and with IE 11 (11.239.18362.0) and Windows 10 Pro (1093), it worked as expected (i.e., no error was thrown).

jason0x43 avatar Jul 30 '19 12:07 jason0x43

Interesting. It doesn't work on any version of IE11 for us. My particular setup is Windows 10 Enterprise (1803), OS build 17134.885, using IE11 11.0.135 (11.885.17134.0).

I have the page up here if anyone wants to try it: https://static.adp.com/mas/mdf-sample/21.0.4/webComponentTest.html

kurtinatlanta avatar Jul 30 '19 13:07 kurtinatlanta

I just tried the URL in my last message on Windows 10 Pro (1903), OS build 18362.267 with IE11 11.0.135 (11.239.13262.0) and it fails as I expect.

It only fails if document.domain is set.

kurtinatlanta avatar Jul 30 '19 13:07 kurtinatlanta

Ah, the issue at https://static.adp.com/mas/mdf-sample/21.0.4/webComponentTest.html is likely that the document.domain value is set to the parent domain rather than the domain of the page itself. Try setting it to static.adp.com.

jason0x43 avatar Jul 30 '19 13:07 jason0x43

(Or don't set it, in which case the default will be static.adp.com)

jason0x43 avatar Jul 30 '19 14:07 jason0x43

I disagree - it's quite normal in integration environments, where we may use iframe from different hosts, to set document.domain to the same value (a more general domain) so that the apps can interact.

kurtinatlanta avatar Jul 30 '19 15:07 kurtinatlanta

Sorry, I didn't mean to say it was incorrect, just that the problem is that document.domain is being set to something that isn't exactly the document domain, and that's what's causing the breakage.

jason0x43 avatar Jul 30 '19 16:07 jason0x43

And my assertion is that its use should not cause breakage. Which is borne out by the behavior of every other browser, including Edge.

If, in the end, we can't use web components in IE11 because we also use document.domain, then let's get that documented at webcomponents.org on the polyfills page so that others don't struggle with the same issue.

kurtinatlanta avatar Jul 30 '19 17:07 kurtinatlanta

First, many thanks to anyone who may be looking at this. Here is more data from moving up the stack:

The exception is thrown in the replacement for Node.prototype.appendChild found at line 84 of packages/template/template.js:

origAppendChild.call(this, child);

The code is now calling the original Node.appendChild to append to the actual DOM.

This was called from the insertBefore function line 350 of packages/shadydom/src/patches/Node.js:

container[utils.NATIVE_PREFIX + 'appendChild'](node);

Next up is the innerHTML setter at line 54 of packages/shadydom/src/patches/ElementOrShadowRoot.js:

this[utils.SHADY_PREFIX + 'insertBefore'](firstChild);

This is called from another innerHTML setter at line 63 of packages/custom-elements/src/Patch/Element.js:

baseDescriptor.set.call(this, htmlString);

And that code is triggered by setting innerHTML in my web page at line 20:

node.innerHTML = 'New node';

and the node is just a div created with document.createElement().

It feels like (and I can't say for sure) that the code is mixing 'shady' DOM and 'real' DOM in a way that confuses IE at this point, but I don't have an environment (yet) where I can tweak the polyfills and see what happens.

I'm hoping those with more experience with the polyfills can point the way.

kurtinatlanta avatar Jul 30 '19 17:07 kurtinatlanta

The next level down in my investigation points to the inertDoc created in packages/shadydom/src/patches/ElementOrShadowRoot.js.

I'm guessing that document.implementation.createHTMLDocument('inert') creates a document object that does not have the same domain as the original document object, so that when the code creates a new htmlContainer at line 45:

htmlContainer = inertDoc.createElementNS(this.namespaceURI, containerName);

that new div has the full host name (static.adp.com) as the document.domain instead of the the assigned document.domain (adp.com) set in the original document.

Does this seem like I'm on the right track?

kurtinatlanta avatar Jul 30 '19 18:07 kurtinatlanta

My suspicion was correct. If I add this to ElementOrShadowRoot.js right after inertDoc is created:

if (inertDoc.domain !== document.domain) {
  inertDoc.domain = document.domain;
}

and then setting innerHTML in IE11 works for us.

I will look at how to create a pull request for this change.

kurtinatlanta avatar Jul 30 '19 19:07 kurtinatlanta

We also facing same issue while integrating custom elements on one of our page. Usage of document.domain='someValue'; just bombs in template.js.

Any plan to get the raised MR merged? or fix this issue?

piyushsh avatar Oct 29 '20 12:10 piyushsh

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Oct 30 '21 10:10 stale[bot]