Bug 1493599 - Expose reason of security blocking on nsILoadInfo and add new http observer notification for failed asyncOpens, r=Honza,dragana

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Honza Bambas 2019-04-26 10:59:41 +00:00
parent 99a71d624d
commit 5f945421d4
24 changed files with 324 additions and 37 deletions

View File

@ -132,6 +132,8 @@ function NetworkObserver(filters, owner) {
DevToolsUtils.makeInfallible(this._httpResponseExaminer).bind(this);
this._httpModifyExaminer =
DevToolsUtils.makeInfallible(this._httpModifyExaminer).bind(this);
this._httpFailedOpening =
DevToolsUtils.makeInfallible(this._httpFailedOpening).bind(this);
this._serviceWorkerRequest = this._serviceWorkerRequest.bind(this);
this._throttleData = null;
@ -207,6 +209,9 @@ NetworkObserver.prototype = {
"http-on-examine-cached-response");
Services.obs.addObserver(this._httpModifyExaminer,
"http-on-modify-request");
} else {
Services.obs.addObserver(this._httpFailedOpening,
"http-on-failed-opening-request");
}
// In child processes, only watch for service worker requests
// everything else only happens in the parent process
@ -244,6 +249,27 @@ NetworkObserver.prototype = {
this._httpResponseExaminer(channel, "http-on-examine-cached-response");
},
/**
* Observes for http-on-failed-opening-request notification to catch any
* channels for which asyncOpen has synchronously failed. This is the only
* place to catch early security check failures.
*/
_httpFailedOpening: function(subject, topic) {
if (!this.owner ||
(topic != "http-on-failed-opening-request") ||
!(subject instanceof Ci.nsIHttpChannel)) {
return;
}
const channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!matchRequest(channel, this.filters)) {
return;
}
"add your handling code here";
},
/**
* Observe notifications for the http-on-examine-response topic, coming from
* the nsIObserverService.
@ -1131,6 +1157,9 @@ NetworkObserver.prototype = {
"http-on-examine-cached-response");
Services.obs.removeObserver(this._httpModifyExaminer,
"http-on-modify-request");
} else {
Services.obs.removeObserver(this._httpFailedOpening,
"http-on-failed-opening-request");
}
Services.obs.removeObserver(this._serviceWorkerRequest,

View File

@ -16,6 +16,7 @@
#include "nsIProtocolHandler.h"
#include "nsScriptSecurityManager.h"
#include "mozilla/dom/Document.h"
#include "mozilla/ScopeExit.h"
#include "nsINode.h"
#include "nsIDOMWindow.h"
#include "nsIURI.h"
@ -39,6 +40,13 @@ nsDataDocumentContentPolicy::ShouldLoad(nsIURI *aContentLocation,
nsILoadInfo *aLoadInfo,
const nsACString &aMimeGuess,
int16_t *aDecision) {
auto setBlockingReason = MakeScopeExit([&]() {
if (NS_CP_REJECTED(*aDecision)) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_DATA_DOCUMENT);
}
});
uint32_t contentType = aLoadInfo->GetExternalContentPolicyType();
nsCOMPtr<nsISupports> requestingContext = aLoadInfo->GetLoadingContext();

View File

@ -56,6 +56,9 @@ nsNoDataProtocolContentPolicy::ShouldLoad(nsIURI *aContentLocation,
aContentLocation, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
&shouldBlock);
if (NS_SUCCEEDED(rv) && shouldBlock) {
NS_SetRequestBlockingReason(
aLoadInfo,
nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_NO_DATA_PROTOCOL);
*aDecision = nsIContentPolicy::REJECT_REQUEST;
}
}

View File

@ -196,6 +196,9 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
// if the preload policy already denied the load, then there
// is no point in checking the real policy
if (NS_CP_REJECTED(*aDecision)) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_PRELOAD);
return NS_OK;
}
}
@ -213,6 +216,12 @@ CSPService::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
nullptr, // no redirect, aOriginal URL is null.
aLoadInfo->GetSendCSPViolationEvents(), cspNonce,
aDecision);
if (NS_CP_REJECTED(*aDecision)) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_GENERAL);
}
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;

View File

@ -616,6 +616,9 @@ static nsresult DoContentSecurityChecks(nsIChannel* aChannel,
nsContentUtils::GetContentPolicy());
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
NS_SetRequestBlockingReasonIfNull(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_GENERAL);
if ((NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) &&
(contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT)) {

View File

@ -361,6 +361,12 @@ nsMixedContentBlocker::ShouldLoad(nsIURI* aContentLocation,
ShouldLoad(false, // aHadInsecureImageRedirect
contentType, aContentLocation, requestingLocation,
requestingContext, aMimeGuess, requestPrincipal, aDecision);
if (*aDecision == nsIContentPolicy::REJECT_REQUEST) {
NS_SetRequestBlockingReason(aLoadInfo,
nsILoadInfo::BLOCKING_REASON_MIXED_BLOCKED);
}
return rv;
}
@ -1089,6 +1095,8 @@ nsMixedContentBlocker::ShouldProcess(nsIURI* aContentLocation,
return NS_OK;
}
NS_SetRequestBlockingReason(aLoadInfo,
nsILoadInfo::BLOCKING_REASON_MIXED_BLOCKED);
*aDecision = REJECT_REQUEST;
return NS_ERROR_FAILURE;
}

View File

@ -15,6 +15,7 @@
#include "nsIObjectLoadingContent.h"
#include "mozilla/ArrayUtils.h"
#include "nsContentUtils.h"
#include "nsNetUtil.h"
// Possible behavior pref values
// Those map to the nsIPermissionManager values where possible
@ -190,6 +191,9 @@ nsContentBlocker::ShouldLoad(nsIURI *aContentLocation, nsILoadInfo *aLoadInfo,
&shouldLoad, &fromPrefs);
NS_ENSURE_SUCCESS(rv, rv);
if (!shouldLoad) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_CONTENT_BLOCKED);
if (fromPrefs) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
} else {
@ -242,6 +246,10 @@ nsContentBlocker::ShouldProcess(nsIURI *aContentLocation,
contentType, &shouldLoad, &fromPrefs);
NS_ENSURE_SUCCESS(rv, rv);
if (!shouldLoad) {
NS_SetRequestBlockingReason(
aLoadInfo,
nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_CONTENT_BLOCKED);
if (fromPrefs) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
} else {

View File

@ -534,7 +534,8 @@ nsresult LoadInfoToLoadInfoArgs(nsILoadInfo* aLoadInfo,
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetDocumentHasLoaded(), cspNonce,
aLoadInfo->GetIsFromProcessingFrameAttributes(), cookieSettingsArgs));
aLoadInfo->GetIsFromProcessingFrameAttributes(), cookieSettingsArgs,
aLoadInfo->GetRequestBlockingReason()));
return NS_OK;
}
@ -685,7 +686,8 @@ nsresult LoadInfoArgsToLoadInfo(
loadInfoArgs.isPreflight(), loadInfoArgs.loadTriggeredFromExternal(),
loadInfoArgs.serviceWorkerTaintingSynthesized(),
loadInfoArgs.documentHasUserInteracted(),
loadInfoArgs.documentHasLoaded(), loadInfoArgs.cspNonce());
loadInfoArgs.documentHasLoaded(), loadInfoArgs.cspNonce(),
loadInfoArgs.requestBlockingReason());
if (loadInfoArgs.isFromProcessingFrameAttributes()) {
loadInfo->SetIsFromProcessingFrameAttributes();
@ -703,7 +705,8 @@ void LoadInfoToParentLoadInfoForwarder(
false, // serviceWorkerTaintingSynthesized
false, // documentHasUserInteracted
false, // documentHasLoaded
Maybe<CookieSettingsArgs>());
Maybe<CookieSettingsArgs>(),
nsILoadInfo::BLOCKING_REASON_NONE); // requestBlockingReason
return;
}
@ -731,7 +734,8 @@ void LoadInfoToParentLoadInfoForwarder(
aLoadInfo->GetAllowInsecureRedirectToDataURI(), ipcController, tainting,
aLoadInfo->GetServiceWorkerTaintingSynthesized(),
aLoadInfo->GetDocumentHasUserInteracted(),
aLoadInfo->GetDocumentHasLoaded(), cookieSettingsArgs);
aLoadInfo->GetDocumentHasLoaded(), cookieSettingsArgs,
aLoadInfo->GetRequestBlockingReason());
}
nsresult MergeParentLoadInfoForwarder(
@ -763,6 +767,8 @@ nsresult MergeParentLoadInfoForwarder(
aForwarderArgs.documentHasUserInteracted()));
MOZ_ALWAYS_SUCCEEDS(
aLoadInfo->SetDocumentHasLoaded(aForwarderArgs.documentHasLoaded()));
MOZ_ALWAYS_SUCCEEDS(aLoadInfo->SetRequestBlockingReason(
aForwarderArgs.requestBlockingReason()));
const Maybe<CookieSettingsArgs>& cookieSettingsArgs =
aForwarderArgs.cookieSettings();

View File

@ -90,6 +90,7 @@ LoadInfo::LoadInfo(
mIsThirdPartyContext(false),
mIsDocshellReload(false),
mSendCSPViolationEvents(true),
mRequestBlockingReason(BLOCKING_REASON_NONE),
mForcePreflight(false),
mIsPreflight(false),
mLoadTriggeredFromExternal(false),
@ -355,6 +356,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
mIsThirdPartyContext(false), // NB: TYPE_DOCUMENT implies !third-party.
mIsDocshellReload(false),
mSendCSPViolationEvents(true),
mRequestBlockingReason(BLOCKING_REASON_NONE),
mForcePreflight(false),
mIsPreflight(false),
mLoadTriggeredFromExternal(false),
@ -466,6 +468,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
mAncestorPrincipals(rhs.mAncestorPrincipals),
mAncestorOuterWindowIDs(rhs.mAncestorOuterWindowIDs),
mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders),
mRequestBlockingReason(rhs.mRequestBlockingReason),
mForcePreflight(rhs.mForcePreflight),
mIsPreflight(rhs.mIsPreflight),
mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal),
@ -507,7 +510,8 @@ LoadInfo::LoadInfo(
const nsTArray<nsCString>& aCorsUnsafeHeaders, bool aForcePreflight,
bool aIsPreflight, bool aLoadTriggeredFromExternal,
bool aServiceWorkerTaintingSynthesized, bool aDocumentHasUserInteracted,
bool aDocumentHasLoaded, const nsAString& aCspNonce)
bool aDocumentHasLoaded, const nsAString& aCspNonce,
uint32_t aRequestBlockingReason)
: mLoadingPrincipal(aLoadingPrincipal),
mTriggeringPrincipal(aTriggeringPrincipal),
mPrincipalToInherit(aPrincipalToInherit),
@ -549,6 +553,7 @@ LoadInfo::LoadInfo(
mAncestorPrincipals(std::move(aAncestorPrincipals)),
mAncestorOuterWindowIDs(aAncestorOuterWindowIDs),
mCorsUnsafeHeaders(aCorsUnsafeHeaders),
mRequestBlockingReason(aRequestBlockingReason),
mForcePreflight(aForcePreflight),
mIsPreflight(aIsPreflight),
mLoadTriggeredFromExternal(aLoadTriggeredFromExternal),
@ -1351,6 +1356,17 @@ LoadInfo::SetResultPrincipalURI(nsIURI* aURI) {
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::SetRequestBlockingReason(uint32_t aReason) {
mRequestBlockingReason = aReason;
return NS_OK;
}
NS_IMETHODIMP
LoadInfo::GetRequestBlockingReason(uint32_t* aReason) {
*aReason = mRequestBlockingReason;
return NS_OK;
}
void LoadInfo::SetClientInfo(const ClientInfo& aClientInfo) {
mClientInfo.emplace(aClientInfo);
}

View File

@ -125,7 +125,7 @@ class LoadInfo final : public nsILoadInfo {
bool aIsPreflight, bool aLoadTriggeredFromExternal,
bool aServiceWorkerTaintingSynthesized,
bool aDocumentHasUserInteracted, bool aDocumentHasLoaded,
const nsAString& aCspNonce);
const nsAString& aCspNonce, uint32_t aRequestBlockingReason);
LoadInfo(const LoadInfo& rhs);
NS_IMETHOD GetRedirects(JSContext* aCx,
@ -198,6 +198,7 @@ class LoadInfo final : public nsILoadInfo {
nsTArray<nsCOMPtr<nsIPrincipal>> mAncestorPrincipals;
nsTArray<uint64_t> mAncestorOuterWindowIDs;
nsTArray<nsCString> mCorsUnsafeHeaders;
uint32_t mRequestBlockingReason;
bool mForcePreflight;
bool mIsPreflight;
bool mLoadTriggeredFromExternal;

View File

@ -384,7 +384,7 @@ interface nsILoadInfo : nsISupports
*/
[binaryname(LoadingContextXPCOM)]
readonly attribute nsISupports loadingContext;
/**
* A C++ friendly version of the loadingContext.
*/
@ -706,7 +706,7 @@ interface nsILoadInfo : nsISupports
/**
* 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.
* if the load is of TYPE_DOCUMENT.
*/
[infallible] attribute boolean loadTriggeredFromExternal;
@ -1069,6 +1069,55 @@ interface nsILoadInfo : nsISupports
*/
attribute AString cspNonce;
/**
* List of possible reasons the request associated with this load info
* may have been blocked, set by various content blocking checkers.
*/
const uint32_t BLOCKING_REASON_NONE = 0;
const uint32_t BLOCKING_REASON_CORSDISABLED = 1001;
const uint32_t BLOCKING_REASON_CORSDIDNOTSUCCEED = 1002;
const uint32_t BLOCKING_REASON_CORSREQUESTNOTHTTP = 1003;
const uint32_t BLOCKING_REASON_CORSMULTIPLEALLOWORIGINNOTALLOWED = 1004;
const uint32_t BLOCKING_REASON_CORSMISSINGALLOWORIGIN = 1005;
const uint32_t BLOCKING_REASON_CORSNOTSUPPORTINGCREDENTIALS = 1006;
const uint32_t BLOCKING_REASON_CORSALLOWORIGINNOTMATCHINGORIGIN = 1007;
const uint32_t BLOCKING_REASON_CORSMISSINGALLOWCREDENTIALS = 1008;
const uint32_t BLOCKING_REASON_CORSORIGINHEADERNOTADDED = 1009;
const uint32_t BLOCKING_REASON_CORSEXTERNALREDIRECTNOTALLOWED = 1010;
const uint32_t BLOCKING_REASON_CORSPREFLIGHTDIDNOTSUCCEED = 1011;
const uint32_t BLOCKING_REASON_CORSINVALIDALLOWMETHOD = 1012;
const uint32_t BLOCKING_REASON_CORSMETHODNOTFOUND = 1013;
const uint32_t BLOCKING_REASON_CORSINVALIDALLOWHEADER = 1014;
const uint32_t BLOCKING_REASON_CORSMISSINGALLOWHEADERFROMPREFLIGHT = 1015;
const uint32_t BLOCKING_REASON_CLASSIFY_MALWARE_URI = 2001;
const uint32_t BLOCKING_REASON_CLASSIFY_PHISHING_URI = 2002;
const uint32_t BLOCKING_REASON_CLASSIFY_UNWANTED_URI = 2003;
const uint32_t BLOCKING_REASON_CLASSIFY_TRACKING_URI = 2004;
const uint32_t BLOCKING_REASON_CLASSIFY_BLOCKED_URI = 2005;
const uint32_t BLOCKING_REASON_CLASSIFY_HARMFUL_URI = 2006;
const uint32_t BLOCKING_REASON_MIXED_BLOCKED = 3001;
// The general reason comes from nsCSPContext::permitsInternal(),
// which is way too generic to distinguish an exact reason.
const uint32_t BLOCKING_REASON_CONTENT_POLICY_GENERAL = 4000;
const uint32_t BLOCKING_REASON_CONTENT_POLICY_NO_DATA_PROTOCOL = 4001;
const uint32_t BLOCKING_REASON_CONTENT_POLICY_WEBEXT = 4002;
const uint32_t BLOCKING_REASON_CONTENT_POLICY_CONTENT_BLOCKED = 4003;
const uint32_t BLOCKING_REASON_CONTENT_POLICY_DATA_DOCUMENT = 4004;
const uint32_t BLOCKING_REASON_CONTENT_POLICY_WEB_BROWSER = 4005;
const uint32_t BLOCKING_REASON_CONTENT_POLICY_PRELOAD = 4006;
/**
* If the request associated with this load info was blocked by some of
* our content or load blockers, the reason can be found here.
* Note that setting this attribute has NO EFFECT on blocking the request.
* This attribute is only informative!
*
* By default the value is '0' - NONE.
* Each write rewrites the last value.
* Can be accessed only on a single thread.
*/
[infallible] attribute unsigned long requestBlockingReason;
/**
* The object in charged to receive CSP violation events. It can be null.
* This attribute will be merged into the CSP object eventually.

View File

@ -3006,6 +3006,32 @@ uint32_t NS_GetDefaultReferrerPolicy(nsIHttpChannel *aChannel, nsIURI *aURI,
return nsIHttpChannel::REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
}
nsresult NS_SetRequestBlockingReason(nsIChannel *channel, uint32_t reason) {
NS_ENSURE_ARG(channel);
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
return NS_SetRequestBlockingReason(loadInfo, reason);
}
nsresult NS_SetRequestBlockingReason(nsILoadInfo *loadInfo, uint32_t reason) {
NS_ENSURE_ARG(loadInfo);
return loadInfo->SetRequestBlockingReason(reason);
}
nsresult NS_SetRequestBlockingReasonIfNull(nsILoadInfo *loadInfo,
uint32_t reason) {
NS_ENSURE_ARG(loadInfo);
uint32_t existingReason;
if (NS_SUCCEEDED(loadInfo->GetRequestBlockingReason(&existingReason)) &&
existingReason != nsILoadInfo::BLOCKING_REASON_NONE) {
return NS_OK;
}
return loadInfo->SetRequestBlockingReason(reason);
}
bool NS_IsOffline() {
bool offline = true;
bool connectivity = true;

View File

@ -944,6 +944,14 @@ uint32_t NS_GetDefaultReferrerPolicy(nsIHttpChannel *aChannel = nullptr,
*/
bool NS_ShouldClassifyChannel(nsIChannel *aChannel);
/**
* Helper to set the blocking reason on loadinfo of the channel.
*/
nsresult NS_SetRequestBlockingReason(nsIChannel *channel, uint32_t reason);
nsresult NS_SetRequestBlockingReason(nsILoadInfo *loadInfo, uint32_t reason);
nsresult NS_SetRequestBlockingReasonIfNull(nsILoadInfo *loadInfo,
uint32_t reason);
namespace mozilla {
namespace net {

View File

@ -140,8 +140,8 @@ struct LoadInfoArgs
bool documentHasLoaded;
nsString cspNonce;
bool isFromProcessingFrameAttributes;
CookieSettingsArgs cookieSettings;
uint32_t requestBlockingReason;
};
/**
@ -175,6 +175,8 @@ struct ParentLoadInfoForwarderArgs
CookieSettingsArgs? cookieSettings;
uint32_t requestBlockingReason;
// IMPORTANT: when you add new properites here you must also update
// LoadInfoToParentLoadInfoForwarder and MergeParentLoadInfoForwarder
// in BackgroundUtils.cpp/.h!

View File

@ -2411,9 +2411,29 @@ HttpChannelChild::GetSecurityInfo(nsISupports** aSecurityInfo) {
NS_IMETHODIMP
HttpChannelChild::AsyncOpen(nsIStreamListener* aListener) {
LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get()));
nsresult rv = AsyncOpenInternal(aListener);
if (NS_FAILED(rv)) {
uint32_t blockingReason = 0;
if (mLoadInfo) {
mLoadInfo->GetRequestBlockingReason(&blockingReason);
}
LOG(
("HttpChannelChild::AsyncOpen failed [this=%p rv=0x%08x "
"blocking-reason=%u]\n",
this, static_cast<uint32_t>(rv), blockingReason));
gHttpHandler->OnFailedOpeningRequest(this);
}
return rv;
}
nsresult HttpChannelChild::AsyncOpenInternal(nsIStreamListener* aListener) {
nsresult rv;
nsCOMPtr<nsIStreamListener> listener = aListener;
nsresult rv =
nsContentSecurityManager::doContentSecurityCheck(this, listener);
rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
if (NS_WARN_IF(NS_FAILED(rv))) {
ReleaseListeners();
return rv;
@ -2427,7 +2447,6 @@ HttpChannelChild::AsyncOpen(nsIStreamListener* aListener) {
nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
"security flags in loadInfo but doContentSecurityCheck() not called");
LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get()));
LogCallingScriptLocation(this);
if (!mLoadGroup && !mCallbacks) {
@ -2479,8 +2498,8 @@ HttpChannelChild::AsyncOpen(nsIStreamListener* aListener) {
mUserSetCookieHeader = cookie;
}
rv = AddCookiesToRequest();
MOZ_ASSERT(NS_SUCCEEDED(rv));
DebugOnly<nsresult> check = AddCookiesToRequest();
MOZ_ASSERT(NS_SUCCEEDED(check));
//
// NOTE: From now on we must return NS_OK; all errors must be handled via

View File

@ -215,6 +215,10 @@ class HttpChannelChild final : public PHttpChannelChild,
const nsAString& aContentType) override;
private:
// We want to handle failure result of AsyncOpen, hence AsyncOpen calls the
// Internal method
nsresult AsyncOpenInternal(nsIStreamListener* aListener);
nsresult AsyncCallImpl(void (HttpChannelChild::*funcPtr)(),
nsRunnableMethod<HttpChannelChild>** retval);

View File

@ -56,11 +56,14 @@ static bool gDisableCORS = false;
static bool gDisableCORSPrivateData = false;
static void LogBlockedRequest(nsIRequest* aRequest, const char* aProperty,
const char16_t* aParam,
const char16_t* aParam, uint32_t aBlockingReason,
nsIHttpChannel* aCreatingChannel) {
nsresult rv = NS_OK;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
NS_SetRequestBlockingReason(channel, aBlockingReason);
nsCOMPtr<nsIURI> aUri;
channel->GetURI(getter_AddRefs(aUri));
nsAutoCString spec;
@ -510,7 +513,8 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
topChannel.swap(mHttpChannel);
if (gDisableCORS) {
LogBlockedRequest(aRequest, "CORSDisabled", nullptr, topChannel);
LogBlockedRequest(aRequest, "CORSDisabled", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSDISABLED, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -518,14 +522,18 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSDidNotSucceed", nullptr, topChannel);
LogBlockedRequest(aRequest, "CORSDidNotSucceed", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
topChannel);
return rv;
}
if (NS_FAILED(status)) {
if (NS_BINDING_ABORTED != status) {
// Don't want to log mere cancellation as an error.
LogBlockedRequest(aRequest, "CORSDidNotSucceed", nullptr, topChannel);
LogBlockedRequest(aRequest, "CORSDidNotSucceed", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
topChannel);
}
return status;
}
@ -533,7 +541,9 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
// Test that things worked on a HTTP level
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
if (!http) {
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr, topChannel);
LogBlockedRequest(aRequest, "CORSRequestNotHttp", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSREQUESTNOTHTTP,
topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -552,15 +562,19 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
// check for duplicate headers
rv = http->VisitOriginalResponseHeaders(visitor);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSMultipleAllowOriginNotAllowed", nullptr,
topChannel);
LogBlockedRequest(
aRequest, "CORSMultipleAllowOriginNotAllowed", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSMULTIPLEALLOWORIGINNOTALLOWED,
topChannel);
return rv;
}
rv = http->GetResponseHeader(
NS_LITERAL_CSTRING("Access-Control-Allow-Origin"), allowedOriginHeader);
if (NS_FAILED(rv)) {
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr, topChannel);
LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWORIGIN,
topChannel);
return rv;
}
@ -574,6 +588,7 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
//
if (mWithCredentials && allowedOriginHeader.EqualsLiteral("*")) {
LogBlockedRequest(aRequest, "CORSNotSupportingCredentials", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSNOTSUPPORTINGCREDENTIALS,
topChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -584,9 +599,11 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
nsContentUtils::GetASCIIOrigin(mOriginHeaderPrincipal, origin);
if (!allowedOriginHeader.Equals(origin)) {
LogBlockedRequest(aRequest, "CORSAllowOriginNotMatchingOrigin",
NS_ConvertUTF8toUTF16(allowedOriginHeader).get(),
topChannel);
LogBlockedRequest(
aRequest, "CORSAllowOriginNotMatchingOrigin",
NS_ConvertUTF8toUTF16(allowedOriginHeader).get(),
nsILoadInfo::BLOCKING_REASON_CORSALLOWORIGINNOTMATCHINGORIGIN,
topChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -599,8 +616,9 @@ nsresult nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest) {
allowCredentialsHeader);
if (!allowCredentialsHeader.EqualsLiteral("true")) {
LogBlockedRequest(aRequest, "CORSMissingAllowCredentials", nullptr,
topChannel);
LogBlockedRequest(
aRequest, "CORSMissingAllowCredentials", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWCREDENTIALS, topChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -937,6 +955,7 @@ nsresult nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
if (nsContentUtils::IsExpandedPrincipal(mOriginHeaderPrincipal)) {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
LogBlockedRequest(aChannel, "CORSOriginHeaderNotAdded", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSORIGINHEADERNOTADDED,
httpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1007,7 +1026,9 @@ nsresult nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel,
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);
if (!http) {
LogBlockedRequest(aChannel, "CORSRequestNotHttp", nullptr, mHttpChannel);
LogBlockedRequest(aChannel, "CORSRequestNotHttp", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSREQUESTNOTHTTP,
mHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1047,7 +1068,9 @@ nsresult nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel,
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(http);
if (!internal) {
LogBlockedRequest(aChannel, "CORSDidNotSucceed", nullptr, mHttpChannel);
LogBlockedRequest(aChannel, "CORSDidNotSucceed", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
mHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1260,8 +1283,10 @@ nsCORSPreflightListener::AsyncOnChannelRedirect(
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags) &&
!NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags)) {
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
LogBlockedRequest(aOldChannel, "CORSExternalRedirectNotAllowed", nullptr,
httpChannel);
LogBlockedRequest(
aOldChannel, "CORSExternalRedirectNotAllowed", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSEXTERNALREDIRECTNOTALLOWED,
httpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1286,6 +1311,7 @@ nsresult nsCORSPreflightListener::CheckPreflightRequestApproved(
rv = http->GetRequestSucceeded(&succeedded);
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSPREFLIGHTDIDNOTSUCCEED,
parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1306,13 +1332,16 @@ nsresult nsCORSPreflightListener::CheckPreflightRequestApproved(
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get(), parentHttpChannel);
NS_ConvertUTF8toUTF16(method).get(),
nsILoadInfo::BLOCKING_REASON_CORSINVALIDALLOWMETHOD,
parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSMETHODNOTFOUND,
parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
@ -1330,7 +1359,9 @@ nsresult nsCORSPreflightListener::CheckPreflightRequestApproved(
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get(), parentHttpChannel);
NS_ConvertUTF8toUTF16(header).get(),
nsILoadInfo::BLOCKING_REASON_CORSINVALIDALLOWHEADER,
parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
@ -1338,9 +1369,11 @@ nsresult nsCORSPreflightListener::CheckPreflightRequestApproved(
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
const auto& comparator = nsCaseInsensitiveCStringArrayComparator();
if (!headers.Contains(mPreflightHeaders[i], comparator)) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get(),
parentHttpChannel);
LogBlockedRequest(
aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get(),
nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWHEADERFROMPREFLIGHT,
parentHttpChannel);
return NS_ERROR_DOM_BAD_URI;
}
}
@ -1375,7 +1408,8 @@ nsresult nsCORSListenerProxy::StartCORSPreflight(
if (gDisableCORS) {
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequestChannel);
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr, http);
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr,
nsILoadInfo::BLOCKING_REASON_CORSDISABLED, http);
return NS_ERROR_DOM_BAD_URI;
}

View File

@ -324,6 +324,11 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
// callable from socket thread only
uint32_t Get32BitsOfPseudoRandom();
// Called by the channel synchronously during asyncOpen
void OnFailedOpeningRequest(nsIHttpChannel *chan) {
NotifyObservers(chan, NS_HTTP_ON_FAILED_OPENING_REQUEST_TOPIC);
}
// Called by the channel synchronously during asyncOpen
void OnOpeningRequest(nsIHttpChannel *chan) {
NotifyObservers(chan, NS_HTTP_ON_OPENING_REQUEST_TOPIC);

View File

@ -90,6 +90,13 @@ interface nsIHttpProtocolHandler : nsIProxiedProtocolHandler
#define NS_HTTP_STARTUP_TOPIC "http-startup"
/**
* Called when asyncOpen synchronously failes e.g. because of any synchronously
* performed security checks. This only fires on the child process, but if
* needed can be implemented also on the parent process.
*/
#define NS_HTTP_ON_FAILED_OPENING_REQUEST_TOPIC "http-on-failed-opening-request"
/**
* This observer topic is notified when an HTTP channel is opened.
* It is similar to http-on-modify-request, except that
* 1) The notification is guaranteed to occur before on-modify-request, during

View File

@ -158,6 +158,9 @@ UrlClassifierFeatureTrackingProtection::ProcessChannel(
UrlClassifierCommon::SetBlockedContent(aChannel, NS_ERROR_TRACKING_URI, list,
EmptyCString(), EmptyCString());
NS_SetRequestBlockingReason(
aChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_TRACKING_URI);
UC_LOG(
("UrlClassifierFeatureTrackingProtection::ProcessChannel, cancelling "
"channel[%p]",

View File

@ -429,6 +429,35 @@ nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode,
SendThreatHitReport(mChannel, aProvider, aList, aFullHash);
}
switch (aErrorCode) {
case NS_ERROR_MALWARE_URI:
NS_SetRequestBlockingReason(
mChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_MALWARE_URI);
break;
case NS_ERROR_PHISHING_URI:
NS_SetRequestBlockingReason(
mChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_PHISHING_URI);
break;
case NS_ERROR_UNWANTED_URI:
NS_SetRequestBlockingReason(
mChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_UNWANTED_URI);
break;
case NS_ERROR_TRACKING_URI:
NS_SetRequestBlockingReason(
mChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_TRACKING_URI);
break;
case NS_ERROR_BLOCKED_URI:
NS_SetRequestBlockingReason(
mChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_BLOCKED_URI);
break;
case NS_ERROR_HARMFUL_URI:
NS_SetRequestBlockingReason(
mChannel, nsILoadInfo::BLOCKING_REASON_CLASSIFY_HARMFUL_URI);
break;
default:
break;
}
mChannel->Cancel(aErrorCode);
}
LOG_DEBUG(

View File

@ -9,6 +9,7 @@
#include "nsCOMPtr.h"
#include "nsContentPolicyUtils.h"
#include "nsIContentViewer.h"
#include "nsNetUtil.h"
nsWebBrowserContentPolicy::nsWebBrowserContentPolicy() {}
@ -62,6 +63,8 @@ nsWebBrowserContentPolicy::ShouldLoad(nsIURI* aContentLocation,
}
if (NS_SUCCEEDED(rv) && !allowed) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_WEB_BROWSER);
*aShouldLoad = nsIContentPolicy::REJECT_TYPE;
}
return rv;
@ -91,6 +94,8 @@ nsWebBrowserContentPolicy::ShouldProcess(nsIURI* aContentLocation,
nsCOMPtr<nsISupports> context = aLoadInfo->GetLoadingContext();
nsIDocShell* shell = NS_CP_GetDocShellFromContext(context);
if (shell && (!shell->PluginsAllowedInCurrentDoc())) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_WEB_BROWSER);
*aShouldProcess = nsIContentPolicy::REJECT_TYPE;
}

View File

@ -86,6 +86,8 @@ AddonContentPolicy::ShouldLoad(nsIURI* aContentLocation, nsILoadInfo* aLoadInfo,
const nsACString& aMimeTypeGuess,
int16_t* aShouldLoad) {
if (!aContentLocation || !aLoadInfo) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_WEBEXT);
*aShouldLoad = REJECT_REQUEST;
return NS_ERROR_FAILURE;
}
@ -126,6 +128,8 @@ AddonContentPolicy::ShouldLoad(nsIURI* aContentLocation, nsILoadInfo* aLoadInfo,
if (NS_SUCCEEDED(mimeParser.GetType(mimeType)) &&
nsContentUtils::IsJavascriptMIMEType(mimeType) &&
NS_SUCCEEDED(mimeParser.GetParameter("version", version))) {
NS_SetRequestBlockingReason(
aLoadInfo, nsILoadInfo::BLOCKING_REASON_CONTENT_POLICY_WEBEXT);
*aShouldLoad = nsIContentPolicy::REJECT_REQUEST;
nsCOMPtr<nsISupports> context = aLoadInfo->GetLoadingContext();

View File

@ -186,6 +186,7 @@ nsresult nsObserverService::FilterHttpOnTopics(const char* aTopic) {
// Specifically allow http-on-opening-request and http-on-stop-request in the
// child process; see bug 1269765.
if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8) &&
strcmp(aTopic, "http-on-failed-opening-request") &&
strcmp(aTopic, "http-on-opening-request") &&
strcmp(aTopic, "http-on-stop-request")) {
nsCOMPtr<nsIConsoleService> console(