--- a/content/base/src/nsCSPService.cpp
+++ b/content/base/src/nsCSPService.cpp
@@ -18,17 +18,16 @@
#include "nsIWritablePropertyBag2.h"
#include "nsError.h"
#include "nsChannelProperties.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsAsyncRedirectVerifyHelper.h"
#include "mozilla/Preferences.h"
#include "nsIScriptError.h"
#include "nsContentUtils.h"
-#include "nsContentPolicyUtils.h"
#include "nsPrincipal.h"
using namespace mozilla;
/* Keeps track of whether or not CSP is enabled */
bool CSPService::sCSPEnabled = true;
#ifdef PR_LOGGING
@@ -232,66 +231,63 @@ CSPService::ShouldProcess(uint32_t
NS_IMETHODIMP
CSPService::AsyncOnChannelRedirect(nsIChannel *oldChannel,
nsIChannel *newChannel,
uint32_t flags,
nsIAsyncVerifyRedirectCallback *callback)
{
nsAsyncRedirectAutoCallback autoCallback(callback);
- nsCOMPtr<nsILoadInfo> loadInfo;
- nsresult rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
-
- // if no loadInfo on the channel, nothing for us to do
- if (!loadInfo) {
+ // get the Content Security Policy and load type from the property bag
+ nsCOMPtr<nsISupports> policyContainer;
+ nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(oldChannel));
+ if (!props)
return NS_OK;
- }
- // The loadInfo must not necessarily contain a Node, hence we try to query
- // the CSP in the following order:
- // a) Get the Node, the Principal of that Node, and the CSP of that Principal
- // b) Get the Principal and the CSP of that Principal
+ props->GetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
+ NS_GET_IID(nsISupports),
+ getter_AddRefs(policyContainer));
- nsCOMPtr<nsINode> loadingNode = loadInfo->LoadingNode();
- nsCOMPtr<nsIPrincipal> principal = loadingNode ?
- loadingNode->NodePrincipal() :
- loadInfo->LoadingPrincipal();
- NS_ASSERTION(principal, "Can not evaluate CSP without a principal");
+ // see if we have a valid nsIChannelPolicy containing CSP and load type
+ nsCOMPtr<nsIChannelPolicy> channelPolicy(do_QueryInterface(policyContainer));
+ if (!channelPolicy)
+ return NS_OK;
+
+ nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIContentSecurityPolicy> csp;
- rv = principal->GetCsp(getter_AddRefs(csp));
- NS_ENSURE_SUCCESS(rv, rv);
+ channelPolicy->GetContentSecurityPolicy(getter_AddRefs(supports));
+ csp = do_QueryInterface(supports);
+ uint32_t loadType;
+ channelPolicy->GetLoadType(&loadType);
- // if there is no CSP, nothing for us to do
- if (!csp) {
+ // if no CSP in the channelPolicy, nothing for us to add to the channel
+ if (!csp)
return NS_OK;
- }
/* Since redirecting channels don't call into nsIContentPolicy, we call our
- * Content Policy implementation directly when redirects occur using the
- * information set in the LoadInfo when channels are created.
- *
- * We check if the CSP permits this host for this type of load, if not,
- * we cancel the load now.
+ * Content Policy implementation directly when redirects occur. When channels
+ * are created using NS_NewChannel(), callers can optionally pass in a
+ * nsIChannelPolicy containing a CSP object and load type, which is placed in
+ * the new channel's property bag. This container is propagated forward when
+ * channels redirect.
*/
+ // Does the CSP permit this host for this type of load?
+ // If not, cancel the load now.
nsCOMPtr<nsIURI> newUri;
- rv = newChannel->GetURI(getter_AddRefs(newUri));
- NS_ENSURE_SUCCESS(rv, rv);
+ newChannel->GetURI(getter_AddRefs(newUri));
nsCOMPtr<nsIURI> originalUri;
- rv = oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
- NS_ENSURE_SUCCESS(rv, rv);
- nsContentPolicyType policyType = loadInfo->GetContentPolicyType();
-
+ oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
int16_t aDecision = nsIContentPolicy::ACCEPT;
- csp->ShouldLoad(policyType, // load type per nsIContentPolicy (uint32_t)
- newUri, // nsIURI
- nullptr, // nsIURI
- nullptr, // nsISupports
- EmptyCString(), // ACString - MIME guess
- originalUri, // aMimeTypeGuess
+ csp->ShouldLoad(loadType, // load type per nsIContentPolicy (uint32_t)
+ newUri, // nsIURI
+ nullptr, // nsIURI
+ nullptr, // nsISupports
+ EmptyCString(), // ACString - MIME guess
+ originalUri, // nsISupports - extra
&aDecision);
#ifdef PR_LOGGING
if (newUri) {
nsAutoCString newUriSpec("None");
newUri->GetSpec(newUriSpec);
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("CSPService::AsyncOnChannelRedirect called for %s",
@@ -301,14 +297,41 @@ CSPService::AsyncOnChannelRedirect(nsICh
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("CSPService::AsyncOnChannelRedirect ALLOWING request."));
else
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
("CSPService::AsyncOnChannelRedirect CANCELLING request."));
#endif
// if ShouldLoad doesn't accept the load, cancel the request
- if (!NS_CP_ACCEPTED(aDecision)) {
+ if (aDecision != 1) {
autoCallback.DontCallback();
return NS_BINDING_FAILED;
}
- return NS_OK;
+
+ // the redirect is permitted, so propagate the Content Security Policy
+ // and load type to the redirecting channel
+ nsresult rv;
+ nsCOMPtr<nsIWritablePropertyBag2> props2 = do_QueryInterface(newChannel);
+ if (props2) {
+ rv = props2->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY,
+ channelPolicy);
+ if (NS_SUCCEEDED(rv)) {
+ return NS_OK;
+ }
+ }
+
+ // The redirecting channel isn't a writable property bag, we won't be able
+ // to enforce the load policy if it redirects again, so we stop it now.
+ nsAutoCString newUriSpec;
+ rv = newUri->GetSpec(newUriSpec);
+ NS_ConvertUTF8toUTF16 unicodeSpec(newUriSpec);
+ const char16_t *formatParams[] = { unicodeSpec.get() };
+ if (NS_SUCCEEDED(rv)) {
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("Redirect Error"), nullptr,
+ nsContentUtils::eDOM_PROPERTIES,
+ "InvalidRedirectChannelWarning",
+ formatParams, 1);
+ }
+
+ return NS_BINDING_FAILED;
}