Bug 1476592 - Remove the cache from nsCSPContext - part 2 - sendViolationReports parameter, r=ckerschb, r=aosmond
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 01 Aug 2018 06:35:24 +0200
changeset 429554 42983355094d0bb4151673575907394b0b05b7c0
parent 429553 0494194533841bc515e8dcda9964d6ffe263a318
child 429555 a914cedebde5404d735d3d6fc3df957c8b4e7437
push id34366
push userdluca@mozilla.com
push dateWed, 01 Aug 2018 09:52:20 +0000
treeherdermozilla-central@af6a7edf0069 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb, aosmond
bugs1476592
milestone63.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 1476592 - Remove the cache from nsCSPContext - part 2 - sendViolationReports parameter, r=ckerschb, r=aosmond
dom/interfaces/security/nsIContentSecurityPolicy.idl
dom/security/nsCSPContext.cpp
dom/security/nsCSPService.cpp
dom/security/test/unit/test_csp_reports.js
image/imgLoader.cpp
image/imgLoader.h
ipc/glue/BackgroundUtils.cpp
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/nsILoadInfo.idl
netwerk/ipc/NeckoChannelParams.ipdlh
testing/web-platform/meta/content-security-policy/media-src/media-src-7_1_2.sub.html.ini
testing/web-platform/meta/content-security-policy/media-src/media-src-7_2_2.sub.html.ini
testing/web-platform/meta/content-security-policy/media-src/media-src-blocked.sub.html.ini
testing/web-platform/meta/service-workers/service-worker/fetch-csp.https.html.ini
testing/web-platform/meta/subresource-integrity/subresource-ed25519-with-csp.tentative.html.ini
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -299,17 +299,18 @@ interface nsIContentSecurityPolicy : nsI
    * of a redirect. In this case, aOriginalURIIfRedirect must be the original
    * URL.
    */
   short shouldLoad(in nsContentPolicyType aContentType,
                    in nsIURI          aContentLocation,
                    in nsIURI          aRequestOrigin,
                    in nsISupports     aContext,
                    in ACString        aMimeTypeGuess,
-                   in nsIURI          aOriginalURIIfRedirect);
+                   in nsIURI          aOriginalURIIfRedirect,
+                   in bool            aSendViolationReports);
 
 %{ C++
 // nsIObserver topic to fire when the policy encounters a violation.
 #define CSP_VIOLATION_TOPIC "csp-on-violate-policy"
 %}
 
   /**
    * Returns the CSP in JSON notation.
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -118,16 +118,17 @@ BlockedContentSourceToString(nsCSPContex
 
 NS_IMETHODIMP
 nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
                          nsIURI*             aContentLocation,
                          nsIURI*             aRequestOrigin,
                          nsISupports*        aRequestContext,
                          const nsACString&   aMimeTypeGuess,
                          nsIURI*             aOriginalURIIfRedirect,
+                         bool                aSendViolationReports,
                          int16_t*            outDecision)
 {
   if (CSPCONTEXTLOGENABLED()) {
     CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, aContentLocation: %s",
                    aContentLocation->GetSpecOrDefault().get()));
     CSPCONTEXTLOG((">>>>                      aContentType: %d", aContentType));
   }
 
@@ -177,17 +178,17 @@ nsCSPContext::ShouldLoad(nsContentPolicy
 
   bool permitted = permitsInternal(dir,
                                    nullptr, // aTriggeringElement
                                    aContentLocation,
                                    aOriginalURIIfRedirect,
                                    nonce,
                                    isPreload,
                                    false,     // allow fallback to default-src
-                                   true,      // send violation reports
+                                   aSendViolationReports,
                                    true,     // send blocked URI in violation reports
                                    parserCreated);
 
   *outDecision = permitted ? nsIContentPolicy::ACCEPT
                            : nsIContentPolicy::REJECT_SERVER;
 
   if (CSPCONTEXTLOGENABLED()) {
     CSPCONTEXTLOG(("nsCSPContext::ShouldLoad, decision: %s, "
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -183,16 +183,17 @@ CSPService::ShouldLoad(nsIURI *aContentL
     if (preloadCsp) {
       // obtain the enforcement decision
       rv = preloadCsp->ShouldLoad(contentType,
                                   aContentLocation,
                                   requestOrigin,
                                   requestContext,
                                   aMimeTypeGuess,
                                   nullptr, // no redirect, aOriginal URL is null.
+                                  aLoadInfo->GetSendCSPViolationEvents(),
                                   aDecision);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // if the preload policy already denied the load, then there
       // is no point in checking the real policy
       if (NS_CP_REJECTED(*aDecision)) {
         return NS_OK;
       }
@@ -207,16 +208,17 @@ CSPService::ShouldLoad(nsIURI *aContentL
   if (csp) {
     // obtain the enforcement decision
     rv = csp->ShouldLoad(contentType,
                          aContentLocation,
                          requestOrigin,
                          requestContext,
                          aMimeTypeGuess,
                          nullptr, // no redirect, aOriginal URL is null.
+                         aLoadInfo->GetSendCSPViolationEvents(),
                          aDecision);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 CSPService::ShouldProcess(nsIURI           *aContentLocation,
@@ -319,16 +321,17 @@ CSPService::AsyncOnChannelRedirect(nsICh
     if (preloadCsp) {
       // Pass  originalURI to indicate the redirect
       preloadCsp->ShouldLoad(policyType,     // load type per nsIContentPolicy (uint32_t)
                              newUri,         // nsIURI
                              nullptr,        // nsIURI
                              requestContext, // nsISupports
                              EmptyCString(), // ACString - MIME guess
                              originalUri,    // Original nsIURI
+                             true,           // aSendViolationReports
                              &aDecision);
 
       // if the preload policy already denied the load, then there
       // is no point in checking the real policy
       if (NS_CP_REJECTED(aDecision)) {
         autoCallback.DontCallback();
         oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
         return NS_BINDING_FAILED;
@@ -343,16 +346,17 @@ CSPService::AsyncOnChannelRedirect(nsICh
   if (csp) {
     // Pass  originalURI to indicate the redirect
     csp->ShouldLoad(policyType,     // load type per nsIContentPolicy (uint32_t)
                     newUri,         // nsIURI
                     nullptr,        // nsIURI
                     requestContext, // nsISupports
                     EmptyCString(), // ACString - MIME guess
                     originalUri,    // Original nsIURI
+                    true,           // aSendViolationReports
                     &aDecision);
   }
 
   // if ShouldLoad doesn't accept the load, cancel the request
   if (!NS_CP_ACCEPTED(aDecision)) {
     autoCallback.DontCallback();
     oldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
     return NS_BINDING_FAILED;
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -147,17 +147,17 @@ function run_test() {
         }
       });
 
   makeTest(2, {"blocked-uri": "http://blocked.test/foo.js"}, false,
       function(csp) {
         // shouldLoad creates and sends out the report here.
         csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
                       NetUtil.newURI("http://blocked.test/foo.js"),
-                      null, null, null, null);
+                      null, null, null, null, true);
       });
 
   // test that inline script violations cause a report in report-only policy
   makeTest(3, {"blocked-uri": "inline"}, true,
       function(csp) {
         let inlineOK = true;
         inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
                                        "", // aNonce
@@ -197,40 +197,40 @@ function run_test() {
   makeTest(5, {"blocked-uri": "data"}, false,
     function(csp) {
       var base64data =
         "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
         "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
       // shouldLoad creates and sends out the report here.
       csp.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
                      NetUtil.newURI("data:image/png;base64," + base64data),
-                     null, null, null, null);
+                     null, null, null, null, true);
       });
 
   // test that only the uri's scheme is reported for globally unique identifiers
   makeTest(6, {"blocked-uri": "intent"}, false,
     function(csp) {
       // shouldLoad creates and sends out the report here.
       csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
                      NetUtil.newURI("intent://mymaps.com/maps?um=1&ie=UTF-8&fb=1&sll"),
-                     null, null, null, null);
+                     null, null, null, null, true);
       });
 
   // test fragment removal
   var selfSpec = REPORT_SERVER_URI + ":" + REPORT_SERVER_PORT + "/foo/self/foo.js";
   makeTest(7, {"blocked-uri": selfSpec}, false,
     function(csp) {
       var uri = NetUtil
       // shouldLoad creates and sends out the report here.
       csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
                      NetUtil.newURI(selfSpec + "#bar"),
-                     null, null, null, null);
+                     null, null, null, null, true);
       });
 
   // test scheme of ftp:
   makeTest(8, {"blocked-uri": "ftp://blocked.test/profile.png"}, false,
     function(csp) {
       // shouldLoad creates and sends out the report here.
       csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
                     NetUtil.newURI("ftp://blocked.test/profile.png"),
-                    null, null, null, null);
+                    null, null, null, null, true);
     });
 }
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -611,17 +611,18 @@ ShouldRevalidateEntry(imgCacheEntry* aEn
   return bValidateEntry;
 }
 
 /* Call content policies on cached images that went through a redirect */
 static bool
 ShouldLoadCachedImage(imgRequest* aImgRequest,
                       nsISupports* aLoadingContext,
                       nsIPrincipal* aTriggeringPrincipal,
-                      nsContentPolicyType aPolicyType)
+                      nsContentPolicyType aPolicyType,
+                      bool aSendCSPViolationReports)
 {
   /* Call content policies on cached images - Bug 1082837
    * Cached images are keyed off of the first uri in a redirect chain.
    * Hence content policies don't get a chance to test the intermediate hops
    * or the final desitnation.  Here we test the final destination using
    * mFinalURI off of the imgRequest and passing it into content policies.
    * For Mixed Content Blocker, we do an additional check to determine if any
    * of the intermediary hops went through an insecure redirect with the
@@ -645,16 +646,18 @@ ShouldLoadCachedImage(imgRequest* aImgRe
 
   nsCOMPtr<nsILoadInfo> secCheckLoadInfo =
     new LoadInfo(loadingPrincipal,
                  aTriggeringPrincipal,
                  requestingNode,
                  nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
                  aPolicyType);
 
+  secCheckLoadInfo->SetSendCSPViolationEvents(aSendCSPViolationReports);
+
   int16_t decision = nsIContentPolicy::REJECT_REQUEST;
   rv = NS_CheckContentLoadPolicy(contentLocation,
                                  secCheckLoadInfo,
                                  EmptyCString(), //mime guess
                                  &decision,
                                  nsContentUtils::GetContentPolicy());
   if (NS_FAILED(rv) || !NS_CP_ACCEPTED(decision)) {
     return false;
@@ -741,17 +744,18 @@ ValidateSecurityInfo(imgRequest* request
       otherprincipal->Equals(triggeringPrincipal, &equals);
       if (!equals) {
         return false;
       }
     }
   }
 
   // Content Policy Check on Cached Images
-  return ShouldLoadCachedImage(request, aCX, triggeringPrincipal, aPolicyType);
+  return ShouldLoadCachedImage(request, aCX, triggeringPrincipal, aPolicyType,
+                               /* aSendCSPViolationReports */ false);
 }
 
 static nsresult
 NewImageChannel(nsIChannel** aResult,
                 // If aForcePrincipalCheckForCacheEntry is true, then we will
                 // force a principal check even when not using CORS before
                 // assuming we have a cache hit on a cache entry that we
                 // create for this channel.  This is an out param that should
@@ -1792,17 +1796,18 @@ imgLoader::ValidateRequestWithNewChannel
                                          nsILoadGroup* aLoadGroup,
                                          imgINotificationObserver* aObserver,
                                          nsISupports* aCX,
                                          nsIDocument* aLoadingDocument,
                                          nsLoadFlags aLoadFlags,
                                          nsContentPolicyType aLoadPolicyType,
                                          imgRequestProxy** aProxyRequest,
                                          nsIPrincipal* aTriggeringPrincipal,
-                                         int32_t aCORSMode)
+                                         int32_t aCORSMode,
+                                         bool* aNewChannelCreated)
 {
   // now we need to insert a new channel request object inbetween the real
   // request and the proxy that basically delays loading the image until it
   // gets a 304 or figures out that this needs to be a new request
 
   nsresult rv;
 
   // If we're currently in the middle of validating this request, just hand
@@ -1848,16 +1853,20 @@ imgLoader::ValidateRequestWithNewChannel
                        aLoadPolicyType,
                        aTriggeringPrincipal,
                        aCX,
                        mRespectPrivacy);
   if (NS_FAILED(rv)) {
     return false;
   }
 
+  if (aNewChannelCreated) {
+    *aNewChannelCreated = true;
+  }
+
   RefPtr<imgRequestProxy> req;
   rv = CreateNewProxyForRequest(request, aLoadGroup, aLoadingDocument,
                                 aObserver, aLoadFlags, getter_AddRefs(req));
   if (NS_FAILED(rv)) {
     return false;
   }
 
   // Make sure that OnStatus/OnProgress calls have the right request set...
@@ -1912,16 +1921,17 @@ imgLoader::ValidateEntry(imgCacheEntry* 
                          ReferrerPolicy aReferrerPolicy,
                          nsILoadGroup* aLoadGroup,
                          imgINotificationObserver* aObserver,
                          nsISupports* aCX,
                          nsIDocument* aLoadingDocument,
                          nsLoadFlags aLoadFlags,
                          nsContentPolicyType aLoadPolicyType,
                          bool aCanMakeNewChannel,
+                         bool* aNewChannelCreated,
                          imgRequestProxy** aProxyRequest,
                          nsIPrincipal* aTriggeringPrincipal,
                          int32_t aCORSMode)
 {
   LOG_SCOPE(gImgLog, "imgLoader::ValidateEntry");
 
   // If the expiration time is zero, then the request has not gotten far enough
   // to know when it will expire.
@@ -2031,17 +2041,17 @@ imgLoader::ValidateEntry(imgCacheEntry* 
               "imgLoader::ValidateRequest |cache hit| must validate");
 
     return ValidateRequestWithNewChannel(request, aURI, aInitialDocumentURI,
                                          aReferrerURI, aReferrerPolicy,
                                          aLoadGroup, aObserver,
                                          aCX, aLoadingDocument,
                                          aLoadFlags, aLoadPolicyType,
                                          aProxyRequest, aTriggeringPrincipal,
-                                         aCORSMode);
+                                         aCORSMode, aNewChannelCreated);
   }
 
   return !validateRequest;
 }
 
 bool
 imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
 {
@@ -2336,20 +2346,22 @@ imgLoader::LoadImage(nsIURI* aURI,
   if (aTriggeringPrincipal) {
     attrs = aTriggeringPrincipal->OriginAttributesRef();
   }
   ImageCacheKey key(aURI, attrs, aLoadingDocument, rv);
   NS_ENSURE_SUCCESS(rv, rv);
   imgCacheTable& cache = GetCache(key);
 
   if (cache.Get(key, getter_AddRefs(entry)) && entry) {
+    bool newChannelCreated = false;
     if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
                       aReferrerPolicy, aLoadGroup, aObserver, aLoadingDocument,
                       aLoadingDocument, requestFlags, aContentPolicyType, true,
-                      _retval, aTriggeringPrincipal, corsmode)) {
+                      &newChannelCreated, _retval, aTriggeringPrincipal,
+                      corsmode)) {
       request = entry->GetRequest();
 
       // If this entry has no proxies, its request has no reference to the
       // entry.
       if (entry->HasNoProxies()) {
         LOG_FUNC_WITH_PARAM(gImgLog,
           "imgLoader::LoadImage() adding proxyless entry", "uri", key.URI());
         MOZ_ASSERT(!request->HasCacheEntry(),
@@ -2358,16 +2370,28 @@ imgLoader::LoadImage(nsIURI* aURI,
 
         if (mCacheTracker && entry->GetExpirationState()->IsTracked()) {
           mCacheTracker->MarkUsed(entry);
         }
       }
 
       entry->Touch();
 
+      if (!newChannelCreated) {
+        // This is ugly but it's needed to report CSP violations. We have 3
+        // scenarios:
+        // - we don't have cache. We are not in this if() stmt. A new channel is
+        //   created and that triggers the CSP checks.
+        // - We have a cache entry and this is blocked by CSP directives.
+        DebugOnly<bool> shouldLoad =
+          ShouldLoadCachedImage(request, aLoadingDocument, aTriggeringPrincipal,
+                                aContentPolicyType,
+                                /* aSendCSPViolationReports */ true);
+        MOZ_ASSERT(shouldLoad);
+      }
     } else {
       // We can't use this entry. We'll try to load it off the network, and if
       // successful, overwrite the old entry in the cache with a new one.
       entry = nullptr;
     }
   }
 
   // Keep the channel in this scope, so we can adjust its notificationCallbacks
@@ -2608,17 +2632,17 @@ imgLoader::LoadImageWithChannel(nsIChann
       // if there is a loadInfo, use the right contentType, otherwise
       // default to the internal image type
       nsContentPolicyType policyType = loadInfo
         ? loadInfo->InternalContentPolicyType()
         : nsIContentPolicy::TYPE_INTERNAL_IMAGE;
 
       if (ValidateEntry(entry, uri, nullptr, nullptr, RP_Unset,
                         nullptr, aObserver, aCX, doc, requestFlags,
-                        policyType, false, nullptr,
+                        policyType, false, nullptr, nullptr,
                         nullptr, imgIRequest::CORS_NONE)) {
         request = entry->GetRequest();
       } else {
         nsCOMPtr<nsICacheInfoChannel> cacheChan(do_QueryInterface(channel));
         bool bUseCacheCopy;
 
         if (cacheChan) {
           cacheChan->IsFromCache(&bUseCacheCopy);
--- a/image/imgLoader.h
+++ b/image/imgLoader.h
@@ -408,33 +408,35 @@ private: // methods
                      nsIURI* aInitialDocumentURI, nsIURI* aReferrerURI,
                      ReferrerPolicy aReferrerPolicy,
                      nsILoadGroup* aLoadGroup,
                      imgINotificationObserver* aObserver, nsISupports* aCX,
                      nsIDocument* aLoadingDocument,
                      nsLoadFlags aLoadFlags,
                      nsContentPolicyType aContentPolicyType,
                      bool aCanMakeNewChannel,
+                     bool* aNewChannelCreated,
                      imgRequestProxy** aProxyRequest,
                      nsIPrincipal* aLoadingPrincipal,
                      int32_t aCORSMode);
 
   bool ValidateRequestWithNewChannel(imgRequest* request, nsIURI* aURI,
                                      nsIURI* aInitialDocumentURI,
                                      nsIURI* aReferrerURI,
                                      ReferrerPolicy aReferrerPolicy,
                                      nsILoadGroup* aLoadGroup,
                                      imgINotificationObserver* aObserver,
                                      nsISupports* aCX,
                                      nsIDocument* aLoadingDocument,
                                      nsLoadFlags aLoadFlags,
                                      nsContentPolicyType aContentPolicyType,
                                      imgRequestProxy** aProxyRequest,
                                      nsIPrincipal* aLoadingPrincipal,
-                                     int32_t aCORSMode);
+                                     int32_t aCORSMode,
+                                     bool* aNewChannelCreated);
 
   nsresult CreateNewProxyForRequest(imgRequest* aRequest,
                                     nsILoadGroup* aLoadGroup,
                                     nsIDocument* aLoadingDocument,
                                     imgINotificationObserver* aObserver,
                                     nsLoadFlags aLoadFlags,
                                     imgRequestProxy** _retval);
 
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -426,16 +426,17 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoa
       aLoadInfo->GetOuterWindowID(),
       aLoadInfo->GetParentOuterWindowID(),
       aLoadInfo->GetTopOuterWindowID(),
       aLoadInfo->GetFrameOuterWindowID(),
       aLoadInfo->GetEnforceSecurity(),
       aLoadInfo->GetInitialSecurityCheckDone(),
       aLoadInfo->GetIsInThirdPartyContext(),
       aLoadInfo->GetIsDocshellReload(),
+      aLoadInfo->GetSendCSPViolationEvents(),
       aLoadInfo->GetOriginAttributes(),
       redirectChainIncludingInternalRedirects,
       redirectChain,
       ancestorPrincipals,
       aLoadInfo->AncestorOuterWindowIDs(),
       ipcClientInfo,
       ipcReservedClientInfo,
       ipcInitialClientInfo,
@@ -582,16 +583,17 @@ LoadInfoArgsToLoadInfo(const OptionalLoa
                           loadInfoArgs.outerWindowID(),
                           loadInfoArgs.parentOuterWindowID(),
                           loadInfoArgs.topOuterWindowID(),
                           loadInfoArgs.frameOuterWindowID(),
                           loadInfoArgs.enforceSecurity(),
                           loadInfoArgs.initialSecurityCheckDone(),
                           loadInfoArgs.isInThirdPartyContext(),
                           loadInfoArgs.isDocshellReload(),
+                          loadInfoArgs.sendCSPViolationEvents(),
                           loadInfoArgs.originAttributes(),
                           redirectChainIncludingInternalRedirects,
                           redirectChain,
                           std::move(ancestorPrincipals),
                           loadInfoArgs.ancestorOuterWindowIDs(),
                           loadInfoArgs.corsUnsafeHeaders(),
                           loadInfoArgs.forcePreflight(),
                           loadInfoArgs.isPreflight(),
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -77,16 +77,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mOuterWindowID(0)
   , mParentOuterWindowID(0)
   , mTopOuterWindowID(0)
   , mFrameOuterWindowID(0)
   , mEnforceSecurity(false)
   , mInitialSecurityCheckDone(false)
   , mIsThirdPartyContext(false)
   , mIsDocshellReload(false)
+  , mSendCSPViolationEvents(true)
   , mForcePreflight(false)
   , mIsPreflight(false)
   , mLoadTriggeredFromExternal(false)
   , mServiceWorkerTaintingSynthesized(false)
 {
   MOZ_ASSERT(mLoadingPrincipal);
   MOZ_ASSERT(mTriggeringPrincipal);
 
@@ -310,16 +311,17 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* a
   , mOuterWindowID(0)
   , mParentOuterWindowID(0)
   , mTopOuterWindowID(0)
   , mFrameOuterWindowID(0)
   , mEnforceSecurity(false)
   , mInitialSecurityCheckDone(false)
   , mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party.
   , mIsDocshellReload(false)
+  , mSendCSPViolationEvents(true)
   , mForcePreflight(false)
   , mIsPreflight(false)
   , mLoadTriggeredFromExternal(false)
   , mServiceWorkerTaintingSynthesized(false)
 {
   // Top-level loads are never third-party
   // Grab the information we can out of the window.
   MOZ_ASSERT(aOuterWindow);
@@ -396,16 +398,17 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   , mOuterWindowID(rhs.mOuterWindowID)
   , mParentOuterWindowID(rhs.mParentOuterWindowID)
   , mTopOuterWindowID(rhs.mTopOuterWindowID)
   , mFrameOuterWindowID(rhs.mFrameOuterWindowID)
   , mEnforceSecurity(rhs.mEnforceSecurity)
   , mInitialSecurityCheckDone(rhs.mInitialSecurityCheckDone)
   , mIsThirdPartyContext(rhs.mIsThirdPartyContext)
   , mIsDocshellReload(rhs.mIsDocshellReload)
+  , mSendCSPViolationEvents(rhs.mSendCSPViolationEvents)
   , mOriginAttributes(rhs.mOriginAttributes)
   , mRedirectChainIncludingInternalRedirects(
       rhs.mRedirectChainIncludingInternalRedirects)
   , mRedirectChain(rhs.mRedirectChain)
   , mAncestorPrincipals(rhs.mAncestorPrincipals)
   , mAncestorOuterWindowIDs(rhs.mAncestorOuterWindowIDs)
   , mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders)
   , mForcePreflight(rhs.mForcePreflight)
@@ -442,16 +445,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
                    uint64_t aOuterWindowID,
                    uint64_t aParentOuterWindowID,
                    uint64_t aTopOuterWindowID,
                    uint64_t aFrameOuterWindowID,
                    bool aEnforceSecurity,
                    bool aInitialSecurityCheckDone,
                    bool aIsThirdPartyContext,
                    bool aIsDocshellReload,
+                   bool aSendCSPViolationEvents,
                    const OriginAttributes& aOriginAttributes,
                    RedirectHistoryArray& aRedirectChainIncludingInternalRedirects,
                    RedirectHistoryArray& aRedirectChain,
                    nsTArray<nsCOMPtr<nsIPrincipal>>&& aAncestorPrincipals,
                    const nsTArray<uint64_t>& aAncestorOuterWindowIDs,
                    const nsTArray<nsCString>& aCorsUnsafeHeaders,
                    bool aForcePreflight,
                    bool aIsPreflight,
@@ -483,16 +487,17 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin
   , mOuterWindowID(aOuterWindowID)
   , mParentOuterWindowID(aParentOuterWindowID)
   , mTopOuterWindowID(aTopOuterWindowID)
   , mFrameOuterWindowID(aFrameOuterWindowID)
   , mEnforceSecurity(aEnforceSecurity)
   , mInitialSecurityCheckDone(aInitialSecurityCheckDone)
   , mIsThirdPartyContext(aIsThirdPartyContext)
   , mIsDocshellReload(aIsDocshellReload)
+  , mSendCSPViolationEvents(aSendCSPViolationEvents)
   , mOriginAttributes(aOriginAttributes)
   , mAncestorPrincipals(std::move(aAncestorPrincipals))
   , mAncestorOuterWindowIDs(aAncestorOuterWindowIDs)
   , mCorsUnsafeHeaders(aCorsUnsafeHeaders)
   , mForcePreflight(aForcePreflight)
   , mIsPreflight(aIsPreflight)
   , mLoadTriggeredFromExternal(aLoadTriggeredFromExternal)
   , mServiceWorkerTaintingSynthesized(aServiceWorkerTaintingSynthesized)
@@ -835,16 +840,30 @@ LoadInfo::GetIsDocshellReload(bool* aRes
 NS_IMETHODIMP
 LoadInfo::SetIsDocshellReload(bool aValue)
 {
   mIsDocshellReload = aValue;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+LoadInfo::GetSendCSPViolationEvents(bool* aResult)
+{
+  *aResult = mSendCSPViolationEvents;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::SetSendCSPViolationEvents(bool aValue)
+{
+  mSendCSPViolationEvents = aValue;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 LoadInfo::GetExternalContentPolicyType(nsContentPolicyType* aResult)
 {
   *aResult = nsContentUtils::InternalContentPolicyTypeToExternal(mInternalContentPolicyType);
   return NS_OK;
 }
 
 nsContentPolicyType
 LoadInfo::InternalContentPolicyType()
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -119,16 +119,17 @@ private:
            uint64_t aOuterWindowID,
            uint64_t aParentOuterWindowID,
            uint64_t aTopOuterWindowID,
            uint64_t aFrameOuterWindowID,
            bool aEnforceSecurity,
            bool aInitialSecurityCheckDone,
            bool aIsThirdPartyRequest,
            bool aIsDocshellReload,
+           bool aSendCSPViolationEvents,
            const OriginAttributes& aOriginAttributes,
            RedirectHistoryArray& aRedirectChainIncludingInternalRedirects,
            RedirectHistoryArray& aRedirectChain,
            nsTArray<nsCOMPtr<nsIPrincipal>>&& aAncestorPrincipals,
            const nsTArray<uint64_t>& aAncestorOuterWindowIDs,
            const nsTArray<nsCString>& aUnsafeHeaders,
            bool aForcePreflight,
            bool aIsPreflight,
@@ -189,16 +190,17 @@ private:
   uint64_t                         mOuterWindowID;
   uint64_t                         mParentOuterWindowID;
   uint64_t                         mTopOuterWindowID;
   uint64_t                         mFrameOuterWindowID;
   bool                             mEnforceSecurity;
   bool                             mInitialSecurityCheckDone;
   bool                             mIsThirdPartyContext;
   bool                             mIsDocshellReload;
+  bool                             mSendCSPViolationEvents;
   OriginAttributes                 mOriginAttributes;
   RedirectHistoryArray             mRedirectChainIncludingInternalRedirects;
   RedirectHistoryArray             mRedirectChain;
   nsTArray<nsCOMPtr<nsIPrincipal>> mAncestorPrincipals;
   nsTArray<uint64_t>               mAncestorOuterWindowIDs;
   nsTArray<nsCString>              mCorsUnsafeHeaders;
   bool                             mForcePreflight;
   bool                             mIsPreflight;
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -497,16 +497,22 @@ interface nsILoadInfo : nsISupports
    * The external contentPolicyType of the channel, used for security checks
    * like Mixed Content Blocking and Content Security Policy.
    *
    * Specifically, content policy types with _INTERNAL_ in their name will
    * never get returned from this attribute.
    */
   readonly attribute nsContentPolicyType externalContentPolicyType;
 
+  /**
+   * CSP uses this parameter to send or not CSP violation events.
+   * Default value: true.
+   */
+  [infallible] attribute boolean sendCSPViolationEvents;
+
 %{ C++
   inline nsContentPolicyType GetExternalContentPolicyType()
   {
     nsContentPolicyType result;
     mozilla::DebugOnly<nsresult> rv = GetExternalContentPolicyType(&result);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     return result;
   }
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -60,16 +60,17 @@ struct LoadInfoArgs
   uint64_t                    outerWindowID;
   uint64_t                    parentOuterWindowID;
   uint64_t                    topOuterWindowID;
   uint64_t                    frameOuterWindowID;
   bool                        enforceSecurity;
   bool                        initialSecurityCheckDone;
   bool                        isInThirdPartyContext;
   bool                        isDocshellReload;
+  bool                        sendCSPViolationEvents;
   OriginAttributes            originAttributes;
   RedirectHistoryEntryInfo[]  redirectChainIncludingInternalRedirects;
   RedirectHistoryEntryInfo[]  redirectChain;
 
   /**
    * Ancestor data for use with the WebRequest API.
    * See nsILoadInfo.idl for details.
    */
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-7_1_2.sub.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[media-src-7_1_2.sub.html]
-  expected: TIMEOUT
-  [Test that securitypolicyviolation events are fired]
-    expected: TIMEOUT
-
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-7_2_2.sub.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[media-src-7_2_2.sub.html]
-  expected: TIMEOUT
-  [Test that securitypolicyviolation events are fired]
-    expected: TIMEOUT
-
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/media-src/media-src-blocked.sub.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[media-src-blocked.sub.html]
-  expected: TIMEOUT
-  [Test that securitypolicyviolation events are fired]
-    expected: TIMEOUT
-
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/service-workers/service-worker/fetch-csp.https.html.ini
@@ -0,0 +1,3 @@
+[fetch-csp.https.html]
+  [Verify CSP control of fetch() in a Service Worker]
+    expected: FAIL
--- a/testing/web-platform/meta/subresource-integrity/subresource-ed25519-with-csp.tentative.html.ini
+++ b/testing/web-platform/meta/subresource-integrity/subresource-ed25519-with-csp.tentative.html.ini
@@ -1,7 +1,4 @@
 [subresource-ed25519-with-csp.tentative.html]
   [Script: Ed25519-with-CSP, passes, valid key, valid signature.]
     expected: FAIL
 
-  [Script: Ed25519-with-CSP, fails, valid key, valid signature, key not in CSP.]
-    expected: FAIL
-