Bug 1407891: Allow view-image to open a data: URI by setting a flag on the loadinfo. r=bz
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Wed, 08 Nov 2017 20:01:41 +0100
changeset 428564 69e828da2238c01a3ab7c449d8c13b23792a7555
parent 428563 a06f5967bcb6d135c7283e0cc9adab5ddb3442a3
child 428565 5a5b81ec0ae6e4854788be270674b0f9833a667e
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs1407891
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1407891: Allow view-image to open a data: URI by setting a flag on the loadinfo. r=bz
browser/base/content/nsContextMenu.js
browser/base/content/utilityOverlay.js
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadInfo.cpp
docshell/base/nsDocShellLoadInfo.h
docshell/base/nsIDocShell.idl
docshell/base/nsIDocShellLoadInfo.idl
docshell/base/nsIWebNavigation.idl
dom/security/nsContentSecurityManager.cpp
ipc/glue/BackgroundUtils.cpp
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/nsILoadInfo.idl
netwerk/ipc/NeckoChannelParams.ipdlh
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -946,17 +946,18 @@ nsContextMenu.prototype = {
                                  referrerURI,
                                  triggeringPrincipal: systemPrincipal});
       }, Cu.reportError);
     } else {
       urlSecurityCheck(this.mediaURL,
                        this.browser.contentPrincipal,
                        Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
       openUILink(this.mediaURL, e, { disallowInheritPrincipal: true,
-                                     referrerURI });
+                                     referrerURI,
+                                     forceAllowDataURI: true });
     }
   },
 
   saveVideoFrameAsImage() {
     let mm = this.browser.messageManager;
     let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(this.browser);
 
     let name = "";
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -202,31 +202,33 @@ function openUILinkIn(url, where, aAllow
     };
   }
 
   params.fromChrome = true;
 
   openLinkIn(url, where, params);
 }
 
+/* eslint-disable complexity */
 function openLinkIn(url, where, params) {
   if (!where || !url)
     return;
   const Cc = Components.classes;
   const Ci = Components.interfaces;
 
   var aFromChrome           = params.fromChrome;
   var aAllowThirdPartyFixup = params.allowThirdPartyFixup;
   var aPostData             = params.postData;
   var aCharset              = params.charset;
   var aReferrerURI          = params.referrerURI;
   var aReferrerPolicy       = ("referrerPolicy" in params ?
       params.referrerPolicy : Ci.nsIHttpChannel.REFERRER_POLICY_UNSET);
   var aRelatedToCurrent     = params.relatedToCurrent;
   var aAllowMixedContent    = params.allowMixedContent;
+  var aForceAllowDataURI    = params.forceAllowDataURI;
   var aInBackground         = params.inBackground;
   var aDisallowInheritPrincipal = params.disallowInheritPrincipal;
   var aInitiatingDoc        = params.initiatingDoc;
   var aIsPrivate            = params.private;
   var aSkipTabAnimation     = params.skipTabAnimation;
   var aAllowPinnedTabHostChange = !!params.allowPinnedTabHostChange;
   var aNoReferrer           = params.noReferrer;
   var aAllowPopups          = !!params.allowPopups;
@@ -428,16 +430,19 @@ function openLinkIn(url, where, params) 
     }
 
     if (aAllowPopups) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_POPUPS;
     }
     if (aIndicateErrorPageLoad) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ERROR_LOAD_CHANGES_RV;
     }
+    if (aForceAllowDataURI) {
+      flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+    }
 
     let {URI_INHERITS_SECURITY_CONTEXT} = Ci.nsIProtocolHandler;
     if (aForceAboutBlankViewerInCurrent &&
         (!uriObj ||
          (doGetProtocolFlags(uriObj) & URI_INHERITS_SECURITY_CONTEXT))) {
       // Unless we know for sure we're not inheriting principals,
       // force the about:blank viewer to have the right principal:
       targetBrowser.createAboutBlankContentViewer(aPrincipal);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1305,16 +1305,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
   bool inheritPrincipal = false;
   bool principalIsExplicit = false;
   bool sendReferrer = true;
   uint32_t referrerPolicy = mozilla::net::RP_Unset;
   bool isSrcdoc = false;
   nsCOMPtr<nsISHEntry> shEntry;
   nsString target;
   nsAutoString srcdoc;
+  bool forceAllowDataURI = false;
   nsCOMPtr<nsIDocShell> sourceDocShell;
   nsCOMPtr<nsIURI> baseURI;
 
   uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
 
   NS_ENSURE_ARG(aURI);
 
   if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
@@ -1341,16 +1342,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
     aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
     aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
     aLoadInfo->GetSendReferrer(&sendReferrer);
     aLoadInfo->GetReferrerPolicy(&referrerPolicy);
     aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
     aLoadInfo->GetSrcdocData(srcdoc);
     aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
     aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
+    aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI);
   }
 
   MOZ_LOG(gDocShellLeakLog, LogLevel::Debug,
           ("nsDocShell[%p]: loading %s with flags 0x%08x",
            this, aURI->GetSpecOrDefault().get(), aLoadFlags));
 
   if (!shEntry &&
       !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
@@ -1604,16 +1606,20 @@ nsDocShell::LoadURI(nsIURI* aURI,
   if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
     flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
   }
 
   if (isSrcdoc) {
     flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
   }
 
+  if (forceAllowDataURI) {
+    flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+  }
+
   return InternalLoad(aURI,
                       originalURI,
                       resultPrincipalURI,
                       loadReplace,
                       referrer,
                       referrerPolicy,
                       triggeringPrincipal,
                       principalToInherit,
@@ -4912,16 +4918,19 @@ nsDocShell::LoadURIWithOptions(const cha
   if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
     popupState = openAllowed;
     aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
   } else {
     popupState = openOverridden;
   }
   nsAutoPopupStatePusher statePusher(popupState);
 
+  bool forceAllowDataURI =
+    aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
+
   // Don't pass certain flags that aren't needed and end up confusing
   // ConvertLoadTypeToDocShellLoadInfo.  We do need to ensure that they are
   // passed to LoadURI though, since it uses them.
   uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
   aLoadFlags &= ~EXTRA_LOAD_FLAGS;
 
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   rv = CreateLoadInfo(getter_AddRefs(loadInfo));
@@ -4942,16 +4951,17 @@ nsDocShell::LoadURIWithOptions(const cha
 
   loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
   loadInfo->SetPostDataStream(postStream);
   loadInfo->SetReferrer(aReferringURI);
   loadInfo->SetReferrerPolicy(aReferrerPolicy);
   loadInfo->SetHeadersStream(aHeaderStream);
   loadInfo->SetBaseURI(aBaseURI);
   loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
+  loadInfo->SetForceAllowDataURI(forceAllowDataURI);
 
   if (fixupInfo) {
     nsAutoString searchProvider, keyword;
     fixupInfo->GetKeywordProviderName(searchProvider);
     fixupInfo->GetKeywordAsSent(keyword);
     MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
   }
 
@@ -10184,16 +10194,17 @@ nsDocShell::InternalLoad(nsIURI* aURI,
         loadInfo->SetLoadReplace(aLoadReplace);
         loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
         loadInfo->SetInheritPrincipal(
           aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
         // Explicit principal because we do not want any guesses as to what the
         // principal to inherit is: it should be aTriggeringPrincipal.
         loadInfo->SetPrincipalIsExplicit(true);
         loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK));
+        loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
 
         rv = win->Open(NS_ConvertUTF8toUTF16(spec),
                        aWindowTarget, // window name
                        EmptyString(), // Features
                        loadInfo,
                        true, // aForceNoOpener
                        getter_AddRefs(newWin));
         MOZ_ASSERT(!newWin);
@@ -10861,17 +10872,19 @@ nsDocShell::InternalLoad(nsIURI* aURI,
 
   net::PredictorLearn(aURI, nullptr,
                       nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, attrs);
   net::PredictorPredict(aURI, nullptr,
                         nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
 
   nsCOMPtr<nsIRequest> req;
   rv = DoURILoad(aURI, aOriginalURI, aResultPrincipalURI, aLoadReplace,
-                 loadFromExternal, aReferrer,
+                 loadFromExternal,
+                 (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
+                 aReferrer,
                  !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
                  aReferrerPolicy,
                  aTriggeringPrincipal, principalToInherit, aTypeHint,
                  aFileName, aPostData, aPostDataLength, aHeadersData,
                  aFirstParty, aDocShell, getter_AddRefs(req),
                  (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
                  (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
                  (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
@@ -10999,16 +11012,17 @@ IsConsideredSameOriginForUIR(nsIPrincipa
 }
 
 nsresult
 nsDocShell::DoURILoad(nsIURI* aURI,
                       nsIURI* aOriginalURI,
                       Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                       bool aLoadReplace,
                       bool aLoadFromExternal,
+                      bool aForceAllowDataURI,
                       nsIURI* aReferrerURI,
                       bool aSendReferrer,
                       uint32_t aReferrerPolicy,
                       nsIPrincipal* aTriggeringPrincipal,
                       nsIPrincipal* aPrincipalToInherit,
                       const char* aTypeHint,
                       const nsAString& aFileName,
                       nsIInputStream* aPostData,
@@ -11179,16 +11193,17 @@ nsDocShell::DoURILoad(nsIURI* aURI,
                    securityFlags) :
       new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
                    securityFlags, aContentPolicyType);
 
   if (aPrincipalToInherit) {
     loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
   }
   loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal);
+  loadInfo->SetForceAllowDataURI(aForceAllowDataURI);
 
   // We have to do this in case our OriginAttributes are different from the
   // OriginAttributes of the parent document. Or in case there isn't a
   // parent document.
   bool isTopLevelDoc = mItemType == typeContent &&
                        (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
                         GetIsMozBrowser());
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -447,16 +447,17 @@ protected:
   // aOriginalURI will be set as the originalURI on the channel that does the
   // load. If aOriginalURI is null, aURI will be set as the originalURI.
   // If aLoadReplace is true, LOAD_REPLACE flag will be set to the nsIChannel.
   nsresult DoURILoad(nsIURI* aURI,
                      nsIURI* aOriginalURI,
                      mozilla::Maybe<nsCOMPtr<nsIURI>> const& aResultPrincipalURI,
                      bool aLoadReplace,
                      bool aLoadFromExternal,
+                     bool aForceAllowDataURI,
                      nsIURI* aReferrer,
                      bool aSendReferrer,
                      uint32_t aReferrerPolicy,
                      nsIPrincipal* aTriggeringPrincipal,
                      nsIPrincipal* aPrincipalToInherit,
                      const char* aTypeHint,
                      const nsAString& aFileName,
                      nsIInputStream* aPostData,
--- a/docshell/base/nsDocShellLoadInfo.cpp
+++ b/docshell/base/nsDocShellLoadInfo.cpp
@@ -62,16 +62,17 @@ SetMaybeResultPrincipalURI(nsIDocShellLo
 
 } // mozilla
 
 nsDocShellLoadInfo::nsDocShellLoadInfo()
   : mResultPrincipalURIIsSome(false)
   , mLoadReplace(false)
   , mInheritPrincipal(false)
   , mPrincipalIsExplicit(false)
+  , mForceAllowDataURI(false)
   , mSendReferrer(true)
   , mReferrerPolicy(mozilla::net::RP_Unset)
   , mLoadType(nsIDocShellLoadInfo::loadNormal)
   , mIsSrcdocLoad(false)
 {
 }
 
 nsDocShellLoadInfo::~nsDocShellLoadInfo()
@@ -205,16 +206,30 @@ nsDocShellLoadInfo::GetPrincipalIsExplic
 NS_IMETHODIMP
 nsDocShellLoadInfo::SetPrincipalIsExplicit(bool aPrincipalIsExplicit)
 {
   mPrincipalIsExplicit = aPrincipalIsExplicit;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShellLoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI)
+{
+  *aForceAllowDataURI = mForceAllowDataURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShellLoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI)
+{
+  mForceAllowDataURI = aForceAllowDataURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShellLoadInfo::GetLoadType(nsDocShellInfoLoadType* aLoadType)
 {
   NS_ENSURE_ARG_POINTER(aLoadType);
 
   *aLoadType = mLoadType;
   return NS_OK;
 }
 
--- a/docshell/base/nsDocShellLoadInfo.h
+++ b/docshell/base/nsDocShellLoadInfo.h
@@ -34,16 +34,17 @@ protected:
   nsCOMPtr<nsIURI> mReferrer;
   nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mResultPrincipalURI;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mResultPrincipalURIIsSome;
   bool mLoadReplace;
   bool mInheritPrincipal;
   bool mPrincipalIsExplicit;
+  bool mForceAllowDataURI;
   bool mSendReferrer;
   nsDocShellInfoReferrerPolicy mReferrerPolicy;
   nsDocShellInfoLoadType mLoadType;
   nsCOMPtr<nsISHEntry> mSHEntry;
   nsString mTarget;
   nsCOMPtr<nsIInputStream> mPostDataStream;
   nsCOMPtr<nsIInputStream> mHeadersStream;
   bool mIsSrcdocLoad;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -122,16 +122,19 @@ interface nsIDocShell : nsIDocShellTreeI
   const long INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER       = 0x10;
   const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES     = 0x20;
 
   // Whether the load should be treated as srcdoc load, rather than a URI one.
   const long INTERNAL_LOAD_FLAGS_IS_SRCDOC               = 0x40;
 
   const long INTERNAL_LOAD_FLAGS_NO_OPENER               = 0x100;
 
+  // Whether a top-level data URI navigation is allowed for that load
+  const long INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI    = 0x200;
+
   // NB: 0x80 is available.
 
   /**
    * Loads the given URI.  This method is identical to loadURI(...) except
    * that its parameter list is broken out instead of being packaged inside
    * of an nsIDocShellLoadInfo object...
    *
    * @param aURI                 - The URI to load.
--- a/docshell/base/nsIDocShellLoadInfo.idl
+++ b/docshell/base/nsIDocShellLoadInfo.idl
@@ -60,16 +60,22 @@ interface nsIDocShellLoadInfo : nsISuppo
     /** If this attribute is true only ever use the principal specified
      *  by the triggeringPrincipal and inheritPrincipal attributes.
      *  If there are security reasons for why this is unsafe, such
      *  as trying to use a systemprincipal as the triggeringPrincipal
      *  for a content docshell the load fails.
      */
     attribute boolean principalIsExplicit;
 
+    /**
+     * If this attribute is true, then a top-level navigation
+     * to a data URI will be allowed.
+     */
+    attribute boolean forceAllowDataURI;
+
     /* these are load type enums... */
     const long loadNormal = 0;                     // Normal Load
     const long loadNormalReplace = 1;              // Normal Load but replaces current history slot
     const long loadHistory = 2;                    // Load from history
     const long loadReloadNormal = 3;               // Reload
     const long loadReloadBypassCache = 4;
     const long loadReloadBypassProxy = 5;
     const long loadReloadBypassProxyAndCache = 6;
--- a/docshell/base/nsIWebNavigation.idl
+++ b/docshell/base/nsIWebNavigation.idl
@@ -202,16 +202,22 @@ interface nsIWebNavigation : nsISupports
   const unsigned long LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP = 0x100000;
 
   /**
    * This flag specifies that common scheme typos should be corrected.
    */
   const unsigned long LOAD_FLAGS_FIXUP_SCHEME_TYPOS = 0x200000;
 
   /**
+   * Allows a top-level data: navigation to occur. E.g. view-image
+   * is an explicit user action which should be allowed.
+   */
+  const unsigned long LOAD_FLAGS_FORCE_ALLOW_DATA_URI = 0x400000;
+
+  /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URI dispatcher will go through its normal process of content
    * loading.
    *
    * @param aURI
    *        The URI string to load.  For HTTP and FTP URLs and possibly others,
    *        characters above U+007F will be converted to UTF-8 and then URL-
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -43,16 +43,20 @@ nsContentSecurityManager::AllowTopLevelN
   }
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   if (!loadInfo) {
     return true;
   }
   if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
     return true;
   }
+  if (loadInfo->GetForceAllowDataURI()) {
+    // if the loadinfo explicitly allows the data URI navigation, let's allow it now
+    return true;
+  }
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, true);
   bool isDataURI =
     (NS_SUCCEEDED(uri->SchemeIs("data", &isDataURI)) && isDataURI);
   if (!isDataURI) {
     return true;
   }
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -382,16 +382,17 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
       sandboxedLoadingPrincipalInfo,
       optionalResultPrincipalURI,
       aLoadInfo->GetSecurityFlags(),
       aLoadInfo->InternalContentPolicyType(),
       static_cast<uint32_t>(aLoadInfo->GetTainting()),
       aLoadInfo->GetUpgradeInsecureRequests(),
       aLoadInfo->GetVerifySignedContent(),
       aLoadInfo->GetEnforceSRI(),
+      aLoadInfo->GetForceAllowDataURI(),
       aLoadInfo->GetForceInheritPrincipalDropped(),
       aLoadInfo->GetInnerWindowID(),
       aLoadInfo->GetOuterWindowID(),
       aLoadInfo->GetParentOuterWindowID(),
       aLoadInfo->GetTopOuterWindowID(),
       aLoadInfo->GetFrameOuterWindowID(),
       aLoadInfo->GetEnforceSecurity(),
       aLoadInfo->GetInitialSecurityCheckDone(),
@@ -490,16 +491,17 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
                           sandboxedLoadingPrincipal,
                           resultPrincipalURI,
                           loadInfoArgs.securityFlags(),
                           loadInfoArgs.contentPolicyType(),
                           static_cast<LoadTainting>(loadInfoArgs.tainting()),
                           loadInfoArgs.upgradeInsecureRequests(),
                           loadInfoArgs.verifySignedContent(),
                           loadInfoArgs.enforceSRI(),
+                          loadInfoArgs.forceAllowDataURI(),
                           loadInfoArgs.forceInheritPrincipalDropped(),
                           loadInfoArgs.innerWindowID(),
                           loadInfoArgs.outerWindowID(),
                           loadInfoArgs.parentOuterWindowID(),
                           loadInfoArgs.topOuterWindowID(),
                           loadInfoArgs.frameOuterWindowID(),
                           loadInfoArgs.enforceSecurity(),
                           loadInfoArgs.initialSecurityCheckDone(),
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -53,16 +53,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mLoadingContext(do_GetWeakReference(aLoadingContext))
   , mContextForTopLevelLoad(nullptr)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
   , mEnforceSRI(false)
+  , mForceAllowDataURI(false)
   , mForceInheritPrincipalDropped(false)
   , mInnerWindowID(0)
   , mOuterWindowID(0)
   , mParentOuterWindowID(0)
   , mTopOuterWindowID(0)
   , mFrameOuterWindowID(0)
   , mEnforceSecurity(false)
   , mInitialSecurityCheckDone(false)
@@ -236,16 +237,17 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
   , mPrincipalToInherit(nullptr)
   , mContextForTopLevelLoad(do_GetWeakReference(aContextForTopLevelLoad))
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(nsIContentPolicy::TYPE_DOCUMENT)
   , mTainting(LoadTainting::Basic)
   , mUpgradeInsecureRequests(false)
   , mVerifySignedContent(false)
   , mEnforceSRI(false)
+  , mForceAllowDataURI(false)
   , mForceInheritPrincipalDropped(false)
   , mInnerWindowID(0)
   , mOuterWindowID(0)
   , mParentOuterWindowID(0)
   , mTopOuterWindowID(0)
   , mFrameOuterWindowID(0)
   , mEnforceSecurity(false)
   , mInitialSecurityCheckDone(false)
@@ -304,16 +306,17 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   , mLoadingContext(rhs.mLoadingContext)
   , mContextForTopLevelLoad(rhs.mContextForTopLevelLoad)
   , mSecurityFlags(rhs.mSecurityFlags)
   , mInternalContentPolicyType(rhs.mInternalContentPolicyType)
   , mTainting(rhs.mTainting)
   , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests)
   , mVerifySignedContent(rhs.mVerifySignedContent)
   , mEnforceSRI(rhs.mEnforceSRI)
+  , mForceAllowDataURI(rhs.mForceAllowDataURI)
   , mForceInheritPrincipalDropped(rhs.mForceInheritPrincipalDropped)
   , mInnerWindowID(rhs.mInnerWindowID)
   , mOuterWindowID(rhs.mOuterWindowID)
   , mParentOuterWindowID(rhs.mParentOuterWindowID)
   , mTopOuterWindowID(rhs.mTopOuterWindowID)
   , mFrameOuterWindowID(rhs.mFrameOuterWindowID)
   , mEnforceSecurity(rhs.mEnforceSecurity)
   , mInitialSecurityCheckDone(rhs.mInitialSecurityCheckDone)
@@ -341,16 +344,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    nsIPrincipal* aSandboxedLoadingPrincipal,
                    nsIURI* aResultPrincipalURI,
                    nsSecurityFlags aSecurityFlags,
                    nsContentPolicyType aContentPolicyType,
                    LoadTainting aTainting,
                    bool aUpgradeInsecureRequests,
                    bool aVerifySignedContent,
                    bool aEnforceSRI,
+                   bool aForceAllowDataURI,
                    bool aForceInheritPrincipalDropped,
                    uint64_t aInnerWindowID,
                    uint64_t aOuterWindowID,
                    uint64_t aParentOuterWindowID,
                    uint64_t aTopOuterWindowID,
                    uint64_t aFrameOuterWindowID,
                    bool aEnforceSecurity,
                    bool aInitialSecurityCheckDone,
@@ -373,16 +377,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mPrincipalToInherit(aPrincipalToInherit)
   , mResultPrincipalURI(aResultPrincipalURI)
   , mSecurityFlags(aSecurityFlags)
   , mInternalContentPolicyType(aContentPolicyType)
   , mTainting(aTainting)
   , mUpgradeInsecureRequests(aUpgradeInsecureRequests)
   , mVerifySignedContent(aVerifySignedContent)
   , mEnforceSRI(aEnforceSRI)
+  , mForceAllowDataURI(aForceAllowDataURI)
   , mForceInheritPrincipalDropped(aForceInheritPrincipalDropped)
   , mInnerWindowID(aInnerWindowID)
   , mOuterWindowID(aOuterWindowID)
   , mParentOuterWindowID(aParentOuterWindowID)
   , mTopOuterWindowID(aTopOuterWindowID)
   , mFrameOuterWindowID(aFrameOuterWindowID)
   , mEnforceSecurity(aEnforceSecurity)
   , mInitialSecurityCheckDone(aInitialSecurityCheckDone)
@@ -747,16 +752,33 @@ LoadInfo::SetEnforceSRI(bool aEnforceSRI
 NS_IMETHODIMP
 LoadInfo::GetEnforceSRI(bool* aResult)
 {
   *aResult = mEnforceSRI;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+LoadInfo::SetForceAllowDataURI(bool aForceAllowDataURI)
+{
+  MOZ_ASSERT(!mForceAllowDataURI ||
+             mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
+             "can only allow data URI navigation for TYPE_DOCUMENT");
+  mForceAllowDataURI = aForceAllowDataURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetForceAllowDataURI(bool* aForceAllowDataURI)
+{
+  *aForceAllowDataURI = mForceAllowDataURI;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 LoadInfo::GetForceInheritPrincipalDropped(bool* aResult)
 {
   *aResult = mForceInheritPrincipalDropped;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 LoadInfo::GetInnerWindowID(uint64_t* aResult)
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -98,16 +98,17 @@ private:
            nsIPrincipal* aSandboxedLoadingPrincipal,
            nsIURI* aResultPrincipalURI,
            nsSecurityFlags aSecurityFlags,
            nsContentPolicyType aContentPolicyType,
            LoadTainting aTainting,
            bool aUpgradeInsecureRequests,
            bool aVerifySignedContent,
            bool aEnforceSRI,
+           bool aForceAllowDataURI,
            bool aForceInheritPrincipalDropped,
            uint64_t aInnerWindowID,
            uint64_t aOuterWindowID,
            uint64_t aParentOuterWindowID,
            uint64_t aTopOuterWindowID,
            uint64_t aFrameOuterWindowID,
            bool aEnforceSecurity,
            bool aInitialSecurityCheckDone,
@@ -154,16 +155,17 @@ private:
   nsWeakPtr                        mLoadingContext;
   nsWeakPtr                        mContextForTopLevelLoad;
   nsSecurityFlags                  mSecurityFlags;
   nsContentPolicyType              mInternalContentPolicyType;
   LoadTainting                     mTainting;
   bool                             mUpgradeInsecureRequests;
   bool                             mVerifySignedContent;
   bool                             mEnforceSRI;
+  bool                             mForceAllowDataURI;
   bool                             mForceInheritPrincipalDropped;
   uint64_t                         mInnerWindowID;
   uint64_t                         mOuterWindowID;
   uint64_t                         mParentOuterWindowID;
   uint64_t                         mTopOuterWindowID;
   uint64_t                         mFrameOuterWindowID;
   bool                             mEnforceSecurity;
   bool                             mInitialSecurityCheckDone;
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -502,16 +502,21 @@ interface nsILoadInfo : nsISupports
   [infallible] attribute boolean verifySignedContent;
 
   /**
    * If true, this load will fail if it has no SRI integrity
    */
   [infallible] attribute boolean enforceSRI;
 
   /**
+   * If true, toplevel data: URI navigation is allowed
+   */
+  [infallible] attribute boolean forceAllowDataURI;
+
+  /**
    * The SEC_FORCE_INHERIT_PRINCIPAL flag may be dropped when a load info
    * object is created.  Specifically, it will be dropped if the SEC_SANDBOXED
    * flag is also present.  This flag is set if SEC_FORCE_INHERIT_PRINCIPAL was
    * dropped.
    */
   [infallible] readonly attribute boolean forceInheritPrincipalDropped;
 
   /**
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -42,16 +42,17 @@ struct LoadInfoArgs
   OptionalPrincipalInfo       sandboxedLoadingPrincipalInfo;
   OptionalURIParams           resultPrincipalURI;
   uint32_t                    securityFlags;
   uint32_t                    contentPolicyType;
   uint32_t                    tainting;
   bool                        upgradeInsecureRequests;
   bool                        verifySignedContent;
   bool                        enforceSRI;
+  bool                        forceAllowDataURI;
   bool                        forceInheritPrincipalDropped;
   uint64_t                    innerWindowID;
   uint64_t                    outerWindowID;
   uint64_t                    parentOuterWindowID;
   uint64_t                    topOuterWindowID;
   uint64_t                    frameOuterWindowID;
   bool                        enforceSecurity;
   bool                        initialSecurityCheckDone;