Merge mozilla-central to autoland. a=merge
authorDaniel Varga <dvarga@mozilla.com>
Thu, 25 Oct 2018 19:18:54 +0300
changeset 491350 f8e052dc4f52301738cf54b951e0b2564d04f59d
parent 491349 d7641a700ff64f760f0f8483a458f9870418141f (current diff)
parent 491318 37d240a1d498bd1662e0f9d6053ee75ccdb90786 (diff)
child 491351 a6b6d4cec0733fe115dc41377e88f238ca137875
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersmerge
milestone65.0a1
Merge mozilla-central to autoland. a=merge
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -433,17 +433,17 @@ private:
   uint32_t mBufferLength;
   uint32_t mStride;
   gfx::SurfaceFormat mFormat;
   gfx::IntSize mSize;
   const Maybe<IntRect>& mCropRect;
 };
 
 static bool
-CheckSecurityForHTMLElements(bool aIsWriteOnly, bool aCORSUsed, nsIPrincipal* aPrincipal)
+CheckSecurityForElements(bool aIsWriteOnly, bool aCORSUsed, nsIPrincipal* aPrincipal)
 {
   if (aIsWriteOnly || !aPrincipal) {
     return false;
   }
 
   if (!aCORSUsed) {
     nsIGlobalObject* incumbentSettingsObject = GetIncumbentGlobal();
     if (NS_WARN_IF(!incumbentSettingsObject)) {
@@ -455,71 +455,46 @@ CheckSecurityForHTMLElements(bool aIsWri
       return false;
     }
   }
 
   return true;
 }
 
 static bool
-CheckSecurityForHTMLElements(const nsLayoutUtils::SurfaceFromElementResult& aRes)
+CheckSecurityForElements(const nsLayoutUtils::SurfaceFromElementResult& aRes)
 {
-  return CheckSecurityForHTMLElements(aRes.mIsWriteOnly, aRes.mCORSUsed, aRes.mPrincipal);
+  return CheckSecurityForElements(aRes.mIsWriteOnly, aRes.mCORSUsed, aRes.mPrincipal);
 }
 
 /*
  * A wrapper to the nsLayoutUtils::SurfaceFromElement() function followed by the
  * security checking.
  */
-template<class HTMLElementType>
+template<class ElementType>
 static already_AddRefed<SourceSurface>
-GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, ErrorResult& aRv)
+GetSurfaceFromElement(nsIGlobalObject* aGlobal, ElementType& aElement, ErrorResult& aRv)
 {
   nsLayoutUtils::SurfaceFromElementResult res =
     nsLayoutUtils::SurfaceFromElement(&aElement, nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE);
 
-  // check origin-clean
-  if (!CheckSecurityForHTMLElements(res)) {
-    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-    return nullptr;
-  }
-
   RefPtr<SourceSurface> surface = res.GetSourceSurface();
-
   if (NS_WARN_IF(!surface)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  return surface.forget();
-}
 
-/*
- * The specification doesn't allow to create an ImegeBitmap from a vector image.
- * This function is used to check if the given HTMLImageElement contains a
- * raster image.
- */
-static bool
-HasRasterImage(HTMLImageElement& aImageEl)
-{
-  nsresult rv;
-
-  nsCOMPtr<imgIRequest> imgRequest;
-  rv = aImageEl.GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
-                           getter_AddRefs(imgRequest));
-  if (NS_SUCCEEDED(rv) && imgRequest) {
-    nsCOMPtr<imgIContainer> imgContainer;
-    rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
-    if (NS_SUCCEEDED(rv) && imgContainer &&
-        imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
-      return true;
-    }
+  // check origin-clean
+  if (!CheckSecurityForElements(res)) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
   }
 
-  return false;
+  return surface.forget();
 }
 
 ImageBitmap::ImageBitmap(nsIGlobalObject* aGlobal, layers::Image* aData,
                          gfxAlphaType aAlphaType)
   : mParent(aGlobal)
   , mData(aData)
   , mSurface(nullptr)
   , mDataWrapper(new ImageUtils(mData))
@@ -855,22 +830,46 @@ ImageBitmap::CreateInternal(nsIGlobalObj
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
   // Check if the image element is completely available or not.
   if (!aImageEl.Complete()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  // Check if the image element is a bitmap (e.g. it's a vector graphic) or not.
-  if (!HasRasterImage(aImageEl)) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  // Get the SourceSurface out from the image element and then do security
+  // checking.
+  RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
+
+  if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
+  // Create ImageBitmap.
+  RefPtr<layers::Image> data = CreateImageFromSurface(surface);
+
+  if (NS_WARN_IF(!data)) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return nullptr;
+  }
+
+  RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data);
+
+  // Set the picture rectangle.
+  if (ret && aCropRect.isSome()) {
+    ret->SetPictureRect(aCropRect.ref(), aRv);
+  }
+
+  return ret.forget();
+}
+
+/* static */ already_AddRefed<ImageBitmap>
+ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
+                            const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
+{
   // Get the SourceSurface out from the image element and then do security
   // checking.
   RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aImageEl, aRv);
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
@@ -909,17 +908,17 @@ ImageBitmap::CreateInternal(nsIGlobalObj
   if (aVideoEl.ReadyState() <= HAVE_METADATA) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Check security.
   nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentVideoPrincipal();
   bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE;
-  if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) {
+  if (!CheckSecurityForElements(false, CORSUsed, principal)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   // Create ImageBitmap.
   RefPtr<layers::Image> data = aVideoEl.GetCurrentImage();
   if (!data) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
@@ -1368,16 +1367,20 @@ ImageBitmap::Create(nsIGlobalObject* aGl
   }
 
   RefPtr<ImageBitmap> imageBitmap;
 
   if (aSrc.IsHTMLImageElement()) {
     MOZ_ASSERT(NS_IsMainThread(),
                "Creating ImageBitmap from HTMLImageElement off the main thread.");
     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLImageElement(), aCropRect, aRv);
+  } else if (aSrc.IsSVGImageElement()) {
+    MOZ_ASSERT(NS_IsMainThread(),
+               "Creating ImageBitmap from SVGImageElement off the main thread.");
+    imageBitmap = CreateInternal(aGlobal, aSrc.GetAsSVGImageElement(), aCropRect, aRv);
   } else if (aSrc.IsHTMLVideoElement()) {
     MOZ_ASSERT(NS_IsMainThread(),
                "Creating ImageBitmap from HTMLVideoElement off the main thread.");
     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLVideoElement(), aCropRect, aRv);
   } else if (aSrc.IsHTMLCanvasElement()) {
     MOZ_ASSERT(NS_IsMainThread(),
                "Creating ImageBitmap from HTMLCanvasElement off the main thread.");
     imageBitmap = CreateInternal(aGlobal, aSrc.GetAsHTMLCanvasElement(), aCropRect, aRv);
--- a/dom/canvas/ImageBitmap.h
+++ b/dom/canvas/ImageBitmap.h
@@ -43,22 +43,22 @@ class ArrayBufferViewOrArrayBuffer;
 class CanvasRenderingContext2D;
 class CreateImageBitmapFromBlob;
 class CreateImageBitmapFromBlobTask;
 class CreateImageBitmapFromBlobWorkerTask;
 class File;
 class HTMLCanvasElement;
 class HTMLImageElement;
 class HTMLVideoElement;
-enum class ImageBitmapFormat : uint8_t;
+class ImageBitmapShutdownObserver;
 class ImageData;
 class ImageUtils;
 class Promise;
 class PostMessageEvent; // For StructuredClone between windows.
-class ImageBitmapShutdownObserver;
+class SVGImageElement;
 
 struct ImageBitmapCloneData final
 {
   RefPtr<gfx::DataSourceSurface> mSurface;
   gfx::IntRect mPictureRect;
   gfxAlphaType mAlphaType;
 };
 
@@ -180,16 +180,20 @@ protected:
 
   void SetPictureRect(const gfx::IntRect& aRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLImageElement& aImageEl,
                  const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
+  CreateInternal(nsIGlobalObject* aGlobal, SVGImageElement& aImageEl,
+                 const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
+
+  static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
                  const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
   CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl,
                  const Maybe<gfx::IntRect>& aCropRect, ErrorResult& aRv);
 
   static already_AddRefed<ImageBitmap>
--- a/dom/canvas/ImageBitmapSource.h
+++ b/dom/canvas/ImageBitmapSource.h
@@ -6,15 +6,15 @@
 
 #ifndef mozilla_dom_ImageBitmapSource_h
 #define mozilla_dom_ImageBitmapSource_h
 
 namespace mozilla {
 namespace dom {
 
 // So we don't have to forward declare this elsewhere.
-class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData;
-typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData ImageBitmapSource;
+class HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData;
+typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmapOrBlobOrCanvasRenderingContext2DOrImageData ImageBitmapSource;
 
 }
 }
 
 #endif
--- a/dom/serviceworkers/test/browser.ini
+++ b/dom/serviceworkers/test/browser.ini
@@ -13,16 +13,17 @@ support-files =
   empty.html
   empty_with_utils.html
   empty.js
   page_post_controlled.html
   storage_recovery_worker.sjs
   utils.js
 
 [browser_antitracking.js]
+[browser_antitracking_subiframes.js]
 [browser_devtools_serviceworker_interception.js]
 skip-if = serviceworker_e10s
 [browser_force_refresh.js]
 [browser_download.js]
 [browser_download_canceled.js]
 skip-if = verify
 [browser_storage_permission.js]
 skip-if = (verify && debug && (os == 'win' || os == 'mac'))
--- a/dom/serviceworkers/test/browser_antitracking.js
+++ b/dom/serviceworkers/test/browser_antitracking.js
@@ -27,77 +27,71 @@ const SW_REL_SW_SCRIPT = "empty.js";
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({'set': [
     ['dom.serviceWorkers.enabled', true],
     ['dom.serviceWorkers.exemptFromPerDomainMax', true],
     ['dom.serviceWorkers.testing.enabled', true],
     ['network.cookie.cookieBehavior', BEHAVIOR_ACCEPT],
   ]});
 
+  // Open the top-level page.
+  info("Opening a new tab: " + SW_REGISTER_PAGE);
+  let topTab = await BrowserTestUtils.openNewForegroundTab({
+    gBrowser,
+    opening: SW_REGISTER_PAGE
+  });
+
   // ## Install SW
   info("Installing SW");
-  await BrowserTestUtils.withNewTab(
-    {
-      gBrowser,
-      url: SW_REGISTER_PAGE
-    },
-    async function(linkedBrowser) {
-      await ContentTask.spawn(
-        linkedBrowser,
-        { sw: SW_REL_SW_SCRIPT },
-        async function({ sw }) {
-          // Waive the xray to use the content utils.js script functions.
-          await content.wrappedJSObject.registerAndWaitForActive(sw);
-        }
-      );
+  await ContentTask.spawn(
+    topTab.linkedBrowser,
+    { sw: SW_REL_SW_SCRIPT },
+    async function({ sw }) {
+      // Waive the xray to use the content utils.js script functions.
+      await content.wrappedJSObject.registerAndWaitForActive(sw);
     }
   );
 
   // Enable Anti-tracking.
   await SpecialPowers.pushPrefEnv({'set': [
     ['privacy.trackingprotection.enabled', false],
     ["privacy.trackingprotection.pbmode.enabled", false],
     ["privacy.trackingprotection.annotate_channels", true],
     ['network.cookie.cookieBehavior', BEHAVIOR_REJECT_TRACKER],
   ]});
   await UrlClassifierTestUtils.addTestTrackers();
 
-  // Open the top-level page.
-  info("Open top-level page");
-  let topTab = await BrowserTestUtils.openNewForegroundTab({
-    gBrowser,
-    opening: TOP_EMPTY_PAGE
-  });
+  // Open the top-level URL.
+  info("Loading a new top-level URL: " + TOP_EMPTY_PAGE);
+  let browserLoadedPromise = BrowserTestUtils.browserLoaded(topTab.linkedBrowser);
+  await BrowserTestUtils.loadURI(topTab.linkedBrowser, TOP_EMPTY_PAGE);
+  await browserLoadedPromise;
 
   // Create Iframe in the top-level page and verify its state.
   let { controlled } = await ContentTask.spawn(
     topTab.linkedBrowser,
     { url: SW_IFRAME_PAGE },
     async function ({ url }) {
       const payload =
         await content.wrappedJSObject.createIframeAndWaitForMessage(url);
       return payload;
     }
   );
 
   ok(!controlled, "Should not be controlled!");
 
   // ## Cleanup
+  info("Loading the SW unregister page: " + SW_REGISTER_PAGE);
+  browserLoadedPromise = BrowserTestUtils.browserLoaded(topTab.linkedBrowser);
+  await BrowserTestUtils.loadURI(topTab.linkedBrowser, SW_REGISTER_PAGE);
+  await browserLoadedPromise;
+
+  await ContentTask.spawn(
+    topTab.linkedBrowser,
+    null,
+    async function() {
+      await content.wrappedJSObject.unregisterAll();
+    }
+  );
+
   // Close the testing tab.
   BrowserTestUtils.removeTab(topTab);
-  // Unregister the SW we registered for the tracking protection origin.
-  await BrowserTestUtils.withNewTab(
-    {
-      gBrowser,
-      url: SW_REGISTER_PAGE
-    },
-    async function(linkedBrowser) {
-      await ContentTask.spawn(
-        linkedBrowser,
-        {},
-        async function() {
-          // Waive the xray to use the content utils.js script functions.
-          await content.wrappedJSObject.unregisterAll();
-        }
-      );
-    }
-  );
 });
new file mode 100644
--- /dev/null
+++ b/dom/serviceworkers/test/browser_antitracking_subiframes.js
@@ -0,0 +1,99 @@
+const BEHAVIOR_REJECT_TRACKER = Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER;
+
+const TOP_DOMAIN = "http://mochi.test:8888/";
+const SW_DOMAIN = "https://example.org/";
+
+const TOP_TEST_ROOT = getRootDirectory(gTestPath)
+  .replace("chrome://mochitests/content/", TOP_DOMAIN);
+const SW_TEST_ROOT = getRootDirectory(gTestPath)
+  .replace("chrome://mochitests/content/", SW_DOMAIN);
+
+const TOP_EMPTY_PAGE = `${TOP_TEST_ROOT}empty_with_utils.html`;
+const SW_REGISTER_PAGE = `${SW_TEST_ROOT}empty_with_utils.html`;
+const SW_IFRAME_PAGE = `${SW_TEST_ROOT}page_post_controlled.html`;
+const SW_REL_SW_SCRIPT = "empty.js";
+
+/**
+ * Set up a ServiceWorker on a domain that will be used as 3rd party iframe.
+ * That 3rd party frame should be controlled by the ServiceWorker.
+ * After that, we open a second iframe into the first one. That should not be
+ * controlled.
+ */
+add_task(async function() {
+  await SpecialPowers.pushPrefEnv({'set': [
+    ['dom.serviceWorkers.enabled', true],
+    ['dom.serviceWorkers.exemptFromPerDomainMax', true],
+    ['dom.serviceWorkers.testing.enabled', true],
+    ['network.cookie.cookieBehavior', BEHAVIOR_REJECT_TRACKER],
+  ]});
+
+  // Open the top-level page.
+  info("Opening a new tab: " + SW_REGISTER_PAGE);
+  let topTab = await BrowserTestUtils.openNewForegroundTab({
+    gBrowser,
+    opening: SW_REGISTER_PAGE
+  });
+
+  // Install SW
+  info("Registering a SW: " + SW_REL_SW_SCRIPT);
+  await ContentTask.spawn(
+    topTab.linkedBrowser,
+    { sw: SW_REL_SW_SCRIPT },
+    async function({ sw }) {
+      // Waive the xray to use the content utils.js script functions.
+      await content.wrappedJSObject.registerAndWaitForActive(sw);
+      // User interaction
+      content.document.userInteractionForTesting();
+    }
+  );
+
+  info("Loading a new top-level URL: " + TOP_EMPTY_PAGE);
+  let browserLoadedPromise = BrowserTestUtils.browserLoaded(topTab.linkedBrowser);
+  await BrowserTestUtils.loadURI(topTab.linkedBrowser, TOP_EMPTY_PAGE);
+  await browserLoadedPromise;
+
+  // Create Iframe in the top-level page and verify its state.
+  info("Creating iframe and checking if controlled");
+  let { controlled } = await ContentTask.spawn(
+    topTab.linkedBrowser,
+    { url: SW_IFRAME_PAGE },
+    async function ({ url }) {
+      content.document.userInteractionForTesting();
+      const payload =
+        await content.wrappedJSObject.createIframeAndWaitForMessage(url);
+      return payload;
+    }
+  );
+
+  ok(controlled, "Should be controlled!");
+
+  // Create a nested Iframe.
+  info("Creating nested-iframe and checking if controlled");
+  let { nested_controlled } = await ContentTask.spawn(
+    topTab.linkedBrowser,
+    { url: SW_IFRAME_PAGE },
+    async function ({ url }) {
+      const payload =
+        await content.wrappedJSObject.createNestedIframeAndWaitForMessage(url);
+      return payload;
+    }
+  );
+
+  ok(!nested_controlled, "Should not be controlled!");
+
+  info("Loading the SW unregister page: " + SW_REGISTER_PAGE);
+  browserLoadedPromise = BrowserTestUtils.browserLoaded(topTab.linkedBrowser);
+  await BrowserTestUtils.loadURI(topTab.linkedBrowser, SW_REGISTER_PAGE);
+  await browserLoadedPromise;
+
+  await ContentTask.spawn(
+    topTab.linkedBrowser,
+    null,
+    async function() {
+      await content.wrappedJSObject.unregisterAll();
+    }
+  );
+
+  // Close the testing tab.
+  BrowserTestUtils.removeTab(topTab);
+});
--- a/dom/serviceworkers/test/page_post_controlled.html
+++ b/dom/serviceworkers/test/page_post_controlled.html
@@ -7,11 +7,21 @@
 <head>
   <meta charset="utf-8">
 </head>
 <body>
 <script type="text/javascript">
   window.parent.postMessage({
     controlled: !!navigator.serviceWorker.controller
   }, "*");
+
+  addEventListener("message", e => {
+    if (e.data == "create nested iframe") {
+      const iframe = document.createElement('iframe');
+      document.body.appendChild(iframe);
+      iframe.src = location.href;
+    } else {
+      window.parent.postMessage(e.data, "*");
+    }
+  });
 </script>
 </body>
 </html>
--- a/dom/serviceworkers/test/utils.js
+++ b/dom/serviceworkers/test/utils.js
@@ -56,14 +56,32 @@ function createIframeAndWaitForMessage(u
     window.addEventListener(
       'message',
       (event) => { resolve(event.data); },
       { once: true });
     iframe.src = url;
   });
 }
 
+/**
+ * Helper to create a nested iframe into the iframe created by
+ * createIframeAndWaitForMessage().
+ *
+ * A promise will be returned that resolves with the payload of the postMessage
+ * call.
+ */
+function createNestedIframeAndWaitForMessage(url) {
+  const iframe = document.getElementsByTagName('iframe')[0];
+  iframe.contentWindow.postMessage("create nested iframe", "*");
+  return new Promise((resolve) => {
+    window.addEventListener(
+      'message',
+      (event) => { resolve(event.data); },
+      { once: true });
+  });
+}
+
 async function unregisterAll() {
   const registrations = await navigator.serviceWorker.getRegistrations();
   for (const reg of registrations) {
     await reg.unregister();
   }
 }
--- a/dom/webidl/ImageBitmap.webidl
+++ b/dom/webidl/ImageBitmap.webidl
@@ -5,24 +5,17 @@
  *
  * The origin of this IDL file is
  * https://html.spec.whatwg.org/multipage/webappapis.html#images
  *
  * The origin of the extended IDL file is
  * http://w3c.github.io/mediacapture-worker/#imagebitmap-extensions
  */
 
-// This is needed because we don't support SVG element as canvas image source.
-// See bug 1500768.
-typedef (HTMLImageElement or
-         HTMLCanvasElement or
-         HTMLVideoElement or
-         ImageBitmap) CanvasImageSourceExcludedSVG;
-
-typedef (CanvasImageSourceExcludedSVG or
+typedef (CanvasImageSource or
          Blob or
          CanvasRenderingContext2D or // This is out of spec.
          ImageData) ImageBitmapSource;
 
 [Exposed=(Window,Worker)]
 interface ImageBitmap {
   [Constant]
   readonly attribute unsigned long width;
new file mode 100644
--- /dev/null
+++ b/js/src/vm/BytecodeIterator-inl.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BytecodeIterator_inl_h
+#define vm_BytecodeIterator_inl_h
+
+#include "vm/BytecodeIterator.h"
+
+#include "vm/JSScript.h"
+namespace js {
+
+BytecodeIterator::BytecodeIterator(const JSScript* script)
+  : current_(script, script->code())
+{}
+
+// AllBytecodesIterable
+
+inline BytecodeIterator
+AllBytecodesIterable::begin() {
+    return BytecodeIterator(script_);
+}
+
+inline BytecodeIterator
+AllBytecodesIterable::end() {
+    return BytecodeIterator(BytecodeLocation(script_, script_->codeEnd()));
+}
+
+}
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/src/vm/BytecodeIterator.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BytecodeIterator_h
+#define vm_BytecodeIterator_h
+
+#include "vm/BytecodeLocation.h"
+
+namespace js {
+
+class BytecodeIterator
+{
+    BytecodeLocation current_;
+
+  public:
+
+    explicit BytecodeIterator(const JSScript* script);
+
+    explicit BytecodeIterator(BytecodeLocation loc)
+      : current_(loc)
+    {}
+
+    bool operator==(const BytecodeIterator& other) const {
+        return other.current_ == current_;
+    }
+
+    bool operator!=(const BytecodeIterator& other) const {
+        return !(other.current_ == current_);
+    }
+
+    const BytecodeLocation& operator*() const {
+        return current_;
+    }
+
+    const BytecodeLocation* operator->() const {
+        return &current_;
+    }
+
+    // Pre-increment
+    BytecodeIterator& operator++() {
+        current_ = current_.next();
+        return *this;
+    }
+
+    // Post-increment
+    BytecodeIterator operator++(int) {
+        current_ = current_.next();
+        return *this;
+    }
+
+};
+
+// Given a JSScript, allow the construction of a range based for-loop
+// that will visit all script locations in that script.
+class AllBytecodesIterable
+{
+
+    const JSScript* script_;
+  public:
+
+    explicit AllBytecodesIterable(const JSScript* script)
+      : script_(script)
+    {}
+
+    BytecodeIterator begin();
+    BytecodeIterator end();
+};
+
+}
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/src/vm/BytecodeLocation-inl.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BytecodeLocation_inl_h
+#define vm_BytecodeLocation_inl_h
+
+#include "vm/BytecodeLocation.h"
+
+#include "vm/JSScript.h"
+
+namespace js {
+
+inline bool
+BytecodeLocation::isValid(const JSScript* script) const {
+    // Note: Don't create a new BytecodeLocation during the implementation of this, as it
+    // is used in the constructor, and will recurse forever.
+    return script->contains(*this) ||toRawBytecode() == script->codeEnd();
+}
+
+inline bool
+BytecodeLocation::isInBounds(const JSScript* script) const {
+    return script->contains(*this);
+}
+
+}
+
+#endif
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/js/src/vm/BytecodeLocation.h
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BytecodeLocation_h
+#define vm_BytecodeLocation_h
+
+#include "js/TypeDecls.h"
+#include "vm/BytecodeUtil.h"
+
+namespace js {
+
+typedef uint32_t RawBytecodeLocationOffset;
+
+
+class BytecodeLocationOffset
+{
+    RawBytecodeLocationOffset rawOffset_;
+
+  public:
+    explicit BytecodeLocationOffset(RawBytecodeLocationOffset offset)
+      : rawOffset_(offset)
+    {}
+
+    RawBytecodeLocationOffset rawOffset() const {
+        return rawOffset_;
+    }
+
+};
+
+
+typedef jsbytecode* RawBytecode;
+
+// A immutable representation of a program location
+//
+class BytecodeLocation
+{
+    RawBytecode rawBytecode_;
+#ifdef DEBUG
+    const JSScript* debugOnlyScript_;
+#endif
+
+    // Construct a new BytecodeLocation, while borrowing scriptIdentity
+    // from some other BytecodeLocation.
+    BytecodeLocation(const BytecodeLocation& loc, RawBytecode pc)
+      : rawBytecode_(pc)
+#ifdef DEBUG
+      , debugOnlyScript_(loc.debugOnlyScript_)
+#endif
+    {
+        MOZ_ASSERT(isValid());
+    }
+
+  public:
+    BytecodeLocation(const JSScript* script, RawBytecode pc)
+      : rawBytecode_(pc)
+#ifdef DEBUG
+      , debugOnlyScript_(script)
+#endif
+    {
+        MOZ_ASSERT(isValid());
+    }
+
+    RawBytecode toRawBytecode() const {
+        return rawBytecode_;
+    }
+
+    // Return true if this bytecode location is valid for the given script.
+    // This includes the location 1-past the end of the bytecode.
+    bool isValid(const JSScript* script) const;
+
+    // Return true if this bytecode location is within the bounds of the
+    // bytecode for a given script.
+    bool isInBounds(const JSScript* script) const;
+
+    bool operator==(const BytecodeLocation& other) const {
+        MOZ_ASSERT(this->debugOnlyScript_ == other.debugOnlyScript_);
+        return rawBytecode_ == other.rawBytecode_;
+    }
+
+    bool operator!=(const BytecodeLocation& other) const {
+        return !(other == *this);
+    }
+
+    bool operator<(const BytecodeLocation& other) const {
+        MOZ_ASSERT(this->debugOnlyScript_ == other.debugOnlyScript_);
+        return rawBytecode_ < other.rawBytecode_;
+    }
+
+    // It is traditional to represent the rest of the relational operators
+    // using operator<, so we don't need to assert for these.
+    bool operator>(const BytecodeLocation& other) const {
+        return other < *this;
+    }
+
+    bool operator<=(const BytecodeLocation& other) const {
+        return !(other < *this);
+    }
+
+    bool operator>=(const BytecodeLocation& other) const {
+        return !(*this < other);
+    }
+
+    // Return the next bytecode
+    BytecodeLocation next() const {
+        return BytecodeLocation(*this, rawBytecode_ + GetBytecodeLength(rawBytecode_));
+    }
+
+    // Add an offset.
+    BytecodeLocation operator+(const BytecodeLocationOffset& offset) {
+        return BytecodeLocation(*this, rawBytecode_ + offset.rawOffset());
+    }
+
+    // Identity Checks
+    bool is(JSOp op) const {
+        MOZ_ASSERT(isInBounds());
+        return getOp() == op;
+    }
+
+    bool isJumpTarget() const {
+        return BytecodeIsJumpTarget(getOp());
+    }
+
+    bool isJump() const {
+        return IsJumpOpcode(getOp());
+    }
+
+    bool fallsThrough() const {
+        return BytecodeFallsThrough(getOp());
+    }
+
+    // Accessors:
+    JSOp getOp() const {
+        return JSOp(*rawBytecode_);
+    }
+
+    BytecodeLocation getJumpTarget() const {
+        // The default target of a JSOP_TABLESWITCH also follows this format.
+        MOZ_ASSERT(isJump() || is(JSOP_TABLESWITCH));
+        return BytecodeLocation(*this, rawBytecode_ + GET_JUMP_OFFSET(rawBytecode_));
+    }
+
+    // Return the 'low' parameter to the tableswitch opcode
+    int32_t getTableSwitchLow() const {
+        MOZ_ASSERT(is(JSOP_TABLESWITCH));
+        return GET_JUMP_OFFSET(rawBytecode_ + JUMP_OFFSET_LEN);
+    }
+
+    // Return the 'high' parameter to the tableswitch opcode
+    int32_t getTableSwitchHigh() const {
+        MOZ_ASSERT(is(JSOP_TABLESWITCH));
+        return GET_JUMP_OFFSET(rawBytecode_ + (2 * JUMP_OFFSET_LEN));
+    }
+
+    // Return the BytecodeLocation referred to by index number in the table
+    // of the table switch.
+    //
+    // Returns (effectively) |this| on a gap in the table.
+    BytecodeLocation getTableSwitchCaseByIndex(size_t index) const {
+        MOZ_ASSERT(is(JSOP_TABLESWITCH));
+        RawBytecode offsetLoc = rawBytecode_ +
+                                (3 *  JUMP_OFFSET_LEN) + // Skip over low and high
+                                (index * JUMP_OFFSET_LEN); // Select table entry
+        return BytecodeLocation(*this, rawBytecode_ + GET_JUMP_OFFSET(offsetLoc));
+    }
+
+#ifdef DEBUG
+    // To ease writing assertions
+    bool isValid() const {
+        return isValid(debugOnlyScript_);
+    }
+
+    bool isInBounds() const {
+        return isInBounds(debugOnlyScript_);
+    }
+#endif
+
+};
+
+
+}
+
+
+#endif
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -42,31 +42,35 @@
 #include "js/Printf.h"
 #include "js/SourceBufferHolder.h"
 #include "js/UniquePtr.h"
 #include "js/Utility.h"
 #include "js/Wrapper.h"
 #include "util/StringBuffer.h"
 #include "util/Text.h"
 #include "vm/ArgumentsObject.h"
+#include "vm/BytecodeIterator.h"
+#include "vm/BytecodeLocation.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/Compression.h"
 #include "vm/Debugger.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSObject.h"
 #include "vm/Opcodes.h"
 #include "vm/SelfHosting.h"
 #include "vm/Shape.h"
 #include "vm/SharedImmutableStringsCache.h"
 #include "vm/Xdr.h"
 #include "vtune/VTuneWrapper.h"
 
 #include "gc/Marking-inl.h"
+#include "vm/BytecodeIterator-inl.h"
+#include "vm/BytecodeLocation-inl.h"
 #include "vm/Compartment-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSFunction-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/SharedImmutableStringsCache-inl.h"
 #include "vm/Stack-inl.h"
 
@@ -1124,21 +1128,22 @@ JSScript::maybeForwardedScriptSource() c
 
 bool
 JSScript::initScriptCounts(JSContext* cx)
 {
     MOZ_ASSERT(!hasScriptCounts());
 
     // Record all pc which are the first instruction of a basic block.
     mozilla::Vector<jsbytecode*, 16, SystemAllocPolicy> jumpTargets;
-    jsbytecode* mainPc = main();
-    jsbytecode* end = codeEnd();
-    for (jsbytecode* pc = code(); pc != end; pc = GetNextPc(pc)) {
-        if (BytecodeIsJumpTarget(JSOp(*pc)) || pc == mainPc) {
-            if (!jumpTargets.append(pc)) {
+
+    js::BytecodeLocation main = mainLocation();
+    AllBytecodesIterable iterable(this);
+    for (auto& loc : iterable) {
+        if (loc.isJumpTarget() || loc == main) {
+            if (!jumpTargets.append(loc.toRawBytecode())) {
                 ReportOutOfMemory(cx);
                 return false;
             }
         }
     }
 
     // Initialize all PCCounts counters to 0.
     ScriptCounts::PCCountsVector base;
@@ -3559,60 +3564,59 @@ JSScript::fullyInitFromEmitter(JSContext
 
     return true;
 }
 
 #ifdef DEBUG
 void
 JSScript::assertValidJumpTargets() const
 {
-    jsbytecode* end = codeEnd();
-    jsbytecode* mainEntry = main();
-    for (jsbytecode* pc = code(); pc != end; pc = GetNextPc(pc)) {
+    BytecodeLocation mainLoc = mainLocation();
+    BytecodeLocation endLoc = endLocation();
+    AllBytecodesIterable iter(this);
+    for (BytecodeLocation loc : iter) {
         // Check jump instructions' target.
-        if (IsJumpOpcode(JSOp(*pc))) {
-            jsbytecode* target = pc + GET_JUMP_OFFSET(pc);
-            MOZ_ASSERT(mainEntry <= target && target < end);
-            MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*target)));
+        if (loc.isJump()){
+            BytecodeLocation target = loc.getJumpTarget();
+            MOZ_ASSERT(mainLoc <= target && target < endLoc);
+            MOZ_ASSERT(target.isJumpTarget());
 
             // Check fallthrough of conditional jump instructions.
-            if (BytecodeFallsThrough(JSOp(*pc))) {
-                jsbytecode* fallthrough = GetNextPc(pc);
-                MOZ_ASSERT(mainEntry <= fallthrough && fallthrough < end);
-                MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*fallthrough)));
+            if (loc.fallsThrough()) {
+                BytecodeLocation fallthrough = loc.next();
+                MOZ_ASSERT(mainLoc <= fallthrough && fallthrough < endLoc);
+                MOZ_ASSERT(fallthrough.isJumpTarget());
             }
         }
 
         // Check table switch case labels.
-        if (JSOp(*pc) == JSOP_TABLESWITCH) {
-            jsbytecode* pc2 = pc;
-            int32_t len = GET_JUMP_OFFSET(pc2);
+        if (loc.is(JSOP_TABLESWITCH)) {
+            BytecodeLocation target = loc.getJumpTarget();
 
             // Default target.
-            MOZ_ASSERT(mainEntry <= pc + len && pc + len < end);
-            MOZ_ASSERT(BytecodeIsJumpTarget(JSOp(*(pc + len))));
-
-            pc2 += JUMP_OFFSET_LEN;
-            int32_t low = GET_JUMP_OFFSET(pc2);
-            pc2 += JUMP_OFFSET_LEN;
-            int32_t high = GET_JUMP_OFFSET(pc2);
+            MOZ_ASSERT(mainLoc <= target && target < endLoc);
+            MOZ_ASSERT(target.isJumpTarget());
+
+            int32_t low = loc.getTableSwitchLow();
+            int32_t high = loc.getTableSwitchHigh();
 
             for (int i = 0; i < high - low + 1; i++) {
-                pc2 += JUMP_OFFSET_LEN;
-                int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
-                // Case (i + low)
-                MOZ_ASSERT_IF(off, mainEntry <= pc + off && pc + off < end);
-                MOZ_ASSERT_IF(off, BytecodeIsJumpTarget(JSOp(*(pc + off))));
+                BytecodeLocation switchCase = loc.getTableSwitchCaseByIndex(i);
+                MOZ_ASSERT_IF(switchCase != loc, mainLoc <= switchCase && switchCase < endLoc);
+                MOZ_ASSERT_IF(switchCase != loc, switchCase.isJumpTarget());
             }
         }
     }
 
     // Check catch/finally blocks as jump targets.
     if (hasTrynotes()) {
         for (const JSTryNote& tn : trynotes()) {
+            jsbytecode* end = codeEnd();
+            jsbytecode* mainEntry = main();
+
             jsbytecode* tryStart = offsetToPC(tn.start);
             jsbytecode* tryPc = tryStart - 1;
             if (tn.kind != JSTRY_CATCH && tn.kind != JSTRY_FINALLY) {
                 continue;
             }
 
             MOZ_ASSERT(JSOp(*tryPc) == JSOP_TRY);
             jsbytecode* tryTarget = tryStart + tn.length;
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -28,16 +28,18 @@
 #include "frontend/NameAnalysisTypes.h"
 #include "gc/Barrier.h"
 #include "gc/Rooting.h"
 #include "jit/IonCode.h"
 #include "js/CompileOptions.h"
 #include "js/UbiNode.h"
 #include "js/UniquePtr.h"
 #include "js/Utility.h"
+#include "vm/BytecodeIterator.h"
+#include "vm/BytecodeLocation.h"
 #include "vm/BytecodeUtil.h"
 #include "vm/JSAtom.h"
 #include "vm/NativeObject.h"
 #include "vm/Scope.h"
 #include "vm/Shape.h"
 #include "vm/SharedImmutableStringsCache.h"
 #include "vm/Time.h"
 
@@ -1743,16 +1745,25 @@ class JSScript : public js::gc::TenuredC
 
     // Script bytecode is immutable after creation.
     jsbytecode* code() const {
         if (!scriptData_) {
             return nullptr;
         }
         return scriptData_->code();
     }
+
+    js::AllBytecodesIterable allLocations() {
+        return js::AllBytecodesIterable(this);
+    }
+
+    js::BytecodeLocation location() {
+        return js::BytecodeLocation(this, code());
+    }
+
     bool isUncompleted() const {
         // code() becomes non-null only if this script is complete.
         // See the comment in JSScript::fullyInitFromEmitter.
         return !code();
     }
 
     size_t length() const {
         MOZ_ASSERT(scriptData_);
@@ -1766,16 +1777,20 @@ class JSScript : public js::gc::TenuredC
         MOZ_ASSERT(*pc == JSOP_RETRVAL);
         return pc;
     }
 
     bool containsPC(const jsbytecode* pc) const {
         return pc >= code() && pc < codeEnd();
     }
 
+    bool contains(const js::BytecodeLocation& loc) const {
+        return containsPC(loc.toRawBytecode());
+    }
+
     size_t pcToOffset(const jsbytecode* pc) const {
         MOZ_ASSERT(containsPC(pc));
         return size_t(pc - code());
     }
 
     jsbytecode* offsetToPC(size_t offset) const {
         MOZ_ASSERT(offset < length());
         return code() + offset;
@@ -2354,16 +2369,24 @@ class JSScript : public js::gc::TenuredC
     void destroyScriptCounts();
     void destroyScriptName();
     void clearHasScriptCounts();
 
     jsbytecode* main() const {
         return code() + mainOffset();
     }
 
+    js::BytecodeLocation mainLocation() const {
+        return js::BytecodeLocation(this, main());
+    }
+
+    js::BytecodeLocation endLocation() const {
+        return js::BytecodeLocation(this, codeEnd());
+    }
+
     /*
      * computedSizeOfData() is the in-use size of all the data sections.
      * sizeOfData() is the size of the block allocated to hold all the data
      * sections (which can be larger than the in-use size).
      */
     size_t computedSizeOfData() const;
     size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
     size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -23,16 +23,17 @@
 #include "nsISupportsImpl.h"
 #include "nsISupportsUtils.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
 #include "nsDocShell.h"
 #include "nsGlobalWindow.h"
 #include "nsMixedContentBlocker.h"
 #include "nsRedirectHistoryEntry.h"
+#include "nsSandboxFlags.h"
 #include "LoadInfo.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace net {
 
 static uint64_t
@@ -128,16 +129,19 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
 
   // if the load is sandboxed, we can not also inherit the principal
   if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) {
     mForceInheritPrincipalDropped =
       (mSecurityFlags & nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL);
     mSecurityFlags &= ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
+  uint32_t externalType =
+    nsContentUtils::InternalContentPolicyTypeToExternal(aContentPolicyType);
+
   if (aLoadingContext) {
     // Ensure that all network requests for a window client have the ClientInfo
     // properly set.  Workers must currently pass the loading ClientInfo explicitly.
     // We allow main thread requests to explicitly pass the value as well.
     if (mClientInfo.isNothing()) {
       mClientInfo = aLoadingContext->OwnerDoc()->GetClientInfo();
     }
 
@@ -157,18 +161,33 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
       nsCOMPtr<nsPIDOMWindowOuter> parent = contextOuter->GetScriptableParent();
       mParentOuterWindowID = parent ? parent->WindowID() : mOuterWindowID;
       mTopOuterWindowID = FindTopOuterWindowID(contextOuter);
 
       nsGlobalWindowInner* innerWindow =
         nsGlobalWindowInner::Cast(contextOuter->GetCurrentInnerWindow());
       if (innerWindow) {
         mTopLevelPrincipal = innerWindow->GetTopLevelPrincipal();
-        mTopLevelStorageAreaPrincipal =
-          innerWindow->GetTopLevelStorageAreaPrincipal();
+
+        // The top-level-storage-area-principal is not null only for the first
+        // level of iframes (null for top-level contexts, and null for
+        // sub-iframes). If we are loading a sub-document resource, we must
+        // calculate what the top-level-storage-area-principal will be for the
+        // new context.
+        if (externalType != nsIContentPolicy::TYPE_SUBDOCUMENT) {
+          mTopLevelStorageAreaPrincipal =
+            innerWindow->GetTopLevelStorageAreaPrincipal();
+        } else if (contextOuter->IsTopLevelWindow()) {
+          nsIDocument* doc = innerWindow->GetExtantDoc();
+          if (!doc || ((doc->GetSandboxFlags() & SANDBOXED_STORAGE_ACCESS) == 0 &&
+                       !nsContentUtils::IsInPrivateBrowsing(doc))) {
+            mTopLevelStorageAreaPrincipal = innerWindow->GetPrincipal();
+          }
+        }
+
         mDocumentHasLoaded = innerWindow->IsDocumentLoaded();
 
         if (innerWindow->IsFrame()) {
           // For resources within iframes, we actually want the
           // top-level document's flag, not the iframe document's.
           mDocumentHasLoaded = false;
           nsGlobalWindowOuter* topOuter = innerWindow->GetScriptableTopInternal();
           if (topOuter) {
@@ -212,18 +231,16 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
     // if the document forces all requests to be upgraded from http to https, then
     // we should do that for all requests. If it only forces preloads to be upgraded
     // then we should enforce upgrade insecure requests only for preloads.
     mUpgradeInsecureRequests =
       aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(false) ||
       (nsContentUtils::IsPreloadType(mInternalContentPolicyType) &&
        aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(true));
 
-    uint32_t externalType =
-      nsContentUtils::InternalContentPolicyTypeToExternal(mInternalContentPolicyType);
     if (nsContentUtils::IsUpgradableDisplayType(externalType)) {
       nsCOMPtr<nsIURI> uri;
       mLoadingPrincipal->GetURI(getter_AddRefs(uri));
       if (uri) {
         // Checking https not secure context as http://localhost can't be upgraded
         bool isHttpsScheme;
         nsresult rv = uri->SchemeIs("https", &isHttpsScheme);
         if (NS_SUCCEEDED(rv) && isHttpsScheme) {
@@ -370,18 +387,18 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
   nsCOMPtr<nsPIDOMWindowOuter> parent = aOuterWindow->GetScriptableParent();
   mParentOuterWindowID = parent ? parent->WindowID() : 0;
   mTopOuterWindowID = FindTopOuterWindowID(aOuterWindow);
 
   nsGlobalWindowInner* innerWindow =
     nsGlobalWindowInner::Cast(aOuterWindow->GetCurrentInnerWindow());
   if (innerWindow) {
     mTopLevelPrincipal = innerWindow->GetTopLevelPrincipal();
-    mTopLevelStorageAreaPrincipal =
-      innerWindow->GetTopLevelStorageAreaPrincipal();
+    // mTopLevelStorageAreaPrincipal is always null for top-level document
+    // loading.
   }
 
   // get the docshell from the outerwindow, and then get the originattributes
   nsCOMPtr<nsIDocShell> docShell = aOuterWindow->GetDocShell();
   MOZ_ASSERT(docShell);
   mOriginAttributes = nsDocShell::Cast(docShell)->GetOriginAttributes();
   mAncestorPrincipals = nsDocShell::Cast(docShell)->AncestorPrincipals();
   mAncestorOuterWindowIDs = nsDocShell::Cast(docShell)->AncestorOuterWindowIDs();
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -532,16 +532,18 @@ NeckoChild::RecvNetworkChangeNotificatio
     obsService->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
                                 NS_ConvertUTF8toUTF16(type).get());
   }
   return IPC_OK();
 }
 
 PTrackingDummyChannelChild*
 NeckoChild::AllocPTrackingDummyChannelChild(nsIURI* aURI,
+                                            nsIURI* aTopWindowURI,
+                                            const nsresult& aTopWindowURIResult,
                                             const OptionalLoadInfoArgs& aLoadInfo)
 {
   return new TrackingDummyChannelChild();
 }
 
 bool
 NeckoChild::DeallocPTrackingDummyChannelChild(PTrackingDummyChannelChild* aActor)
 {
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -103,16 +103,18 @@ protected:
                                     const uint32_t& aNewLoadFlags,
                                     const OptionalLoadInfoArgs& aLoadInfoForwarder,
                                     const uint64_t& aChannelId,
                                     nsIURI* aOriginalURI,
                                     const uint64_t& aIdentifier) override;
 
   virtual PTrackingDummyChannelChild*
     AllocPTrackingDummyChannelChild(nsIURI* aURI,
+                                    nsIURI* aTopWindowURI,
+                                    const nsresult& aTopWindowURIResult,
                                     const OptionalLoadInfoArgs& aLoadInfo) override;
 
   virtual bool
     DeallocPTrackingDummyChannelChild(PTrackingDummyChannelChild* aChannel) override;
 };
 
 /**
  * Reference to the PNecko Child protocol.
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -1013,41 +1013,45 @@ NeckoParent::RecvGetExtensionFD(const UR
     aResolve(invalidFD);
   }
 
   return IPC_OK();
 }
 
 PTrackingDummyChannelParent*
 NeckoParent::AllocPTrackingDummyChannelParent(nsIURI* aURI,
+                                              nsIURI* aTopWindowURI,
+                                              const nsresult& aTopWindowURIResult,
                                               const OptionalLoadInfoArgs& aLoadInfo)
 {
   RefPtr<TrackingDummyChannelParent> c = new TrackingDummyChannelParent();
   return c.forget().take();
 }
 
 mozilla::ipc::IPCResult
 NeckoParent::RecvPTrackingDummyChannelConstructor(PTrackingDummyChannelParent* aActor,
                                                   nsIURI* aURI,
+                                                  nsIURI* aTopWindowURI,
+                                                  const nsresult& aTopWindowURIResult,
                                                   const OptionalLoadInfoArgs& aLoadInfo)
 {
   TrackingDummyChannelParent* p =
     static_cast<TrackingDummyChannelParent*>(aActor);
 
   if (NS_WARN_IF(!aURI)) {
     return IPC_FAIL_NO_REASON(this);
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo;
   nsresult rv = LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(loadInfo));
   if (NS_WARN_IF(NS_FAILED(rv)) || !loadInfo) {
     return IPC_FAIL_NO_REASON(this);
   }
 
-  p->Init(aURI, loadInfo);
+  p->Init(aURI, aTopWindowURI, aTopWindowURIResult, loadInfo);
   return IPC_OK();
 }
 
 bool
 NeckoParent::DeallocPTrackingDummyChannelParent(PTrackingDummyChannelParent* aActor)
 {
   RefPtr<TrackingDummyChannelParent> c =
     dont_AddRef(static_cast<TrackingDummyChannelParent*>(aActor));
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -238,23 +238,27 @@ protected:
                            GetExtensionStreamResolver&& aResolve) override;
 
   virtual mozilla::ipc::IPCResult
     RecvGetExtensionFD(const URIParams& aURI,
                        GetExtensionFDResolver&& aResolve) override;
 
   virtual PTrackingDummyChannelParent*
     AllocPTrackingDummyChannelParent(nsIURI* aURI,
+                                     nsIURI* aTopWindowURI,
+                                     const nsresult& aTopWindowURIResult,
                                      const OptionalLoadInfoArgs& aLoadInfo) override;
 
   virtual bool
     DeallocPTrackingDummyChannelParent(PTrackingDummyChannelParent* aChild) override;
 
   virtual mozilla::ipc::IPCResult
     RecvPTrackingDummyChannelConstructor(PTrackingDummyChannelParent* aActor,
                                          nsIURI* aURI,
+                                         nsIURI* aTopWindowURI,
+                                         const nsresult& aTopWindowURIResult,
                                          const OptionalLoadInfoArgs& aLoadInfo) override;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_NeckoParent_h
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -107,17 +107,19 @@ parent:
    * the parent and the child when we're redirecting to a data: URI.
    */
   async PDataChannel(uint32_t channelId);
   async PSimpleChannel(uint32_t channelId);
   async PFileChannel(uint32_t channelId);
 
   async PChannelDiverter(ChannelDiverterArgs channel);
 
-  async PTrackingDummyChannel(nsIURI uri, OptionalLoadInfoArgs loadInfo);
+  async PTrackingDummyChannel(nsIURI uri, nsIURI aTopWindowURI,
+                              nsresult aTopWindowURIResult,
+                              OptionalLoadInfoArgs loadInfo);
 
   /**
    * These are called from the child with the results of the auth prompt.
    * callbackId is the id that was passed in PBrowser::AsyncAuthPrompt,
    * corresponding to an nsIAuthPromptCallback
    */
   async OnAuthAvailable(uint64_t callbackId, nsString user,
                         nsString password, nsString domain);
--- a/netwerk/protocol/http/TrackingDummyChannel.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannel.cpp
@@ -85,22 +85,27 @@ TrackingDummyChannel::StorageAllowed(nsI
 }
 
 NS_IMPL_ADDREF(TrackingDummyChannel)
 NS_IMPL_RELEASE(TrackingDummyChannel)
 
 NS_INTERFACE_MAP_BEGIN(TrackingDummyChannel)
   NS_INTERFACE_MAP_ENTRY(nsIRequest)
   NS_INTERFACE_MAP_ENTRY(nsIChannel)
+  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
   NS_INTERFACE_MAP_ENTRY_CONCRETE(TrackingDummyChannel)
 NS_INTERFACE_MAP_END
 
 TrackingDummyChannel::TrackingDummyChannel(nsIURI* aURI,
+                                           nsIURI* aTopWindowURI,
+                                           nsresult aTopWindowURIResult,
                                            nsILoadInfo* aLoadInfo)
-  : mIsTrackingResource(false)
+  : mTopWindowURI(aTopWindowURI)
+  , mTopWindowURIResult(aTopWindowURIResult)
+  , mIsTrackingResource(false)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   SetOriginalURI(aURI);
   SetLoadInfo(aLoadInfo);
 }
 
 TrackingDummyChannel::~TrackingDummyChannel() = default;
@@ -347,10 +352,367 @@ TrackingDummyChannel::SetLoadFlags(nsLoa
 }
 
 NS_IMETHODIMP
 TrackingDummyChannel::GetIsDocument(bool* aIsDocument)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+//-----------------------------------------------------------------------------
+// TrackingDummyChannel::nsIHttpChannelInternal
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetDocumentURI(nsIURI** aDocumentURI)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetDocumentURI(nsIURI* aDocumentURI)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetRequestVersion(uint32_t* aMajor, uint32_t* aMinor)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetResponseVersion(uint32_t* aMajor, uint32_t* aMinor)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetCookie(const char* aCookieHeader)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetupFallbackChannel(const char* aFallbackKey)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetThirdPartyFlags(uint32_t* aThirdPartyFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetThirdPartyFlags(uint32_t aThirdPartyFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetForceAllowThirdPartyCookie(bool* aForceAllowThirdPartyCookie)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetForceAllowThirdPartyCookie(bool aForceAllowThirdPartyCookie)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetCanceled(bool* aCanceled)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetChannelIsForDownload(bool* aChannlIsForDownload)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetChannelIsForDownload(bool aChannlIsForDownload)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetLocalAddress(nsACString& aLocalAddress)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetLocalPort(int32_t* aLocalPort)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetRemoteAddress(nsACString& aRemoteAddress)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetRemotePort(int32_t* aRemotePort)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetCacheKeysRedirectChain(nsTArray<nsCString>* aCacheKeys)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::HTTPUpgrade(const nsACString& aProtocolName,
+                                  nsIHttpUpgradeListener* aListener)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetAllowSpdy(bool* aAllowSpdy)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetAllowSpdy(bool aAllowSpdy)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetResponseTimeoutEnabled(bool* aResponseTimeoutEnabled)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetResponseTimeoutEnabled(bool aResponseTimeoutEnabled)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetInitialRwin(uint32_t* aInitialRwin)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetInitialRwin(uint32_t aInitialRwin)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetApiRedirectToURI(nsIURI** aApiRedirectToURI)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetAllowAltSvc(bool* aAllowAltSvc)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetAllowAltSvc(bool aAllowAltSvc)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetBeConservative(bool* aBeConservative)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetBeConservative(bool aBeConservative)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetTrr(bool* aTrr)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetTrr(bool aTrr)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetTlsFlags(uint32_t* aTlsFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetTlsFlags(uint32_t aTlsFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetLastModifiedTime(PRTime* aLastModifiedTime)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetCorsIncludeCredentials(bool* aCorsIncludeCredentials)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetCorsIncludeCredentials(bool aCorsIncludeCredentials)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetCorsMode(uint32_t* aCorsMode)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetCorsMode(uint32_t aCorsMode)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetRedirectMode(uint32_t* aRedirectMode)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetRedirectMode(uint32_t aRedirectMode)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetFetchCacheMode(uint32_t* aFetchCacheMode)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetFetchCacheMode(uint32_t aFetchCacheMode)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetTopWindowURI(nsIURI** aTopWindowURI)
+{
+  nsCOMPtr<nsIURI> topWindowURI = mTopWindowURI;
+  topWindowURI.forget(aTopWindowURI);
+  return mTopWindowURIResult;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetTopWindowURIIfUnknown(nsIURI* aTopWindowURI)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetProxyURI(nsIURI** aProxyURI)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+TrackingDummyChannel::SetCorsPreflightParameters(const nsTArray<nsCString>& aUnsafeHeaders)
+{}
+
+void
+TrackingDummyChannel::SetAltDataForChild(bool aIsForChild)
+{}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetBlockAuthPrompt(bool* aBlockAuthPrompt)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetBlockAuthPrompt(bool aBlockAuthPrompt)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetIntegrityMetadata(nsAString& aIntegrityMetadata)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetIntegrityMetadata(const nsAString& aIntegrityMetadata)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetConnectionInfoHashKey(nsACString& aConnectionInfoHashKey)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetLastRedirectFlags(uint32_t* aLastRedirectFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetLastRedirectFlags(uint32_t aLastRedirectFlags)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::GetNavigationStartTimeStamp(TimeStamp* aNavigationStartTimeStamp)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::SetNavigationStartTimeStamp(TimeStamp aNavigationStartTimeStamp)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+TrackingDummyChannel::CancelForTrackingProtection()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 } // net namespace
 } // mozilla namespace
--- a/netwerk/protocol/http/TrackingDummyChannel.h
+++ b/netwerk/protocol/http/TrackingDummyChannel.h
@@ -37,49 +37,55 @@ namespace net {
  *
  * This hack can be removed once Bug 1231208's new "parent intercept" mechanism
  * fully lands, the pref is enabled by default it stays enabled for long enough
  * to be confident we will never need/want to turn it off.  Then as part of bug
  * 1496997 we can remove this implementation.  Bug 1498259 covers removing this
  * hack in particular.
  */
 class TrackingDummyChannel final : public nsIChannel
+                                 , public nsIHttpChannelInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(TRACKING_DUMMY_CHANNEL_IID)
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIREQUEST
   NS_DECL_NSICHANNEL
+  NS_DECL_NSIHTTPCHANNELINTERNAL
 
   enum StorageAllowedState
   {
     eStorageGranted,
     eStorageDenied,
     eAsyncNeeded,
   };
 
   static StorageAllowedState
   StorageAllowed(nsIChannel* aChannel,
                  const std::function<void(bool)>& aCallback);
 
   TrackingDummyChannel(nsIURI* aURI,
+                       nsIURI* aTopWindowURI,
+                       nsresult aTopWindowURIResult,
                        nsILoadInfo* aLoadInfo);
 
   bool
   IsTrackingResource() const;
 
   void
   SetIsTrackingResource();
 
 private:
   ~TrackingDummyChannel();
 
   nsCOMPtr<nsILoadInfo> mLoadInfo;
   nsCOMPtr<nsIURI> mURI;
+  nsCOMPtr<nsIURI> mTopWindowURI;
+  nsresult mTopWindowURIResult;
 
   bool mIsTrackingResource;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(TrackingDummyChannel, TRACKING_DUMMY_CHANNEL_IID)
 
 } // net namespace
 } // mozilla namespace
--- a/netwerk/protocol/http/TrackingDummyChannelChild.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannelChild.cpp
@@ -17,26 +17,39 @@ namespace net {
 TrackingDummyChannelChild::Create(nsIHttpChannel* aChannel, nsIURI* aURI,
                                   const std::function<void(bool)>& aCallback)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MOZ_ASSERT(aChannel);
   MOZ_ASSERT(aURI);
 
+  nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
+    do_QueryInterface(aChannel);
+  if (!httpChannelInternal) {
+    // Any non-http channel is allowed.
+    return true;
+  }
+
+  nsCOMPtr<nsIURI> topWindowURI;
+  nsresult topWindowURIResult =
+    httpChannelInternal->GetTopWindowURI(getter_AddRefs(topWindowURI));
+
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   if (!loadInfo) {
     return false;
   }
 
   OptionalLoadInfoArgs loadInfoArgs;
   mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs);
 
   PTrackingDummyChannelChild* actor =
-    gNeckoChild->SendPTrackingDummyChannelConstructor(aURI, loadInfoArgs);
+    gNeckoChild->SendPTrackingDummyChannelConstructor(aURI, topWindowURI,
+                                                      topWindowURIResult,
+                                                      loadInfoArgs);
   if (!actor) {
     return false;
   }
 
   bool isThirdParty =
     nsContentUtils::IsThirdPartyWindowOrChannel(nullptr, aChannel, aURI);
 
   static_cast<TrackingDummyChannelChild*>(actor)->Initialize(aChannel, aURI,
@@ -72,17 +85,19 @@ TrackingDummyChannelChild::Recv__delete_
 
   if (!mChannel) {
     return IPC_OK();
   }
 
   nsCOMPtr<nsIHttpChannel> channel = std::move(mChannel);
 
   RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(channel);
-  httpChannel->SetIsTrackingResource(mIsThirdParty);
+  if (aTrackingResource) {
+    httpChannel->SetIsTrackingResource(mIsThirdParty);
+  }
 
   bool storageGranted =
     AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel, mURI,
                                                             nullptr);
   mCallback(storageGranted);
   return IPC_OK();
 }
 
--- a/netwerk/protocol/http/TrackingDummyChannelParent.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannelParent.cpp
@@ -17,31 +17,34 @@ namespace net {
 TrackingDummyChannelParent::TrackingDummyChannelParent()
   : mIPCActive(true)
 {}
 
 TrackingDummyChannelParent::~TrackingDummyChannelParent() = default;
 
 void
 TrackingDummyChannelParent::Init(nsIURI* aURI,
+                                 nsIURI* aTopWindowURI,
+                                 nsresult aTopWindowURIResult,
                                  nsILoadInfo* aLoadInfo)
 {
   MOZ_ASSERT(mIPCActive);
 
   RefPtr<TrackingDummyChannelParent> self = this;
   auto onExit = MakeScopeExit([self] {
     Unused << Send__delete__(self, false);
   });
 
   if (!aURI) {
     return;
   }
 
   RefPtr<TrackingDummyChannel> channel =
-    new TrackingDummyChannel(aURI, aLoadInfo);
+    new TrackingDummyChannel(aURI, aTopWindowURI, aTopWindowURIResult,
+                             aLoadInfo);
 
   RefPtr<nsChannelClassifier> channelClassifier =
     new nsChannelClassifier(channel);
 
   bool willCallback =
     NS_SUCCEEDED(channelClassifier->CheckIsTrackerWithLocalTable(
       [self = std::move(self), channel]() {
         if (self->mIPCActive) {
--- a/netwerk/protocol/http/TrackingDummyChannelParent.h
+++ b/netwerk/protocol/http/TrackingDummyChannelParent.h
@@ -20,16 +20,18 @@ class TrackingDummyChannelParent final :
 {
 public:
   NS_INLINE_DECL_REFCOUNTING(TrackingDummyChannelParent)
 
   TrackingDummyChannelParent();
 
   void
   Init(nsIURI* aURI,
+       nsIURI* aTopWindowURI,
+       nsresult aTopWindowURIResult,
        nsILoadInfo* aLoadInfo);
 
 private:
   ~TrackingDummyChannelParent();
 
   void
   ActorDestroy(ActorDestroyReason aWhy) override;
 
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-drawImage.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-drawImage.html.ini
@@ -3,34 +3,16 @@
     expected: FAIL
 
   [createImageBitmap from an OffscreenCanvas with negative sw/sh, and drawImage on the created ImageBitmap]
     expected: FAIL
 
   [createImageBitmap from a Blob with negative sw/sh, and drawImage on the created ImageBitmap]
     expected: FAIL
 
-  [createImageBitmap from a vector HTMLImageElement, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
-  [createImageBitmap from a vector HTMLImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
-  [createImageBitmap from a bitmap SVGImageElement, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
-  [createImageBitmap from a bitmap SVGImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
-  [createImageBitmap from a vector SVGImageElement, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
-  [createImageBitmap from a vector SVGImageElement with negative sw/sh, and drawImage on the created ImageBitmap]
-    expected: FAIL
-
   [createImageBitmap from an HTMLCanvasElement scaled down, and drawImage on the created ImageBitmap]
     expected: FAIL
 
   [createImageBitmap from an HTMLCanvasElement scaled up, and drawImage on the created ImageBitmap]
     expected: FAIL
 
   [createImageBitmap from an HTMLCanvasElement resized, and drawImage on the created ImageBitmap]
     expected: FAIL
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-invalid-args.html.ini
@@ -6,29 +6,11 @@
     expected: FAIL
 
   [createImageBitmap with an OffscreenCanvas source and oversized (unallocatable) crop region]
     expected: FAIL
 
   [createImageBitmap with an invalid OffscreenCanvas source.]
     expected: FAIL
 
-  [createImageBitmap with a broken image source.]
-    expected: FAIL
-
-  [createImageBitmap with an available but undecodable image source.]
-    expected: FAIL
-
-  [createImageBitmap with a bitmap SVGImageElement source and sw set to 0]
-    expected: FAIL
-
-  [createImageBitmap with a bitmap SVGImageElement source and sh set to 0]
-    expected: FAIL
-
-  [createImageBitmap with a vector SVGImageElement source and sw set to 0]
-    expected: FAIL
-
-  [createImageBitmap with a vector SVGImageElement source and sh set to 0]
-    expected: FAIL
-
   [createImageBitmap with CanvasRenderingContext2D image source.]
     expected: FAIL
 
--- a/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-transfer.html.ini
+++ b/testing/web-platform/meta/2dcontext/imagebitmap/createImageBitmap-transfer.html.ini
@@ -1,13 +1,4 @@
 [createImageBitmap-transfer.html]
-  [Transfer ImageBitmap created from a vector HTMLImageElement]
-    expected: FAIL
-
-  [Transfer ImageBitmap created from a bitmap SVGImageElement]
-    expected: FAIL
-
-  [Transfer ImageBitmap created from a vector SVGImageElement]
-    expected: FAIL
-
   [Transfer ImageBitmap created from an OffscreenCanvas]
     expected: FAIL
 
--- a/testing/web-platform/tests/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
+++ b/testing/web-platform/tests/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
@@ -75,17 +75,17 @@ testCases = [
             assert_equals(i.height, 100000000);
           })
           .catch(e => {
             // This case is not explicitly documented in the specification for
             // createImageBitmap, but it is expected that internal failures
             // cause InvalidStateError.
             //
             // Note: https://bugs.chromium.org/p/chromium/issues/detail?id=799025
-            assert_throws(e, function() { throw e }, new DOMException('', 'InvalidStateError'));
+            assert_throws("InvalidStateError", () => { throw e });
           });
       }
   },
 ];
 
 // Generate the test matrix for each sourceType + testCase combo.
 imageSourceTypes.forEach(imageSourceType => {
   testCases.forEach(testCase => {
--- a/toolkit/mozapps/extensions/AddonContentPolicy.cpp
+++ b/toolkit/mozapps/extensions/AddonContentPolicy.cpp
@@ -92,16 +92,21 @@ LogMessage(const nsAString &aMessage, ns
 // Content policy enforcement:
 
 NS_IMETHODIMP
 AddonContentPolicy::ShouldLoad(nsIURI* aContentLocation,
                                nsILoadInfo* aLoadInfo,
                                const nsACString& aMimeTypeGuess,
                                int16_t* aShouldLoad)
 {
+  if (!aContentLocation || !aLoadInfo) {
+    *aShouldLoad = REJECT_REQUEST;
+    return NS_ERROR_FAILURE;
+  }
+
   uint32_t contentType = aLoadInfo->GetExternalContentPolicyType();
   nsCOMPtr<nsIURI> requestOrigin;
   nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadInfo->LoadingPrincipal();
   if (loadingPrincipal) {
     loadingPrincipal->GetURI(getter_AddRefs(requestOrigin));
   }
 
   MOZ_ASSERT(contentType == nsContentUtils::InternalContentPolicyTypeToExternal(contentType),