diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index bd8dfbfbd88d..d749daebd72f 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -296,12 +296,13 @@ CSPService::AsyncOnChannelRedirect(nsIChannel* oldChannel, return rv; } - int16_t decision = nsIContentPolicy::ACCEPT; - rv = ConsultCSPForRedirect(originalUri, newUri, loadInfo, &decision); - if (NS_CP_REJECTED(decision)) { + Maybe cancelCode; + rv = ConsultCSPForRedirect(originalUri, newUri, loadInfo, cancelCode); + if (cancelCode) { + oldChannel->Cancel(*cancelCode); + } + if (NS_FAILED(rv)) { autoCallback.DontCallback(); - oldChannel->Cancel(NS_ERROR_DOM_BAD_URI); - return NS_BINDING_FAILED; } return rv; @@ -310,15 +311,15 @@ CSPService::AsyncOnChannelRedirect(nsIChannel* oldChannel, nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI, nsIURI* aNewURI, nsILoadInfo* aLoadInfo, - int16_t* aDecision) { + Maybe& aCancelCode) { nsCOMPtr cspEventListener; nsresult rv = aLoadInfo->GetCspEventListener(getter_AddRefs(cspEventListener)); - NS_ENSURE_SUCCESS(rv, rv); + MOZ_ALWAYS_SUCCEEDS(rv); nsAutoString cspNonce; rv = aLoadInfo->GetCspNonce(cspNonce); - NS_ENSURE_SUCCESS(rv, rv); + MOZ_ALWAYS_SUCCEEDS(rv); nsContentPolicyType policyType = aLoadInfo->InternalContentPolicyType(); bool isPreload = nsContentUtils::IsPreloadType(policyType); @@ -330,6 +331,7 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI, policyType = nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(policyType); + int16_t decision = nsIContentPolicy::ACCEPT; nsCOMPtr requestContext = aLoadInfo->GetLoadingContext(); // 1) Apply speculative CSP for preloads if (isPreload) { @@ -346,12 +348,13 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI, aOriginalURI, // Original nsIURI true, // aSendViolationReports cspNonce, // nonce - aDecision); + &decision); // if the preload policy already denied the load, then there // is no point in checking the real policy - if (NS_CP_REJECTED(*aDecision)) { - return NS_OK; + if (NS_CP_REJECTED(decision)) { + aCancelCode = Some(NS_ERROR_DOM_BAD_URI); + return NS_BINDING_FAILED; } } } @@ -369,7 +372,11 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI, aOriginalURI, // Original nsIURI true, // aSendViolationReports cspNonce, // nonce - aDecision); + &decision); + if (NS_CP_REJECTED(decision)) { + aCancelCode = Some(NS_ERROR_DOM_BAD_URI); + return NS_BINDING_FAILED; + } } return NS_OK; diff --git a/dom/security/nsCSPService.h b/dom/security/nsCSPService.h index a90627a61ce3..b94e1f421557 100644 --- a/dom/security/nsCSPService.h +++ b/dom/security/nsCSPService.h @@ -34,9 +34,13 @@ class CSPService : public nsIContentPolicy, public nsIChannelEventSink { const nsACString& aMimeTypeGuess, int16_t* aDecision); + // Static helper to check CSP when doing a channel redirect. + // Returns the results to returns from + // AsyncOnChannelRedirect/nsIAsyncVerifyRedirectCallback. Optionally returns + // an nsresult to Cancel the old channel with. static nsresult ConsultCSPForRedirect(nsIURI* aOriginalURI, nsIURI* aNewURI, nsILoadInfo* aLoadInfo, - int16_t* aDecision); + Maybe& aCancelCode); protected: virtual ~CSPService(); diff --git a/netwerk/ipc/DocumentChannelChild.cpp b/netwerk/ipc/DocumentChannelChild.cpp index 1889933b0952..eaea8faa73be 100644 --- a/netwerk/ipc/DocumentChannelChild.cpp +++ b/netwerk/ipc/DocumentChannelChild.cpp @@ -412,22 +412,15 @@ IPCResult DocumentChannelChild::RecvConfirmRedirect( nsCOMPtr originalUri; nsresult rv = GetOriginalURI(getter_AddRefs(originalUri)); if (NS_FAILED(rv)) { - aResolve(rv); + aResolve(Tuple&>(NS_BINDING_FAILED, + Some(rv))); return IPC_OK(); } - int16_t decision = nsIContentPolicy::ACCEPT; + Maybe cancelCode; rv = CSPService::ConsultCSPForRedirect(originalUri, aNewUri, mLoadInfo, - &decision); - if (NS_FAILED(rv)) { - aResolve(rv); - return IPC_OK(); - } - if (NS_CP_REJECTED(decision)) { - aResolve(NS_BINDING_FAILED); - } else { - aResolve(NS_OK); - } + cancelCode); + aResolve(Tuple&>(rv, cancelCode)); return IPC_OK(); } diff --git a/netwerk/ipc/DocumentChannelParent.cpp b/netwerk/ipc/DocumentChannelParent.cpp index b6b7092a4b69..720450d2ef2c 100644 --- a/netwerk/ipc/DocumentChannelParent.cpp +++ b/netwerk/ipc/DocumentChannelParent.cpp @@ -240,8 +240,8 @@ void DocumentChannelParent::FinishReplacementChannelSetup(bool aSucceeded) { newChannel->Cancel(NS_BINDING_ABORTED); } } - // Release all previously registered channels, they are no longer needed to be - // kept in the registrar from this moment. + // Release all previously registered channels, they are no longer needed to + // be kept in the registrar from this moment. registrar->DeregisterChannels(mRedirectChannelId); mRedirectChannelId = 0; @@ -809,11 +809,11 @@ DocumentChannelParent::AsyncOnChannelRedirect( nsCOMPtr oldChannel(aOldChannel); SendConfirmRedirect(newUri)->Then( GetCurrentThreadSerialEventTarget(), __func__, - [callback, oldChannel](nsresult aRv) { - if (NS_FAILED(aRv)) { - oldChannel->Cancel(NS_ERROR_DOM_BAD_URI); + [callback, oldChannel](const Tuple>& aResult) { + if (Get<1>(aResult)) { + oldChannel->Cancel(*Get<1>(aResult)); } - callback->OnRedirectVerifyCallback(aRv); + callback->OnRedirectVerifyCallback(Get<0>(aResult)); }, [callback, oldChannel](const mozilla::ipc::ResponseRejectReason) { oldChannel->Cancel(NS_ERROR_DOM_BAD_URI); diff --git a/netwerk/ipc/PDocumentChannel.ipdl b/netwerk/ipc/PDocumentChannel.ipdl index 5491cd944fcf..86a725b96fb0 100644 --- a/netwerk/ipc/PDocumentChannel.ipdl +++ b/netwerk/ipc/PDocumentChannel.ipdl @@ -75,7 +75,7 @@ child: uint32_t? aContentDisposition, nsString? aContentDispositionFilename) returns(nsresult rv); - async ConfirmRedirect(nsIURI aNewURI) returns(nsresult rv); + async ConfirmRedirect(nsIURI aNewURI) returns(nsresult rv, nsresult? cancelCode); // Tell child to delete channel (all IPDL deletes must be done from child to // avoid races: see bug 591708).