Bug 1188028 - Queue up CSP console messages till windowID is available (r=sicking)
authorChristoph Kerschbaumer <mozilla@christophkerschbaumer.com>
Wed, 11 Nov 2015 06:23:57 -0800
changeset 272105 573a41d3890e2f7a38c30ba7f484099c0bb930b4
parent 272104 acc983ca0dec710088764398caba4eb10512de21
child 272106 bfe8a49ff8808fd20f6432ee4294bcf7ad6640c6
push id67865
push usermozilla@christophkerschbaumer.com
push dateWed, 11 Nov 2015 14:48:14 +0000
treeherdermozilla-inbound@bfe8a49ff880 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs1188028
milestone45.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 1188028 - Queue up CSP console messages till windowID is available (r=sicking)
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/security/nsCSPContext.cpp
dom/security/nsCSPContext.h
dom/security/nsCSPParser.cpp
dom/security/nsCSPParser.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -169,16 +169,17 @@
 #include "imgIContainer.h"
 #include "nsSVGUtils.h"
 #include "SVGElementFactory.h"
 
 #include "nsRefreshDriver.h"
 
 // FOR CSP (autogenerated by xpidl)
 #include "nsIContentSecurityPolicy.h"
+#include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/nsCSPService.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsHTMLCSSStyleSheet.h"
 #include "SVGAttrAnimationRuleProcessor.h"
 #include "mozilla/dom/DOMImplementation.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/Comment.h"
 #include "nsTextNode.h"
@@ -2579,34 +2580,16 @@ 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,
-        NS_LITERAL_CSTRING("CSP"), aDocument,
-        nsContentUtils::eSECURITY_PROPERTIES,
-        mErrors[i]);
-  }
-  mErrors.Clear();
-}
-
-void
 nsDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
 {
   for (uint32_t i = 0; i < aMessages.Length(); ++i) {
     nsAutoString messageTag;
     aMessages[i]->GetTag(messageTag);
 
     nsAutoString category;
     aMessages[i]->GetCategory(category);
@@ -4593,17 +4576,22 @@ nsDocument::SetScriptGlobalObject(nsIScr
   // 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. We are flushing all messages that occured and were stored
   // in the queue prior to this point.
-  FlushCSPWebConsoleErrorQueue();
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  NodePrincipal()->GetCsp(getter_AddRefs(csp));
+  if (csp) {
+    static_cast<nsCSPContext*>(csp.get())->flushConsoleMessages();
+  }
+
   nsCOMPtr<nsIHttpChannelInternal> internalChannel =
     do_QueryInterface(GetChannel());
   if (internalChannel) {
     nsCOMArray<nsISecurityConsoleMessage> messages;
     internalChannel->TakeAllSecurityMessages(messages);
     SendToConsole(messages);
   }
 
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -656,39 +656,16 @@ 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
@@ -1735,21 +1712,16 @@ private:
 
   void PostUnblockOnloadEvent();
   void DoUnblockOnload();
 
   nsresult CheckFrameOptions();
   bool IsLoopDocument(nsIChannel* aChannel);
   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.
    */
@@ -1863,18 +1835,16 @@ private:
   mozilla::LayoutDeviceToScreenScale mScaleFloat;
   mozilla::CSSToLayoutDeviceScale mPixelRatio;
   bool mAutoSize, mAllowZoom, mAllowDoubleTapZoom, mValidScaleFloat, mValidMaxScale, mScaleStrEmpty, mWidthStrEmpty;
   mozilla::CSSSize mViewportSize;
 
   nsrefcnt mStackRefCnt;
   bool mNeedsReleaseAfterStackRefCntRelease;
 
-  CSPErrorQueue mCSPWebConsoleErrorQueue;
-
   nsCOMPtr<nsIDocument> mMasterDocument;
   RefPtr<mozilla::dom::ImportManager> mImportManager;
   nsTArray<nsCOMPtr<nsINode> > mSubImportLinks;
 
   // Set to true when the document is possibly controlled by the ServiceWorker.
   // Used to prevent multiple requests to ServiceWorkerManager.
   bool mMaybeServiceWorkerControlled;
 
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -263,16 +263,17 @@ NS_IMPL_CLASSINFO(nsCSPContext,
 NS_IMPL_ISUPPORTS_CI(nsCSPContext,
                      nsIContentSecurityPolicy,
                      nsISerializable)
 
 nsCSPContext::nsCSPContext()
   : mInnerWindowID(0)
   , mLoadingContext(nullptr)
   , mLoadingPrincipal(nullptr)
+  , mQueueUpMessages(true)
 {
   CSPCONTEXTLOG(("nsCSPContext::nsCSPContext"));
 }
 
 nsCSPContext::~nsCSPContext()
 {
   CSPCONTEXTLOG(("nsCSPContext::~nsCSPContext"));
   for (uint32_t i = 0; i < mPolicies.Length(); i++) {
@@ -355,17 +356,17 @@ NS_IMETHODIMP
 nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
                            bool aReportOnly)
 {
   CSPCONTEXTLOG(("nsCSPContext::AppendPolicy: %s",
                  NS_ConvertUTF16toUTF8(aPolicyString).get()));
 
   // Use the mSelfURI from setRequestContext, see bug 991474
   NS_ASSERTION(mSelfURI, "mSelfURI required for AppendPolicy, but not set");
-  nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI, aReportOnly, mInnerWindowID);
+  nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI, aReportOnly, this);
   if (policy) {
     mPolicies.AppendElement(policy);
     // reset cache since effective policy changes
     mShouldLoadCache.Clear();
   }
   return NS_OK;
 }
 
@@ -600,28 +601,91 @@ nsCSPContext::SetRequestContext(nsIDOMDo
   NS_ENSURE_ARG(aDOMDocument || aPrincipal);
 
   if (aDOMDocument) {
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDocument);
     mLoadingContext = do_GetWeakReference(doc);
     mSelfURI = doc->GetDocumentURI();
     doc->GetReferrer(mReferrer);
     mInnerWindowID = doc->InnerWindowID();
+    // the innerWindowID is not available for CSPs delivered through the
+    // header at the time setReqeustContext is called - let's queue up
+    // console messages until it becomes available, see flushConsoleMessages
+    mQueueUpMessages = !mInnerWindowID;
     mCallingChannelLoadGroup = doc->GetDocumentLoadGroup();
   }
   else {
+    NS_WARNING("No Document in SetRequestContext; can not query loadgroup; sending reports may fail.");
     mLoadingPrincipal = aPrincipal;
     mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
-    NS_WARNING("No Document in SetRequestContext; can not query loadgroup; sending reports may fail.");
+    // if no document is available, then it also does not make sense to queue console messages
+    // sending messages to the browser conolse instead of the web console in that case.
+    mQueueUpMessages = false;
   }
 
   NS_ASSERTION(mSelfURI, "mSelfURI not available, can not translate 'self' into actual URI");
   return NS_OK;
 }
 
+struct ConsoleMsgQueueElem {
+  nsXPIDLString mMsg;
+  nsString      mSourceName;
+  nsString      mSourceLine;
+  uint32_t      mLineNumber;
+  uint32_t      mColumnNumber;
+  uint32_t      mSeverityFlag;
+};
+
+void
+nsCSPContext::flushConsoleMessages()
+{
+  // should flush messages even if doc is not available
+  nsCOMPtr<nsIDocument> doc = do_QueryReferent(mLoadingContext);
+  if (doc) {
+    mInnerWindowID = doc->InnerWindowID();
+  }
+  mQueueUpMessages = false;
+
+  for (uint32_t i = 0; i < mConsoleMsgQueue.Length(); i++) {
+    ConsoleMsgQueueElem &elem = mConsoleMsgQueue[i];
+    CSP_LogMessage(elem.mMsg, elem.mSourceName, elem.mSourceLine,
+                   elem.mLineNumber, elem.mColumnNumber,
+                   elem.mSeverityFlag, "CSP", mInnerWindowID);
+  }
+  mConsoleMsgQueue.Clear();
+}
+
+void
+nsCSPContext::logToConsole(const char16_t* aName,
+                           const char16_t** aParams,
+                           uint32_t aParamsLength,
+                           const nsAString& aSourceName,
+                           const nsAString& aSourceLine,
+                           uint32_t aLineNumber,
+                           uint32_t aColumnNumber,
+                           uint32_t aSeverityFlag)
+{
+  // let's check if we have to queue up console messages
+  if (mQueueUpMessages) {
+    nsXPIDLString msg;
+    CSP_GetLocalizedStr(aName, aParams, aParamsLength, getter_Copies(msg));
+    ConsoleMsgQueueElem &elem = *mConsoleMsgQueue.AppendElement();
+    elem.mMsg = msg;
+    elem.mSourceName = PromiseFlatString(aSourceName);
+    elem.mSourceLine = PromiseFlatString(aSourceLine);
+    elem.mLineNumber = aLineNumber;
+    elem.mColumnNumber = aColumnNumber;
+    elem.mSeverityFlag = aSeverityFlag;
+    return;
+  }
+  CSP_LogLocalizedStr(aName, aParams, aParamsLength, aSourceName,
+                      aSourceLine, aLineNumber, aColumnNumber,
+                      aSeverityFlag, "CSP", mInnerWindowID);
+}
+
 /**
  * Sends CSP violation reports to all sources listed under report-uri.
  *
  * @param aBlockedContentSource
  *        Either a CSP Source (like 'self', as string) or nsIURI: the source
  *        of the violation.
  * @param aOriginalUri
  *        The original URI if the blocked content is a redirect, else null
@@ -749,20 +813,18 @@ nsCSPContext::SendReports(nsISupports* a
   for (uint32_t r = 0; r < reportURIs.Length(); r++) {
     nsAutoCString reportURICstring = NS_ConvertUTF16toUTF8(reportURIs[r]);
     // try to create a new uri from every report-uri string
     rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]);
     if (NS_FAILED(rv)) {
       const char16_t* params[] = { reportURIs[r].get() };
       CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
                      reportURICstring.get()));
-      CSP_LogLocalizedStr(MOZ_UTF16("triedToSendReport"),
-                          params, ArrayLength(params),
-                          aSourceFile, aScriptSample, aLineNum, 0,
-                          nsIScriptError::errorFlag, "CSP", mInnerWindowID);
+      logToConsole(MOZ_UTF16("triedToSendReport"), params, ArrayLength(params),
+                   aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
       continue; // don't return yet, there may be more URIs
     }
 
     // try to create a new channel for every report-uri
     if (doc) {
       rv = NS_NewChannel(getter_AddRefs(reportChannel),
                          reportURI,
                          doc,
@@ -785,20 +847,18 @@ nsCSPContext::SendReports(nsISupports* a
 
     // log a warning to console if scheme is not http or https
     bool isHttpScheme =
       (NS_SUCCEEDED(reportURI->SchemeIs("http", &isHttpScheme)) && isHttpScheme) ||
       (NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme);
 
     if (!isHttpScheme) {
       const char16_t* params[] = { reportURIs[r].get() };
-      CSP_LogLocalizedStr(MOZ_UTF16("reportURInotHttpsOrHttp2"),
-                          params, ArrayLength(params),
-                          aSourceFile, aScriptSample, aLineNum, 0,
-                          nsIScriptError::errorFlag, "CSP", mInnerWindowID);
+      logToConsole(MOZ_UTF16("reportURInotHttpsOrHttp2"), params, ArrayLength(params),
+                   aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
     }
 
     // make sure this is an anonymous request (no cookies) so in case the
     // policy URI is injected, it can't be abused for CSRF.
     nsLoadFlags flags;
     rv = reportChannel->GetLoadFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
     flags |= nsIRequest::LOAD_ANONYMOUS;
@@ -844,20 +904,18 @@ nsCSPContext::SendReports(nsISupports* a
     // AsyncOpen should not fail, but could if there's no load group (like if
     // SetRequestContext is not given a channel).  This should fail quietly and
     // not return an error since it's really ok if reports don't go out, but
     // it's good to log the error locally.
 
     if (NS_FAILED(rv)) {
       const char16_t* params[] = { reportURIs[r].get() };
       CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", params[0]));
-      CSP_LogLocalizedStr(MOZ_UTF16("triedToSendReport"),
-                          params, ArrayLength(params),
-                          aSourceFile, aScriptSample, aLineNum, 0,
-                          nsIScriptError::errorFlag, "CSP", mInnerWindowID);
+      logToConsole(MOZ_UTF16("triedToSendReport"), params, ArrayLength(params),
+                   aSourceFile, aScriptSample, aLineNum, 0, nsIScriptError::errorFlag);
     } else {
       CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
     }
   }
   return NS_OK;
 }
 
 /**
@@ -870,27 +928,25 @@ class CSPReportSenderRunnable final : pu
                             nsIURI* aOriginalURI,
                             uint32_t aViolatedPolicyIndex,
                             bool aReportOnlyFlag,
                             const nsAString& aViolatedDirective,
                             const nsAString& aObserverSubject,
                             const nsAString& aSourceFile,
                             const nsAString& aScriptSample,
                             uint32_t aLineNum,
-                            uint64_t aInnerWindowID,
                             nsCSPContext* aCSPContext)
       : mBlockedContentSource(aBlockedContentSource)
       , mOriginalURI(aOriginalURI)
       , mViolatedPolicyIndex(aViolatedPolicyIndex)
       , mReportOnlyFlag(aReportOnlyFlag)
       , mViolatedDirective(aViolatedDirective)
       , mSourceFile(aSourceFile)
       , mScriptSample(aScriptSample)
       , mLineNum(aLineNum)
-      , mInnerWindowID(aInnerWindowID)
       , mCSPContext(aCSPContext)
     {
       NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
       // the observer subject is an nsISupports: either an nsISupportsCString
       // from the arg passed in directly, or if that's empty, it's the blocked
       // source.
       if (aObserverSubject.IsEmpty()) {
         mObserverSubject = aBlockedContentSource;
@@ -933,38 +989,35 @@ class CSPReportSenderRunnable final : pu
       } else if (blockedString) {
         blockedString->GetData(blockedDataStr);
       }
 
       if (blockedDataStr.Length() > 0) {
         nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr);
         const char16_t* params[] = { mViolatedDirective.get(),
                                      blockedDataChar16.get() };
-
-        CSP_LogLocalizedStr(mReportOnlyFlag ? MOZ_UTF16("CSPROViolationWithURI") :
-                                              MOZ_UTF16("CSPViolationWithURI"),
-                            params, ArrayLength(params),
-                            mSourceFile, mScriptSample, mLineNum, 0,
-                            nsIScriptError::errorFlag, "CSP", mInnerWindowID);
+        mCSPContext->logToConsole(mReportOnlyFlag ? MOZ_UTF16("CSPROViolationWithURI") :
+                                                    MOZ_UTF16("CSPViolationWithURI"),
+                                  params, ArrayLength(params), mSourceFile, mScriptSample,
+                                  mLineNum, 0, nsIScriptError::errorFlag);
       }
       return NS_OK;
     }
 
   private:
     nsCOMPtr<nsISupports>   mBlockedContentSource;
     nsCOMPtr<nsIURI>        mOriginalURI;
     uint32_t                mViolatedPolicyIndex;
     bool                    mReportOnlyFlag;
     nsString                mViolatedDirective;
     nsCOMPtr<nsISupports>   mObserverSubject;
     nsString                mSourceFile;
     nsString                mScriptSample;
     uint32_t                mLineNum;
-    uint64_t                mInnerWindowID;
-    RefPtr<nsCSPContext>  mCSPContext;
+    RefPtr<nsCSPContext>    mCSPContext;
 };
 
 /**
  * Asynchronously notifies any nsIObservers listening to the CSP violation
  * topic that a violation occurred.  Also triggers report sending and console
  * logging.  All asynchronous on the main thread.
  *
  * @param aBlockedContentSource
@@ -1003,17 +1056,16 @@ nsCSPContext::AsyncReportViolation(nsISu
                                                       aOriginalURI,
                                                       aViolatedPolicyIndex,
                                                       mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
                                                       aViolatedDirective,
                                                       aObserverSubject,
                                                       aSourceFile,
                                                       aScriptSample,
                                                       aLineNum,
-                                                      mInnerWindowID,
                                                       this));
    return NS_OK;
 }
 
 /**
  * Based on the given docshell, determines if this CSP context allows the
  * ancestry.
  *
@@ -1311,17 +1363,17 @@ nsCSPContext::Read(nsIObjectInputStream*
 
     bool reportOnly = false;
     rv = aStream->ReadBoolean(&reportOnly);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(policyString,
                                                                   mSelfURI,
                                                                   reportOnly,
-                                                                  mInnerWindowID);
+                                                                  this);
     if (policy) {
       mPolicies.AppendElement(policy);
     }
   }
 
   return NS_OK;
 }
 
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -21,30 +21,47 @@
 
 #define NS_CSPCONTEXT_CONTRACTID "@mozilla.org/cspcontext;1"
  // 09d9ed1a-e5d4-4004-bfe0-27ceb923d9ac
 #define NS_CSPCONTEXT_CID \
 { 0x09d9ed1a, 0xe5d4, 0x4004, \
   { 0xbf, 0xe0, 0x27, 0xce, 0xb9, 0x23, 0xd9, 0xac } }
 
 class nsINetworkInterceptController;
+struct ConsoleMsgQueueElem;
 
 class nsCSPContext : public nsIContentSecurityPolicy
 {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSICONTENTSECURITYPOLICY
     NS_DECL_NSISERIALIZABLE
 
   protected:
     virtual ~nsCSPContext();
 
   public:
     nsCSPContext();
 
+    /**
+     * SetRequestContext() needs to be called before the innerWindowID
+     * is initialized on the document. Use this function to call back to
+     * flush queued up console messages and initalize the innerWindowID.
+     */
+    void flushConsoleMessages();
+
+    void logToConsole(const char16_t* aName,
+                      const char16_t** aParams,
+                      uint32_t aParamsLength,
+                      const nsAString& aSourceName,
+                      const nsAString& aSourceLine,
+                      uint32_t aLineNumber,
+                      uint32_t aColumnNumber,
+                      uint32_t aSeverityFlag);
+
     nsresult SendReports(nsISupports* aBlockedContentSource,
                          nsIURI* aOriginalURI,
                          nsAString& aViolatedDirective,
                          uint32_t aViolatedPolicyIndex,
                          nsAString& aSourceFile,
                          nsAString& aScriptSample,
                          uint32_t aLineNum);
 
@@ -89,16 +106,21 @@ class nsCSPContext : public nsIContentSe
     nsCOMPtr<nsIURI>                           mSelfURI;
     nsDataHashtable<nsCStringHashKey, int16_t> mShouldLoadCache;
     nsCOMPtr<nsILoadGroup>                     mCallingChannelLoadGroup;
     nsWeakPtr                                  mLoadingContext;
     // The CSP hangs off the principal, so let's store a raw pointer of the principal
     // to avoid memory leaks. Within the destructor of the principal we explicitly
     // set mLoadingPrincipal to null.
     nsIPrincipal*                              mLoadingPrincipal;
+
+    // helper members used to queue up web console messages till
+    // the windowID becomes available. see flushConsoleMessages()
+    nsTArray<ConsoleMsgQueueElem>              mConsoleMsgQueue;
+    bool                                       mQueueUpMessages;
 };
 
 // Class that listens to violation report transmission and logs errors.
 class CSPViolationReportListener : public nsIStreamListener
 {
   public:
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIREQUESTOBSERVER
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -117,24 +117,24 @@ nsCSPTokenizer::tokenizeCSPPolicy(const 
 
   tokenizer.generateTokens(outTokens);
 }
 
 /* ===== nsCSPParser ==================== */
 
 nsCSPParser::nsCSPParser(cspTokens& aTokens,
                          nsIURI* aSelfURI,
-                         uint64_t aInnerWindowID)
+                         nsCSPContext* aCSPContext)
  : mHasHashOrNonce(false)
  , mUnsafeInlineKeywordSrc(nullptr)
  , mChildSrc(nullptr)
  , mFrameSrc(nullptr)
  , mTokens(aTokens)
  , mSelfURI(aSelfURI)
- , mInnerWindowID(aInnerWindowID)
+ , mCSPContext(aCSPContext)
 {
   CSPPARSERLOG(("nsCSPParser::nsCSPParser"));
 }
 
 nsCSPParser::~nsCSPParser()
 {
   CSPPARSERLOG(("nsCSPParser::~nsCSPParser"));
 }
@@ -291,26 +291,26 @@ nsCSPParser::atValidPathChar()
 
 void
 nsCSPParser::logWarningErrorToConsole(uint32_t aSeverityFlag,
                                       const char* aProperty,
                                       const char16_t* aParams[],
                                       uint32_t aParamsLength)
 {
   CSPPARSERLOG(("nsCSPParser::logWarningErrorToConsole: %s", aProperty));
-
-  nsXPIDLString logMsg;
-  CSP_GetLocalizedStr(NS_ConvertUTF8toUTF16(aProperty).get(),
-                      aParams,
-                      aParamsLength,
-                      getter_Copies(logMsg));
-
-  CSP_LogMessage(logMsg, EmptyString(), EmptyString(),
-                 0, 0, aSeverityFlag,
-                 "CSP", mInnerWindowID);
+  // send console messages off to the context and let the context
+  // deal with it (potentially messages need to be queued up)
+  mCSPContext->logToConsole(NS_ConvertUTF8toUTF16(aProperty).get(),
+                            aParams,
+                            aParamsLength,
+                            EmptyString(), // aSourceName
+                            EmptyString(), // aSourceLine
+                            0,             // aLineNumber
+                            0,             // aColumnNumber
+                            aSeverityFlag); // aFlags
 }
 
 bool
 nsCSPParser::hostChar()
 {
   if (atEnd()) {
     return false;
   }
@@ -1111,17 +1111,17 @@ nsCSPParser::policy()
 
   return mPolicy;
 }
 
 nsCSPPolicy*
 nsCSPParser::parseContentSecurityPolicy(const nsAString& aPolicyString,
                                         nsIURI *aSelfURI,
                                         bool aReportOnly,
-                                        uint64_t aInnerWindowID)
+                                        nsCSPContext* aCSPContext)
 {
   if (CSPPARSERLOGENABLED()) {
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, policy: %s",
                  NS_ConvertUTF16toUTF8(aPolicyString).get()));
     nsAutoCString spec;
     aSelfURI->GetSpec(spec);
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, selfURI: %s", spec.get()));
     CSPPARSERLOG(("nsCSPParser::parseContentSecurityPolicy, reportOnly: %s",
@@ -1133,17 +1133,17 @@ nsCSPParser::parseContentSecurityPolicy(
   // Separate all input into tokens and store them in the form of:
   // [ [ name, src, src, ... ], [ name, src, src, ... ], ... ]
   // The tokenizer itself can not fail; all eventual errors
   // are detected in the parser itself.
 
   nsTArray< nsTArray<nsString> > tokens;
   nsCSPTokenizer::tokenizeCSPPolicy(aPolicyString, tokens);
 
-  nsCSPParser parser(tokens, aSelfURI, aInnerWindowID);
+  nsCSPParser parser(tokens, aSelfURI, aCSPContext);
 
   // 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->hasDirective(nsIContentSecurityPolicy::REPORT_URI_DIRECTIVE)) {
--- a/dom/security/nsCSPParser.h
+++ b/dom/security/nsCSPParser.h
@@ -95,22 +95,22 @@ class nsCSPParser {
      * Internally the input string is separated into string tokens and policy() is called, which starts
      * parsing the policy. The parser calls one function after the other according the the source-list
      * from http://www.w3.org/TR/CSP11/#source-list. E.g., the parser can only call port() after the parser
      * has already processed any possible host in host(), similar to a finite state machine.
      */
     static nsCSPPolicy* parseContentSecurityPolicy(const nsAString &aPolicyString,
                                                    nsIURI *aSelfURI,
                                                    bool aReportOnly,
-                                                   uint64_t aInnerWindowID);
+                                                   nsCSPContext* aCSPContext);
 
   private:
     nsCSPParser(cspTokens& aTokens,
                 nsIURI* aSelfURI,
-                uint64_t aInnerWindowID);
+                nsCSPContext* aCSPContext);
     ~nsCSPParser();
 
 
     // Parsing the CSP using the source-list from http://www.w3.org/TR/CSP11/#source-list
     nsCSPPolicy*    policy();
     void            directive();
     nsCSPDirective* directiveName();
     void            directiveValue(nsTArray<nsCSPBaseSrc*>& outSrcs);
@@ -240,12 +240,12 @@ class nsCSPParser {
     // decide whether it will handle frames, or if there is a frame-src we
     // should honor instead.
     nsCSPChildSrcDirective* mChildSrc;
     nsCSPDirective*         mFrameSrc;
 
     cspTokens          mTokens;
     nsIURI*            mSelfURI;
     nsCSPPolicy*       mPolicy;
-    uint64_t           mInnerWindowID; // used for console reporting
+    nsCSPContext*      mCSPContext; // used for console logging
 };
 
 #endif /* nsCSPParser_h___ */