[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 c975930e7cb579bd55fa4d17f0fbe97809c1bad4..b01d18df3f40a94736532744fd3ad06b3ec9a1e6 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 ee197a3a164cd60ecf67d03652795bc73dec1afc..8bc5ca4106d256d0a68007b996f135a429bcafb1 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 6220f447daad749657ba1d935569cdfb7b48f944..d05132dd0f96444957184cc0d2ee8dfc0de3d3d6 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 0ac3b7d3dd9463737aa0a2677a92365167cccd0d..3f9656ee86009cb55e22197ae0207eb9e83f8569 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 992b6bbf770380c8fb58d5a564a976bba981676f..0a6b158235eb7f74d850f9007326eb39ab0176d3 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 a92110a95ade9e7ca649d1510c40b38358ad291b..8e6ee518141f109165b012650e2c772c7bda4aca 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 aec391568c635126d20381e6af3eddd58c5cf683..d75417ee66b450c7a2dad09498726f8c83b2e667 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 84a86b1567eec03e3761b8887ed6e5cddcf7b89f..0661b8107302a27d2637c77124067fa40e1056ac 100644 (file)
@@ -504,7 +504,7 @@ public:
 
     PluginInfoProvider& pluginInfoProvider();
 
-    UserContentProvider& userContentProvider();
+    WEBCORE_EXPORT UserContentProvider& userContentProvider();
     WEBCORE_EXPORT void setUserContentProvider(Ref<UserContentProvider>&&);
 
     VisitedLinkStore& visitedLinkStore();
index d5524d9bdaa4a1b4683b9e599a34496d8e46940a..0017e9a4f93eb416ee63f6c12c1adbbf3179ac5e 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 d421c1e78c61991cad995db8bf86f8004d861a7d..a65d1bbfd24bcf3db6f90a206f69b50919d7380a 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 fafc81ddcb796d241cdf13b5cb4ce17a83cfa817..48c37956bf4443863744640f2809db6f91e357b1 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 982f679aae7f6b363555f404fa859d8bdc715a8f..fdee5819779fe4622d39e6d193d8d447de0ee6d3 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 5c92ee0cec9243f524a29c80690b7210caf5bd85..c2918ef9ecbbaa1e7b59dd2e44905947f894f904 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 212c7a651cde91e8f493d143fa1953ea5e57e237..db68a089aed4df4c4d985fc3662f4996faffee4b 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 cf6aa10ab8afde668c19f0c32d79eaed14e00720..e993d161023a06f105922595342d90797d488d21 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 6fbe306e4d75760a0c26cb6325c882f0c4e42649..05b8014a7975c11375507d4ec86c0faf09e2368a 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));