Commit f5d501ed authored by Sean Feng's avatar Sean Feng Committed by Matthew Finkel
Browse files

Bug 1590526 - Temporarily allow node adoption across different docGroups for...

Bug 1590526 - Temporarily allow node adoption across different docGroups for the content/content case r=smaug,zombie a=pascalc

As web extensions rely on this node adoption between content to content
documents, we want to continue allowing this capability to work for now.

Differential Revision: https://phabricator.services.mozilla.com/D50348

--HG--
extra : source : 78c33df33145bd63cd303264734d0b7d85151908
extra : histedit_source : 280627c1dba1ad7b8d82f5a315b5c2170bf3167b
parent 21ca8ccc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -272,3 +272,5 @@ skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mod
skip-if = (verify && (os == 'mac'))
tags = fullscreen
[browser_ext_contentscript_animate.js]
[browser_ext_contentscript_cross_docGroup_adoption.js]
[browser_ext_contentscript_cross_docGroup_adoption_xhr.js]
+58 −0
Original line number Diff line number Diff line
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

add_task(async function test_cross_docGroup_adoption() {
  let tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "http://example.com/"
  );

  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      content_scripts: [
        {
          matches: ["http://example.com/"],
          js: ["content-script.js"],
        },
      ],
    },

    files: {
      "current.html": "<html>data</html>",
      "content-script.js": function() {
        let iframe = document.createElement("iframe");
        iframe.src = browser.extension.getURL("current.html");
        document.body.appendChild(iframe);

        iframe.addEventListener(
          "load",
          () => {
            let parser = new DOMParser();
            let bold = parser.parseFromString(
              "<b>NodeAdopted</b>",
              "text/html"
            );
            let doc = iframe.contentDocument;

            let node = document.adoptNode(bold.documentElement);
            doc.replaceChild(node, doc.documentElement);

            const expected =
              "<html><head></head><body><b>NodeAdopted</b></body></html>";
            browser.test.assertEq(expected, doc.documentElement.outerHTML);

            browser.test.notifyPass("nodeAdopted");
          },
          { once: true }
        );
      },
    },
  });

  await extension.startup();
  await extension.awaitFinish("nodeAdopted");
  await extension.unload();

  BrowserTestUtils.removeTab(tab);
});
+51 −0
Original line number Diff line number Diff line
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

add_task(async function test_cross_docGroup_adoption() {
  let tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "http://example.com/"
  );

  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      content_scripts: [
        {
          matches: ["http://example.com/"],
          js: ["content-script.js"],
        },
      ],
    },

    files: {
      "blank.html": "<html>data</html>",
      "content-script.js": function() {
        let xhr = new XMLHttpRequest();
        xhr.responseType = "document";
        xhr.open("GET", browser.extension.getURL("blank.html"));

        xhr.onload = function() {
          let doc = xhr.response;
          try {
            let node = doc.body.cloneNode(true);
            document.body.appendChild(node);
            browser.test.notifyPass("nodeAdopted");
          } catch (SecurityError) {
            browser.test.assertTrue(
              false,
              "The above node adoption should not fail"
            );
          }
        };
        xhr.send();
      },
    },
  });

  await extension.startup();
  await extension.awaitFinish("nodeAdopted");
  await extension.unload();

  BrowserTestUtils.removeTab(tab);
});
+15 −7
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include "mozilla/dom/Document.h"
#include "js/TypeDecls.h"
#include "nsCOMArray.h"
#include "nsContentUtils.h"

struct CharacterDataChangeInfo;
template <class E>
@@ -206,15 +207,22 @@ class nsNodeUtils {
                    nsCOMArray<nsINode>& aNodesWithProperties,
                    mozilla::ErrorResult& aError) {
    if (aNode && aNewNodeInfoManager) {
      mozilla::dom::Document* newDoc = aNewNodeInfoManager->GetDocument();
      mozilla::dom::Document* oldDoc = aNode->OwnerDoc();
      if (newDoc && oldDoc &&
          (oldDoc->GetDocGroup() != newDoc->GetDocGroup())) {
        MOZ_ASSERT(false, "Cross docGroup adoption is not allowed");
      mozilla::dom::Document* afterAdoptDoc =
          aNewNodeInfoManager->GetDocument();
      mozilla::dom::Document* beforeAdoptDoc = aNode->OwnerDoc();

      if (afterAdoptDoc && beforeAdoptDoc &&
          (afterAdoptDoc->GetDocGroup() != beforeAdoptDoc->GetDocGroup())) {
        // This is a temporary solution for Bug 1590526 to only limit
        // the restriction to chrome level documents because web extensions
        // rely on content to content node adoption.
        if (nsContentUtils::IsChromeDoc(afterAdoptDoc) ||
            nsContentUtils::IsChromeDoc(beforeAdoptDoc)) {
          aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
          return;
        }
      }
    }

    // Just need to store the return value of CloneAndAdopt in a
    // temporary nsCOMPtr to make sure we release it.
+1 −0
Original line number Diff line number Diff line
@@ -5,3 +5,4 @@ skip-if = os == 'android'
[test_offsets.xul]
support-files = test_offsets.css test_offsets.js
[test_spacetopagedown.html]
[test_nodeAdoption_chrome_boundary.xul]
Loading