Implement the `require-sri-for` CSP directive

As defined in [1], this CSP directive allows developers to block resource
requests that do not contain integrity metadata. This includes contexts
like external scripts, workers, shared workers, service workers, external
stylesheets, preload requests, and requests originated by CSS @import.

[1]: https://w3c.github.io/webappsec-subresource-integrity/#opt-in-require-sri-for

Intent to implement: https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/jyCdW1dHyYA/YefRSKs1AQAJ

BUG=618924
R=mkwst@chromium.org

Review-Url: https://codereview.chromium.org/2056183002
Cr-Commit-Position: refs/heads/master@{#405530}
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/not-ran.js b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/not-ran.js
new file mode 100644
index 0000000..307112a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/not-ran.js
@@ -0,0 +1 @@
+unexecuted_test.assert_unreached("This code block should not execute.");
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/ran.js b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/ran.js
new file mode 100644
index 0000000..d3af8c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/ran.js
@@ -0,0 +1 @@
+var z = 13;
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-allowed-meta.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-allowed-meta.html
new file mode 100644
index 0000000..f7d03b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-allowed-meta.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+<script>
+	assert_equals(z, 13);
+    executed_test.done();
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-allowed.php
new file mode 100644
index 0000000..f7d03b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-allowed.php
@@ -0,0 +1,13 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+<script>
+	assert_equals(z, 13);
+    executed_test.done();
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-blocked-meta.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-blocked-meta.html
new file mode 100644
index 0000000..c0352581
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-blocked-meta.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/not-ran.js");
+            }));
+    }, "Script without integrity generates reports.");
+
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    var unexecuted_test = async_test("Request to script without integrity is blocked, and generates violation report");
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+<script src="not-ran.js"></script>
+<script>
+    executed_test.done();
+    unexecuted_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-blocked.php
new file mode 100644
index 0000000..c0352581
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-blocked.php
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/not-ran.js");
+            }));
+    }, "Script without integrity generates reports.");
+
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    var unexecuted_test = async_test("Request to script without integrity is blocked, and generates violation report");
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+<script src="not-ran.js"></script>
+<script>
+    executed_test.done();
+    unexecuted_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php
new file mode 100644
index 0000000..1175e59
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php
@@ -0,0 +1,21 @@
+<!doctype html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+// TODO(mkwst) extend the policy when preload supports SRI
+<meta http-equiv="Content-Security-Policy" content="require-sri-for; script-src 'self' 'unsafe-inline'">
+<link rel="preload" href="not-ran.js" as="script">
+</head>
+<script>
+	var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+	document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+   	var t = async_test('Makes sure that require-sri-for applies to preloaded resources.');
+    window.addEventListener("load", t.step_func(function() {
+        var entries = performance.getEntriesByType("resource");
+        assert_equals(entries.length, 4);
+        t.done();
+    }));
+    executed_test.done();
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-blocked.php
new file mode 100644
index 0000000..656ac69
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-blocked.php
@@ -0,0 +1,20 @@
+<!doctype html>
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<link rel="preload" href="not-ran.js" as="script">
+</head>
+<script>
+	var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+	document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+   	var t = async_test('Makes sure that require-sri-for applies to preloaded resources.');
+    window.addEventListener("load", t.step_func(function() {
+        var entries = performance.getEntriesByType("resource");
+        assert_equals(entries.length, 3);
+        t.done();
+    }));
+    executed_test.done();
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-allowed.php
new file mode 100644
index 0000000..cb0f773
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-allowed.php
@@ -0,0 +1,14 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+// TODO(mkwst) switch to report-only header
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+<script>
+	assert_equals(z, 13);
+    executed_test.done();
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-blocked.php
new file mode 100644
index 0000000..450c9fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-blocked.php
@@ -0,0 +1,27 @@
+<?php
+    header("Content-Security-Policy-Report-Only: require-sri-for script; script-src 'self' 'unsafe-inline'");
+?>
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation','securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/resources/testharnessreport.js");
+                return watcher.wait_for('securitypolicyviolation');
+            }))
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/ran.js");
+            }));
+    }, "Script without integrity generates reports.");
+
+    var executed_test = async_test("Script that requires integrity executes and generates a violation report.");
+</script>
+<script src="ran.js"></script>
+<script>
+    assert_equals(z, 13);
+    executed_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-serviceworker-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-serviceworker-blocked.php
new file mode 100644
index 0000000..c51fb1a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-serviceworker-blocked.php
@@ -0,0 +1,12 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test('Test that a service worker can not be registered.');
+   	navigator.serviceWorker.register("resources/service-worker.js").then(function (registration) {
+    }).catch(function (error) {
+        executed_test.done();
+    });
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated"));
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-sharedworker-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-sharedworker-allowed.php
new file mode 100644
index 0000000..de4a15a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-sharedworker-allowed.php
@@ -0,0 +1,15 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test('Test that a sharedworker can be created');
+    try {
+   		var worker = new SharedWorker("/security/contentSecurityPolicy/require-sri-for/sri-sharedworker.js");
+   	} catch(e) {
+   		executed_test.unreached_func("No errors should be thrown.");
+   	}
+   	document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated"));
+	executed_test.done();
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-sharedworker-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-sharedworker-blocked.php
new file mode 100644
index 0000000..9f76d9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-sharedworker-blocked.php
@@ -0,0 +1,13 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+	test(function () {
+    	assert_throws("SecurityError",
+    		function() {
+    			new SharedWorker("http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/sri-sharedworker.js");
+    		},
+        	"The worker creation was blocked");
+	}, "Checks that shared worker creation is blocked");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-allowed.php
new file mode 100644
index 0000000..eea0d0d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-allowed.php
@@ -0,0 +1,16 @@
+<?php
+    header("Content-Security-Policy: require-sri-for style; script-src 'self' 'unsafe-inline'");
+?>
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" crossorigin integrity="sha256-48sSy1L+0pGBMr3XQog56zBcXid1hhmpAwenUuKoe5w=" href="/security/contentSecurityPolicy/resources/style-set-red.css">
+<script>
+    async_test(t => {
+        document.addEventListener('securitypolicyviolation', t.unreached_func("No report should be generated"));
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 1);
+            assert_equals(document.styleSheets[0].href, "http://127.0.0.1:8000/security/contentSecurityPolicy/resources/style-set-red.css");
+        });
+    }, "Stylesheet with integrity loads, and does not trigger reports.");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-blocked.php
new file mode 100644
index 0000000..d616d51
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-blocked.php
@@ -0,0 +1,25 @@
+<?php
+    header("Content-Security-Policy: require-sri-for style;");
+?>
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/resources/style-set-red.css");
+                assert_equals(e.lineNumber, 15);
+            }));
+    }, "Stylesheets without integrity generate reports.");
+</script>
+<link rel="stylesheet" href="/security/contentSecurityPolicy/resources/style-set-red.css">
+<script>
+    async_test(t => {
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 0);
+        });
+    }, "Stylesheets without integrity do not load.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-import-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-import-blocked.php
new file mode 100644
index 0000000..9bbd1a8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-import-blocked.php
@@ -0,0 +1,25 @@
+<?php
+    header("Content-Security-Policy: require-sri-for style;");
+?>
+<!doctype html>
+<style>
+@import url("/security/contentSecurityPolicy/resources/style-set-red.css");
+div {
+    width: 100px;
+    height: 100px;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    
+</script>
+<script>
+    async_test(t => {
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 1);
+            document.body.appendChild(document.createElement("p"));
+            assert_equals(window.getComputedStyle(document.querySelector("p")).color, "rgb(0, 0, 0)");
+        });
+    }, "CSS imports without integrity do not load.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-preload-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-preload-allowed.php
new file mode 100644
index 0000000..ec36e954
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-preload-allowed.php
@@ -0,0 +1,23 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+// extend this when preload supports SRI
+<script>
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+    var t = async_test('Makes sure that require-sri-for applies to preloaded resources.');
+    window.addEventListener("load", t.step_func(function() {
+        var entries = performance.getEntriesByType("resource");
+        assert_equals(entries.length, 3);
+        t.done();
+    }));
+    executed_test.done();
+</script>
+<script>
+    async_test(t => {
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 0);
+        });
+    }, "Stylesheets without integrity do not load.");
+</script>
+<link rel="preload" href="/security/contentSecurityPolicy/resources/style-set-red.css" as="style">
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-preload-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-preload-blocked.php
new file mode 100644
index 0000000..b44365f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-preload-blocked.php
@@ -0,0 +1,25 @@
+<?php
+    header("Content-Security-Policy: require-sri-for style;");
+?>
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+	var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+	document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+  	var t = async_test('Makes sure that require-sri-for applies to preloaded resources.');
+    window.addEventListener("load", t.step_func(function() {
+        var entries = performance.getEntriesByType("resource");
+        assert_equals(entries.length, 2);
+        t.done();
+    }));
+    executed_test.done();
+</script>
+<script>
+    async_test(t => {
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 0);
+        });
+    }, "Stylesheets without integrity do not load.");
+</script>
+<link rel="preload" href="/security/contentSecurityPolicy/resources/style-set-red.css" as="style">
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-reportonly-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-reportonly-allowed.php
new file mode 100644
index 0000000..d4631d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-reportonly-allowed.php
@@ -0,0 +1,28 @@
+<?php
+    header("Content-Security-Policy-Report-Only: require-sri-for style; script-src 'self' 'unsafe-inline'");
+?>
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" crossorigin integrity="sha256-48sSy1L+0pGBMr3XQog56zBcXid1hhmpAwenUuKoe5w=" href="/security/contentSecurityPolicy/resources/style-set-red.css">
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/blue.css");
+                assert_equals(e.lineNumber, 16);
+            }));
+    }, "Stylesheets without integrity generate reports.");
+</script>
+<link rel="stylesheet" href="/security/contentSecurityPolicy/blue.css">
+<script>
+    async_test(t => {
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 2);
+            assert_equals(document.styleSheets[0].href, "http://127.0.0.1:8000/security/contentSecurityPolicy/resources/style-set-red.css");
+            assert_equals(document.styleSheets[1].href, "http://127.0.0.1:8000/security/contentSecurityPolicy/blue.css");
+        });
+    }, "Stylesheet with integrity loads, and does not trigger reports.");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-reportonly-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-reportonly-blocked.php
new file mode 100644
index 0000000..01d8ccb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-style-reportonly-blocked.php
@@ -0,0 +1,26 @@
+<?php
+    header("Content-Security-Policy-Report-Only: require-sri-for style;");
+?>
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/resources/style-set-red.css");
+                assert_equals(e.lineNumber, 15);
+            }));
+    }, "Stylesheets without integrity generate reports.");
+</script>
+<link rel="stylesheet" href="/security/contentSecurityPolicy/resources/style-set-red.css">
+<script>
+    async_test(t => {
+        window.onload = t.step_func_done(_ => {
+            assert_equals(document.styleSheets.length, 1);
+            assert_equals(document.styleSheets[0].href, "http://127.0.0.1:8000/security/contentSecurityPolicy/resources/style-set-red.css");
+        });
+    }, "Stylesheets without integrity do not load.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-svg-script-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-svg-script-blocked.php
new file mode 100644
index 0000000..40732bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-svg-script-blocked.php
@@ -0,0 +1,26 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    async_test(t => {
+        var watcher = new EventWatcher(t, document, ['securitypolicyviolation']);
+        watcher
+            .wait_for('securitypolicyviolation')
+            .then(t.step_func_done(e => {
+                assert_equals(e.blockedURI, "http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/not-ran.js");
+            }));
+    }, "Script without integrity generates reports.");
+
+    var executed_test = async_test("Script that requires integrity executes and does not generate a violation report.");
+    var unexecuted_test = async_test("Request to script without integrity is blocked, and generates violation report");
+</script>
+<script crossorigin integrity="sha384-SOGIJ0vOWzweNE6RLF/TOXGmPzCxF5+dNuBP4x1NgnKsfC4yFCVIDJILalTMwUrp" src="ran.js"></script>
+<svg xmlns="http://www.w3.org/2000/svg">
+<script xlink:href="not-ran.js"></script>
+</svg>
+<script>
+    executed_test.done();
+    unexecuted_test.done();
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-allowed.php
new file mode 100644
index 0000000..006d9d0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-allowed.php
@@ -0,0 +1,15 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+// TODO(mkwst) extend the policy when workers support SRI
+<meta http-equiv="Content-Security-Policy" content="require-sri-for; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test('Test that a worker can be created.');
+    var worker = new Worker("/security/contentSecurityPolicy/require-sri-for/sri-worker.js");
+    
+    worker.onmessage = function(e){
+        assert_equals(e.data, "ping");
+    };
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated"));
+    executed_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-blocked.php
new file mode 100644
index 0000000..b7f4461
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-blocked.php
@@ -0,0 +1,17 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test('Test that a worker can be created, but execution is blocked.');
+    try {
+    	var worker = new Worker("/security/contentSecurityPolicy/require-sri-for/sri-worker.js");
+        worker.onmessage = function(e){
+            executed_test.assert_unreached("This code block should not execute.");
+        };
+    } catch (e) {
+    	assert_equals(e.message, "Failed to construct 'Worker': Access to the script at 'http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/sri-worker.js' is denied by the document's Content Security Policy.");
+    }
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated."));
+    executed_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-fromblob-allowed.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-fromblob-allowed.php
new file mode 100644
index 0000000..22143dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-fromblob-allowed.php
@@ -0,0 +1,15 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+// TODO(mkwst) extend the policy when workers support SRI
+<meta http-equiv="Content-Security-Policy" content="require-sri-for; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test('Test that a worker can be created.');
+    var blob = URL.createObjectURL(new Blob(['importScripts("http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/sri-worker.js")']));
+    var worker = new Worker(blob);
+    worker.onmessage = function(e){
+        assert_equals(e.data, "ping");
+    };
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated"));
+    executed_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-fromblob-blocked.php b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-fromblob-blocked.php
new file mode 100644
index 0000000..d36e1b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-worker-fromblob-blocked.php
@@ -0,0 +1,18 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<meta http-equiv="Content-Security-Policy" content="require-sri-for script; script-src 'self' 'unsafe-inline'">
+<script>
+    var executed_test = async_test('Test that a worker can be created.');
+    var blob = URL.createObjectURL(new Blob(['importScripts("http://127.0.0.1:8000/security/contentSecurityPolicy/require-sri-for/sri-worker.js")']));
+    try {
+    	var worker = new Worker(blob);
+    	worker.onmessage = function(e){
+        	executed_test.assert_unreached("This code block should not execute.");
+    	};
+	} catch (e) {
+		assert_true(e.message.startsWith("Failed to construct 'Worker': Access to the script at 'blob:http://127.0.0.1:8000/"));
+	}
+    document.addEventListener('securitypolicyviolation', executed_test.unreached_func("No report should be generated"));
+    executed_test.done();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/sri-sharedworker.js b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/sri-sharedworker.js
new file mode 100644
index 0000000..5c9a61e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/sri-sharedworker.js
@@ -0,0 +1,5 @@
+onconnect = function(e) {
+  var port = e.ports[0];
+  port.postMessage("shared ping");
+}
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/sri-worker.js b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/sri-worker.js
new file mode 100644
index 0000000..a9070264
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/require-sri-for/sri-worker.js
@@ -0,0 +1 @@
+postMessage("ping");
diff --git a/third_party/WebKit/Source/core/fetch/FetchRequest.h b/third_party/WebKit/Source/core/fetch/FetchRequest.h
index e6632cb..e072017 100644
--- a/third_party/WebKit/Source/core/fetch/FetchRequest.h
+++ b/third_party/WebKit/Source/core/fetch/FetchRequest.h
@@ -96,8 +96,8 @@
     void setCrossOriginAccessControl(SecurityOrigin*, CrossOriginAttributeValue);
     OriginRestriction getOriginRestriction() const { return m_originRestriction; }
     void setOriginRestriction(OriginRestriction restriction) { m_originRestriction = restriction; }
-    const IntegrityMetadataSet& integrityMetadata() const { return m_integrityMetadata; }
-    void setIntegrityMetadata(const IntegrityMetadataSet& metadata) { m_integrityMetadata = metadata; }
+    const IntegrityMetadataSet integrityMetadata() const { return m_options.integrityMetadata; }
+    void setIntegrityMetadata(const IntegrityMetadataSet& metadata) { m_options.integrityMetadata = metadata; }
 
     String contentSecurityPolicyNonce() const { return m_options.contentSecurityPolicyNonce; }
     void setContentSecurityPolicyNonce(const String& nonce) { m_options.contentSecurityPolicyNonce = nonce; }
@@ -114,7 +114,6 @@
     OriginRestriction m_originRestriction;
     ResourceWidth m_resourceWidth;
     ClientHintsPreferences m_clientHintPreferences;
-    IntegrityMetadataSet m_integrityMetadata;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/fetch/ResourceLoaderOptions.h b/third_party/WebKit/Source/core/fetch/ResourceLoaderOptions.h
index 1fb9193..69d180c 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceLoaderOptions.h
+++ b/third_party/WebKit/Source/core/fetch/ResourceLoaderOptions.h
@@ -32,6 +32,7 @@
 #define ResourceLoaderOptions_h
 
 #include "core/fetch/FetchInitiatorInfo.h"
+#include "core/fetch/IntegrityMetadata.h"
 #include "platform/CrossThreadCopier.h"
 #include "platform/weborigin/SecurityOrigin.h"
 #include "wtf/Allocator.h"
@@ -137,6 +138,7 @@
     CORSEnabled corsEnabled; // If the resource is loaded out-of-origin, whether or not to use CORS.
     RefPtr<SecurityOrigin> securityOrigin;
     String contentSecurityPolicyNonce;
+    IntegrityMetadataSet integrityMetadata;
 };
 
 // Encode AtomicString (in FetchInitiatorInfo) as String to cross threads.
@@ -153,6 +155,7 @@
         , corsEnabled(options.corsEnabled)
         , securityOrigin(options.securityOrigin ? options.securityOrigin->isolatedCopy() : nullptr)
         , contentSecurityPolicyNonce(options.contentSecurityPolicyNonce)
+        , integrityMetadata(options.integrityMetadata)
     {
     }
 
@@ -169,6 +172,7 @@
         options.corsEnabled = corsEnabled;
         options.securityOrigin = securityOrigin;
         options.contentSecurityPolicyNonce = contentSecurityPolicyNonce;
+        options.integrityMetadata = integrityMetadata;
         return options;
     }
 
@@ -182,6 +186,7 @@
     CORSEnabled corsEnabled;
     RefPtr<SecurityOrigin> securityOrigin;
     String contentSecurityPolicyNonce;
+    IntegrityMetadataSet integrityMetadata;
 };
 
 template <>
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
index 885ac53..37081e5 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -55,6 +55,7 @@
     , m_strictMixedContentCheckingEnforced(false)
     , m_upgradeInsecureRequests(false)
     , m_treatAsPublicAddress(false)
+    , m_requireSRIFor(RequireSRIForToken::None)
 {
     m_reportOnly = type == ContentSecurityPolicyHeaderTypeReport;
 }
@@ -173,6 +174,63 @@
     return true;
 }
 
+bool CSPDirectiveList::checkRequestWithoutIntegrity(WebURLRequest::RequestContext context) const
+{
+    if (m_requireSRIFor == RequireSRIForToken::None)
+        return true;
+    // SRI specification (https://w3c.github.io/webappsec-subresource-integrity/#apply-algorithm-to-request)
+    // says to match token with request's destination with the token.
+    // Keep this logic aligned with ContentSecurityPolicy::allowRequest
+    if ((m_requireSRIFor & RequireSRIForToken::Script)
+        && (context == WebURLRequest::RequestContextScript
+            || context == WebURLRequest::RequestContextImport
+            || context == WebURLRequest::RequestContextServiceWorker
+            || context == WebURLRequest::RequestContextSharedWorker
+            || context == WebURLRequest::RequestContextWorker)) {
+        return false;
+    }
+    if ((m_requireSRIFor & RequireSRIForToken::Style) && context == WebURLRequest::RequestContextStyle)
+        return false;
+    return true;
+}
+
+bool CSPDirectiveList::checkRequestWithoutIntegrityAndReportViolation(WebURLRequest::RequestContext context, const KURL& url, ResourceRequest::RedirectStatus redirectStatus) const
+{
+    if (checkRequestWithoutIntegrity(context))
+        return true;
+    String resourceType;
+    switch (context) {
+    case WebURLRequest::RequestContextScript:
+    case WebURLRequest::RequestContextImport:
+        resourceType = "script";
+        break;
+    case WebURLRequest::RequestContextStyle:
+        resourceType = "stylesheet";
+        break;
+    case WebURLRequest::RequestContextServiceWorker:
+        resourceType = "service worker";
+        break;
+    case WebURLRequest::RequestContextSharedWorker:
+        resourceType = "shared worker";
+        break;
+    case WebURLRequest::RequestContextWorker:
+        resourceType = "worker";
+        break;
+    default:
+        break;
+    }
+
+    reportViolation(ContentSecurityPolicy::RequireSRIFor, ContentSecurityPolicy::RequireSRIFor, "Refused to load the " + resourceType + " '" + url.elidedString() + "' because 'require-sri-for' directive requires integrity attribute be present for all " + resourceType + "s.", url, redirectStatus);
+    return denyIfEnforcingPolicy();
+}
+
+bool CSPDirectiveList::allowRequestWithoutIntegrity(WebURLRequest::RequestContext context, const KURL& url, ResourceRequest::RedirectStatus redirectStatus, ContentSecurityPolicy::ReportingStatus reportingStatus) const
+{
+    if (reportingStatus == ContentSecurityPolicy::SendReport)
+        return checkRequestWithoutIntegrityAndReportViolation(context, url, redirectStatus);
+    return denyIfEnforcingPolicy() || checkRequestWithoutIntegrity(context);
+}
+
 bool CSPDirectiveList::checkMediaType(MediaListDirective* directive, const String& type, const String& typeAttribute) const
 {
     if (!directive)
@@ -551,6 +609,60 @@
     return true;
 }
 
+void CSPDirectiveList::parseRequireSRIFor(const String& name, const String& value)
+{
+    if (m_requireSRIFor != 0) {
+        m_policy->reportDuplicateDirective(name);
+        return;
+    }
+    StringBuilder tokenErrors;
+    unsigned numberOfTokenErrors = 0;
+    Vector<UChar> characters;
+    value.appendTo(characters);
+
+    const UChar* position = characters.data();
+    const UChar* end = position + characters.size();
+
+    while (position < end) {
+        skipWhile<UChar, isASCIISpace>(position, end);
+
+        const UChar* tokenBegin = position;
+        skipWhile<UChar, isNotASCIISpace>(position, end);
+
+        if (tokenBegin < position) {
+            String token = String(tokenBegin, position - tokenBegin);
+            if (equalIgnoringCase(token, "script")) {
+                m_requireSRIFor |= RequireSRIForToken::Script;
+            } else if (equalIgnoringCase(token, "style")) {
+                m_requireSRIFor |= RequireSRIForToken::Style;
+            } else {
+                if (numberOfTokenErrors)
+                    tokenErrors.append(", \'");
+                else
+                    tokenErrors.append('\'');
+                tokenErrors.append(token);
+                tokenErrors.append('\'');
+                numberOfTokenErrors++;
+            }
+        }
+    }
+
+    if (numberOfTokenErrors == 0)
+        return;
+
+    String invalidTokensErrorMessage;
+    if (numberOfTokenErrors > 1)
+        tokenErrors.append(" are invalid 'require-sri-for' tokens.");
+    else
+        tokenErrors.append(" is an invalid 'require-sri-for' token.");
+
+    invalidTokensErrorMessage = tokenErrors.toString();
+
+    DCHECK(!invalidTokensErrorMessage.isEmpty());
+
+    m_policy->reportInvalidRequireSRIForTokens(invalidTokensErrorMessage);
+}
+
 void CSPDirectiveList::parseReportURI(const String& name, const String& value)
 {
     if (!m_reportEndpoints.isEmpty()) {
@@ -826,6 +938,8 @@
         setCSPDirective<SourceListDirective>(name, value, m_manifestSrc);
     } else if (equalIgnoringCase(name, ContentSecurityPolicy::TreatAsPublicAddress)) {
         treatAsPublicAddress(name, value);
+    } else if (equalIgnoringCase(name, ContentSecurityPolicy::RequireSRIFor) && m_policy->experimentalFeaturesEnabled()) {
+        parseRequireSRIFor(name, value);
     } else {
         m_policy->reportUnsupportedDirective(name);
     }
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
index 3b61111..7720a50 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.h
@@ -65,6 +65,8 @@
     bool allowStyleHash(const CSPHashValue&, ContentSecurityPolicy::InlineType) const;
     bool allowDynamic() const;
 
+    bool allowRequestWithoutIntegrity(WebURLRequest::RequestContext, const KURL&, ResourceRequest::RedirectStatus, ContentSecurityPolicy::ReportingStatus) const;
+
     bool strictMixedContentChecking() const { return m_strictMixedContentCheckingEnforced; }
     void reportMixedContent(const KURL& mixedURL, ResourceRequest::RedirectStatus) const;
 
@@ -74,6 +76,7 @@
     bool didSetReferrerPolicy() const { return m_didSetReferrerPolicy; }
     bool isReportOnly() const { return m_reportOnly; }
     const Vector<String>& reportEndpoints() const { return m_reportEndpoints; }
+    uint8_t requireSRIForTokens() const { return m_requireSRIFor; }
     bool isFrameAncestorsEnforced() const { return m_frameAncestors.get() && !m_reportOnly; }
 
     // Used to copy plugin-types into a plugin document in a nested
@@ -88,9 +91,16 @@
 private:
     FRIEND_TEST_ALL_PREFIXES(CSPDirectiveListTest, IsMatchingNoncePresent);
 
+    enum RequireSRIForToken {
+        None = 0,
+        Script = 1 << 0,
+        Style = 1 << 1
+    };
+
     CSPDirectiveList(ContentSecurityPolicy*, ContentSecurityPolicyHeaderType, ContentSecurityPolicyHeaderSource);
 
     bool parseDirective(const UChar* begin, const UChar* end, String& name, String& value);
+    void parseRequireSRIFor(const String& name, const String& value);
     void parseReportURI(const String& name, const String& value);
     void parsePluginTypes(const String& name, const String& value);
     void parseReflectedXSS(const String& name, const String& value);
@@ -120,6 +130,7 @@
     bool checkSource(SourceListDirective*, const KURL&, ResourceRequest::RedirectStatus) const;
     bool checkMediaType(MediaListDirective*, const String& type, const String& typeAttribute) const;
     bool checkAncestors(SourceListDirective*, LocalFrame*) const;
+    bool checkRequestWithoutIntegrity(WebURLRequest::RequestContext) const;
 
     void setEvalDisabledErrorMessage(const String& errorMessage) { m_evalDisabledErrorMessage = errorMessage; }
 
@@ -129,6 +140,7 @@
     bool checkSourceAndReportViolation(SourceListDirective*, const KURL&, const String& effectiveDirective, ResourceRequest::RedirectStatus) const;
     bool checkMediaTypeAndReportViolation(MediaListDirective*, const String& type, const String& typeAttribute, const String& consoleMessage) const;
     bool checkAncestorsAndReportViolation(SourceListDirective*, LocalFrame*, const KURL&) const;
+    bool checkRequestWithoutIntegrityAndReportViolation(WebURLRequest::RequestContext, const KURL&, ResourceRequest::RedirectStatus) const;
 
     bool denyIfEnforcingPolicy() const { return m_reportOnly; }
 
@@ -166,6 +178,8 @@
     Member<SourceListDirective> m_scriptSrc;
     Member<SourceListDirective> m_styleSrc;
 
+    uint8_t m_requireSRIFor;
+
     Vector<String> m_reportEndpoints;
 
     String m_evalDisabledErrorMessage;
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
index 424b8a5..eb1e62c 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveListTest.cpp
@@ -183,4 +183,81 @@
     }
 }
 
+TEST_F(CSPDirectiveListTest, allowRequestWithoutIntegrity)
+{
+    struct TestCase {
+        const char* list;
+        const char* url;
+        const WebURLRequest::RequestContext context;
+        bool expected;
+    } cases[] = {
+
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+
+        // Extra WSP
+        { "require-sri-for  script     script  ", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for      style    script", "https://example.com/file", WebURLRequest::RequestContextStyle, false },
+
+        { "require-sri-for style script", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for style script", "https://example.com/file", WebURLRequest::RequestContextImport, false },
+        { "require-sri-for style script", "https://example.com/file", WebURLRequest::RequestContextImage, true },
+
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextAudio, true },
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextImport, false },
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextServiceWorker, false },
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextSharedWorker, false },
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextWorker, false },
+        { "require-sri-for script", "https://example.com/file", WebURLRequest::RequestContextStyle, true },
+
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextAudio, true },
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextScript, true },
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextImport, true },
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextServiceWorker, true },
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextSharedWorker, true },
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextWorker, true },
+        { "require-sri-for style", "https://example.com/file", WebURLRequest::RequestContextStyle, false },
+
+        // Multiple tokens
+        { "require-sri-for script style", "https://example.com/file", WebURLRequest::RequestContextStyle, false },
+        { "require-sri-for script style", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for script style", "https://example.com/file", WebURLRequest::RequestContextImport, false },
+        { "require-sri-for script style", "https://example.com/file", WebURLRequest::RequestContextImage, true },
+
+        // Matching is case-insensitive
+        { "require-sri-for Script", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+
+        // Unknown tokens do not affect result
+        { "require-sri-for blabla12 as", "https://example.com/file", WebURLRequest::RequestContextScript, true },
+        { "require-sri-for blabla12 as  script", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for script style img", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for script style img", "https://example.com/file", WebURLRequest::RequestContextImport, false },
+        { "require-sri-for script style img", "https://example.com/file", WebURLRequest::RequestContextStyle, false },
+        { "require-sri-for script style img", "https://example.com/file", WebURLRequest::RequestContextImage, true },
+
+        // Empty token list has no effect
+        { "require-sri-for      ", "https://example.com/file", WebURLRequest::RequestContextScript, true },
+        { "require-sri-for      ", "https://example.com/file", WebURLRequest::RequestContextImport, true },
+        { "require-sri-for      ", "https://example.com/file", WebURLRequest::RequestContextStyle, true },
+        { "require-sri-for      ", "https://example.com/file", WebURLRequest::RequestContextServiceWorker, true },
+        { "require-sri-for      ", "https://example.com/file", WebURLRequest::RequestContextSharedWorker, true },
+        { "require-sri-for      ", "https://example.com/file", WebURLRequest::RequestContextWorker, true },
+
+        // Order does not matter
+        { "require-sri-for a b script", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+        { "require-sri-for a script b", "https://example.com/file", WebURLRequest::RequestContextScript, false },
+    };
+
+    for (const auto& test : cases) {
+        KURL resource = KURL(KURL(), test.url);
+        // Report-only
+        Member<CSPDirectiveList> directiveList = createList(test.list, ContentSecurityPolicyHeaderTypeReport);
+        EXPECT_EQ(true, directiveList->allowRequestWithoutIntegrity(test.context, resource, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+
+        // Enforce
+        directiveList = createList(test.list, ContentSecurityPolicyHeaderTypeEnforce);
+        EXPECT_EQ(test.expected, directiveList->allowRequestWithoutIntegrity(test.context, resource, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    }
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
index e2cc8c7..7c759fd 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.cpp
@@ -31,6 +31,7 @@
 #include "core/dom/Document.h"
 #include "core/dom/SandboxFlags.h"
 #include "core/events/SecurityPolicyViolationEvent.h"
+#include "core/fetch/IntegrityMetadata.h"
 #include "core/frame/FrameClient.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
@@ -104,6 +105,9 @@
 // https://mikewest.github.io/cors-rfc1918/#csp
 const char ContentSecurityPolicy::TreatAsPublicAddress[] = "treat-as-public-address";
 
+// https://w3c.github.io/webappsec-subresource-integrity/#require-sri-for
+const char ContentSecurityPolicy::RequireSRIFor[] = "require-sri-for";
+
 bool ContentSecurityPolicy::isDirectiveName(const String& name)
 {
     return (equalIgnoringCase(name, ConnectSrc)
@@ -127,7 +131,8 @@
         || equalIgnoringCase(name, ManifestSrc)
         || equalIgnoringCase(name, BlockAllMixedContent)
         || equalIgnoringCase(name, UpgradeInsecureRequests)
-        || equalIgnoringCase(name, TreatAsPublicAddress));
+        || equalIgnoringCase(name, TreatAsPublicAddress)
+        || equalIgnoringCase(name, RequireSRIFor));
 }
 
 static UseCounter::Feature getUseCounterType(ContentSecurityPolicyHeaderType type)
@@ -560,8 +565,21 @@
     return checkDigest<&CSPDirectiveList::allowStyleHash>(source, type, m_styleHashAlgorithmsUsed, m_policies);
 }
 
-bool ContentSecurityPolicy::allowRequest(WebURLRequest::RequestContext context, const KURL& url, const String& nonce, RedirectStatus redirectStatus, ReportingStatus reportingStatus) const
+bool ContentSecurityPolicy::allowRequestWithoutIntegrity(WebURLRequest::RequestContext context, const KURL& url, RedirectStatus redirectStatus, ContentSecurityPolicy::ReportingStatus reportingStatus) const
 {
+    for (const auto& policy : m_policies) {
+        if (!policy->allowRequestWithoutIntegrity(context, url, redirectStatus, reportingStatus))
+            return false;
+    }
+    return true;
+}
+
+bool ContentSecurityPolicy::allowRequest(WebURLRequest::RequestContext context, const KURL& url, const String& nonce, const IntegrityMetadataSet& integrityMetadata, RedirectStatus redirectStatus, ReportingStatus reportingStatus) const
+{
+    if (integrityMetadata.isEmpty()
+        && !allowRequestWithoutIntegrity(context, url, redirectStatus, reportingStatus))
+        return false;
+
     switch (context) {
     case WebURLRequest::RequestContextAudio:
     case WebURLRequest::RequestContextTrack:
@@ -588,6 +606,7 @@
         return allowChildFrameFromSource(url, redirectStatus, reportingStatus);
     case WebURLRequest::RequestContextImport:
     case WebURLRequest::RequestContextScript:
+        return allowScriptFromSource(url, nonce, redirectStatus, reportingStatus);
     case WebURLRequest::RequestContextXSLT:
         return allowScriptFromSource(url, nonce, redirectStatus, reportingStatus);
     case WebURLRequest::RequestContextManifest:
@@ -995,6 +1014,11 @@
     logToConsole("The 'reflected-xss' Content Security Policy directive has the invalid value \"" + invalidValue + "\". Valid values are \"allow\", \"filter\", and \"block\".");
 }
 
+void ContentSecurityPolicy::reportInvalidRequireSRIForTokens(const String& invalidTokens)
+{
+    logToConsole("Error while parsing the 'require-sri-for' Content Security Policy directive: " + invalidTokens);
+}
+
 void ContentSecurityPolicy::reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value)
 {
     String message = "The value for Content Security Policy directive '" + directiveName + "' contains an invalid character: '" + value + "'. Non-whitespace characters outside ASCII 0x21-0x7E must be percent-encoded, as described in RFC 3986, section 2.1: http://tools.ietf.org/html/rfc3986#section-2.1.";
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
index 961d790..bc89a13 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicy.h
@@ -106,6 +106,9 @@
     // https://mikewest.github.io/cors-rfc1918/#csp
     static const char TreatAsPublicAddress[];
 
+    // https://w3c.github.io/webappsec-subresource-integrity/#require-sri-for
+    static const char RequireSRIFor[];
+
     enum ReportingStatus {
         SendReport,
         SuppressReport
@@ -206,7 +209,9 @@
     bool allowScriptWithHash(const String& source, InlineType) const;
     bool allowStyleWithHash(const String& source, InlineType) const;
 
-    bool allowRequest(WebURLRequest::RequestContext, const KURL&, const String& nonce, RedirectStatus = RedirectStatus::NoRedirect, ReportingStatus = SendReport) const;
+    bool allowRequestWithoutIntegrity(WebURLRequest::RequestContext, const KURL&, RedirectStatus = RedirectStatus::NoRedirect, ReportingStatus = SendReport) const;
+
+    bool allowRequest(WebURLRequest::RequestContext, const KURL&, const String& nonce, const IntegrityMetadataSet&, RedirectStatus = RedirectStatus::NoRedirect, ReportingStatus = SendReport) const;
 
     void usesScriptHashAlgorithms(uint8_t ContentSecurityPolicyHashAlgorithm);
     void usesStyleHashAlgorithms(uint8_t ContentSecurityPolicyHashAlgorithm);
@@ -229,6 +234,7 @@
     void reportInvalidDirectiveValueCharacter(const String& directiveName, const String& value);
     void reportInvalidPathCharacter(const String& directiveName, const String& value, const char);
     void reportInvalidPluginTypes(const String&);
+    void reportInvalidRequireSRIForTokens(const String&);
     void reportInvalidSandboxFlags(const String&);
     void reportInvalidSourceExpression(const String& directiveName, const String& source);
     void reportInvalidReflectedXSS(const String&);
diff --git a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp
index 1034f8b5c..fdc9c60 100644
--- a/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/ContentSecurityPolicyTest.cpp
@@ -5,9 +5,11 @@
 #include "core/frame/csp/ContentSecurityPolicy.h"
 
 #include "core/dom/Document.h"
+#include "core/fetch/IntegrityMetadata.h"
 #include "core/frame/csp/CSPDirectiveList.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/testing/DummyPageHolder.h"
+#include "platform/Crypto.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/network/ContentSecurityPolicyParsers.h"
 #include "platform/network/ResourceRequest.h"
@@ -108,8 +110,8 @@
 
 TEST_F(ContentSecurityPolicyTest, CopyStateFrom)
 {
-    csp->didReceiveHeader("script-src 'none'; plugin-types application/x-type-1", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
-    csp->didReceiveHeader("img-src http://example.com", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
+    csp->didReceiveHeader("script-src 'none'; plugin-types application/x-type-1", ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
+    csp->didReceiveHeader("img-src http://example.com", ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
 
     KURL exampleUrl(KURL(), "http://example.com");
     KURL notExampleUrl(KURL(), "http://not-example.com");
@@ -230,9 +232,134 @@
     KURL url(KURL(), "https://example.test");
     csp->bindToExecutionContext(document.get());
     csp->didReceiveHeader("object-src 'none';", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceMeta);
-    EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextObject, url, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
-    EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextEmbed, url, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
-    EXPECT_TRUE(csp->allowRequest(WebURLRequest::RequestContextPlugin, url, String(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextObject, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(csp->allowRequest(WebURLRequest::RequestContextEmbed, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(csp->allowRequest(WebURLRequest::RequestContextPlugin, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+}
+
+// Tests that requests for scripts and styles are blocked
+// if `require-sri-for` delivered in HTTP header requires integrity be present
+TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderMissingIntegrity)
+{
+    KURL url(KURL(), "https://example.test");
+    // Enforce
+    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    // Report
+    policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+}
+
+// Tests that requests for scripts and styles are allowed
+// if `require-sri-for` delivered in HTTP header requires integrity be present
+TEST_F(ContentSecurityPolicyTest, RequireSRIForInHeaderPresentIntegrity)
+{
+    KURL url(KURL(), "https://example.test");
+    IntegrityMetadataSet integrityMetadata;
+    integrityMetadata.add(IntegrityMetadata("1234", HashAlgorithmSha384).toPair());
+    csp->bindToExecutionContext(document.get());
+    // Enforce
+    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP);
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    // Content-Security-Policy-Report-Only is not supported in meta element,
+    // so nothing should be blocked
+    policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceHTTP);
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+}
+
+// Tests that requests for scripts and styles are blocked
+// if `require-sri-for` delivered in meta tag requires integrity be present
+TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaMissingIntegrity)
+{
+    KURL url(KURL(), "https://example.test");
+    // Enforce
+    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceMeta);
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_FALSE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    // Content-Security-Policy-Report-Only is not supported in meta element,
+    // so nothing should be blocked
+    policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceMeta);
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), IntegrityMetadataSet(), ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+}
+
+// Tests that requests for scripts and styles are allowed
+// if `require-sri-for` delivered meta tag requires integrity be present
+TEST_F(ContentSecurityPolicyTest, RequireSRIForInMetaPresentIntegrity)
+{
+    KURL url(KURL(), "https://example.test");
+    IntegrityMetadataSet integrityMetadata;
+    integrityMetadata.add(IntegrityMetadata("1234", HashAlgorithmSha384).toPair());
+    csp->bindToExecutionContext(document.get());
+    // Enforce
+    Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceMeta);
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    // Content-Security-Policy-Report-Only is not supported in meta element,
+    // so nothing should be blocked
+    policy = ContentSecurityPolicy::create();
+    policy->bindToExecutionContext(document.get());
+    policy->didReceiveHeader("require-sri-for script style", ContentSecurityPolicyHeaderTypeReport, ContentSecurityPolicyHeaderSourceMeta);
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextScript, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImport, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextStyle, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextServiceWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextSharedWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextWorker, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
+    EXPECT_TRUE(policy->allowRequest(WebURLRequest::RequestContextImage, url, String(), integrityMetadata, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SuppressReport));
 }
 
 TEST_F(ContentSecurityPolicyTest, NonceSinglePolicy)
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
index 1fc1315..52ccb2c 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -688,6 +688,13 @@
             request.setCrossOriginAccessControl(document().getSecurityOrigin(), crossOrigin);
             setFetchFollowingCORS();
         }
+
+        String integrityAttr = m_owner->fastGetAttribute(HTMLNames::integrityAttr);
+        if (!integrityAttr.isEmpty()) {
+            IntegrityMetadataSet metadataSet;
+            SubresourceIntegrity::parseIntegrityAttribute(integrityAttr, metadataSet);
+            request.setIntegrityMetadata(metadataSet);
+        }
         setResource(CSSStyleSheetResource::fetch(request, document().fetcher()));
 
         if (m_loading && !resource()) {
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 5d0b11f..830f1eb 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -546,7 +546,7 @@
 
     if (m_document) {
         DCHECK(m_document->contentSecurityPolicy());
-        if (!shouldBypassMainWorldCSP && !m_document->contentSecurityPolicy()->allowRequest(resourceRequest.requestContext(), url, options.contentSecurityPolicyNonce, redirectStatus, cspReporting))
+        if (!shouldBypassMainWorldCSP && !m_document->contentSecurityPolicy()->allowRequest(resourceRequest.requestContext(), url, options.contentSecurityPolicyNonce, options.integrityMetadata, redirectStatus, cspReporting))
             return ResourceRequestBlockedReasonCSP;
     }
 
diff --git a/third_party/WebKit/Source/core/workers/AbstractWorker.cpp b/third_party/WebKit/Source/core/workers/AbstractWorker.cpp
index 3f669f80..0632b186d 100644
--- a/third_party/WebKit/Source/core/workers/AbstractWorker.cpp
+++ b/third_party/WebKit/Source/core/workers/AbstractWorker.cpp
@@ -47,7 +47,7 @@
 {
 }
 
-KURL AbstractWorker::resolveURL(const String& url, ExceptionState& exceptionState)
+KURL AbstractWorker::resolveURL(const String& url, ExceptionState& exceptionState, WebURLRequest::RequestContext requestContext)
 {
     // FIXME: This should use the dynamic global scope (bug #27887)
     KURL scriptURL = getExecutionContext()->completeURL(url);
@@ -62,7 +62,9 @@
         return KURL();
     }
 
-    if (getExecutionContext()->contentSecurityPolicy() && !getExecutionContext()->contentSecurityPolicy()->allowWorkerContextFromSource(scriptURL)) {
+    if (getExecutionContext()->contentSecurityPolicy()
+        && !(getExecutionContext()->contentSecurityPolicy()->allowRequestWithoutIntegrity(requestContext, scriptURL)
+            && getExecutionContext()->contentSecurityPolicy()->allowWorkerContextFromSource(scriptURL))) {
         exceptionState.throwSecurityError("Access to the script at '" + scriptURL.elidedString() + "' is denied by the document's Content Security Policy.");
         return KURL();
     }
diff --git a/third_party/WebKit/Source/core/workers/AbstractWorker.h b/third_party/WebKit/Source/core/workers/AbstractWorker.h
index 7a3db01..feda32b 100644
--- a/third_party/WebKit/Source/core/workers/AbstractWorker.h
+++ b/third_party/WebKit/Source/core/workers/AbstractWorker.h
@@ -59,7 +59,7 @@
 
 protected:
     // Helper function that converts a URL to an absolute URL and checks the result for validity.
-    KURL resolveURL(const String& url, ExceptionState&);
+    KURL resolveURL(const String& url, ExceptionState&, WebURLRequest::RequestContext);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp
index d5b1f61..0714ccf 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerBase.cpp
@@ -47,7 +47,8 @@
 {
     suspendIfNeeded();
 
-    KURL scriptURL = resolveURL(url, exceptionState);
+    // TODO(mkwst): Revisit the context as https://drafts.css-houdini.org/worklets/ evolves.
+    KURL scriptURL = resolveURL(url, exceptionState, WebURLRequest::RequestContextScript);
     if (scriptURL.isEmpty())
         return false;
 
diff --git a/third_party/WebKit/Source/core/workers/SharedWorker.cpp b/third_party/WebKit/Source/core/workers/SharedWorker.cpp
index d0bca97..7bdb535 100644
--- a/third_party/WebKit/Source/core/workers/SharedWorker.cpp
+++ b/third_party/WebKit/Source/core/workers/SharedWorker.cpp
@@ -76,7 +76,7 @@
         return nullptr;
     }
 
-    KURL scriptURL = worker->resolveURL(url, exceptionState);
+    KURL scriptURL = worker->resolveURL(url, exceptionState, WebURLRequest::RequestContextSharedWorker);
     if (scriptURL.isEmpty())
         return nullptr;
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
index c7a4522..a631d2c 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
@@ -252,7 +252,7 @@
 
     ContentSecurityPolicy* csp = executionContext->contentSecurityPolicy();
     if (csp) {
-        if (!csp->allowWorkerContextFromSource(scriptURL, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SendReport)) {
+        if (!(csp->allowRequestWithoutIntegrity(WebURLRequest::RequestContextServiceWorker, scriptURL) && csp->allowWorkerContextFromSource(scriptURL, ResourceRequest::RedirectStatus::NoRedirect, ContentSecurityPolicy::SendReport))) {
             callbacks->onError(WebServiceWorkerError(WebServiceWorkerError::ErrorTypeSecurity, String("Failed to register a ServiceWorker: The provided scriptURL ('" + scriptURL.getString() + "') violates the Content Security Policy.")));
             return;
         }