[Beacon] Content extensions should be able to intercept Beacon / Ping redirects
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Aug 2017 01:32:24 +0000 (01:32 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Aug 2017 01:32:24 +0000 (01:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175746
<rdar://problem/33946050>

Reviewed by Alex Christensen.

Source/WebCore:

Update PingLoad to process content extension rules upon redirect. This allows content
extensions to block and upgrade to HTTPS beacon / ping loads.

Because ping loads can outlive the WebProcess, the content extensions rules are passed
to the NetworkProcess when starting the Ping load. The PingLoad can then consult those
rules upon redirect, on the NetworkProcess side.

Tests: http/wpt/beacon/contentextensions/beacon-blocked.html
       http/wpt/beacon/contentextensions/beacon-redirect-blocked.html

* contentextensions/ContentExtensionActions.h:
* contentextensions/ContentExtensionsBackend.cpp:
(WebCore::ContentExtensions::ContentExtensionsBackend::forEach):
(WebCore::ContentExtensions::ContentExtensionsBackend::processContentExtensionRulesForPingLoad):
* contentextensions/ContentExtensionsBackend.h:
* page/Page.h:
* page/UserContentProvider.cpp:
(WebCore::UserContentProvider::forEachContentExtension):
* page/UserContentProvider.h:

Source/WebKit:

Update PingLoad to process content extension rules upon redirect. This allows content
extensions to block and upgrade to HTTPS beacon / ping loads.

Because ping loads can outlive the WebProcess, the content extensions rules are passed
to the NetworkProcess when starting the Ping load. The PingLoad can then consult those
rules upon redirect, on the NetworkProcess side.

* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::encode const):
(WebKit::NetworkResourceLoadParameters::decode):
* NetworkProcess/NetworkResourceLoadParameters.h:
* NetworkProcess/PingLoad.cpp:
(WebKit::PingLoad::willPerformHTTPRedirection):
(WebKit::PingLoad::contentExtensionsBackend):
(WebKit::PingLoad::processContentExtensionRulesForLoad):
* NetworkProcess/PingLoad.h:
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::startPingLoad):

LayoutTests:

Add layout test coverage for blocking beacon loads via content extensions.

* http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt:
* http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html:
* http/wpt/beacon/contentextensions/beacon-blocked-expected.txt: Added.
* http/wpt/beacon/contentextensions/beacon-blocked.html: Added.
* http/wpt/beacon/contentextensions/beacon-blocked.html.json: Added.
* http/wpt/beacon/contentextensions/beacon-redirect-blocked-expected.txt: Added.
* http/wpt/beacon/contentextensions/beacon-redirect-blocked.html: Added.
* http/wpt/beacon/contentextensions/beacon-redirect-blocked.html.json: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@220996 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
LayoutTests/ChangeLog
LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt
LayoutTests/http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html
LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked.html [new file with mode: 0644]
LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked.html.json [new file with mode: 0644]
LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked-expected.txt [new file with mode: 0644]
LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked.html [new file with mode: 0644]
LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked.html.json [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/contentextensions/ContentExtensionActions.h
Source/WebCore/contentextensions/ContentExtensionsBackend.cpp
Source/WebCore/contentextensions/ContentExtensionsBackend.h
Source/WebCore/page/Page.h
Source/WebCore/page/UserContentProvider.cpp
Source/WebCore/page/UserContentProvider.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp
Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.h
Source/WebKit/NetworkProcess/PingLoad.cpp
Source/WebKit/NetworkProcess/PingLoad.h
Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp

index c975930..b01d18d 100644 (file)
@@ -1,3 +1,22 @@
+2017-08-21  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Content extensions should be able to intercept Beacon / Ping redirects
+        https://bugs.webkit.org/show_bug.cgi?id=175746
+        <rdar://problem/33946050>
+
+        Reviewed by Alex Christensen.
+
+        Add layout test coverage for blocking beacon loads via content extensions.
+
+        * http/wpt/beacon/connect-src-beacon-redirect-blocked.sub-expected.txt:
+        * http/wpt/beacon/connect-src-beacon-redirect-blocked.sub.html:
+        * http/wpt/beacon/contentextensions/beacon-blocked-expected.txt: Added.
+        * http/wpt/beacon/contentextensions/beacon-blocked.html: Added.
+        * http/wpt/beacon/contentextensions/beacon-blocked.html.json: Added.
+        * http/wpt/beacon/contentextensions/beacon-redirect-blocked-expected.txt: Added.
+        * http/wpt/beacon/contentextensions/beacon-redirect-blocked.html: Added.
+        * http/wpt/beacon/contentextensions/beacon-redirect-blocked.html.json: Added.
+
 2017-08-21  Matt Lewis  <jlewis3@apple.com>
 
         Fixed expectations.
index ee197a3..8bc5ca4 100644 (file)
@@ -1,3 +1,4 @@
+CONSOLE MESSAGE: Beacon API cannot load http://127.0.0.1:8800/WebKit/beacon/resources/beacon-preflight.py?allowCors=1&cmd=put&id=2539e883-7dfb-4dde-a227-a41c670d5fe1&redirect_status=307&location=http%3A%2F%2F127.0.0.1%3A8800%2FWebKit%2Fbeacon%2Fresources%2Fbeacon-preflight.py%3FallowCors%3D1%26cmd%3Dput%26id%3D2539e883-7dfb-4dde-a227-a41c670d5fe1&count=1. Blocked by Content Security Policy
 
 PASS Redirect is blocked by CSP 
 
index 6220f44..d05132d 100644 (file)
@@ -29,7 +29,7 @@ function pollResult(test, id) {
 
 function testCORSPreflightRedirectSuccess(what) {
   var testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
-  var id = self.token();
+  var id = "2539e883-7dfb-4dde-a227-a41c670d5fe1"; // Use a static token because the URL is logged.
   var target = encodeURIComponent(testBase + "beacon-preflight.py?allowCors=1&cmd=put&id=" + id);
 
   // 307 & 308 redirections are the only ones that maintain the POST method.
diff --git a/LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked-expected.txt b/LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked-expected.txt
new file mode 100644 (file)
index 0000000..a21f092
--- /dev/null
@@ -0,0 +1,5 @@
+CONSOLE MESSAGE: line 9: Content blocker prevented frame displaying http://localhost:8800/WebKit/beacon/contentextensions/beacon-blocked.html from loading a resource from http://localhost:8800/WebKit/beacon/resources/beacon-preflight.py
+CONSOLE MESSAGE: line 9: Beacon API cannot load http://localhost:8800/WebKit/beacon/resources/beacon-preflight.py. Resource blocked by content blocker
+
+PASS Content extensions should be able to block beacons 
+
diff --git a/LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked.html b/LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked.html
new file mode 100644 (file)
index 0000000..07ea018
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script>
+    const RESOURCES_DIR = "/WebKit/beacon/resources/";
+
+    test(function() {
+    assert_false(navigator.sendBeacon(RESOURCES_DIR + "beacon-preflight.py"), "sendBeacon should return false");
+    }, "Content extensions should be able to block beacons");
+</script>
diff --git a/LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked.html.json b/LayoutTests/http/wpt/beacon/contentextensions/beacon-blocked.html.json
new file mode 100644 (file)
index 0000000..c3a601c
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "beacon-preflight.py"
+        },
+        "action": {
+            "type": "block"
+        }
+    }
+]
diff --git a/LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked-expected.txt b/LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked-expected.txt
new file mode 100644 (file)
index 0000000..97b7952
--- /dev/null
@@ -0,0 +1,4 @@
+CONSOLE MESSAGE: Beacon API cannot load http://127.0.0.1:8800/WebKit/beacon/resources/beacon-preflight.py?allowCors=1&cmd=put&id=f470f43c-258c-4c82-b880-ace3bcdb211c&redirect_status=307&location=http%3A%2F%2F127.0.0.1%3A8800%2FWebKit%2Fbeacon%2Fresources%2Fbeacon-preflight.py%3FallowCors%3D1%26cmd%3Dput%26id%3Df470f43c-258c-4c82-b880-ace3bcdb211c&count=1. Blocked by content extension
+
+PASS Content extensions should be able to block beacon redirects 
+
diff --git a/LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked.html b/LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked.html
new file mode 100644 (file)
index 0000000..4155eb4
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+const RESOURCES_DIR = "/WebKit/beacon/resources/";
+
+function pollResult(test, id) {
+  var checkUrl = RESOURCES_DIR + "beacon-preflight.py?cmd=get&id=" + id;
+
+  return new Promise(resolve => {
+    step_timeout(test.step_func(() => {
+      fetch(checkUrl).then(response => {
+        response.json().then(body => {
+          resolve(body);
+        });
+      });
+    }), 1000);
+  });
+}
+
+promise_test(function(test) {
+  var testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+  var id = "f470f43c-258c-4c82-b880-ace3bcdb211c"; // Use a static token since the URL is logged.
+  var target = encodeURIComponent(testBase + "beacon-preflight.py?allowCors=1&cmd=put&id=" + id);
+
+  // 307 & 308 redirections are the only ones that maintain the POST method.
+  var testUrl = RESOURCES_DIR + "redirect.py?redirect_status=307&location=" + target;
+
+  assert_true(navigator.sendBeacon(testUrl), "sendBeacon should return true");
+  return pollResult(test, id) .then(result => {
+    // Redirected URL contains "&count=" which the content filter blocks.
+    assert_equals(result['beacon'], 0, "Did not receive beacon")
+  });
+}, "Content extensions should be able to block beacon redirects");
+</script>
diff --git a/LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked.html.json b/LayoutTests/http/wpt/beacon/contentextensions/beacon-redirect-blocked.html.json
new file mode 100644 (file)
index 0000000..a44556e
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "count"
+        },
+        "action": {
+            "type": "block"
+        }
+    }
+]
index 0ac3b7d..3f9656e 100644 (file)
@@ -1,3 +1,31 @@
+2017-08-21  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Content extensions should be able to intercept Beacon / Ping redirects
+        https://bugs.webkit.org/show_bug.cgi?id=175746
+        <rdar://problem/33946050>
+
+        Reviewed by Alex Christensen.
+
+        Update PingLoad to process content extension rules upon redirect. This allows content
+        extensions to block and upgrade to HTTPS beacon / ping loads.
+
+        Because ping loads can outlive the WebProcess, the content extensions rules are passed
+        to the NetworkProcess when starting the Ping load. The PingLoad can then consult those
+        rules upon redirect, on the NetworkProcess side.
+
+        Tests: http/wpt/beacon/contentextensions/beacon-blocked.html
+               http/wpt/beacon/contentextensions/beacon-redirect-blocked.html
+
+        * contentextensions/ContentExtensionActions.h:
+        * contentextensions/ContentExtensionsBackend.cpp:
+        (WebCore::ContentExtensions::ContentExtensionsBackend::forEach):
+        (WebCore::ContentExtensions::ContentExtensionsBackend::processContentExtensionRulesForPingLoad):
+        * contentextensions/ContentExtensionsBackend.h:
+        * page/Page.h:
+        * page/UserContentProvider.cpp:
+        (WebCore::UserContentProvider::forEachContentExtension):
+        * page/UserContentProvider.h:
+
 2017-08-21  Brady Eidson  <beidson@apple.com>
 
         ASSERTION FAILED: !m_connections.contains(&connection) in WebCore::SWServer::unregisterConnection(WebCore::SWServer::Connection&).
index 992b6bb..0a6b158 100644 (file)
@@ -51,7 +51,7 @@ struct BlockedStatus {
     bool madeHTTPS { false };
 };
 
-void applyBlockedStatusToRequest(const BlockedStatus&, ResourceRequest&);
+WEBCORE_EXPORT void applyBlockedStatusToRequest(const BlockedStatus&, ResourceRequest&);
 
 } // namespace ContentExtensions
 
index a92110a..8e6ee51 100644 (file)
@@ -134,6 +134,12 @@ Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLo
     return finalActions;
 }
 
+void ContentExtensionsBackend::forEach(const WTF::Function<void(const String&, ContentExtension&)>& apply)
+{
+    for (auto& pair : m_contentExtensions)
+        apply(pair.key, pair.value);
+}
+
 StyleSheetContents* ContentExtensionsBackend::globalDisplayNoneStyleSheet(const String& identifier) const
 {
     const auto& contentExtension = m_contentExtensions.get(identifier);
@@ -213,6 +219,41 @@ BlockedStatus ContentExtensionsBackend::processContentExtensionRulesForLoad(cons
     return { willBlockLoad, willBlockCookies, willMakeHTTPS };
 }
 
+BlockedStatus ContentExtensionsBackend::processContentExtensionRulesForPingLoad(const URL& url, const URL& mainDocumentURL)
+{
+    if (m_contentExtensions.isEmpty())
+        return { };
+
+    ResourceLoadInfo resourceLoadInfo = { url, mainDocumentURL, ResourceType::Raw };
+    Vector<ContentExtensions::Action> actions = actionsForResourceLoad(resourceLoadInfo);
+
+    bool willBlockLoad = false;
+    bool willBlockCookies = false;
+    bool willMakeHTTPS = false;
+    for (const auto& action : actions) {
+        switch (action.type()) {
+        case ContentExtensions::ActionType::BlockLoad:
+            willBlockLoad = true;
+            break;
+        case ContentExtensions::ActionType::BlockCookies:
+            willBlockCookies = true;
+            break;
+        case ContentExtensions::ActionType::MakeHTTPS:
+            if ((url.protocolIs("http") || url.protocolIs("ws")) && (!url.port() || isDefaultPortForProtocol(url.port().value(), url.protocol())))
+                willMakeHTTPS = true;
+            break;
+        case ContentExtensions::ActionType::CSSDisplayNoneSelector:
+        case ContentExtensions::ActionType::CSSDisplayNoneStyleSheet:
+            break;
+        case ContentExtensions::ActionType::IgnorePreviousRules:
+        case ContentExtensions::ActionType::InvalidAction:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+
+    return { willBlockLoad, willBlockCookies, willMakeHTTPS };
+}
+
 const String& ContentExtensionsBackend::displayNoneCSSRule()
 {
     static NeverDestroyed<const String> rule(MAKE_STATIC_STRING_IMPL("display:none !important;"));
index aec3915..d75417e 100644 (file)
@@ -65,9 +65,12 @@ public:
     WEBCORE_EXPORT StyleSheetContents* globalDisplayNoneStyleSheet(const String& identifier) const;
 
     BlockedStatus processContentExtensionRulesForLoad(const URL&, ResourceType, DocumentLoader& initiatingDocumentLoader);
+    WEBCORE_EXPORT BlockedStatus processContentExtensionRulesForPingLoad(const URL&, const URL& mainDocumentURL);
 
     static const String& displayNoneCSSRule();
 
+    void forEach(const WTF::Function<void(const String&, ContentExtension&)>&);
+
 private:
     HashMap<String, Ref<ContentExtension>> m_contentExtensions;
 };
index 84a86b1..0661b81 100644 (file)
@@ -504,7 +504,7 @@ public:
 
     PluginInfoProvider& pluginInfoProvider();
 
-    UserContentProvider& userContentProvider();
+    WEBCORE_EXPORT UserContentProvider& userContentProvider();
     WEBCORE_EXPORT void setUserContentProvider(Ref<UserContentProvider>&&);
 
     VisitedLinkStore& visitedLinkStore();
index d5524d9..0017e9a 100644 (file)
@@ -116,6 +116,15 @@ Vector<ContentExtensions::Action> UserContentProvider::actionsForResourceLoad(co
 
     return userContentExtensionBackend().actionsForResourceLoad(resourceLoadInfo);
 }
+
+void UserContentProvider::forEachContentExtension(const WTF::Function<void(const String&, ContentExtensions::ContentExtension&)>& apply, DocumentLoader& initiatingDocumentLoader)
+{
+    if (!contentExtensionsEnabled(initiatingDocumentLoader))
+        return;
+
+    userContentExtensionBackend().forEach(apply);
+}
+
 #endif
 
 } // namespace WebCore
index d421c1e..a65d1bb 100644 (file)
@@ -92,6 +92,7 @@ public:
     // which should always exist.
     ContentExtensions::BlockedStatus processContentExtensionRulesForLoad(const URL&, ResourceType, DocumentLoader& initiatingDocumentLoader);
     Vector<ContentExtensions::Action> actionsForResourceLoad(const ResourceLoadInfo&, DocumentLoader& initiatingDocumentLoader);
+    WEBCORE_EXPORT void forEachContentExtension(const WTF::Function<void(const String&, ContentExtensions::ContentExtension&)>&, DocumentLoader& initiatingDocumentLoader);
 #endif
 
 protected:
index fafc81d..48c3795 100644 (file)
@@ -1,3 +1,30 @@
+2017-08-21  Chris Dumez  <cdumez@apple.com>
+
+        [Beacon] Content extensions should be able to intercept Beacon / Ping redirects
+        https://bugs.webkit.org/show_bug.cgi?id=175746
+        <rdar://problem/33946050>
+
+        Reviewed by Alex Christensen.
+
+        Update PingLoad to process content extension rules upon redirect. This allows content
+        extensions to block and upgrade to HTTPS beacon / ping loads.
+
+        Because ping loads can outlive the WebProcess, the content extensions rules are passed
+        to the NetworkProcess when starting the Ping load. The PingLoad can then consult those
+        rules upon redirect, on the NetworkProcess side.
+
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::encode const):
+        (WebKit::NetworkResourceLoadParameters::decode):
+        * NetworkProcess/NetworkResourceLoadParameters.h:
+        * NetworkProcess/PingLoad.cpp:
+        (WebKit::PingLoad::willPerformHTTPRedirection):
+        (WebKit::PingLoad::contentExtensionsBackend):
+        (WebKit::PingLoad::processContentExtensionRulesForLoad):
+        * NetworkProcess/PingLoad.h:
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::WebLoaderStrategy::startPingLoad):
+
 2017-08-21  Adrian Perez de Castro  <aperez@igalia.com>
 
         [WPE][GTK] Unused variables in UserMediaProcessManager.cpp
index 982f679..fdee581 100644 (file)
@@ -88,6 +88,11 @@ void NetworkResourceLoadParameters::encode(IPC::Encoder& encoder) const
         encoder << SecurityOriginData::fromSecurityOrigin(*sourceOrigin);
     encoder.encodeEnum(mode);
     encoder << cspResponseHeaders;
+
+#if ENABLE(CONTENT_EXTENSIONS)
+    encoder << mainDocumentURL;
+    encoder << contentRuleLists;
+#endif
 }
 
 bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourceLoadParameters& result)
@@ -167,6 +172,14 @@ bool NetworkResourceLoadParameters::decode(IPC::Decoder& decoder, NetworkResourc
     if (!decoder.decode(result.cspResponseHeaders))
         return false;
 
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (!decoder.decode(result.mainDocumentURL))
+        return false;
+
+    if (!decoder.decode(result.contentRuleLists))
+        return false;
+#endif
+
     return true;
 }
     
index 5c92ee0..c2918ef 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "NetworkLoadParameters.h"
 #include "SandboxExtension.h"
+#include "WebCompiledContentRuleListData.h"
 #include <WebCore/ContentSecurityPolicyResponseHeaders.h>
 #include <WebCore/FetchOptions.h>
 #include <WebCore/ResourceHandle.h>
@@ -59,6 +60,11 @@ public:
     RefPtr<WebCore::SecurityOrigin> sourceOrigin;
     WebCore::FetchOptions::Mode mode;
     std::optional<WebCore::ContentSecurityPolicyResponseHeaders> cspResponseHeaders;
+
+#if ENABLE(CONTENT_EXTENSIONS)
+    WebCore::URL mainDocumentURL;
+    Vector<std::pair<String, WebCompiledContentRuleListData>> contentRuleLists;
+#endif
 };
 
 } // namespace WebKit
index 212c7a6..db68a08 100644 (file)
@@ -33,6 +33,7 @@
 #include "NetworkCORSPreflightChecker.h"
 #include "NetworkConnectionToWebProcess.h"
 #include "SessionTracker.h"
+#include "WebCompiledContentRuleList.h"
 #include "WebErrors.h"
 #include <WebCore/ContentSecurityPolicy.h>
 #include <WebCore/CrossOriginAccessControl.h>
@@ -102,18 +103,30 @@ SecurityOrigin& PingLoad::securityOrigin() const
 
 void PingLoad::willPerformHTTPRedirection(ResourceResponse&& redirectResponse, ResourceRequest&& request, RedirectCompletionHandler&& completionHandler)
 {
-    m_lastRedirectionRequest = request;
-
     RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - shouldFollowRedirects? %d", m_parameters.shouldFollowRedirects);
     if (!m_parameters.shouldFollowRedirects) {
         completionHandler({ });
+        didFinish(ResourceError { String(), 0, currentRequest().url(), ASCIILiteral("Not allowed to follow redirects"), ResourceError::Type::AccessControl });
         return;
     }
 
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (processContentExtensionRulesForLoad(request)) {
+        RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - Redirect was blocked by content extensions");
+        m_lastRedirectionRequest = request;
+        completionHandler({ });
+        didFinish(ResourceError { String(), 0, currentRequest().url(), ASCIILiteral("Blocked by content extension"), ResourceError::Type::AccessControl });
+        return;
+    }
+#endif
+
+    m_lastRedirectionRequest = request;
+
     if (auto* contentSecurityPolicy = this->contentSecurityPolicy()) {
         if (!contentSecurityPolicy->allowConnectToSource(request.url(), redirectResponse.isNull() ? ContentSecurityPolicy::RedirectResponseReceived::No : ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
             RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - Redirect was blocked by CSP");
             completionHandler({ });
+            didFinish(ResourceError { String(), 0, currentRequest().url(), ASCIILiteral("Blocked by Content Security Policy"), ResourceError::Type::AccessControl });
             return;
         }
     }
@@ -296,6 +309,28 @@ void PingLoad::preflightSuccess(ResourceRequest&& request)
         loadRequest(WTFMove(actualRequest));
 }
 
+#if ENABLE(CONTENT_EXTENSIONS)
+
+ContentExtensions::ContentExtensionsBackend& PingLoad::contentExtensionsBackend()
+{
+    if (!m_contentExtensionsBackend) {
+        m_contentExtensionsBackend = std::make_unique<ContentExtensions::ContentExtensionsBackend>();
+        for (auto& pair : m_parameters.contentRuleLists)
+            m_contentExtensionsBackend->addContentExtension(pair.first, WebCompiledContentRuleList::create(WTFMove(pair.second)));
+    }
+    return *m_contentExtensionsBackend;
+}
+
+// Returns true if we should block the load.
+bool PingLoad::processContentExtensionRulesForLoad(ResourceRequest& request)
+{
+    auto status = contentExtensionsBackend().processContentExtensionRulesForPingLoad(request.url(), m_parameters.mainDocumentURL);
+    applyBlockedStatusToRequest(status, request);
+    return status.blockedLoad;
+}
+
+#endif // ENABLE(CONTENT_EXTENSIONS)
+
 } // namespace WebKit
 
 #endif // USE(NETWORK_SESSION)
index cf6aa10..e993d16 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "NetworkDataTask.h"
 #include "NetworkResourceLoadParameters.h"
+#include <WebCore/ContentExtensionsBackend.h>
 #include <WebCore/ResourceError.h>
 
 namespace WebCore {
@@ -68,6 +69,11 @@ private:
     void makeCrossOriginAccessRequestWithPreflight(WebCore::ResourceRequest&&);
     void preflightSuccess(WebCore::ResourceRequest&&);
 
+#if ENABLE(CONTENT_EXTENSIONS)
+    WebCore::ContentExtensions::ContentExtensionsBackend& contentExtensionsBackend();
+    bool processContentExtensionRulesForLoad(WebCore::ResourceRequest&);
+#endif
+
     WebCore::SecurityOrigin& securityOrigin() const;
 
     const WebCore::ResourceRequest& currentRequest() const;
@@ -84,6 +90,9 @@ private:
     bool m_isSimpleRequest { true };
     RedirectCompletionHandler m_redirectHandler;
     mutable std::unique_ptr<WebCore::ContentSecurityPolicy> m_contentSecurityPolicy;
+#if ENABLE(CONTENT_EXTENSIONS)
+    std::unique_ptr<WebCore::ContentExtensions::ContentExtensionsBackend> m_contentExtensionsBackend;
+#endif
     std::optional<WebCore::ResourceRequest> m_lastRedirectionRequest;
 };
 
index 6fbe306..05b8014 100644 (file)
@@ -33,6 +33,7 @@
 #include "NetworkProcessConnection.h"
 #include "NetworkResourceLoadParameters.h"
 #include "SessionTracker.h"
+#include "WebCompiledContentRuleList.h"
 #include "WebCoreArgumentCoders.h"
 #include "WebErrors.h"
 #include "WebFrame.h"
@@ -61,6 +62,7 @@
 #include <WebCore/SecurityOrigin.h>
 #include <WebCore/Settings.h>
 #include <WebCore/SubresourceLoader.h>
+#include <WebCore/UserContentProvider.h>
 #include <pal/SessionID.h>
 #include <wtf/text/CString.h>
 
@@ -433,6 +435,18 @@ void WebLoaderStrategy::startPingLoad(Frame& frame, ResourceRequest& request, co
             loadParameters.cspResponseHeaders = contentSecurityPolicy->responseHeaders();
     }
 
+#if ENABLE(CONTENT_EXTENSIONS)
+    loadParameters.mainDocumentURL = document->topDocument().url();
+
+    if (auto* documentLoader = frame.loader().documentLoader()) {
+        if (auto* page = frame.page()) {
+            page->userContentProvider().forEachContentExtension([&loadParameters](const String& identifier, ContentExtensions::ContentExtension& contentExtension) {
+                loadParameters.contentRuleLists.append(std::make_pair(identifier, static_cast<const WebCompiledContentRuleList&>(contentExtension.compiledExtension()).data()));
+            }, *documentLoader);
+        }
+    }
+#endif
+
     if (completionHandler)
         m_pingLoadCompletionHandlers.add(loadParameters.identifier, WTFMove(completionHandler));