Bug 878790 - Undo backout of 821877. a=lsblakk
authorGarrett Robinson <grobinson@mozilla.com>
Tue, 04 Jun 2013 15:54:47 -0400
changeset 138653 158f14d242d7d710b4ea627e45b93e60306b11dc
parent 138652 afa4b9a24f20c6c84866a57438b6886cea3a5b4a
child 138654 089956e907ede88347bad202149fbdcbdc62d544
push id3839
push userryanvm@gmail.com
push dateTue, 04 Jun 2013 20:00:37 +0000
treeherdermozilla-aurora@158f14d242d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsblakk
bugs878790, 821877, 863878
milestone23.0a2
Bug 878790 - Undo backout of 821877. a=lsblakk Bug 821877 - Log CSP errors to Web Console. r=bz * * * Browser Mochitest for CSP error logging to Web Console Also fixes another CSP brower chrome test that was broken because it uses the old CSP headers and assumed that only one warning would be logged to the Web Console. * * * Bug 863878 - The CSP logging from bug 821877 should go to the new Security Pane in the Web Console
browser/devtools/webconsole/test/Makefile.in
browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
browser/devtools/webconsole/test/browser_webconsole_bug_821877_csp_errors.js
browser/devtools/webconsole/test/test-bug-821877-csperrors.html
browser/devtools/webconsole/test/test-bug-821877-csperrors.html^headers^
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
dom/locales/en-US/chrome/security/security.properties
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -124,16 +124,19 @@ MOCHITEST_BROWSER_FILES = \
 	browser_webconsole_bug_837351_securityerrors.js \
 	browser_bug_865871_variables_view_close_on_esc_key.js \
 	browser_bug_865288_repeat_different_objects.js \
 	browser_jsterm_inspect.js \
 	browser_bug_869003_inspect_cross_domain_object.js \
 	browser_bug_862916_console_dir_and_filter_off.js \
 	browser_console_native_getters.js \
 	browser_bug_871156_ctrlw_close_tab.js \
+	browser_webconsole_bug_821877_csp_errors.js \
+	test-bug-821877-csperrors.html \
+	test-bug-821877-csperrors.html^headers^ \
 	head.js \
 	$(NULL)
 
 ifeq ($(OS_ARCH), Darwin)
 MOCHITEST_BROWSER_FILES += \
 	browser_webconsole_bug_804845_ctrl_key_nav.js \
         $(NULL)
 endif
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js
@@ -3,16 +3,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that the Web Console CSP messages are displayed
 
 const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html";
+const CSP_VIOLATION_MSG = "CSP WARN:  Directive default-src https://example.com:443 violated by http://some.example.com/test.png"
 
 let hud = undefined;
 
 function test() {
   addTab("data:text/html;charset=utf8,Web Console CSP violation test");
   browser.addEventListener("load", function _onLoad() {
     browser.removeEventListener("load", _onLoad, true);
     openConsole(null, loadDocument);
@@ -29,27 +30,17 @@ function loadDocument(theHud){
 function onLoad(aEvent) {
   browser.removeEventListener("load", onLoad, true);
   testViolationMessage();
 }
 
 function testViolationMessage(){
   let aOutputNode = hud.outputNode;
 
-  waitForSuccess(
-    {
+  waitForSuccess({
       name: "CSP policy URI warning displayed successfully",
       validatorFn: function() {
-        return aOutputNode.querySelector(".webconsole-msg-warn");
+        return hud.outputNode.textContent.indexOf(CSP_VIOLATION_MSG) > -1;
       },
-
-      successFn: function() {
-        //tests on the urlnode
-        let node = aOutputNode.querySelector(".webconsole-msg-warn");
-        isnot(node.textContent.indexOf("violated"), -1,
-                                       "CSP violation message found");
-        finishTest();
-      },
-
+      successFn: finishTest,
       failureFn: finishTest,
-    }
-  );
+    });
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_821877_csp_errors.js
@@ -0,0 +1,28 @@
+// Tests that CSP errors from nsDocument::InitCSP are logged to the Web Console
+
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-bug-821877-csperrors.html";
+const CSP_DEPRECATED_HEADER_MSG = "The X-Content-Security-Policy and X-Content-Security-Report-Only headers will be deprecated in the future. Please use the Content-Security-Policy and Content-Security-Report-Only headers with CSP spec compliant syntax instead.";
+
+function test()
+{
+  addTab(TEST_URI);
+  browser.addEventListener("load", function onLoad(aEvent) {
+    browser.removeEventListener(aEvent.type, onLoad, true);
+    openConsole(null, function testCSPErrorLogged (hud) {
+      waitForMessages({
+        webconsole: hud,
+        messages: [
+          {
+            name: "Deprecated CSP header error displayed successfully",
+            text: CSP_DEPRECATED_HEADER_MSG,
+            category: CATEGORY_SECURITY,
+            severity: SEVERITY_WARNING
+          },
+        ],
+      }).then(finishTest);
+    });
+  }, true);
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-821877-csperrors.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf8">
+    <title>Bug 821877 - Log CSP Errors to Web Console</title>
+    <!-- Any copyright is dedicated to the Public Domain.
+       - http://creativecommons.org/publicdomain/zero/1.0/ -->
+  </head>
+  <body>
+    <p>This page is served with a deprecated CSP header.</p>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/test-bug-821877-csperrors.html^headers^
@@ -0,0 +1,1 @@
+X-Content-Security-Policy: default-src *; options inline-script
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2399,16 +2399,34 @@ nsDocument::StartDocumentLoad(const char
   }
 
   nsresult rv = InitCSP(aChannel);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
+void
+CSPErrorQueue::Add(const char* aMessageName)
+{
+  mErrors.AppendElement(aMessageName);
+}
+
+void
+CSPErrorQueue::Flush(nsIDocument* aDocument)
+{
+  for (uint32_t i = 0; i < mErrors.Length(); i++) {
+    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+        "CSP", aDocument,
+        nsContentUtils::eSECURITY_PROPERTIES,
+        mErrors[i]);
+  }
+  mErrors.Clear();
+}
+
 nsresult
 nsDocument::InitCSP(nsIChannel* aChannel)
 {
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   if (!CSPService::sCSPEnabled) {
 #ifdef PR_LOGGING
     PR_LOG(gCspPRLog, PR_LOG_DEBUG,
            ("CSP is disabled, skipping CSP init for document %p", this));
@@ -2550,28 +2568,22 @@ nsDocument::InitCSP(nsIChannel* aChannel
 
   // While we are supporting both CSP 1.0 and the x- headers, the 1.0 headers
   // take priority.  If any spec-compliant headers are present, the x- headers
   // are ignored, and the spec compliant parser is used.
   bool cspSpecCompliant = (!cspHeaderValue.IsEmpty() || !cspROHeaderValue.IsEmpty());
 
   // If the old header is present, warn that it will be deprecated.
   if (!cspOldHeaderValue.IsEmpty() || !cspOldROHeaderValue.IsEmpty()) {
-    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
-                                    "CSP", this,
-                                    nsContentUtils::eSECURITY_PROPERTIES,
-                                    "OldCSPHeaderDeprecated");
+    mCSPWebConsoleErrorQueue.Add("OldCSPHeaderDeprecated");
 
     // Also, if the new headers AND the old headers were present, warn
     // that the old headers will be ignored.
     if (cspSpecCompliant) {
-      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
-                                      "CSP", this,
-                                      nsContentUtils::eSECURITY_PROPERTIES,
-                                      "BothCSPHeadersPresent");
+      mCSPWebConsoleErrorQueue.Add("BothCSPHeadersPresent");
     }
   }
 
   // ----- if there's a full-strength CSP header, apply it.
   bool applyCSPFromHeader =
     (( cspSpecCompliant && !cspHeaderValue.IsEmpty()) ||
      (!cspSpecCompliant && !cspOldHeaderValue.IsEmpty()));
 
@@ -2597,20 +2609,17 @@ nsDocument::InitCSP(nsIChannel* aChannel
 
   // ----- if there's a report-only CSP header, apply it
   if (( cspSpecCompliant && !cspROHeaderValue.IsEmpty()) ||
       (!cspSpecCompliant && !cspOldROHeaderValue.IsEmpty())) {
     // post a warning and skip report-only CSP when both read only and regular
     // CSP policies are present since CSP only allows one policy and it can't
     // be partially report-only.
     if (applyAppDefaultCSP || applyCSPFromHeader) {
-      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
-                                      "CSP", this,
-                                      nsContentUtils::eSECURITY_PROPERTIES,
-                                      "ReportOnlyCSPIgnored");
+      mCSPWebConsoleErrorQueue.Add("ReportOnlyCSPIgnored");
 #ifdef PR_LOGGING
       PR_LOG(gCspPRLog, PR_LOG_DEBUG,
               ("Skipped report-only CSP init for document %p because another, enforced policy is set", this));
 #endif
     } else {
       // we can apply the report-only policy because there's no other CSP
       // applied.
       csp->SetReportOnlyMode(true);
@@ -4184,16 +4193,20 @@ nsDocument::SetScriptGlobalObject(nsIScr
     MaybeRescheduleAnimationFrameNotifications();
   }
 
   // Remember the pointer to our window (or lack there of), to avoid
   // having to QI every time it's asked for.
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
   mWindow = window;
 
+  // Now that we know what our window is, we can flush the CSP errors to the
+  // Web Console.
+  FlushCSPWebConsoleErrorQueue();
+
   // Set our visibility state, but do not fire the event.  This is correct
   // because either we're coming out of bfcache (in which case IsVisible() will
   // still test false at this point and no state change will happen) or we're
   // doing the initial document load and don't want to fire the event for this
   // change.
   mVisibilityState = GetVisibilityState();
 }
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -458,16 +458,39 @@ protected:
                                nsILoadGroup* aLoadGroup,
                                nsIDocument* aDisplayDocument);
   
   nsClassHashtable<nsURIHashKey, ExternalResource> mMap;
   nsRefPtrHashtable<nsURIHashKey, PendingLoad> mPendingLoads;
   bool mHaveShutDown;
 };
 
+class CSPErrorQueue
+{
+  public:
+    /**
+     * Note this was designed to be passed string literals. If you give it
+     * a dynamically allocated string, it is your responsibility to make sure
+     * it never dies and is properly freed!
+     */
+    void Add(const char* aMessageName);
+    void Flush(nsIDocument* aDocument);
+
+    CSPErrorQueue()
+    {
+    }
+
+    ~CSPErrorQueue()
+    {
+    }
+
+  private:
+    nsAutoTArray<const char*,5> mErrors;
+};
+
 // Base class for our document implementations.
 //
 // Note that this class *implements* nsIDOMXMLDocument, but it's not
 // really an nsIDOMXMLDocument. The reason for implementing
 // nsIDOMXMLDocument on this class is to avoid having to duplicate all
 // its inherited methods on document classes that *are*
 // nsIDOMXMLDocument's. nsDocument's QI should *not* claim to support
 // nsIDOMXMLDocument unless someone writes a real implementation of
@@ -1312,16 +1335,21 @@ private:
   void NotifyStyleSheetRemoved(nsIStyleSheet* aSheet, bool aDocumentSheet);
 
   void PostUnblockOnloadEvent();
   void DoUnblockOnload();
 
   nsresult CheckFrameOptions();
   nsresult InitCSP(nsIChannel* aChannel);
 
+  void FlushCSPWebConsoleErrorQueue()
+  {
+    mCSPWebConsoleErrorQueue.Flush(this);
+  }
+
   /**
    * Find the (non-anonymous) content in this document for aFrame. It will
    * be aFrame's content node if that content is in this document and not
    * anonymous. Otherwise, when aFrame is in a subdocument, we use the frame
    * element containing the subdocument containing aFrame, and/or find the
    * nearest non-anonymous ancestor in this document.
    * Returns null if there is no such element.
    */
@@ -1410,16 +1438,18 @@ private:
   bool mValidWidth, mValidHeight;
   float mScaleMinFloat, mScaleMaxFloat, mScaleFloat, mPixelRatio;
   bool mAutoSize, mAllowZoom, mValidScaleFloat, mValidMaxScale, mScaleStrEmpty, mWidthStrEmpty;
   uint32_t mViewportWidth, mViewportHeight;
 
   nsrefcnt mStackRefCnt;
   bool mNeedsReleaseAfterStackRefCntRelease;
 
+  CSPErrorQueue mCSPWebConsoleErrorQueue;
+
 #ifdef DEBUG
 protected:
   bool mWillReparent;
 #endif
 };
 
 class nsDocumentOnStack
 {
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -1,11 +1,19 @@
 # Mixed Content Blocker
 # LOCALIZATION NOTE: "%1$S" is the URI of the blocked mixed content resource
+# Mixed Content Blocker
 BlockMixedDisplayContent = Blocked loading mixed display content "%1$S"
 BlockMixedActiveContent = Blocked loading mixed active content "%1$S"
 
 # CSP
 ReportOnlyCSPIgnored=Report-only CSP policy will be ignored because there are other non-report-only CSP policies applied.
 # LOCALIZATION NOTE: Do not translate "X-Content-Security-Policy", "X-Content-Security-Policy-Report-Only",  "Content-Security-Policy" or "Content-Security-Policy-Report-Only"
 OldCSPHeaderDeprecated=The X-Content-Security-Policy and X-Content-Security-Report-Only headers will be deprecated in the future. Please use the Content-Security-Policy and Content-Security-Report-Only headers with CSP spec compliant syntax instead.
 # LOCALIZATION NOTE: Do not translate "X-Content-Security-Policy/Report-Only" or "Content-Security-Policy/Report-Only"
 BothCSPHeadersPresent=This site specified both an X-Content-Security-Policy/Report-Only header and a Content-Security-Policy/Report-Only header. The X-Content-Security-Policy/Report-Only header(s) will be ignored.
+
+# CSP
+ReportOnlyCSPIgnored=Report-only CSP policy will be ignored because there are other non-report-only CSP policies applied.
+# LOCALIZATION NOTE: Do not translate "X-Content-Security-Policy", "X-Content-Security-Policy-Report-Only",  "Content-Security-Policy" or "Content-Security-Policy-Report-Only"
+OldCSPHeaderDeprecated=The X-Content-Security-Policy and X-Content-Security-Report-Only headers will be deprecated in the future. Please use the Content-Security-Policy and Content-Security-Report-Only headers with CSP spec compliant syntax instead.
+# LOCALIZATION NOTE: Do not translate "X-Content-Security-Policy/Report-Only" or "Content-Security-Policy/Report-Only"
+BothCSPHeadersPresent=This site specified both an X-Content-Security-Policy/Report-Only header and a Content-Security-Policy/Report-Only header. The X-Content-Security-Policy/Report-Only header(s) will be ignored.