Bug 999656 - Fix mappings between content type and CSP directives and refactor permits functions in CSP. r=ckerschb
authorSid Stamm <sstamm@mozilla.com>
Wed, 10 Dec 2014 13:54:00 +0100
changeset 219264 12380b98f9d8a5961eeebe63282f7df1e5a253d8
parent 219263 314367722e079ec33717c6e523da280767aa3366
child 219265 53adf5b021fa08a9e47f8a4e8886df26b34ac481
push id27958
push userkwierso@gmail.com
push dateFri, 12 Dec 2014 01:30:39 +0000
treeherdermozilla-central@5288b15d22de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb
bugs999656
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 999656 - Fix mappings between content type and CSP directives and refactor permits functions in CSP. r=ckerschb
dom/base/nsDocument.cpp
dom/html/HTMLFormElement.cpp
dom/interfaces/security/nsIContentSecurityPolicy.idl
dom/security/nsCSPContext.cpp
dom/security/nsCSPContext.h
dom/security/nsCSPParser.cpp
dom/security/nsCSPUtils.cpp
dom/security/nsCSPUtils.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3560,17 +3560,22 @@ nsDocument::SetBaseURI(nsIURI* aURI)
   }
 
   // Check if CSP allows this base-uri
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
   if (csp) {
     bool permitsBaseURI = false;
-    rv = csp->PermitsBaseURI(aURI, &permitsBaseURI);
+
+    // base-uri is only enforced if explicitly defined in the
+    // policy - do *not* consult default-src, see:
+    // http://www.w3.org/TR/CSP2/#directive-default-src
+    rv = csp->Permits(aURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
+                      true, &permitsBaseURI);
     NS_ENSURE_SUCCESS(rv, rv);
     if (!permitsBaseURI) {
       return NS_OK;
     }
   }
 
   if (aURI) {
     mDocumentBaseURI = NS_TryToMakeImmutable(aURI);
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -1628,17 +1628,22 @@ HTMLFormElement::GetActionURL(nsIURI** a
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Check if CSP allows this form-action
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
   if (csp) {
     bool permitsFormAction = true;
-    rv = csp->PermitsFormAction(actionURL, &permitsFormAction);
+
+    // form-action is only enforced if explicitly defined in the
+    // policy - do *not* consult default-src, see:
+    // http://www.w3.org/TR/CSP2/#directive-default-src
+    rv = csp->Permits(actionURL, nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE,
+                      true, &permitsFormAction);
     NS_ENSURE_SUCCESS(rv, rv);
     if (!permitsFormAction) {
       rv = NS_ERROR_CSP_FORM_ACTION_VIOLATION;
     }
   }
 
   //
   // Assign to the output
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -13,19 +13,45 @@ interface nsIURI;
 
 /**
  * nsIContentSecurityPolicy
  * Describes an XPCOM component used to model and enforce CSPs.  Instances of
  * this class may have multiple policies within them, but there should only be
  * one of these per document/principal.
  */
 
-[scriptable, uuid(dc86b261-5e41-4cab-ace3-a0278f5a7ec7)]
+typedef unsigned short CSPDirective;
+
+[scriptable, uuid(69b7663e-117a-4a3b-81bd-d86420b7c79e)]
 interface nsIContentSecurityPolicy : nsISerializable
 {
+  /**
+   * Directives supported by Content Security Policy.  These are enums for
+   * the CSPDirective type.
+   * The NO_DIRECTIVE entry is  used for checking default permissions and
+   * returning failure when asking CSP which directive to check.
+   *
+   * NOTE: When implementing a new directive, you will need to add it here but also
+   * add it to the CSPStrDirectives array in nsCSPUtils.h.
+   */
+  const unsigned short NO_DIRECTIVE               = 0;
+  const unsigned short DEFAULT_SRC_DIRECTIVE      = 1;
+  const unsigned short SCRIPT_SRC_DIRECTIVE       = 2;
+  const unsigned short OBJECT_SRC_DIRECTIVE       = 3;
+  const unsigned short STYLE_SRC_DIRECTIVE        = 4;
+  const unsigned short IMG_SRC_DIRECTIVE          = 5;
+  const unsigned short MEDIA_SRC_DIRECTIVE        = 6;
+  const unsigned short FRAME_SRC_DIRECTIVE        = 7;
+  const unsigned short FONT_SRC_DIRECTIVE         = 8;
+  const unsigned short CONNECT_SRC_DIRECTIVE      = 9;
+  const unsigned short REPORT_URI_DIRECTIVE       = 10;
+  const unsigned short FRAME_ANCESTORS_DIRECTIVE  = 11;
+  const unsigned short REFLECTED_XSS_DIRECTIVE    = 12;
+  const unsigned short BASE_URI_DIRECTIVE         = 13;
+  const unsigned short FORM_ACTION_DIRECTIVE      = 14;
 
   /**
    * Accessor method for a read-only string version of the policy at a given
    * index.
    */
   AString getPolicy(in unsigned long index);
 
   /**
@@ -191,34 +217,39 @@ interface nsIContentSecurityPolicy : nsI
    *    containing the protected resource
    * @return
    *    true if the frame's ancestors are all allowed by policy (except for
    *    report-only policies, which will send reports and then return true
    *    here when violated).
    */
   boolean permitsAncestry(in nsIDocShell docShell);
 
-  /**
-   * Whether this policy allows setting the document's base URI to
-   * a given value.
-   *
-   * @return
-   *    Whether or not the provided URI is allowed to be used as the
-   *    document's base URI. (block the setting if false).
-   */
-  boolean permitsBaseURI(in nsIURI aURI);
 
   /**
-   * Whether this policy allows submitting HTML forms to a given URI.
+   * Checks if a specific directive permits loading of a URI.
+   *
+   * NOTE: Calls to this may trigger violation reports when queried, so the
+   * return value should not be cached.
    *
+   * @param aURI
+   *    The URI about to be loaded or used.
+   * @param aDir
+   *    The CSPDirective to query (see above constants *_DIRECTIVE).
+   * @param aSpecific
+   *    If "true" and the directive is specified to fall back to "default-src"
+   *    when it's not explicitly provided, directivePermits will NOT try
+   *    default-src when the specific directive is not used.  Setting this to
+   *    "false" allows CSP to fall back to default-src.  This function
+   *    behaves the same for both values of canUseDefault when querying
+   *    directives that don't fall-back.
    * @return
-   *    Whether or not the provided URI is allowed to be used as a
-   *    form's action URI.
+   *    Whether or not the provided URI is allowed by CSP under the given
+   *    directive. (block the pending operation if false).
    */
-  boolean permitsFormAction(in nsIURI aURI);
+  boolean permits(in nsIURI aURI, in CSPDirective aDir, in boolean aSpecific);
 
   /**
    * Delegate method called by the service when sub-elements of the protected
    * document are being loaded.  Given a bit of information about the request,
    * decides whether or not the policy is satisfied.
    *
    * Calls to this may trigger violation reports when queried, so
    * this value should not be cached.
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -130,16 +130,23 @@ nsCSPContext::ShouldLoad(nsContentPolicy
   if (isCached && cacheKey.Length() > 0) {
     // this is cached, use the cached value.
     return NS_OK;
   }
 
   // Default decision, CSP can revise it if there's a policy to enforce
   *outDecision = nsIContentPolicy::ACCEPT;
 
+  // If the content type doesn't map to a CSP directive, there's nothing for
+  // CSP to do.
+  CSPDirective dir = CSP_ContentTypeToDirective(aContentType);
+  if (dir == nsIContentSecurityPolicy::NO_DIRECTIVE) {
+    return NS_OK;
+  }
+
   // This may be a load or a preload. If it is a preload, the document will
   // not have been fully parsed yet, and aRequestContext will be an
   // nsIDOMHTMLDocument rather than the nsIDOMHTMLElement associated with the
   // resource. As a result, we cannot extract the element's corresponding
   // nonce attribute, and so we cannot correctly check the nonce on a preload.
   //
   // Therefore, the decision returned here for a preload may be *incorrect* as
   // it cannot take the nonce into account. We will still check the load, but
@@ -160,63 +167,106 @@ nsCSPContext::ShouldLoad(nsContentPolicy
   if (!isPreload) {
     nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(aRequestContext);
     if (htmlElement) {
       rv = htmlElement->GetAttribute(NS_LITERAL_STRING("nonce"), nonce);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
-  nsAutoString violatedDirective;
-  for (uint32_t p = 0; p < mPolicies.Length(); p++) {
-    if (!mPolicies[p]->permits(aContentType,
-                               aContentLocation,
-                               nonce,
-                               // aExtra is only non-null if
-                               // the channel got redirected.
-                               (aExtra != nullptr),
-                               violatedDirective)) {
-      // If the policy is violated and not report-only, reject the load and
-      // report to the console
-      if (!mPolicies[p]->getReportOnlyFlag()) {
-        CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, nsIContentPolicy::REJECT_SERVER"));
-        *outDecision = nsIContentPolicy::REJECT_SERVER;
-      }
+  // aExtra is only non-null if the channel got redirected.
+  bool wasRedirected = (aExtra != nullptr);
+  nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
 
-      // Do not send a report or notify observers if this is a preload - the
-      // decision may be wrong due to the inability to get the nonce, and will
-      // incorrectly fail the unit tests.
-      if (!isPreload) {
-        nsCOMPtr<nsIURI> originalURI = do_QueryInterface(aExtra);
-        this->AsyncReportViolation(aContentLocation,
-                                   originalURI,   /* in case of redirect originalURI is not null */
-                                   violatedDirective,
-                                   p,             /* policy index        */
-                                   EmptyString(), /* no observer subject */
-                                   EmptyString(), /* no source file      */
-                                   EmptyString(), /* no script sample    */
-                                   0);            /* no line number      */
-      }
-    }
-  }
+  bool permitted = permitsInternal(dir,
+                                   aContentLocation,
+                                   originalURI,
+                                   nonce,
+                                   wasRedirected,
+                                   isPreload,
+                                   false,     // allow fallback to default-src
+                                   true,      // send violation reports
+                                   true);     // send blocked URI in violation reports
+
+  *outDecision = permitted ? nsIContentPolicy::ACCEPT
+                           : nsIContentPolicy::REJECT_SERVER;
+
   // Done looping, cache any relevant result
   if (cacheKey.Length() > 0 && !isPreload) {
     mShouldLoadCache.Put(cacheKey, *outDecision);
   }
 
 #ifdef PR_LOGGING
   {
   nsAutoCString spec;
   aContentLocation->GetSpec(spec);
   CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, aContentLocation: %s", *outDecision ? "load" : "deny", spec.get()));
   }
 #endif
   return NS_OK;
 }
 
+bool
+nsCSPContext::permitsInternal(CSPDirective aDir,
+                              nsIURI* aContentLocation,
+                              nsIURI* aOriginalURI,
+                              const nsAString& aNonce,
+                              bool aWasRedirected,
+                              bool aIsPreload,
+                              bool aSpecific,
+                              bool aSendViolationReports,
+                              bool aSendContentLocationInViolationReports)
+{
+  bool permits = true;
+
+  nsAutoString violatedDirective;
+  for (uint32_t p = 0; p < mPolicies.Length(); p++) {
+
+    // According to the W3C CSP spec, frame-ancestors checks are ignored for
+    // report-only policies (when "monitoring").
+    if (aDir == nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE &&
+        mPolicies[p]->getReportOnlyFlag()) {
+      continue;
+    }
+
+    if (!mPolicies[p]->permits(aDir,
+                               aContentLocation,
+                               aNonce,
+                               aWasRedirected,
+                               aSpecific,
+                               violatedDirective)) {
+      // If the policy is violated and not report-only, reject the load and
+      // report to the console
+      if (!mPolicies[p]->getReportOnlyFlag()) {
+        CSPCONTEXTLOG(("nsCSPContext::permitsInternal, false"));
+        permits = false;
+      }
+
+      // Do not send a report or notify observers if this is a preload - the
+      // decision may be wrong due to the inability to get the nonce, and will
+      // incorrectly fail the unit tests.
+      if (!aIsPreload && aSendViolationReports) {
+        this->AsyncReportViolation((aSendContentLocationInViolationReports ?
+                                    aContentLocation : nullptr),
+                                   aOriginalURI,  /* in case of redirect originalURI is not null */
+                                   violatedDirective,
+                                   p,             /* policy index        */
+                                   EmptyString(), /* no observer subject */
+                                   EmptyString(), /* no source file      */
+                                   EmptyString(), /* no script sample    */
+                                   0);            /* no line number      */
+      }
+    }
+  }
+
+  return permits;
+}
+
+
+
 /* ===== nsISupports implementation ========== */
 
 NS_IMPL_CLASSINFO(nsCSPContext,
                   nullptr,
                   nsIClassInfo::MAIN_THREAD_ONLY,
                   NS_CSPCONTEXT_CID)
 
 NS_IMPL_ISUPPORTS_CI(nsCSPContext,
@@ -1036,138 +1086,76 @@ nsCSPContext::PermitsAncestry(nsIDocShel
     // next ancestor
     treeItem = parentTreeItem;
   }
 
   nsAutoString violatedDirective;
 
   // Now that we've got the ancestry chain in ancestorsArray, time to check
   // them against any CSP.
-  for (uint32_t i = 0; i < mPolicies.Length(); i++) {
-
-    // According to the W3C CSP spec, frame-ancestors checks are ignored for
-    // report-only policies (when "monitoring").
-    if (mPolicies[i]->getReportOnlyFlag()) {
-      continue;
-    }
+  // NOTE:  the ancestors are not allowed to be sent cross origin; this is a
+  // restriction not placed on subresource loads.
 
-    for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
-      // TODO(sid) the mapping from frame-ancestors context to TYPE_DOCUMENT is
-      // forced. while this works for now, we will implement something in
-      // bug 999656.
+  for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
 #ifdef PR_LOGGING
-      {
-      nsAutoCString spec;
-      ancestorsArray[a]->GetSpec(spec);
-      CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
-      }
+    {
+    nsAutoCString spec;
+    ancestorsArray[a]->GetSpec(spec);
+    CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
+    }
 #endif
-      if (!mPolicies[i]->permits(nsIContentPolicy::TYPE_DOCUMENT,
-                                 ancestorsArray[a],
-                                 EmptyString(), // no nonce
-                                 false, // no redirect
-                                 violatedDirective)) {
-        // Policy is violated
-        // Send reports, but omit the ancestor URI if cross-origin as per spec
-        // (it is a violation of the same-origin policy).
-        bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
+    // omit the ancestor URI in violation reports if cross-origin as per spec
+    // (it is a violation of the same-origin policy).
+    bool okToSendAncestor = NS_SecurityCompareURIs(ancestorsArray[a], mSelfURI, true);
+
 
-        this->AsyncReportViolation((okToSendAncestor ? ancestorsArray[a] : nullptr),
-                                   nullptr,       /* originalURI in case of redirect */
-                                   violatedDirective,
-                                   i,             /* policy index        */
-                                   EmptyString(), /* no observer subject */
-                                   EmptyString(), /* no source file      */
-                                   EmptyString(), /* no script sample    */
-                                   0);            /* no line number      */
-        *outPermitsAncestry = false;
-      }
+    bool permits = permitsInternal(nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE,
+                                   ancestorsArray[a],
+                                   nullptr, // no redirect here.
+                                   EmptyString(), // no nonce
+                                   false,   // no redirect here.
+                                   false,   // not a preload.
+                                   true,    // specific, do not use default-src
+                                   true,    // send violation reports
+                                   okToSendAncestor);
+    if (!permits) {
+      *outPermitsAncestry = false;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsCSPContext::PermitsBaseURI(nsIURI* aURI, bool* outPermitsBaseURI)
+nsCSPContext::Permits(nsIURI* aURI,
+                      CSPDirective aDir,
+                      bool aSpecific,
+                      bool* outPermits)
 {
   // Can't perform check without aURI
   if (aURI == nullptr) {
     return NS_ERROR_FAILURE;
   }
 
-  *outPermitsBaseURI = true;
-
-  for (uint32_t i = 0; i < mPolicies.Length(); i++) {
-    if (!mPolicies[i]->permitsBaseURI(aURI)) {
-      // policy is violated, report to caller if not report-only
-      if (!mPolicies[i]->getReportOnlyFlag()) {
-        *outPermitsBaseURI = false;
-      }
-      nsAutoString violatedDirective;
-      mPolicies[i]->getDirectiveAsString(CSP_BASE_URI, violatedDirective);
-      this->AsyncReportViolation(aURI,
-                                 nullptr,       /* originalURI in case of redirect */
-                                 violatedDirective,
-                                 i,             /* policy index        */
-                                 EmptyString(), /* no observer subject */
-                                 EmptyString(), /* no source file      */
-                                 EmptyString(), /* no script sample    */
-                                 0);            /* no line number      */
-    }
-  }
+  *outPermits = permitsInternal(aDir,
+                                aURI,
+                                nullptr,  // no original (pre-redirect) URI
+                                EmptyString(),  // no nonce
+                                false,    // not redirected.
+                                false,    // not a preload.
+                                aSpecific,
+                                true,     // send violation reports
+                                true);    // send blocked URI in violation reports
 
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aURI->GetSpec(spec);
-    CSPCONTEXTLOG(("nsCSPContext::PermitsBaseURI, aUri: %s, isAllowed: %s",
-                  spec.get(),
-                  *outPermitsBaseURI ? "allow" : "deny"));
-  }
-#endif
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsCSPContext::PermitsFormAction(nsIURI* aURI, bool* outPermitsFormAction)
-{
-  // Can't perform check without aURI
-  if (!aURI) {
-    return NS_ERROR_FAILURE;
-  }
-
-  *outPermitsFormAction = true;
-
-  for (uint32_t i = 0; i < mPolicies.Length(); i++) {
-    if (!mPolicies[i]->permitsFormAction(aURI)) {
-      // policy is violated, report to caller if not report-only
-      if (!mPolicies[i]->getReportOnlyFlag()) {
-        *outPermitsFormAction = false;
-      }
-      nsAutoString violatedDirective;
-      mPolicies[i]->getDirectiveAsString(CSP_FORM_ACTION, violatedDirective);
-      this->AsyncReportViolation(aURI,
-                                 mSelfURI,
-                                 violatedDirective,
-                                 i,             /* policy index        */
-                                 EmptyString(), /* no observer subject */
-                                 EmptyString(), /* no source file      */
-                                 EmptyString(), /* no script sample    */
-                                 0);            /* no line number      */
-    }
-  }
-
-#ifdef PR_LOGGING
-  {
-    nsAutoCString spec;
-    aURI->GetSpec(spec);
-    CSPCONTEXTLOG(("nsCSPContext::PermitsFormAction, aUri: %s, isAllowed: %s",
-                  spec.get(),
-                  *outPermitsFormAction ? "allow" : "deny"));
+    CSPCONTEXTLOG(("nsCSPContext::Permits, aUri: %s, aDir: %d, isAllowed: %s",
+                  spec.get(), aDir,
+                  *outPermits ? "allow" : "deny"));
   }
 #endif
 
   return NS_OK;
 }
 
 /* ========== CSPViolationReportListener implementation ========== */
 
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -56,16 +56,26 @@ class nsCSPContext : public nsIContentSe
 
   private:
     NS_IMETHODIMP getAllowsInternal(nsContentPolicyType aContentType,
                                     enum CSPKeyword aKeyword,
                                     const nsAString& aNonceOrContent,
                                     bool* outShouldReportViolations,
                                     bool* outIsAllowed) const;
 
+    bool permitsInternal(CSPDirective aDir,
+                         nsIURI* aContentLocation,
+                         nsIURI* aOriginalURI,
+                         const nsAString& aNonce,
+                         bool aWasRedirected,
+                         bool aIsPreload,
+                         bool aSpecific,
+                         bool aSendViolationReports,
+                         bool aSendContentLocationInViolationReports);
+
     nsCOMPtr<nsIURI>                           mReferrer;
     uint64_t                                   mInnerWindowID; // used for web console logging
     nsTArray<nsCSPPolicy*>                     mPolicies;
     nsCOMPtr<nsIURI>                           mSelfURI;
     nsDataHashtable<nsCStringHashKey, int16_t> mShouldLoadCache;
     nsCOMPtr<nsILoadGroup>                     mCallingChannelLoadGroup;
     nsWeakPtr                                  mLoadingContext;
 };
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -891,17 +891,17 @@ nsCSPParser::reportURIList(nsTArray<nsCS
 void
 nsCSPParser::directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs)
 {
   CSPPARSERLOG(("nsCSPParser::directiveValue"));
 
   // The tokenzier already generated an array in the form of
   // [ name, src, src, ... ], no need to parse again, but
   // special case handling in case the directive is report-uri.
-  if (CSP_IsDirective(mCurDir[0], CSP_REPORT_URI)) {
+  if (CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) {
     reportURIList(outSrcs);
     return;
   }
   // Otherwise just forward to sourceList
   sourceList(outSrcs);
 }
 
 // directive-name = 1*( ALPHA / DIGIT / "-" )
@@ -919,32 +919,32 @@ nsCSPParser::directiveName()
                              params, ArrayLength(params));
     return nullptr;
   }
 
   // The directive 'reflected-xss' is part of CSP 1.1, see:
   // http://www.w3.org/TR/2014/WD-CSP11-20140211/#reflected-xss
   // Currently we are not supporting that directive, hence we log a
   // warning to the console and ignore the directive including its values.
-  if (CSP_IsDirective(mCurToken, CSP_REFLECTED_XSS)) {
+  if (CSP_IsDirective(mCurToken, nsIContentSecurityPolicy::REFLECTED_XSS_DIRECTIVE)) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "notSupportingDirective",
                              params, ArrayLength(params));
     return nullptr;
   }
 
   // Make sure the directive does not already exist
   // (see http://www.w3.org/TR/CSP11/#parsing)
-  if (mPolicy->directiveExists(CSP_DirectiveToEnum(mCurToken))) {
+  if (mPolicy->hasDirective(CSP_StringToCSPDirective(mCurToken))) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "duplicateDirective",
                              params, ArrayLength(params));
     return nullptr;
   }
-  return new nsCSPDirective(CSP_DirectiveToEnum(mCurToken));
+  return new nsCSPDirective(CSP_StringToCSPDirective(mCurToken));
 }
 
 // directive = *WSP [ directive-name [ WSP directive-value ] ]
 void
 nsCSPParser::directive()
 {
   // Set the directiveName to mCurToken
   // Remember, the directive name is stored at index 0
@@ -1034,17 +1034,17 @@ nsCSPParser::parseContentSecurityPolicy(
   nsCSPParser parser(tokens, aSelfURI, aInnerWindowID);
 
   // Start the parser to generate a new CSPPolicy using the generated tokens.
   nsCSPPolicy* policy = parser.policy();
 
   // Check that report-only policies define a report-uri, otherwise log warning.
   if (aReportOnly) {
     policy->setReportOnlyFlag(true);
-    if (!policy->directiveExists(CSP_REPORT_URI)) {
+    if (!policy->hasDirective(nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) {
       nsAutoCString prePath;
       nsresult rv = aSelfURI->GetPrePath(prePath);
       NS_ENSURE_SUCCESS(rv, policy);
       NS_ConvertUTF8toUTF16 unicodePrePath(prePath);
       const char16_t* params[] = { unicodePrePath.get() };
       parser.logWarningErrorToConsole(nsIScriptError::warningFlag, "reportURInotInReportOnlyHeader",
                                       params, ArrayLength(params));
     }
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -122,16 +122,69 @@ CSP_LogLocalizedStr(const char16_t* aNam
   nsXPIDLString logMsg;
   CSP_GetLocalizedStr(aName, aParams, aLength, getter_Copies(logMsg));
   CSP_LogMessage(logMsg, aSourceName, aSourceLine,
                  aLineNumber, aColumnNumber, aFlags,
                  aCategory, aInnerWindowID);
 }
 
 /* ===== Helpers ============================ */
+CSPDirective
+CSP_ContentTypeToDirective(nsContentPolicyType aType)
+{
+  switch (aType) {
+    case nsIContentPolicy::TYPE_IMAGE:
+    case nsIContentPolicy::TYPE_IMAGESET:
+      return nsIContentSecurityPolicy::IMG_SRC_DIRECTIVE;
+
+    // BLock XSLT as script, see bug 910139
+    case nsIContentPolicy::TYPE_XSLT:
+    case nsIContentPolicy::TYPE_SCRIPT:
+      return nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE;
+
+    case nsIContentPolicy::TYPE_STYLESHEET:
+      return nsIContentSecurityPolicy::STYLE_SRC_DIRECTIVE;
+
+    case nsIContentPolicy::TYPE_FONT:
+      return nsIContentSecurityPolicy::FONT_SRC_DIRECTIVE;
+
+    case nsIContentPolicy::TYPE_MEDIA:
+      return nsIContentSecurityPolicy::MEDIA_SRC_DIRECTIVE;
+
+    // TYPE_DOCUMENT shouldn't be used since it's specifically whitelisted by
+    // the CSPService, but in case we do want to know which directive to check,
+    // FRAME_SRC is the best fit.
+    case nsIContentPolicy::TYPE_DOCUMENT:
+    case nsIContentPolicy::TYPE_SUBDOCUMENT:
+      return nsIContentSecurityPolicy::FRAME_SRC_DIRECTIVE;
+
+    case nsIContentPolicy::TYPE_WEBSOCKET:
+    case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
+    case nsIContentPolicy::TYPE_BEACON:
+    case nsIContentPolicy::TYPE_FETCH:
+      return nsIContentSecurityPolicy::CONNECT_SRC_DIRECTIVE;
+
+    case nsIContentPolicy::TYPE_OBJECT:
+    case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST:
+      return nsIContentSecurityPolicy::OBJECT_SRC_DIRECTIVE;
+
+    case nsIContentPolicy::TYPE_XBL:
+    case nsIContentPolicy::TYPE_PING:
+    case nsIContentPolicy::TYPE_DTD:
+    case nsIContentPolicy::TYPE_OTHER:
+      return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
+
+    // CSP can not block csp reports, fall through to error
+    case nsIContentPolicy::TYPE_CSP_REPORT:
+    // Fall through to error for all other directives
+    default:
+      MOZ_ASSERT(false, "Can not map nsContentPolicyType to CSPDirective");
+  }
+  return nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE;
+}
 
 nsCSPHostSrc*
 CSP_CreateHostSrcFromURI(nsIURI* aURI)
 {
   // Create the host first
   nsCString host;
   aURI->GetHost(host);
   nsCSPHostSrc *hostsrc = new nsCSPHostSrc(NS_ConvertUTF8toUTF16(host));
@@ -150,31 +203,29 @@ CSP_CreateHostSrcFromURI(nsIURI* aURI)
     hostsrc->setPort(portStr);
   }
   return hostsrc;
 }
 
 bool
 CSP_IsValidDirective(const nsAString& aDir)
 {
-  static_assert(CSP_LAST_DIRECTIVE_VALUE ==
-                (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0])),
-                "CSP_LAST_DIRECTIVE_VALUE does not match length of CSPStrDirectives");
+  uint32_t numDirs = (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]));
 
-  for (uint32_t i = 0; i < CSP_LAST_DIRECTIVE_VALUE; i++) {
+  for (uint32_t i = 0; i < numDirs; i++) {
     if (aDir.LowerCaseEqualsASCII(CSPStrDirectives[i])) {
       return true;
     }
   }
   return false;
 }
 bool
-CSP_IsDirective(const nsAString& aValue, enum CSPDirective aDir)
+CSP_IsDirective(const nsAString& aValue, CSPDirective aDir)
 {
-  return aValue.LowerCaseEqualsASCII(CSP_EnumToDirective(aDir));
+  return aValue.LowerCaseEqualsASCII(CSP_CSPDirectiveToString(aDir));
 }
 
 bool
 CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey)
 {
   return aValue.LowerCaseEqualsASCII(CSP_EnumToKeyword(aKey));
 }
 
@@ -465,17 +516,17 @@ void
 nsCSPHostSrc::appendPath(const nsAString& aPath)
 {
   mPath.Append(aPath);
   ToLowerCase(mPath);
 }
 
 /* ===== nsCSPKeywordSrc ===================== */
 
-nsCSPKeywordSrc::nsCSPKeywordSrc(CSPKeyword aKeyword)
+nsCSPKeywordSrc::nsCSPKeywordSrc(enum CSPKeyword aKeyword)
 {
   NS_ASSERTION((aKeyword != CSP_SELF),
                "'self' should have been replaced in the parser");
   mKeyword = aKeyword;
 }
 
 nsCSPKeywordSrc::~nsCSPKeywordSrc()
 {
@@ -619,17 +670,17 @@ nsCSPReportURI::toString(nsAString& outS
   if (NS_FAILED(rv)) {
     return;
   }
   outStr.AppendASCII(spec.get());
 }
 
 /* ===== nsCSPDirective ====================== */
 
-nsCSPDirective::nsCSPDirective(enum CSPDirective aDirective)
+nsCSPDirective::nsCSPDirective(CSPDirective aDirective)
 {
   mDirective = aDirective;
 }
 
 nsCSPDirective::~nsCSPDirective()
 {
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
     delete mSrcs[i];
@@ -675,99 +726,43 @@ nsCSPDirective::allows(enum CSPKeyword a
   }
   return false;
 }
 
 void
 nsCSPDirective::toString(nsAString& outStr) const
 {
   // Append directive name
-  outStr.AppendASCII(CSP_EnumToDirective(mDirective));
+  outStr.AppendASCII(CSP_CSPDirectiveToString(mDirective));
   outStr.AppendASCII(" ");
 
   // Append srcs
   uint32_t length = mSrcs.Length();
   for (uint32_t i = 0; i < length; i++) {
     mSrcs[i]->toString(outStr);
     if (i != (length - 1)) {
       outStr.AppendASCII(" ");
     }
   }
 }
 
-enum CSPDirective
-CSP_ContentTypeToDirective(nsContentPolicyType aType)
-{
-  switch (aType) {
-    case nsIContentPolicy::TYPE_IMAGE:
-    case nsIContentPolicy::TYPE_IMAGESET:
-      return CSP_IMG_SRC;
-
-    case nsIContentPolicy::TYPE_SCRIPT:
-      return CSP_SCRIPT_SRC;
-
-    case nsIContentPolicy::TYPE_STYLESHEET:
-      return CSP_STYLE_SRC;
-
-    case nsIContentPolicy::TYPE_FONT:
-      return CSP_FONT_SRC;
-
-    case nsIContentPolicy::TYPE_MEDIA:
-      return CSP_MEDIA_SRC;
-
-    case nsIContentPolicy::TYPE_SUBDOCUMENT:
-      return CSP_FRAME_SRC;
-
-    // BLock XSLT as script, see bug 910139
-    case nsIContentPolicy::TYPE_XSLT:
-      return CSP_SCRIPT_SRC;
-
-    // TODO(sid): fix this mapping to be more precise (bug 999656)
-    case nsIContentPolicy::TYPE_DOCUMENT:
-      return CSP_FRAME_ANCESTORS;
-
-    case nsIContentPolicy::TYPE_WEBSOCKET:
-    case nsIContentPolicy::TYPE_XMLHTTPREQUEST:
-    case nsIContentPolicy::TYPE_BEACON:
-    case nsIContentPolicy::TYPE_FETCH:
-      return CSP_CONNECT_SRC;
-
-    case nsIContentPolicy::TYPE_OBJECT:
-    case nsIContentPolicy::TYPE_OBJECT_SUBREQUEST:
-      return CSP_OBJECT_SRC;
-
-    case nsIContentPolicy::TYPE_XBL:
-    case nsIContentPolicy::TYPE_PING:
-    case nsIContentPolicy::TYPE_DTD:
-    case nsIContentPolicy::TYPE_OTHER:
-      return CSP_DEFAULT_SRC;
-
-    // CSP can not block csp reports, fall through to error
-    case nsIContentPolicy::TYPE_CSP_REPORT:
-    // Fall through to error for all other directives
-    default:
-      NS_ASSERTION(false, "Can not map nsContentPolicyType to CSPDirective");
-  }
-  return CSP_DEFAULT_SRC;
-}
-
 bool
 nsCSPDirective::restrictsContentType(nsContentPolicyType aContentType) const
 {
   // make sure we do not check for the default src before any other sources
   if (isDefaultDirective()) {
     return false;
   }
   return mDirective == CSP_ContentTypeToDirective(aContentType);
 }
 
 void
 nsCSPDirective::getReportURIs(nsTArray<nsString> &outReportURIs) const
 {
-  NS_ASSERTION((mDirective == CSP_REPORT_URI), "not a report-uri directive");
+  NS_ASSERTION((mDirective == nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE), "not a report-uri directive");
 
   // append uris
   nsString tmpReportURI;
   for (uint32_t i = 0; i < mSrcs.Length(); i++) {
     tmpReportURI.Truncate();
     mSrcs[i]->toString(tmpReportURI);
     outReportURIs.AppendElement(tmpReportURI);
   }
@@ -786,118 +781,72 @@ nsCSPPolicy::~nsCSPPolicy()
   CSPUTILSLOG(("nsCSPPolicy::~nsCSPPolicy"));
 
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     delete mDirectives[i];
   }
 }
 
 bool
-nsCSPPolicy::permits(nsContentPolicyType aContentType,
+nsCSPPolicy::permits(CSPDirective aDir,
+                     nsIURI* aUri,
+                     bool aSpecific) const
+{
+  nsString outp;
+  return this->permits(aDir, aUri, EmptyString(), false, aSpecific, outp);
+}
+
+bool
+nsCSPPolicy::permits(CSPDirective aDir,
                      nsIURI* aUri,
                      const nsAString& aNonce,
                      bool aWasRedirected,
+                     bool aSpecific,
                      nsAString& outViolatedDirective) const
 {
 #ifdef PR_LOGGING
   {
     nsAutoCString spec;
     aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPPolicy::permits, aContentType: %d, aUri: %s, aNonce: %s",
-                aContentType, spec.get(), NS_ConvertUTF16toUTF8(aNonce).get()));
+    CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %d, aSpecific: %s",
+                 spec.get(), aDir, aSpecific ? "true" : "false"));
   }
 #endif
 
   NS_ASSERTION(aUri, "permits needs an uri to perform the check!");
 
   nsCSPDirective* defaultDir = nullptr;
 
+  // Try to find a relevant directive
   // These directive arrays are short (1-5 elements), not worth using a hashtable.
-
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
-    // Check if the directive name matches
-    if (mDirectives[i]->restrictsContentType(aContentType)) {
+    if (mDirectives[i]->equals(aDir)) {
       if (!mDirectives[i]->permits(aUri, aNonce, aWasRedirected)) {
         mDirectives[i]->toString(outViolatedDirective);
         return false;
       }
       return true;
     }
     if (mDirectives[i]->isDefaultDirective()) {
       defaultDir = mDirectives[i];
     }
   }
 
-  // If [frame-ancestors] is not listed explicitly then default to true
-  // without consulting [default-src]
-  // TODO: currently [frame-ancestors] is mapped to TYPE_DOCUMENT (needs to be fixed)
-  if (aContentType == nsIContentPolicy::TYPE_DOCUMENT) {
-    return true;
-  }
-
   // If the above loop runs through, we haven't found a matching directive.
   // Avoid relooping, just store the result of default-src while looping.
-  if (defaultDir) {
+  if (!aSpecific && defaultDir) {
     if (!defaultDir->permits(aUri, aNonce, aWasRedirected)) {
       defaultDir->toString(outViolatedDirective);
       return false;
     }
     return true;
   }
 
-  // unspecified default-src should default to no restrictions
-  // see bug 764937
-  return true;
-}
-
-bool
-nsCSPPolicy::permitsBaseURI(nsIURI* aUri) const
-{
-#ifdef PR_LOGGING
-  {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPPolicy::permitsBaseURI, aUri: %s", spec.get()));
-  }
-#endif
-
-  // Try to find a base-uri directive
-  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
-    if (mDirectives[i]->equals(CSP_BASE_URI)) {
-      return mDirectives[i]->permits(aUri);
-    }
-  }
-
-  // base-uri is only enforced if explicitly defined in the
-  // policy - do *not* consult default-src, see:
-  // http://www.w3.org/TR/CSP11/#directive-default-src
-  return true;
-}
-
-bool
-nsCSPPolicy::permitsFormAction(nsIURI* aUri) const
-{
-#ifdef PR_LOGGING
-  {
-    nsAutoCString spec;
-    aUri->GetSpec(spec);
-    CSPUTILSLOG(("nsCSPPolicy::permitsFormAction, aUri: %s", spec.get()));
-  }
-#endif
-
-  // Try to find a form-action directive
-  for (uint32_t i = 0; i < mDirectives.Length(); i++) {
-    if (mDirectives[i]->equals(CSP_FORM_ACTION)) {
-      return mDirectives[i]->permits(aUri);
-    }
-  }
-
-  // form-action is only enforced if explicitly defined in the
-  // policy - do *not* consult default-src, see:
-  // http://www.w3.org/TR/CSP2/#directive-default-src
+  // Nothing restricts this, so we're allowing the load
+  // See bug 764937
   return true;
 }
 
 bool
 nsCSPPolicy::allows(nsContentPolicyType aContentType,
                     enum CSPKeyword aKeyword,
                     const nsAString& aHashOrNonce) const
 {
@@ -953,17 +902,17 @@ nsCSPPolicy::toString(nsAString& outStr)
     mDirectives[i]->toString(outStr);
     if (i != (length - 1)) {
       outStr.AppendASCII("; ");
     }
   }
 }
 
 bool
-nsCSPPolicy::directiveExists(enum CSPDirective aDir) const
+nsCSPPolicy::hasDirective(CSPDirective aDir) const
 {
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->equals(aDir)) {
       return true;
     }
   }
   return false;
 }
@@ -994,28 +943,28 @@ nsCSPPolicy::getDirectiveStringForConten
     defaultDir->toString(outDirective);
     return;
   }
   NS_ASSERTION(false, "Can not query directive string for contentType!");
   outDirective.AppendASCII("couldNotQueryViolatedDirective");
 }
 
 void
-nsCSPPolicy::getDirectiveAsString(enum CSPDirective aDir, nsAString& outDirective) const
+nsCSPPolicy::getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const
 {
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
     if (mDirectives[i]->equals(aDir)) {
       mDirectives[i]->toString(outDirective);
       return;
     }
   }
 }
 
 void
 nsCSPPolicy::getReportURIs(nsTArray<nsString>& outReportURIs) const
 {
   for (uint32_t i = 0; i < mDirectives.Length(); i++) {
-    if (mDirectives[i]->equals(CSP_REPORT_URI)) {
+    if (mDirectives[i]->equals(nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) {
       mDirectives[i]->getReportURIs(outReportURIs);
       return;
     }
   }
 }
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsCSPUtils_h___
 #define nsCSPUtils_h___
 
 #include "nsCOMPtr.h"
 #include "nsIContentPolicy.h"
+#include "nsIContentSecurityPolicy.h"
 #include "nsIURI.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsUnicharUtils.h"
 #include "prlog.h"
 
 /* =============== Logging =================== */
 
@@ -49,82 +50,55 @@ void CSP_LogMessage(const nsAString& aMe
 #define INLINE_STYLE_VIOLATION_OBSERVER_TOPIC   "violated base restriction: Inline Stylesheets will not apply"
 #define INLINE_SCRIPT_VIOLATION_OBSERVER_TOPIC  "violated base restriction: Inline Scripts will not execute"
 #define EVAL_VIOLATION_OBSERVER_TOPIC           "violated base restriction: Code will not be created from strings"
 #define SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC   "Inline Script had invalid nonce"
 #define STYLE_NONCE_VIOLATION_OBSERVER_TOPIC    "Inline Style had invalid nonce"
 #define SCRIPT_HASH_VIOLATION_OBSERVER_TOPIC    "Inline Script had invalid hash"
 #define STYLE_HASH_VIOLATION_OBSERVER_TOPIC     "Inline Style had invalid hash"
 
-
-// Please add any new enum items not only to CSPDirective, but also add
-// a string version for every enum >> using the same index << to
-// CSPStrDirectives underneath.
-enum CSPDirective {
-  CSP_DEFAULT_SRC = 0,
-  CSP_SCRIPT_SRC,
-  CSP_OBJECT_SRC,
-  CSP_STYLE_SRC,
-  CSP_IMG_SRC,
-  CSP_MEDIA_SRC,
-  CSP_FRAME_SRC,
-  CSP_FONT_SRC,
-  CSP_CONNECT_SRC,
-  CSP_REPORT_URI,
-  CSP_FRAME_ANCESTORS,
-  CSP_REFLECTED_XSS,
-  CSP_BASE_URI,
-  CSP_FORM_ACTION,
-  // CSP_LAST_DIRECTIVE_VALUE always needs to be the last element in the enum
-  // because we use it to calculate the size for the char* array.
-  CSP_LAST_DIRECTIVE_VALUE
+// these strings map to the CSPDirectives in nsIContentSecurityPolicy
+// NOTE: When implementing a new directive, you will need to add it here but also
+// add a corresponding entry to the constants in nsIContentSecurityPolicy.idl
+static const char* CSPStrDirectives[] = {
+  "-error-",    // NO_DIRECTIVE
+  "default-src",     // DEFAULT_SRC_DIRECTIVE
+  "script-src",      // SCRIPT_SRC_DIRECTIVE
+  "object-src",      // OBJECT_SRC_DIRECTIVE
+  "style-src",       // STYLE_SRC_DIRECTIVE
+  "img-src",         // IMG_SRC_DIRECTIVE
+  "media-src",       // MEDIA_SRC_DIRECTIVE
+  "frame-src",       // FRAME_SRC_DIRECTIVE
+  "font-src",        // FONT_SRC_DIRECTIVE
+  "connect-src",     // CONNECT_SRC_DIRECTIVE
+  "report-uri",      // REPORT_URI_DIRECTIVE
+  "frame-ancestors", // FRAME_ANCESTORS_DIRECTIVE
+  "reflected-xss",   // REFLECTED_XSS_DIRECTIVE
+  "base-uri",        // BASE_URI_DIRECTIVE
+  "form-action"      // FORM_ACTION_DIRECTIVE
 };
 
-static const char* CSPStrDirectives[] = {
-  "default-src",     // CSP_DEFAULT_SRC = 0
-  "script-src",      // CSP_SCRIPT_SRC
-  "object-src",      // CSP_OBJECT_SRC
-  "style-src",       // CSP_STYLE_SRC
-  "img-src",         // CSP_IMG_SRC
-  "media-src",       // CSP_MEDIA_SRC
-  "frame-src",       // CSP_FRAME_SRC
-  "font-src",        // CSP_FONT_SRC
-  "connect-src",     // CSP_CONNECT_SRC
-  "report-uri",      // CSP_REPORT_URI
-  "frame-ancestors", // CSP_FRAME_ANCESTORS
-  "reflected-xss",   // CSP_REFLECTED_XSS
-  "base-uri",        // CSP_BASE_URI
-  "form-action"      // CSP_FORM_ACTION
-};
-
-inline const char* CSP_EnumToDirective(enum CSPDirective aDir)
+inline const char* CSP_CSPDirectiveToString(CSPDirective aDir)
 {
-  // Make sure all elements in enum CSPDirective got added to CSPStrDirectives.
-  static_assert((sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]) ==
-                static_cast<uint32_t>(CSP_LAST_DIRECTIVE_VALUE)),
-                "CSP_LAST_DIRECTIVE_VALUE does not match length of CSPStrDirectives");
   return CSPStrDirectives[static_cast<uint32_t>(aDir)];
 }
 
-inline CSPDirective CSP_DirectiveToEnum(const nsAString& aDir)
+inline CSPDirective CSP_StringToCSPDirective(const nsAString& aDir)
 {
   nsString lowerDir = PromiseFlatString(aDir);
   ToLowerCase(lowerDir);
 
-  static_assert(CSP_LAST_DIRECTIVE_VALUE ==
-                (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0])),
-                "CSP_LAST_DIRECTIVE_VALUE does not match length of CSPStrDirectives");
-
-  for (uint32_t i = 0; i < CSP_LAST_DIRECTIVE_VALUE; i++) {
+  uint32_t numDirs = (sizeof(CSPStrDirectives) / sizeof(CSPStrDirectives[0]));
+  for (uint32_t i = 1; i < numDirs; i++) {
     if (lowerDir.EqualsASCII(CSPStrDirectives[i])) {
       return static_cast<CSPDirective>(i);
     }
   }
-  NS_ASSERTION(false, "Can not convert unknown Directive to Enum");
-  return CSP_LAST_DIRECTIVE_VALUE;
+  NS_ASSERTION(false, "Can not convert unknown Directive to Integer");
+  return nsIContentSecurityPolicy::NO_DIRECTIVE;
 }
 
 // Please add any new enum items not only to CSPKeyword, but also add
 // a string version for every enum >> using the same index << to
 // CSPStrKeywords underneath.
 enum CSPKeyword {
   CSP_SELF = 0,
   CSP_UNSAFE_INLINE,
@@ -177,19 +151,21 @@ inline CSPKeyword CSP_KeywordToEnum(cons
 }
 
 /* =============== Helpers ================== */
 
 class nsCSPHostSrc;
 
 nsCSPHostSrc* CSP_CreateHostSrcFromURI(nsIURI* aURI);
 bool CSP_IsValidDirective(const nsAString& aDir);
-bool CSP_IsDirective(const nsAString& aValue, enum CSPDirective aDir);
+bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir);
 bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey);
 bool CSP_IsQuotelessKeyword(const nsAString& aKey);
+CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType);
+
 
 /* =============== nsCSPSrc ================== */
 
 class nsCSPBaseSrc {
   public:
     nsCSPBaseSrc();
     virtual ~nsCSPBaseSrc();
 
@@ -291,80 +267,82 @@ class nsCSPReportURI : public nsCSPBaseS
     nsCOMPtr<nsIURI> mReportURI;
 };
 
 /* =============== nsCSPDirective ============= */
 
 class nsCSPDirective {
   public:
     nsCSPDirective();
-    explicit nsCSPDirective(enum CSPDirective aDirective);
+    explicit nsCSPDirective(CSPDirective aDirective);
     virtual ~nsCSPDirective();
 
     bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected) const;
     bool permits(nsIURI* aUri) const;
     bool allows(enum CSPKeyword aKeyword, const nsAString& aHashOrNonce) const;
     void toString(nsAString& outStr) const;
 
     inline void addSrcs(const nsTArray<nsCSPBaseSrc*>& aSrcs)
       { mSrcs = aSrcs; }
 
     bool restrictsContentType(nsContentPolicyType aContentType) const;
 
     inline bool isDefaultDirective() const
-     { return mDirective == CSP_DEFAULT_SRC; }
+     { return mDirective == nsIContentSecurityPolicy::DEFAULT_SRC_DIRECTIVE; }
 
-    inline bool equals(enum CSPDirective aDirective) const
+    inline bool equals(CSPDirective aDirective) const
       { return (mDirective == aDirective); }
 
     void getReportURIs(nsTArray<nsString> &outReportURIs) const;
 
   private:
     CSPDirective            mDirective;
     nsTArray<nsCSPBaseSrc*> mSrcs;
 };
 
 /* =============== nsCSPPolicy ================== */
 
 class nsCSPPolicy {
   public:
     nsCSPPolicy();
     virtual ~nsCSPPolicy();
 
-    bool permits(nsContentPolicyType aContentType,
+    bool permits(CSPDirective aDirective,
                  nsIURI* aUri,
                  const nsAString& aNonce,
                  bool aWasRedirected,
+                 bool aSpecific,
                  nsAString& outViolatedDirective) const;
-    bool permitsBaseURI(nsIURI* aUri) const;
-    bool permitsFormAction(nsIURI* aUri) const;
+    bool permits(CSPDirective aDir,
+                 nsIURI* aUri,
+                 bool aSpecific) const;
     bool allows(nsContentPolicyType aContentType,
                 enum CSPKeyword aKeyword,
                 const nsAString& aHashOrNonce) const;
     bool allows(nsContentPolicyType aContentType,
                 enum CSPKeyword aKeyword) const;
     void toString(nsAString& outStr) const;
 
     inline void addDirective(nsCSPDirective* aDir)
       { mDirectives.AppendElement(aDir); }
 
-    bool directiveExists(enum CSPDirective aDir) const;
+    bool hasDirective(CSPDirective aDir) const;
 
     inline void setReportOnlyFlag(bool aFlag)
       { mReportOnly = aFlag; }
 
     inline bool getReportOnlyFlag() const
       { return mReportOnly; }
 
     void getReportURIs(nsTArray<nsString> &outReportURIs) const;
 
     void getDirectiveStringForContentType(nsContentPolicyType aContentType,
                                           nsAString& outDirective) const;
 
-    void getDirectiveAsString(enum CSPDirective aDir, nsAString& outDirective) const;
+    void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const;
 
     inline uint32_t getNumDirectives() const
       { return mDirectives.Length(); }
 
   private:
     nsTArray<nsCSPDirective*> mDirectives;
     bool                      mReportOnly;
 };