[Content Extensions] Content blocking rules are not consulted for pings
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Oct 2015 04:26:43 +0000 (04:26 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Oct 2015 04:26:43 +0000 (04:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149873

Patch by Roopesh Chander <roop@roopc.net> on 2015-10-15
Reviewed by Alex Christensen.

Source/WebCore:

This patch makes requests sent through the PingLoader
respect content blocking rules. Specifically, the following
are now subject to content blocking rules:

 1. <a ping> pings
 2. Images loaded in unload / beforeunload / pagehide handlers
 3. X-XSS-Protection / CSP violation reports

Tests: http/tests/contentextensions/block-cookies-in-csp-report.html
       http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html
       http/tests/contentextensions/block-cookies-in-ping.html
       http/tests/contentextensions/block-csp-report.html
       http/tests/contentextensions/block-image-load-in-onunload.html
       http/tests/contentextensions/block-ping.html
       http/tests/contentextensions/hide-on-csp-report.html

* loader/PingLoader.cpp:
(WebCore::processContentExtensionRulesForLoad):
(WebCore::PingLoader::loadImage):
(WebCore::PingLoader::sendPing):
(WebCore::PingLoader::sendViolationReport):

LayoutTests:

Tests for ensuring that requests loaded through the PingLoader
are subject to content blocking rules.

* http/tests/contentextensions/block-cookies-in-csp-report-expected.txt: Added.
* http/tests/contentextensions/block-cookies-in-csp-report.html: Added.
* http/tests/contentextensions/block-cookies-in-csp-report.html.json: Added.
* http/tests/contentextensions/block-cookies-in-image-load-in-onunload-expected.txt: Added.
* http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html: Added.
* http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html.json: Added.
* http/tests/contentextensions/block-cookies-in-ping-expected.txt: Added.
* http/tests/contentextensions/block-cookies-in-ping.html: Added.
* http/tests/contentextensions/block-cookies-in-ping.html.json: Added.
* http/tests/contentextensions/block-csp-report-expected.txt: Added.
* http/tests/contentextensions/block-csp-report.html: Added.
* http/tests/contentextensions/block-csp-report.html.json: Added.
* http/tests/contentextensions/block-image-load-in-onunload-expected.txt: Added.
* http/tests/contentextensions/block-image-load-in-onunload.html: Added.
* http/tests/contentextensions/block-image-load-in-onunload.html.json: Added.
* http/tests/contentextensions/block-ping-expected.txt: Added.
* http/tests/contentextensions/block-ping.html: Added.
* http/tests/contentextensions/block-ping.html.json: Added.
* http/tests/contentextensions/hide-on-csp-report-expected.txt: Added.
* http/tests/contentextensions/hide-on-csp-report.html: Added.
* http/tests/contentextensions/hide-on-csp-report.html.json: Added.
* http/tests/contentextensions/resources/check-ping.html: Added.
* http/tests/contentextensions/resources/delete-ping.php: Added.
* http/tests/contentextensions/resources/get-ping-data.php: Added.
* http/tests/contentextensions/resources/ping-file-path.php: Added.
* http/tests/contentextensions/resources/redirect.php: Added.
* http/tests/contentextensions/resources/save-ping.php: Added.

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

30 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-ping-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-ping.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-cookies-in-ping.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-csp-report-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-csp-report.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-csp-report.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-image-load-in-onunload-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-image-load-in-onunload.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-image-load-in-onunload.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-ping-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-ping.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/block-ping.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/hide-on-csp-report-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/hide-on-csp-report.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/hide-on-csp-report.html.json [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/resources/check-ping.html [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/resources/delete-ping.php [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/resources/get-ping-data.php [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/resources/ping-file-path.php [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/resources/redirect.php [new file with mode: 0644]
LayoutTests/http/tests/contentextensions/resources/save-ping.php [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/loader/PingLoader.cpp

index 2894160..54c7ed2 100644 (file)
@@ -1,3 +1,41 @@
+2015-10-15  Roopesh Chander  <roop@roopc.net>
+
+        [Content Extensions] Content blocking rules are not consulted for pings
+        https://bugs.webkit.org/show_bug.cgi?id=149873
+
+        Reviewed by Alex Christensen.
+
+        Tests for ensuring that requests loaded through the PingLoader
+        are subject to content blocking rules.
+
+        * http/tests/contentextensions/block-cookies-in-csp-report-expected.txt: Added.
+        * http/tests/contentextensions/block-cookies-in-csp-report.html: Added.
+        * http/tests/contentextensions/block-cookies-in-csp-report.html.json: Added.
+        * http/tests/contentextensions/block-cookies-in-image-load-in-onunload-expected.txt: Added.
+        * http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html: Added.
+        * http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html.json: Added.
+        * http/tests/contentextensions/block-cookies-in-ping-expected.txt: Added.
+        * http/tests/contentextensions/block-cookies-in-ping.html: Added.
+        * http/tests/contentextensions/block-cookies-in-ping.html.json: Added.
+        * http/tests/contentextensions/block-csp-report-expected.txt: Added.
+        * http/tests/contentextensions/block-csp-report.html: Added.
+        * http/tests/contentextensions/block-csp-report.html.json: Added.
+        * http/tests/contentextensions/block-image-load-in-onunload-expected.txt: Added.
+        * http/tests/contentextensions/block-image-load-in-onunload.html: Added.
+        * http/tests/contentextensions/block-image-load-in-onunload.html.json: Added.
+        * http/tests/contentextensions/block-ping-expected.txt: Added.
+        * http/tests/contentextensions/block-ping.html: Added.
+        * http/tests/contentextensions/block-ping.html.json: Added.
+        * http/tests/contentextensions/hide-on-csp-report-expected.txt: Added.
+        * http/tests/contentextensions/hide-on-csp-report.html: Added.
+        * http/tests/contentextensions/hide-on-csp-report.html.json: Added.
+        * http/tests/contentextensions/resources/check-ping.html: Added.
+        * http/tests/contentextensions/resources/delete-ping.php: Added.
+        * http/tests/contentextensions/resources/get-ping-data.php: Added.
+        * http/tests/contentextensions/resources/ping-file-path.php: Added.
+        * http/tests/contentextensions/resources/redirect.php: Added.
+        * http/tests/contentextensions/resources/save-ping.php: Added.
+
 2015-10-15  Joseph Pecoraro  <pecoraro@apple.com>
 
         Unreviewed gardening. Make inspector/heap/gc.html more reliable.
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report-expected.txt b/LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report-expected.txt
new file mode 100644 (file)
index 0000000..c2a7586
--- /dev/null
@@ -0,0 +1,11 @@
+CONSOLE MESSAGE: Refused to load the image 'http://localhost/foo.png' because it violates the following Content Security Policy directive: "img-src 'self'".
+
+This test creates a CSP violation report, but the report URL matches a 'block-cookie' rule. 
+
+
+
+--------
+Frame: 'result_frame'
+--------
+Ping received.
+No cookies in ping.
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report.html b/LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report.html
new file mode 100644 (file)
index 0000000..a95fc21
--- /dev/null
@@ -0,0 +1,40 @@
+<head>
+<meta http-equiv="Content-Security-Policy" content="img-src 'self'; report-uri /contentextensions/resources/save-ping.php?test=contentextensions-block-cookies-in-csp-report">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+    testRunner.waitUntilDone();
+}
+
+function deletePing() {
+    var deletePingContainer = document.getElementById("delete_ping_container");
+    deletePingContainer.innerHTML = '<img src="resources/delete-ping.php?test=contentextensions-block-cookies-in-csp-report" onerror="loadCrossDomainImage();">';
+}
+
+function loadCrossDomainImage() {
+    // Trying to load an image from a different port
+    // will result in a CSP violation.
+    var img = new Image(1, 1);
+    img.src = "http://localhost/foo.png";
+    showPingResult();
+}
+
+function showPingResult() {
+    var iframe = document.getElementById("result_frame");
+    iframe.onload = function() {
+        if (window.testRunner) { testRunner.notifyDone(); }
+    }
+    iframe.src = "resources/get-ping-data.php?test=contentextensions-block-cookies-in-csp-report";
+}
+</script>
+</head>
+
+<body>
+This test creates a CSP violation report, but the report URL matches a 'block-cookie' rule.
+<img src="/cookies/resources/cookie-utility.php?queryfunction=setFooCookie"
+    onerror="deletePing();">
+<div id="delete_ping_container"></div>
+<iframe id="result_frame"><!-- Will contain ping data received by server --></iframe>
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report.html.json b/LayoutTests/http/tests/contentextensions/block-cookies-in-csp-report.html.json
new file mode 100644 (file)
index 0000000..e7fc6f3
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "block-cookies"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload-expected.txt b/LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload-expected.txt
new file mode 100644 (file)
index 0000000..8c8f52f
--- /dev/null
@@ -0,0 +1,3 @@
+main frame - has 1 onunload handler(s)
+Ping received.
+No cookies in ping.
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html b/LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html
new file mode 100644 (file)
index 0000000..13e6626
--- /dev/null
@@ -0,0 +1,35 @@
+<head>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function deletePing() {
+    var deletePingContainer = document.getElementById("delete_ping_container");
+    deletePingContainer.innerHTML = '<img src="resources/delete-ping.php?test=contentextensions-block-cookies-in-image-load-in-onunload" onerror="loadNextPage();">';
+}
+
+function loadNextPage() {
+    // Navigating to another location invokes the unload handler
+    location.href = "resources/redirect.php?to=" + 
+                        encodeURIComponent(
+                        "/contentextensions/resources/get-ping-data.php?" + 
+                        "test=contentextensions-block-cookies-in-image-load-in-onunload&" +
+                        "end_test=1");
+}
+
+function loadImage() {
+    var img = new Image(1, 1);
+    img.src = "resources/save-ping.php?test=contentextensions-block-cookies-in-image-load-in-onunload";
+}
+</script>
+</head>
+
+<body onunload="loadImage();">
+This test sets a cookie, then loads an image in onunload, where the image URL matches a 'block-cookie' rule.
+<img src="http://127.0.0.1:8000/cookies/resources/cookie-utility.php?queryfunction=setFooCookie"
+    onerror="deletePing();">
+<div id="delete_ping_container"></div>
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html.json b/LayoutTests/http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html.json
new file mode 100644 (file)
index 0000000..e7fc6f3
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "block-cookies"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-ping-expected.txt b/LayoutTests/http/tests/contentextensions/block-cookies-in-ping-expected.txt
new file mode 100644 (file)
index 0000000..4742c66
--- /dev/null
@@ -0,0 +1,12 @@
+This test sets a cookie, then follows a link with a ping attribute where the ping URL matches a 'block-cookie' rule.   
+
+--------
+Frame: 'link_frame'
+--------
+Link with ping was clicked.
+
+--------
+Frame: 'result_frame'
+--------
+Ping received.
+No cookies in ping.
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-ping.html b/LayoutTests/http/tests/contentextensions/block-cookies-in-ping.html
new file mode 100644 (file)
index 0000000..d11f8b5
--- /dev/null
@@ -0,0 +1,55 @@
+<head>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+    testRunner.overridePreference("WebKitHyperlinkAuditingEnabled", 1);
+    testRunner.waitUntilDone();
+}
+
+function loadLinkWithPing() {
+    var iframe = document.getElementById("link_frame");
+    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
+    iframeDoc.write('' +
+        '<img src="resources/delete-ping.php?test=contentextensions-block-cookies-in-ping" ' + 
+            'onerror="parent.clickOnLinkWithPing();">' +
+        '<a id="a" ' +
+            'href="resources/check-ping.html" ' + // check-ping.html calls showPingResult()
+            'ping="resources/save-ping.php?test=contentextensions-block-cookies-in-ping"> ' +
+            'Link with ping' +
+        '</a>'
+        
+    );
+}
+
+function clickOnLinkWithPing() {
+    var iframe = document.getElementById("link_frame");
+    var iframeDoc = iframe.contentDocument;
+    if (window.eventSender) {
+        var a = iframeDoc.getElementById("a");
+        var x = iframe.offsetLeft + a.offsetLeft + 2;
+        var y = iframe.offsetTop + a.offsetTop + 2;
+        eventSender.mouseMoveTo(x, y);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+}
+
+function showPingResult() {
+    var iframe = document.getElementById("result_frame");
+    iframe.onload = function() {
+        if (window.testRunner) { testRunner.notifyDone() }
+    }
+    iframe.src = "resources/get-ping-data.php?test=contentextensions-block-cookies-in-ping";
+}
+</script>
+</head>
+
+<body>
+This test sets a cookie, then follows a link with a ping attribute where the ping URL matches a 'block-cookie' rule.
+<img src="http://localhost:8000/cookies/resources/cookie-utility.php?queryfunction=setFooCookie"
+    onerror="loadLinkWithPing();">
+<iframe id="link_frame"><!-- Will contain link with ping --></iframe>
+<iframe id="result_frame"><!-- Will contain ping data received by server --></iframe>
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/block-cookies-in-ping.html.json b/LayoutTests/http/tests/contentextensions/block-cookies-in-ping.html.json
new file mode 100644 (file)
index 0000000..e7fc6f3
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "block-cookies"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/block-csp-report-expected.txt b/LayoutTests/http/tests/contentextensions/block-csp-report-expected.txt
new file mode 100644 (file)
index 0000000..ee6aec3
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: Refused to load the image 'http://localhost/foo.png' because it violates the following Content Security Policy directive: "img-src 'self'".
+
+CONSOLE MESSAGE: line 34: Content blocker prevented frame displaying http://127.0.0.1:8000/contentextensions/block-csp-report.html from loading a resource from http://localhost:8000/contentextensions/resources/save-ping.php?test=contentextensions-block-csp-report
+This test creates a CSP violation report, but the report URL matches a 'block' rule.  
+
+--------
+Frame: 'result_frame'
+--------
+Ping not received - timed out.
diff --git a/LayoutTests/http/tests/contentextensions/block-csp-report.html b/LayoutTests/http/tests/contentextensions/block-csp-report.html
new file mode 100644 (file)
index 0000000..cedfe38
--- /dev/null
@@ -0,0 +1,37 @@
+<head>
+<meta http-equiv="Content-Security-Policy" content="img-src 'self'; report-uri http://localhost:8000/contentextensions/resources/save-ping.php?test=contentextensions-block-csp-report">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+    testRunner.waitUntilDone();
+}
+
+function loadCrossDomainImage() {
+    // Trying to load an image from a different port
+    // will result in a CSP violation.
+    var img = new Image(1, 1);
+    img.src = "http://localhost/foo.png";
+    showPingResult();
+}
+
+function showPingResult() {
+    var iframe = document.getElementById("result_frame");
+    iframe.onload = function() {
+        if (window.testRunner) { testRunner.notifyDone(); }
+    }
+    iframe.src = "resources/get-ping-data.php?test=contentextensions-block-csp-report&timeout_ms=1000";
+    // Why timeout_ms=1000:
+    // To pass the test, the ping shouldn't arrive, so we need to
+    // timeout at some point. We don't have to wait too long because
+    // the console message can tell us whether the ping was blocked.
+}
+</script>
+</head>
+
+<body>
+This test creates a CSP violation report, but the report URL matches a 'block' rule.
+<img src="resources/delete-ping.php?test=contentextensions-block-csp-report" onerror="loadCrossDomainImage();">
+<iframe id="result_frame"><!-- Will contain ping data received by server --></iframe>
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/block-csp-report.html.json b/LayoutTests/http/tests/contentextensions/block-csp-report.html.json
new file mode 100644 (file)
index 0000000..28ff1e1
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "block"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/block-image-load-in-onunload-expected.txt b/LayoutTests/http/tests/contentextensions/block-image-load-in-onunload-expected.txt
new file mode 100644 (file)
index 0000000..0c71d76
--- /dev/null
@@ -0,0 +1,3 @@
+main frame - has 1 onunload handler(s)
+CONSOLE MESSAGE: line 29: Content blocker prevented frame displaying http://127.0.0.1:8000/contentextensions/block-image-load-in-onunload.html from loading a resource from http://127.0.0.1:8000/contentextensions/resources/save-ping.php?test=contentextensions-block-image-load-in-onunload
+Ping not received - timed out.
diff --git a/LayoutTests/http/tests/contentextensions/block-image-load-in-onunload.html b/LayoutTests/http/tests/contentextensions/block-image-load-in-onunload.html
new file mode 100644 (file)
index 0000000..fe7eb4b
--- /dev/null
@@ -0,0 +1,33 @@
+<head>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function loadNextPage() {
+    // Navigating to another location invokes the unload handler
+    location.href = "resources/redirect.php?to=" + 
+                        encodeURIComponent(
+                        "/contentextensions/resources/get-ping-data.php?" + 
+                        "test=contentextensions-block-image-load-in-onunload&" +
+                        "timeout_ms=1000&" +
+                        "end_test=1");
+    // Why timeout_ms=1000:
+    // To pass the test, the ping shouldn't arrive, so we need to
+    // timeout at some point. We don't have to wait too long because
+    // the console message can tell us whether the ping was blocked.
+}
+
+function loadImage() {
+    var img = new Image(1, 1);
+    img.src = "resources/save-ping.php?test=contentextensions-block-image-load-in-onunload";
+}
+</script>
+</head>
+
+<body onunload="loadImage();">
+This test loads an image in onunload, where the image URL matches a 'block' rule.
+<img src="resources/delete-ping.php?test=contentextensions-block-image-load-in-onunload" onerror="loadNextPage();">
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/block-image-load-in-onunload.html.json b/LayoutTests/http/tests/contentextensions/block-image-load-in-onunload.html.json
new file mode 100644 (file)
index 0000000..28ff1e1
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "block"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/block-ping-expected.txt b/LayoutTests/http/tests/contentextensions/block-ping-expected.txt
new file mode 100644 (file)
index 0000000..73c92c9
--- /dev/null
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: line 34: Content blocker prevented frame displaying http://127.0.0.1:8000/contentextensions/block-ping.html from loading a resource from http://127.0.0.1:8000/contentextensions/resources/save-ping.php?test=contentextensions-block-ping
+This test follows a link with a ping attribute where the ping URL matches a 'block' rule.  
+
+--------
+Frame: 'link_frame'
+--------
+Link with ping was clicked.
+
+--------
+Frame: 'result_frame'
+--------
+Ping not received - timed out.
diff --git a/LayoutTests/http/tests/contentextensions/block-ping.html b/LayoutTests/http/tests/contentextensions/block-ping.html
new file mode 100644 (file)
index 0000000..dde302a
--- /dev/null
@@ -0,0 +1,57 @@
+<head>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+    testRunner.overridePreference("WebKitHyperlinkAuditingEnabled", 1);
+    testRunner.waitUntilDone();
+}
+
+function loadLinkWithPing() {
+    var iframe = document.getElementById("link_frame");
+    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
+    iframeDoc.write('' +
+        '<img src="resources/delete-ping.php?test=contentextensions-block-ping" ' + 
+            'onerror="parent.clickOnLinkWithPing();">' +
+        '<a id="a" ' +
+            'href="resources/check-ping.html" ' + // check-ping.html calls showPingResult()
+            'ping="resources/save-ping.php?test=contentextensions-block-ping"> ' +
+            'Link with ping' +
+        '</a>'
+        
+    );
+}
+
+function clickOnLinkWithPing() {
+    var iframe = document.getElementById("link_frame");
+    var iframeDoc = iframe.contentDocument;
+    if (window.eventSender) {
+        var a = iframeDoc.getElementById("a");
+        var x = iframe.offsetLeft + a.offsetLeft + 2;
+        var y = iframe.offsetTop + a.offsetTop + 2;
+        eventSender.mouseMoveTo(x, y);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+}
+
+function showPingResult() {
+    var iframe = document.getElementById("result_frame");
+    iframe.onload = function() {
+        if (window.testRunner) { testRunner.notifyDone(); }
+    }
+    iframe.src = "resources/get-ping-data.php?test=contentextensions-block-ping&timeout_ms=1000";
+    // Why timeout_ms=1000:
+    // To pass the test, the ping shouldn't arrive, so we need to
+    // timeout at some point. We don't have to wait too long because
+    // the console message can tell us whether the ping was blocked.
+}
+</script>
+</head>
+
+<body onload="loadLinkWithPing();">
+This test follows a link with a ping attribute where the ping URL matches a 'block' rule.
+<iframe id="link_frame"><!-- Will contain link with ping --></iframe>
+<iframe id="result_frame"><!-- Will contain ping data received by server --></iframe>
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/block-ping.html.json b/LayoutTests/http/tests/contentextensions/block-ping.html.json
new file mode 100644 (file)
index 0000000..28ff1e1
--- /dev/null
@@ -0,0 +1,10 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "block"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/hide-on-csp-report-expected.txt b/LayoutTests/http/tests/contentextensions/hide-on-csp-report-expected.txt
new file mode 100644 (file)
index 0000000..923a407
--- /dev/null
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: Refused to load the image 'http://localhost/foo.png' because it violates the following Content Security Policy directive: "img-src 'self'".
+
+This test creates a CSP violation report, but the report URL matches a 'css-display-none' rule.
+This text should remain visible.
+
+
+--------
+Frame: 'result_frame'
+--------
+Ping received.
+No cookies in ping.
diff --git a/LayoutTests/http/tests/contentextensions/hide-on-csp-report.html b/LayoutTests/http/tests/contentextensions/hide-on-csp-report.html
new file mode 100644 (file)
index 0000000..caaacdc
--- /dev/null
@@ -0,0 +1,35 @@
+<head>
+<meta http-equiv="Content-Security-Policy" content="img-src 'self'; report-uri http://localhost:8000/contentextensions/resources/save-ping.php?test=contentextensions-hide-on-csp-report">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+    testRunner.waitUntilDone();
+}
+
+function loadCrossDomainImage() {
+    // Trying to load an image from a different port
+    // will result in a CSP violation.
+    var img = new Image(1, 1);
+    img.src = "http://localhost/foo.png";
+    showPingResult();
+}
+
+function showPingResult() {
+    var iframe = document.getElementById("result_frame");
+    iframe.onload = function() {
+        if (window.testRunner) { testRunner.notifyDone(); }
+    }
+    iframe.src = "resources/get-ping-data.php?test=contentextensions-hide-on-csp-report";
+}
+</script>
+</head>
+
+<body>
+This test creates a CSP violation report, but the report URL matches a 'css-display-none' rule.
+<p class="foo">This text should be hidden once the report is sent.</p>
+<p class="bar">This text should remain visible.</p>
+<img src="resources/delete-ping.php?test=contentextensions-hide-on-csp-report" onerror="loadCrossDomainImage();">
+<iframe id="result_frame"><!-- Will contain ping data received by server --></iframe>
+</body>
+
diff --git a/LayoutTests/http/tests/contentextensions/hide-on-csp-report.html.json b/LayoutTests/http/tests/contentextensions/hide-on-csp-report.html.json
new file mode 100644 (file)
index 0000000..cc104ec
--- /dev/null
@@ -0,0 +1,11 @@
+[
+    {
+        "trigger": {
+            "url-filter": "save-ping.php"
+        },
+        "action": {
+            "type": "css-display-none",
+            "selector": ".foo"
+        }
+    }
+]
diff --git a/LayoutTests/http/tests/contentextensions/resources/check-ping.html b/LayoutTests/http/tests/contentextensions/resources/check-ping.html
new file mode 100644 (file)
index 0000000..8825bef
--- /dev/null
@@ -0,0 +1,4 @@
+<script>
+parent.showPingResult()
+</script>
+Link with ping was clicked.
diff --git a/LayoutTests/http/tests/contentextensions/resources/delete-ping.php b/LayoutTests/http/tests/contentextensions/resources/delete-ping.php
new file mode 100644 (file)
index 0000000..678ffc9
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+require_once 'ping-file-path.php';
+
+unlink($pingFilePath);
+?>
diff --git a/LayoutTests/http/tests/contentextensions/resources/get-ping-data.php b/LayoutTests/http/tests/contentextensions/resources/get-ping-data.php
new file mode 100644 (file)
index 0000000..9b601af
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+require_once 'ping-file-path.php';
+
+$noTimeout = True;
+$timeoutMsecs = 0;
+if (isset($_GET['timeout_ms'])) {
+    $noTimeout = False;
+    $timeoutMsecs = (int) $_GET['timeout_ms'];
+}
+
+$pingFileFound = False;
+while ($noTimeout || $timeoutMsecs > 0) {
+    if (file_exists($pingFilePath)) {
+        $pingFileFound = True;
+        break;
+    }
+    $sleepMsecs = 10;
+    usleep($sleepMsecs * 1000);
+    if (!$noTimeout) {
+        $timeoutMsecs -= $sleepMsecs;
+    }
+    // file_exists() caches results, we want to invalidate the cache.
+    clearstatcache();
+}
+
+
+echo "<html><body>\n";
+
+if ($pingFileFound) {
+    echo "Ping received.";
+    $pingFile = fopen($pingFilePath, 'r');
+    while ($line = fgets($pingFile)) {
+        echo "<br>";
+        echo trim($line);
+    }
+    fclose($pingFile);
+    unlink($pingFilePath);
+} else {
+    echo "Ping not received - timed out.";
+}
+
+if (isset($_GET['end_test'])) {
+    echo "<script>";
+    echo "if (window.testRunner)";
+    echo "    testRunner.notifyDone();";
+    echo "</script>";
+}
+
+echo "</body></html>";
+?>
diff --git a/LayoutTests/http/tests/contentextensions/resources/ping-file-path.php b/LayoutTests/http/tests/contentextensions/resources/ping-file-path.php
new file mode 100644 (file)
index 0000000..4fc6bd0
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+require_once '../../resources/portabilityLayer.php';
+
+if (isset($_GET['test'])) {
+    $pingFilePath = sys_get_temp_dir() . "/" . str_replace("/", "-", $_GET['test']) . ".ping.txt"; 
+}
+
+?>
diff --git a/LayoutTests/http/tests/contentextensions/resources/redirect.php b/LayoutTests/http/tests/contentextensions/resources/redirect.php
new file mode 100644 (file)
index 0000000..b82389e
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+if (isset($_GET['to'])) {
+    echo("<script>location.href='" . $_GET['to'] . "';</script>");
+}
+echo "<body>Redirecting</body>";
+?>
diff --git a/LayoutTests/http/tests/contentextensions/resources/save-ping.php b/LayoutTests/http/tests/contentextensions/resources/save-ping.php
new file mode 100644 (file)
index 0000000..a01d207
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+require_once 'ping-file-path.php';
+
+$pingFile = fopen($pingFilePath . ".tmp", 'w');
+$httpHeaders = $_SERVER;
+$cookiesFound = false;
+foreach ($httpHeaders as $name => $value) {
+    if ($name === "HTTP_COOKIE") {
+        fwrite($pingFile, "Cookies in ping: $value\n");
+        $cookiesFound = true;
+    }
+}
+if (!$cookiesFound) {
+    fwrite($pingFile, "No cookies in ping.\n");
+}
+fclose($pingFile);
+rename($pingFilePath . ".tmp", $pingFilePath);
+foreach ($_COOKIE as $name => $value)
+    setcookie($name, "deleted", time() - 60, "/");
+?>
index 4fc67c0..9ff2a19 100644 (file)
@@ -1,3 +1,32 @@
+2015-10-15  Roopesh Chander  <roop@roopc.net>
+
+        [Content Extensions] Content blocking rules are not consulted for pings
+        https://bugs.webkit.org/show_bug.cgi?id=149873
+
+        Reviewed by Alex Christensen.
+
+        This patch makes requests sent through the PingLoader
+        respect content blocking rules. Specifically, the following
+        are now subject to content blocking rules:
+         1. <a ping> pings
+         2. Images loaded in unload / beforeunload / pagehide handlers
+         3. X-XSS-Protection / CSP violation reports
+
+        Tests: http/tests/contentextensions/block-cookies-in-csp-report.html
+               http/tests/contentextensions/block-cookies-in-image-load-in-onunload.html
+               http/tests/contentextensions/block-cookies-in-ping.html
+               http/tests/contentextensions/block-csp-report.html
+               http/tests/contentextensions/block-image-load-in-onunload.html
+               http/tests/contentextensions/block-ping.html
+               http/tests/contentextensions/hide-on-csp-report.html
+
+        * loader/PingLoader.cpp:
+        (WebCore::processContentExtensionRulesForLoad):
+        (WebCore::PingLoader::loadImage):
+        (WebCore::PingLoader::sendPing):
+        (WebCore::PingLoader::sendViolationReport):
+
 2015-10-14  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Include Garbage Collection Event in Timeline
index 3c5f4c9..c80b2e4 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2015 Roopesh Chander (roop@roopc.net)
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
 #include "PlatformStrategies.h"
 #include "ProgressTracker.h"
 #include "ResourceHandle.h"
+#include "ResourceLoadInfo.h"
 #include "ResourceRequest.h"
 #include "ResourceResponse.h"
 #include "SecurityOrigin.h"
 #include "SecurityPolicy.h"
+#include "UserContentController.h"
 #include <wtf/text/CString.h>
 
 namespace WebCore {
 
+#if ENABLE(CONTENT_EXTENSIONS)
+static ContentExtensions::BlockedStatus processContentExtensionRulesForLoad(const Frame& frame, ResourceRequest& request, ResourceType resourceType)
+{
+    if (DocumentLoader* documentLoader = frame.loader().documentLoader()) {
+        if (Page* page = frame.page()) {
+            if (UserContentController* controller = page->userContentController())
+                return controller->processContentExtensionRulesForLoad(request, resourceType, *documentLoader);
+        }
+    }
+    return ContentExtensions::BlockedStatus::NotBlocked;
+}
+#endif
+
 void PingLoader::loadImage(Frame& frame, const URL& url)
 {
     if (!frame.document()->securityOrigin()->canDisplay(url)) {
@@ -60,6 +76,12 @@ void PingLoader::loadImage(Frame& frame, const URL& url)
     }
 
     ResourceRequest request(url);
+
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (processContentExtensionRulesForLoad(frame, request, ResourceType::Image) == ContentExtensions::BlockedStatus::Blocked)
+        return;
+#endif
+
     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
     String referrer = SecurityPolicy::generateReferrerHeader(frame.document()->referrerPolicy(), request.url(), frame.loader().outgoingReferrer());
     if (!referrer.isEmpty())
@@ -73,6 +95,12 @@ void PingLoader::loadImage(Frame& frame, const URL& url)
 void PingLoader::sendPing(Frame& frame, const URL& pingURL, const URL& destinationURL)
 {
     ResourceRequest request(pingURL);
+    
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (processContentExtensionRulesForLoad(frame, request, ResourceType::Raw) == ContentExtensions::BlockedStatus::Blocked)
+        return;
+#endif
+
     request.setHTTPMethod("POST");
     request.setHTTPContentType("text/ping");
     request.setHTTPBody(FormData::create("PING"));
@@ -98,10 +126,26 @@ void PingLoader::sendPing(Frame& frame, const URL& pingURL, const URL& destinati
 void PingLoader::sendViolationReport(Frame& frame, const URL& reportURL, PassRefPtr<FormData> report)
 {
     ResourceRequest request(reportURL);
+
+#if ENABLE(CONTENT_EXTENSIONS)
+    if (processContentExtensionRulesForLoad(frame, request, ResourceType::Raw) == ContentExtensions::BlockedStatus::Blocked)
+        return;
+#endif
+
     request.setHTTPMethod("POST");
     request.setHTTPContentType("application/json");
     request.setHTTPBody(report);
-    request.setAllowCookies(frame.document()->securityOrigin()->isSameSchemeHostPort(SecurityOrigin::create(reportURL).ptr()));
+
+    bool removeCookies = true;
+    if (Document* document = frame.document()) {
+        if (SecurityOrigin* securityOrigin = document->securityOrigin()) {
+            if (securityOrigin->isSameSchemeHostPort(SecurityOrigin::create(reportURL).ptr()))
+                removeCookies = false;
+        }
+    }
+    if (removeCookies)
+        request.setAllowCookies(false);
+
     frame.loader().addExtraFieldsToSubresourceRequest(request);
 
     String referrer = SecurityPolicy::generateReferrerHeader(frame.document()->referrerPolicy(), reportURL, frame.loader().outgoingReferrer());