Bug 1259678 - Refactor SubjectToCSP to avoid calling ShouldLoad if CSP doesn't apply to the content type. r=ckerschb
authorTanvi Vyas <tanvi@mozilla.com>
Thu, 24 Mar 2016 23:09:00 -0400
changeset 290544 7ca9567ed5c7f2055b9911dee5b41e62398361c7
parent 290543 98fd214bd3f2c3f6b78484c8c19a5f7c84aca880
child 290545 84f912382f78363398ad538abbe0fadb5100020a
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb
bugs1259678
milestone48.0a1
Bug 1259678 - Refactor SubjectToCSP to avoid calling ShouldLoad if CSP doesn't apply to the content type. r=ckerschb
dom/security/nsCSPService.cpp
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -36,19 +36,29 @@ CSPService::CSPService()
 
 CSPService::~CSPService()
 {
   mAppStatusCache.Clear();
 }
 
 NS_IMPL_ISUPPORTS(CSPService, nsIContentPolicy, nsIChannelEventSink)
 
-// Helper function to identify protocols not subject to CSP.
+// Helper function to identify protocols and content types not subject to CSP.
 bool
-subjectToCSP(nsIURI* aURI) {
+subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) {
+  // These content types are not subject to CSP content policy checks:
+  // TYPE_CSP_REPORT -- csp can't block csp reports
+  // TYPE_REFRESH    -- never passed to ShouldLoad (see nsIContentPolicy.idl)
+  // TYPE_DOCUMENT   -- used for frame-ancestors
+  if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT ||
+      aContentType == nsIContentPolicy::TYPE_REFRESH ||
+      aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
+    return false;
+  }
+
   // The three protocols: data:, blob: and filesystem: share the same
   // protocol flag (URI_IS_LOCAL_RESOURCE) with other protocols, like
   // chrome:, resource:, moz-icon:, but those three protocols get
   // special attention in CSP and are subject to CSP, hence we have
   // to make sure those protocols are subject to CSP, see:
   // http://www.w3.org/TR/CSP2/#source-list-guid-matching
   bool match = false;
   nsresult rv = aURI->SchemeIs("data", &match);
@@ -112,31 +122,21 @@ CSPService::ShouldLoad(uint32_t aContent
     MOZ_LOG(gCspPRLog, LogLevel::Debug,
            ("CSPService::ShouldLoad called for %s", location.get()));
   }
 
   // default decision, CSP can revise it if there's a policy to enforce
   *aDecision = nsIContentPolicy::ACCEPT;
 
   // No need to continue processing if CSP is disabled or if the protocol
-  // is *not* subject to CSP.
+  // or type is *not* subject to CSP.
   // Please note, the correct way to opt-out of CSP using a custom
   // protocolHandler is to set one of the nsIProtocolHandler flags
   // that are whitelistet in subjectToCSP()
-  if (!sCSPEnabled || !subjectToCSP(aContentLocation)) {
-    return NS_OK;
-  }
-
-  // These content types are not subject to CSP content policy checks:
-  // TYPE_CSP_REPORT -- csp can't block csp reports
-  // TYPE_REFRESH    -- never passed to ShouldLoad (see nsIContentPolicy.idl)
-  // TYPE_DOCUMENT   -- used for frame-ancestors
-  if (aContentType == nsIContentPolicy::TYPE_CSP_REPORT ||
-    aContentType == nsIContentPolicy::TYPE_REFRESH ||
-    aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
+  if (!sCSPEnabled || !subjectToCSP(aContentLocation, aContentType)) {
     return NS_OK;
   }
 
   // query the principal of the document; if no document is passed, then
   // fall back to using the requestPrincipal (e.g. service workers do not
   // pass a document).
   nsCOMPtr<nsINode> node(do_QueryInterface(aRequestContext));
   nsCOMPtr<nsIPrincipal> principal = node ? node->NodePrincipal()
@@ -247,44 +247,43 @@ CSPService::AsyncOnChannelRedirect(nsICh
                                    nsIAsyncVerifyRedirectCallback *callback)
 {
   nsAsyncRedirectAutoCallback autoCallback(callback);
 
   nsCOMPtr<nsIURI> newUri;
   nsresult rv = newChannel->GetURI(getter_AddRefs(newUri));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsILoadInfo> loadInfo = oldChannel->GetLoadInfo();
+
+  // if no loadInfo on the channel, nothing for us to do
+  if (!loadInfo) {
+    return NS_OK;
+  }
+
   // No need to continue processing if CSP is disabled or if the protocol
   // is *not* subject to CSP.
   // Please note, the correct way to opt-out of CSP using a custom
   // protocolHandler is to set one of the nsIProtocolHandler flags
   // that are whitelistet in subjectToCSP()
-  if (!sCSPEnabled || !subjectToCSP(newUri)) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsILoadInfo> loadInfo;
-  rv = oldChannel->GetLoadInfo(getter_AddRefs(loadInfo));
-
-  // if no loadInfo on the channel, nothing for us to do
-  if (!loadInfo) {
+  nsContentPolicyType policyType = loadInfo->InternalContentPolicyType();
+  if (!sCSPEnabled || !subjectToCSP(newUri, policyType)) {
     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.
    */
   nsCOMPtr<nsIURI> originalUri;
   rv = oldChannel->GetOriginalURI(getter_AddRefs(originalUri));
   NS_ENSURE_SUCCESS(rv, rv);
-  nsContentPolicyType policyType = loadInfo->InternalContentPolicyType();
 
   bool isPreload = nsContentUtils::IsPreloadType(policyType);
 
   /* On redirect, if the content policy is a preload type, rejecting the preload
    * results in the load silently failing, so we convert preloads to the actual
    * type. See Bug 1219453.
    */
   policyType =