Implemented the report-to functionality for webkit-residing csp

The reporting api can now be used to send csp reports
Did not yet implement the content csp version of this change.
spec: https://wicg.github.io/reporting/

Bug: 726634
Change-Id: Icd5cc5699d31d0300e2bcfc6f72b636e855679ea
Reviewed-on: https://chromium-review.googlesource.com/629083
Commit-Queue: Andy Paicu <andypaicu@chromium.org>
Reviewed-by: Julia Tuttle <juliatuttle@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#512107}
diff --git a/content-security-policy/reporting/reporting-api-doesnt-send-reports-without-violation.https.sub.html b/content-security-policy/reporting/reporting-api-doesnt-send-reports-without-violation.https.sub.html
new file mode 100644
index 0000000..cb38428
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-doesnt-send-reports-without-violation.https.sub.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that reports using the report-api service are not sent when there's not validation</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+  <script>
+    var t1 = async_test("Test that image loads");
+    window.addEventListener("securitypolicyviolation",
+         t1.unreached_func("Should not have triggered a violation event"));
+  </script>
+  <img src='/content-security-policy/support/pass.png'
+       onload='t1.done();'
+       onerror='t1.unreached_func("The image should have loaded");'>
+
+  <script async defer src='../support/checkReport.sub.js?reportExists=false'></script>
+</body>
+</html>
diff --git a/content-security-policy/reporting/reporting-api-doesnt-send-reports-without-violation.https.sub.html.sub.headers b/content-security-policy/reporting/reporting-api-doesnt-send-reports-without-violation.https.sub.html.sub.headers
new file mode 100644
index 0000000..9a02581
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-doesnt-send-reports-without-violation.https.sub.html.sub.headers
@@ -0,0 +1,7 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Set-Cookie: reporting-api-doesnt-send-reports-without-violation={{$id:uuid()}}; Path=/content-security-policy/reporting
+Report-To: { "url": "https://{{host}}:{{ports[https][0]}}/content-security-policy/support/report.py?op=put&reportID={{$id}}", "group": "csp-group", "max-age": 10886400 }
+Content-Security-Policy: script-src 'self' 'unsafe-inline'; img-src 'self'; report-to csp-group
diff --git a/content-security-policy/reporting/reporting-api-report-only-sends-reports-on-violation.https.sub.html b/content-security-policy/reporting/reporting-api-report-only-sends-reports-on-violation.https.sub.html
new file mode 100644
index 0000000..6165886
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-report-only-sends-reports-on-violation.https.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that report-only policies still work with report-to</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+  <script>
+    var t1 = async_test("Test that image does not load");
+    async_test(function(t2) {
+    window.addEventListener("securitypolicyviolation", t2.step_func(function(e) {
+        assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/content-security-policy/support/fail.png");
+        assert_equals(e.violatedDirective, "img-src");
+        t2.done();
+      }));
+    }, "Event is fired");
+  </script>
+  <img src='/content-security-policy/support/fail.png'
+       onload='t1.done();'
+       onerror='t1.unreached_func("The image should have loaded");'>
+
+  <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=img-src%20%27none%27'></script>
+</body>
+</html>
diff --git a/content-security-policy/reporting/reporting-api-report-only-sends-reports-on-violation.https.sub.html.sub.headers b/content-security-policy/reporting/reporting-api-report-only-sends-reports-on-violation.https.sub.html.sub.headers
new file mode 100644
index 0000000..990cfaf
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-report-only-sends-reports-on-violation.https.sub.html.sub.headers
@@ -0,0 +1,7 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Set-Cookie: reporting-api-report-only-sends-reports-on-violation={{$id:uuid()}}; Path=/content-security-policy/reporting
+Report-To: { "url": "https://{{host}}:{{ports[https][0]}}/content-security-policy/support/report.py?op=put&reportID={{$id}}", "group": "csp-group", "max-age": 10886400 }
+Content-Security-Policy-Report-Only: script-src 'self' 'unsafe-inline'; img-src 'none'; report-to csp-group
diff --git a/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-1.https.sub.html b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-1.https.sub.html
new file mode 100644
index 0000000..119a027
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-1.https.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that report-to overrides report-uri. This tests report-uri before report-to in the policy</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+  <script>
+    var t1 = async_test("Test that image does not load");
+    async_test(function(t2) {
+    window.addEventListener("securitypolicyviolation", t2.step_func(function(e) {
+        assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/content-security-policy/support/fail.png");
+        assert_equals(e.violatedDirective, "img-src");
+        t2.done();
+      }));
+    }, "Event is fired");
+  </script>
+  <img src='/content-security-policy/support/fail.png'
+       onload='t1.unreached_func("The image should not have loaded");'
+       onerror='t1.done();'>
+  <!-- report-to overrides the report-uri so the report goes to a different endpoint and we should not have any reports sent to this endpoint -->
+  <script async defer src='../support/checkReport.sub.js?reportExists=false></script>
+</body>
+</html>
diff --git a/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-1.https.sub.html.sub.headers b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-1.https.sub.html.sub.headers
new file mode 100644
index 0000000..c696384
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-1.https.sub.html.sub.headers
@@ -0,0 +1,7 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Set-Cookie: reporting-api-report-to-overrides-report-uri-1={{$id:uuid()}}; Path=/content-security-policy/reporting
+Content-Security-Policy: script-src 'self' 'unsafe-inline'; img-src 'none'; report-uri "/content-security-policy/support/report.py?op=put&reportID={{$id}}"; report-to csp-group
+Report-To: { "url": "https://{{host}}:{{ports[https][0]}}/content-security-policy/support/report.py?op=put&reportID={{$id:uuid()}}", "group": "csp-group", "max-age": 10886400 }
diff --git a/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html
new file mode 100644
index 0000000..3c4d244
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that report-to overrides report-uri. This tests report-uri after report-to in the policy</title>  <meta name=timeout content=long>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+  <script>
+    var t1 = async_test("Test that image does not load");
+    async_test(function(t2) {
+    window.addEventListener("securitypolicyviolation", t2.step_func(function(e) {
+        assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/content-security-policy/support/fail.png");
+        assert_equals(e.violatedDirective, "img-src");
+        t2.done();
+      }));
+    }, "Event is fired");
+  </script>
+  <img src='/content-security-policy/support/fail.png'
+       onload='t1.unreached_func("The image should not have loaded");'
+       onerror='t1.done();'>
+  <!-- report-to overrides the report-uri so the report goes to a different endpoint and we should not have any reports sent to this endpoint -->
+  <script async defer src='../support/checkReport.sub.js?reportExists=false></script>
+</body>
+</html>
diff --git a/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html.sub.headers b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html.sub.headers
new file mode 100644
index 0000000..2ac676b
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html.sub.headers
@@ -0,0 +1,7 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Set-Cookie: reporting-api-report-to-overrides-report-uri-2={{$id:uuid()}}; Path=/content-security-policy/reporting
+Content-Security-Policy: script-src 'self' 'unsafe-inline'; img-src 'none'; report-to csp-group; report-uri "/content-security-policy/support/report.py?op=put&reportID={{$id}}"
+Report-To: { "url": "https://{{host}}:{{ports[https][0]}}/content-security-policy/support/report.py?op=put&reportID={{$id:uuid()}}", "group": "csp-group", "max-age": 10886400 }
diff --git a/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html b/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html
new file mode 100644
index 0000000..b2c3ada
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that reports using the report-api service are sent when there's a violation</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+  <script>
+    var t1 = async_test("Test that image does not load");
+    async_test(function(t2) {
+    window.addEventListener("securitypolicyviolation", t2.step_func(function(e) {
+        assert_equals(e.blockedURI, "{{location[scheme]}}://{{location[host]}}/content-security-policy/support/fail.png");
+        assert_equals(e.violatedDirective, "img-src");
+        t2.done();
+      }));
+    }, "Event is fired");
+  </script>
+  <img src='/content-security-policy/support/fail.png'
+       onload='t1.unreached_func("The image should not have loaded");'
+       onerror='t1.done();'>
+
+  <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=img-src%20%27none%27'></script>
+</body>
+</html>
diff --git a/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html.sub.headers b/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html.sub.headers
new file mode 100644
index 0000000..ff4b9e6
--- /dev/null
+++ b/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html.sub.headers
@@ -0,0 +1,7 @@
+Expires: Mon, 26 Jul 1997 05:00:00 GMT
+Cache-Control: no-store, no-cache, must-revalidate
+Cache-Control: post-check=0, pre-check=0, false
+Pragma: no-cache
+Set-Cookie: reporting-api-sends-reports-on-violation={{$id:uuid()}}; Path=/content-security-policy/reporting
+Report-To: { "url": "https://{{host}}:{{ports[https][0]}}/content-security-policy/support/report.py?op=put&reportID={{$id}}", "group": "csp-group", "max-age": 10886400 }
+Content-Security-Policy: script-src 'self' 'unsafe-inline'; img-src 'none'; report-to csp-group
diff --git a/content-security-policy/reporting/securitypolicyviolation-idl.html b/content-security-policy/reporting/securitypolicyviolation-idl.html
index 2259512..237807c 100644
--- a/content-security-policy/reporting/securitypolicyviolation-idl.html
+++ b/content-security-policy/reporting/securitypolicyviolation-idl.html
@@ -38,6 +38,55 @@
     long           lineNumber;
     long           columnNumber;
 };
+
+[
+    Constructor(DOMString type, optional EventInit eventInitDict),
+    Exposed=(Window,Worker)
+] interface Event {
+    readonly attribute DOMString type;
+    readonly attribute EventTarget? target;
+    readonly attribute EventTarget? currentTarget;
+    [MeasureAs=EventComposedPath, CallWith=ScriptState] sequence<EventTarget> composedPath();
+
+    const unsigned short NONE = 0;
+    const unsigned short CAPTURING_PHASE = 1;
+    const unsigned short AT_TARGET = 2;
+    const unsigned short BUBBLING_PHASE = 3;
+    readonly attribute unsigned short eventPhase;
+
+    [Measure] void stopPropagation();
+    [Measure] void stopImmediatePropagation();
+
+    readonly attribute boolean bubbles;
+    readonly attribute boolean cancelable;
+    void preventDefault();
+    readonly attribute boolean defaultPrevented;
+
+    [MeasureAs=EventComposed] readonly attribute boolean composed;
+
+    [Unforgeable] readonly attribute boolean isTrusted;
+
+    [CallWith=ScriptState] readonly attribute DOMHighResTimeStamp timeStamp;
+
+    [Measure] void initEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false);
+
+    // Non-standard APIs
+    [MeasureAs=EventSrcElement] readonly attribute EventTarget srcElement;
+    [MeasureAs=EventReturnValue, CallWith=ScriptState, ImplementedAs=legacyReturnValue] attribute boolean returnValue;
+    [MeasureAs=EventCancelBubble, CallWith=ScriptState] attribute boolean cancelBubble;
+    [MeasureAs=EventPath, CallWith=ScriptState] readonly attribute EventTarget[] path;
+};
+
+[
+    CheckSecurity=Receiver,
+    Exposed=(Window,Worker),
+    ImmutablePrototype
+] interface EventTarget {
+    [Custom=(CallPrologue,CallEpilogue)] void addEventListener(DOMString type, EventListener? listener, optional (AddEventListenerOptions or boolean) options);
+    [Custom=(CallPrologue,CallEpilogue)] void removeEventListener(DOMString type, EventListener? listener, optional (EventListenerOptions or boolean) options);
+    [ImplementedAs=dispatchEventForBindings, RaisesException] boolean dispatchEvent(Event event);
+};
+
 </script>
 <script>
     (function() {
diff --git a/content-security-policy/support/checkReport.sub.js b/content-security-policy/support/checkReport.sub.js
index 803dc06..ba179d6 100644
--- a/content-security-policy/support/checkReport.sub.js
+++ b/content-security-policy/support/checkReport.sub.js
@@ -36,6 +36,13 @@
   var reportLocation = location.protocol + "//" + location.host + "/content-security-policy/support/report.py?op=take&timeout=" + timeout + "&reportID=" + reportID;
 
   var reportTest = async_test("Violation report status OK.");
+
+  function assert_field_value(field, value, field_name) {
+    assert_true(field.indexOf(value.split(" ")[0]) != -1,
+                field_name + " value of  \"" + field + "\" did not match " +
+                value.split(" ")[0] + ".");
+  }
+
   reportTest.step(function () {
 
     var report = new XMLHttpRequest();
@@ -55,9 +62,11 @@
           // is reported, not the details...
 
           if(data["csp-report"] != undefined && data["csp-report"][reportField] != undefined) {
-            assert_true(data["csp-report"][reportField].indexOf(reportValue.split(" ")[0]) != -1,
-                reportField + " value of  \"" + data["csp-report"][reportField] + "\" did not match " +
-                reportValue.split(" ")[0] + ".");
+            assert_field_value(data["csp-report"][reportField], reportValue, reportField);
+          } else if (data[0] != undefined && data[0]["report"] != undefined && data[0]["report"][reportField] != undefined) {
+            assert_field_value(data[0]["report"][reportField], reportValue, reportField);
+          } else {
+            assert_equals("", reportField, "Expected report field could not be found in report");
           }
         }