summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-04-22 19:03:22 +0200
committerjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-04-22 19:03:22 +0200
commitf1e5578718ea8883438cfea06d3c55d25f5c0278 (patch)
tree5afce22662aad4e58a894d061ed65ac3ce68cee7
parent1b4c4256ee7705724b02919b4d432b2a391bcd04 (diff)
downloaduxp-f1e5578718ea8883438cfea06d3c55d25f5c0278.tar.gz
moebius#226: Consider blocking top level window data: URIs (part 2/2 without tests)
https://github.com/MoonchildProductions/moebius/pull/226
-rw-r--r--docshell/base/nsDSURIContentListener.cpp9
-rw-r--r--docshell/base/nsDocShell.cpp10
-rw-r--r--dom/security/nsContentSecurityManager.cpp59
-rw-r--r--dom/security/nsContentSecurityManager.h5
-rw-r--r--dom/security/test/general/browser.ini6
-rw-r--r--dom/security/test/general/browser_test_data_download.js37
-rw-r--r--dom/security/test/general/browser_test_data_text_csv.js37
-rw-r--r--dom/security/test/general/file_data_download.html14
-rw-r--r--dom/security/test/general/file_data_text_csv.html14
-rw-r--r--dom/security/test/general/test_block_toplevel_data_img_navigation.html18
-rw-r--r--dom/security/test/general/test_block_toplevel_data_navigation.html16
-rw-r--r--ipc/glue/BackgroundUtils.cpp2
-rw-r--r--netwerk/base/LoadInfo.cpp23
-rw-r--r--netwerk/base/LoadInfo.h2
-rw-r--r--netwerk/base/nsILoadInfo.idl7
-rw-r--r--netwerk/ipc/NeckoChannelParams.ipdlh1
16 files changed, 194 insertions, 66 deletions
diff --git a/docshell/base/nsDSURIContentListener.cpp b/docshell/base/nsDSURIContentListener.cpp
index 93ce3cb264..ee6a4dd623 100644
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -17,6 +17,7 @@
#include "nsIHttpChannel.h"
#include "nsIScriptSecurityManager.h"
#include "nsError.h"
+#include "nsContentSecurityManager.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
@@ -93,6 +94,14 @@ nsDSURIContentListener::DoContent(const nsACString& aContentType,
if (aOpenedChannel) {
aOpenedChannel->GetLoadFlags(&loadFlags);
+
+ // block top-level data URI navigations if triggered by the web
+ if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(aOpenedChannel)) {
+ // logging to console happens within AllowTopLevelNavigationToDataURI
+ aRequest->Cancel(NS_ERROR_DOM_BAD_URI);
+ *aAbortProcess = true;
+ return NS_OK;
+ }
}
if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI) {
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index ae97a7c9e3..596bd5d848 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9885,15 +9885,6 @@ nsDocShell::InternalLoad(nsIURI* aURI,
contentType = nsIContentPolicy::TYPE_DOCUMENT;
}
- if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
- aURI,
- contentType,
- aTriggeringPrincipal,
- (aLoadType == LOAD_NORMAL_EXTERNAL))) {
- // logging to console happens within AllowTopLevelNavigationToDataURI
- return NS_OK;
- }
-
// If there's no targetDocShell, that means we are about to create a new window,
// perform a content policy check before creating the window.
if (!targetDocShell) {
@@ -10962,6 +10953,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
if (aPrincipalToInherit) {
loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
}
+ loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal);
// 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
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index 069e7d6a70..c987fed67b 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -10,20 +10,16 @@
#include "nsIStreamListener.h"
#include "nsIDocument.h"
#include "nsMixedContentBlocker.h"
-#include "nsNullPrincipal.h"
#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabChild.h"
NS_IMPL_ISUPPORTS(nsContentSecurityManager,
nsIContentSecurityManager,
nsIChannelEventSink)
/* static */ bool
-nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
- nsIURI* aURI,
- nsContentPolicyType aContentPolicyType,
- nsIPrincipal* aTriggeringPrincipal,
- bool aLoadFromExternal)
+nsContentSecurityManager::AllowTopLevelNavigationToDataURI(nsIChannel* aChannel)
{
// Let's block all toplevel document navigations to a data: URI.
// In all cases where the toplevel document is navigated to a
@@ -36,17 +32,24 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) {
return true;
}
- if (aContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT) {
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ if (!loadInfo) {
+ return true;
+ }
+ if (loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
return true;
}
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, true);
bool isDataURI =
- (NS_SUCCEEDED(aURI->SchemeIs("data", &isDataURI)) && isDataURI);
+ (NS_SUCCEEDED(uri->SchemeIs("data", &isDataURI)) && isDataURI);
if (!isDataURI) {
return true;
}
// Whitelist data: images as long as they are not SVGs
nsAutoCString filePath;
- aURI->GetFilePath(filePath);
+ uri->GetFilePath(filePath);
if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) &&
!StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) {
return true;
@@ -56,22 +59,29 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/json"))) {
return true;
}
- if (!aLoadFromExternal &&
- nsContentUtils::IsSystemPrincipal(aTriggeringPrincipal)) {
+ // Redirecting to a toplevel data: URI is not allowed, hence we make
+ // sure the RedirectChain is empty.
+ if (!loadInfo->GetLoadTriggeredFromExternal() &&
+ nsContentUtils::IsSystemPrincipal(loadInfo->TriggeringPrincipal()) &&
+ loadInfo->RedirectChain().IsEmpty()) {
return true;
}
nsAutoCString dataSpec;
- aURI->GetSpec(dataSpec);
+ uri->GetSpec(dataSpec);
if (dataSpec.Length() > 50) {
dataSpec.Truncate(50);
dataSpec.AppendLiteral("...");
}
+ nsCOMPtr<nsITabChild> tabChild = do_QueryInterface(loadInfo->ContextForTopLevelLoad());
+ nsCOMPtr<nsIDocument> doc;
+ if (tabChild) {
+ doc = static_cast<mozilla::dom::TabChild*>(tabChild.get())->GetDocument();
+ }
NS_ConvertUTF8toUTF16 specUTF16(NS_UnescapeURL(dataSpec));
const char16_t* params[] = { specUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DATA_URI_BLOCKED"),
- // no doc available, log to browser console
- nullptr,
+ doc,
nsContentUtils::eSECURITY_PROPERTIES,
"BlockTopLevelDataURINavigation",
params, ArrayLength(params));
@@ -541,27 +551,6 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
}
}
- // Redirecting to a toplevel data: URI is not allowed, hence we pass
- // a NullPrincipal as the TriggeringPrincipal to
- // AllowTopLevelNavigationToDataURI() which definitely blocks any
- // data: URI load.
- nsCOMPtr<nsILoadInfo> newLoadInfo = aNewChannel->GetLoadInfo();
- if (newLoadInfo) {
- nsCOMPtr<nsIURI> uri;
- nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(uri));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPrincipal> nullTriggeringPrincipal = nsNullPrincipal::Create();
- if (!nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
- uri,
- newLoadInfo->GetExternalContentPolicyType(),
- nullTriggeringPrincipal,
- false)) {
- // logging to console happens within AllowTopLevelNavigationToDataURI
- aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
- return NS_ERROR_DOM_BAD_URI;
- }
- }
-
// Also verify that the redirecting server is allowed to redirect to the
// given URI
nsCOMPtr<nsIPrincipal> oldPrincipal;
diff --git a/dom/security/nsContentSecurityManager.h b/dom/security/nsContentSecurityManager.h
index 09b6c86aa1..bab8477434 100644
--- a/dom/security/nsContentSecurityManager.h
+++ b/dom/security/nsContentSecurityManager.h
@@ -32,10 +32,7 @@ public:
static nsresult doContentSecurityCheck(nsIChannel* aChannel,
nsCOMPtr<nsIStreamListener>& aInAndOutListener);
- static bool AllowTopLevelNavigationToDataURI(nsIURI* aURI,
- nsContentPolicyType aContentPolicyType,
- nsIPrincipal* aTriggeringPrincipal,
- bool aLoadFromExternal);
+ static bool AllowTopLevelNavigationToDataURI(nsIChannel* aChannel);
private:
static nsresult CheckChannel(nsIChannel* aChannel);
diff --git a/dom/security/test/general/browser.ini b/dom/security/test/general/browser.ini
index 97ddae3bf3..73ae72dddd 100644
--- a/dom/security/test/general/browser.ini
+++ b/dom/security/test/general/browser.ini
@@ -3,3 +3,9 @@
support-files =
file_toplevel_data_navigations.sjs
file_toplevel_data_meta_redirect.html
+[browser_test_data_download.js]
+support-files =
+ file_data_download.html
+[browser_test_data_text_csv.js]
+support-files =
+ file_data_text_csv.html
diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js
new file mode 100644
index 0000000000..1ee8d58449
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_download.js
@@ -0,0 +1,37 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kTestURI = kTestPath + "file_data_download.html";
+
+function addWindowListener(aURL, aCallback) {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ waitForFocus(function() {
+ is(domwindow.document.location.href, aURL, "should have seen the right window open");
+ aCallback(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) { },
+ onWindowTitleChange(aXULWindow, aNewTitle) { }
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+ });
+ addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
+ is(win.document.getElementById("location").value, "data-foo.html",
+ "file name of download should match");
+ win.close();
+ finish();
+ });
+ gBrowser.loadURI(kTestURI);
+}
diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js
new file mode 100644
index 0000000000..c45e40cc2e
--- /dev/null
+++ b/dom/security/test/general/browser_test_data_text_csv.js
@@ -0,0 +1,37 @@
+"use strict";
+
+const kTestPath = getRootDirectory(gTestPath)
+ .replace("chrome://mochitests/content", "http://example.com")
+const kTestURI = kTestPath + "file_data_text_csv.html";
+
+function addWindowListener(aURL, aCallback) {
+ Services.wm.addListener({
+ onOpenWindow(aXULWindow) {
+ info("window opened, waiting for focus");
+ Services.wm.removeListener(this);
+ var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ waitForFocus(function() {
+ is(domwindow.document.location.href, aURL, "should have seen the right window open");
+ aCallback(domwindow);
+ }, domwindow);
+ },
+ onCloseWindow(aXULWindow) { },
+ onWindowTitleChange(aXULWindow, aNewTitle) { }
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+ Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
+ registerCleanupFunction(function() {
+ Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
+ });
+ addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
+ is(win.document.getElementById("location").value, "text/csv;foo,bar,foobar",
+ "file name of download should match");
+ win.close();
+ finish();
+ });
+ gBrowser.loadURI(kTestURI);
+}
diff --git a/dom/security/test/general/file_data_download.html b/dom/security/test/general/file_data_download.html
new file mode 100644
index 0000000000..4cc92fe8f5
--- /dev/null
+++ b/dom/security/test/general/file_data_download.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test download attribute for data: URI</title>
+</head>
+<body>
+ <a href="data:text/html,<body>data download</body>" download="data-foo.html" id="testlink">download data</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/file_data_text_csv.html b/dom/security/test/general/file_data_text_csv.html
new file mode 100644
index 0000000000..a9ac369d16
--- /dev/null
+++ b/dom/security/test/general/file_data_text_csv.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test open data:text/csv</title>
+</head>
+<body>
+ <a href="data:text/csv;foo,bar,foobar" id="testlink">test text/csv</a>
+ <script>
+ // click the link to have the downoad panel appear
+ let testlink = document.getElementById("testlink");
+ testlink.click();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/test_block_toplevel_data_img_navigation.html b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
index 2b8f62760a..7f8dfc7480 100644
--- a/dom/security/test/general/test_block_toplevel_data_img_navigation.html
+++ b/dom/security/test/general/test_block_toplevel_data_img_navigation.html
@@ -34,15 +34,17 @@ function test_toplevel_data_image_svg() {
const DATA_SVG =
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==";
let win2 = window.open(DATA_SVG);
- let wrappedWin2 = SpecialPowers.wrap(win2);
- setTimeout(function () {
- isnot(wrappedWin2.document.documentElement.localName, "svg",
- "Loading data:image/svg+xml should be blocked");
- wrappedWin2.close();
- SimpleTest.finish();
- }, 1000);
+ // Unfortunately we can't detect whether the window was closed using some event,
+ // hence we are constantly polling till we see that win == null.
+ // Test times out on failure.
+ var win2Closed = setInterval(function() {
+ if (win2 == null || win2.closed) {
+ clearInterval(win2Closed);
+ ok(true, "Loading data:image/svg+xml should be blocked");
+ SimpleTest.finish();
+ }
+ }, 200);
}
-
// fire up the tests
test_toplevel_data_image();
diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html
index fc91f2ec0a..cef232b65a 100644
--- a/dom/security/test/general/test_block_toplevel_data_navigation.html
+++ b/dom/security/test/general/test_block_toplevel_data_navigation.html
@@ -21,16 +21,12 @@ function test1() {
// simple data: URI click navigation should be prevented
let TEST_FILE = "file_block_toplevel_data_navigation.html";
let win1 = window.open(TEST_FILE);
- var readyStateCheckInterval = setInterval(function() {
- let state = win1.document.readyState;
- if (state === "interactive" || state === "complete") {
- clearInterval(readyStateCheckInterval);
- ok(win1.document.body.innerHTML.indexOf("test1:") !== -1,
- "toplevel data: URI navigation through click() should be blocked");
- win1.close();
- test2();
- }
- }, 200);
+ setTimeout(function () {
+ ok(SpecialPowers.wrap(win1).document.body.innerHTML.indexOf("test1:") !== -1,
+ "toplevel data: URI navigation through click() should be blocked");
+ win1.close();
+ test2();
+ }, 1000);
}
function test2() {
diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp
index b335f5c23d..4cfbe8758f 100644
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -294,6 +294,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
aLoadInfo->CorsUnsafeHeaders(),
aLoadInfo->GetForcePreflight(),
aLoadInfo->GetIsPreflight(),
+ aLoadInfo->GetLoadTriggeredFromExternal(),
aLoadInfo->GetForceHSTSPriming(),
aLoadInfo->GetMixedContentWouldBlock());
@@ -370,6 +371,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
loadInfoArgs.corsUnsafeHeaders(),
loadInfoArgs.forcePreflight(),
loadInfoArgs.isPreflight(),
+ loadInfoArgs.loadTriggeredFromExternal(),
loadInfoArgs.forceHSTSPriming(),
loadInfoArgs.mixedContentWouldBlock()
);
diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp
index 42fdea4a18..2f10261cb3 100644
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -7,6 +7,7 @@
#include "mozilla/LoadInfo.h"
#include "mozilla/Assertions.h"
+#include "mozilla/dom/TabChild.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozIThirdPartyUtil.h"
#include "nsFrameLoader.h"
@@ -63,6 +64,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
, mIsThirdPartyContext(false)
, mForcePreflight(false)
, mIsPreflight(false)
+ , mLoadTriggeredFromExternal(false)
, mForceHSTSPriming(false)
, mMixedContentWouldBlock(false)
{
@@ -235,6 +237,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
, mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party.
, mForcePreflight(false)
, mIsPreflight(false)
+ , mLoadTriggeredFromExternal(false)
, mForceHSTSPriming(false)
, mMixedContentWouldBlock(false)
{
@@ -297,6 +300,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
, mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders)
, mForcePreflight(rhs.mForcePreflight)
, mIsPreflight(rhs.mIsPreflight)
+ , mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal)
, mForceHSTSPriming(rhs.mForceHSTSPriming)
, mMixedContentWouldBlock(rhs.mMixedContentWouldBlock)
{
@@ -325,6 +329,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
const nsTArray<nsCString>& aCorsUnsafeHeaders,
bool aForcePreflight,
bool aIsPreflight,
+ bool aLoadTriggeredFromExternal,
bool aForceHSTSPriming,
bool aMixedContentWouldBlock)
: mLoadingPrincipal(aLoadingPrincipal)
@@ -348,6 +353,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
, mCorsUnsafeHeaders(aCorsUnsafeHeaders)
, mForcePreflight(aForcePreflight)
, mIsPreflight(aIsPreflight)
+ , mLoadTriggeredFromExternal(aLoadTriggeredFromExternal)
, mForceHSTSPriming (aForceHSTSPriming)
, mMixedContentWouldBlock(aMixedContentWouldBlock)
{
@@ -873,6 +879,23 @@ LoadInfo::GetIsPreflight(bool* aIsPreflight)
}
NS_IMETHODIMP
+LoadInfo::SetLoadTriggeredFromExternal(bool aLoadTriggeredFromExternal)
+{
+ MOZ_ASSERT(!aLoadTriggeredFromExternal ||
+ mInternalContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
+ "can only set load triggered from external for TYPE_DOCUMENT");
+ mLoadTriggeredFromExternal = aLoadTriggeredFromExternal;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetLoadTriggeredFromExternal(bool* aLoadTriggeredFromExternal)
+{
+ *aLoadTriggeredFromExternal = mLoadTriggeredFromExternal;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
LoadInfo::GetForceHSTSPriming(bool* aForceHSTSPriming)
{
*aForceHSTSPriming = mForceHSTSPriming;
diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h
index 3e1b92ff4c..99deae2d25 100644
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -108,6 +108,7 @@ private:
const nsTArray<nsCString>& aUnsafeHeaders,
bool aForcePreflight,
bool aIsPreflight,
+ bool aLoadTriggeredFromExternal,
bool aForceHSTSPriming,
bool aMixedContentWouldBlock);
LoadInfo(const LoadInfo& rhs);
@@ -152,6 +153,7 @@ private:
nsTArray<nsCString> mCorsUnsafeHeaders;
bool mForcePreflight;
bool mIsPreflight;
+ bool mLoadTriggeredFromExternal;
bool mForceHSTSPriming : 1;
bool mMixedContentWouldBlock : 1;
diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl
index 78433c8b88..5b5eb425a6 100644
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -575,6 +575,13 @@ interface nsILoadInfo : nsISupports
[infallible] attribute boolean initialSecurityCheckDone;
/**
+ * Returns true if the load was triggered from an external application
+ * (e.g. Thunderbird). Please note that this flag will only ever be true
+ * if the load is of TYPE_DOCUMENT.
+ */
+ [infallible] attribute boolean loadTriggeredFromExternal;
+
+ /**
* Whenever a channel gets redirected, append the principal of the
* channel [before the channels got redirected] to the loadinfo,
* so that at every point this array lets us reason about all the
diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh
index 9365397d19..e1438caccb 100644
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -53,6 +53,7 @@ struct LoadInfoArgs
nsCString[] corsUnsafeHeaders;
bool forcePreflight;
bool isPreflight;
+ bool loadTriggeredFromExternal;
bool forceHSTSPriming;
bool mixedContentWouldBlock;
};