Backed out changeset 42614739736d (bug 1041180) for xpcshell failures; CLOSED TREE
authorEd Morley <emorley@mozilla.com>
Fri, 03 Oct 2014 10:14:53 +0100
changeset 208563 9f5ced212c7dc3573c6be4bc9f313af562530105
parent 208562 2c107ce32cbc41569d4e59082c620cfb131c68b3
child 208564 ae5890b31d910c03621e88e61edc76192ad0c9c7
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs1041180
milestone35.0a1
backs out42614739736dfbdef714203887e68438fe1d9e4d
Backed out changeset 42614739736d (bug 1041180) for xpcshell failures; CLOSED TREE
content/base/src/nsCSPService.cpp
--- 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;
 }