summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fetch/corb
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/fetch/corb')
-rw-r--r--testing/web-platform/tests/fetch/corb/README.md67
-rw-r--r--testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html4
-rw-r--r--testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html11
-rw-r--r--testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html85
-rw-r--r--testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html4
-rw-r--r--testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html11
-rw-r--r--testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html4
-rw-r--r--testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html10
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html7
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html11
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html5
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html6
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html6
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html6
-rw-r--r--testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html5
-rw-r--r--testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html24
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers2
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css3
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png0
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html10
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js9
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js10
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers2
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.pngbin0 -> 1010 bytes
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.pngbin0 -> 1010 bytes
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers2
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.pngbin0 -> 1010 bytes
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/response_block_probe.js1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py11
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html16
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg4
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg4
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg3
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg3
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg4
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg.svg3
-rw-r--r--testing/web-platform/tests/fetch/corb/resources/svg.svg.headers1
-rw-r--r--testing/web-platform/tests/fetch/corb/response_block.tentative.https.html50
-rw-r--r--testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html32
-rw-r--r--testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html32
-rw-r--r--testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html38
-rw-r--r--testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html33
-rw-r--r--testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html25
-rw-r--r--testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html85
-rw-r--r--testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html84
-rw-r--r--testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html42
-rw-r--r--testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html36
-rw-r--r--testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html38
-rw-r--r--testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html41
66 files changed, 907 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/corb/README.md b/testing/web-platform/tests/fetch/corb/README.md
new file mode 100644
index 0000000000..f29562b060
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/README.md
@@ -0,0 +1,67 @@
+# Tests related to Cross-Origin Resource Blocking (CORB).
+
+### Summary
+
+This directory contains tests related to the
+[Cross-Origin Resource Blocking (CORB)](https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md)
+algorithm.
+
+The tests in this directory interact with various, random features,
+but the tests have been grouped together into the `fetch/corb` directory,
+because all of these tests verify behavior that is important to the CORB
+algorithm.
+
+
+### CORB is not universally implemented yet
+
+CORB has been included
+in the [Fetch spec](https://fetch.spec.whatwg.org/#corb)
+since [May 2018](https://github.com/whatwg/fetch/pull/686).
+
+Some tests in this directory (e.g.
+`css-with-json-parser-breaker`) cover behavior spec-ed outside of CORB (making
+sure that CORB doesn't change the existing web behavior) and therefore are
+valuable independently from CORB's standardization efforts and should already
+be passing across all browsers.
+
+Tests that cover behavior that is changed by CORB are currently marked as
+[tentative](https://web-platform-tests.org/writing-tests/file-names.html)
+(using `.tentative` substring in their filename).
+Such tests may fail unless CORB is enabled. In practice this means that:
+* Such tests will pass in Chromium
+ (where CORB is enabled by default [since M68](https://crrev.com/553830)).
+* Such tests may fail in other browsers.
+
+
+### Limitations of WPT test coverage
+
+CORB is a defense-in-depth and in general should not cause changes in behavior
+that can be observed by web features or by end users. This makes CORB difficult
+or even impossible to test via WPT.
+
+WPT tests can cover the following:
+
+* Helping verify CORB has no observable impact in specific scenarios.
+ Examples:
+ * image rendering of (an empty response of) a html document blocked by CORB
+ should be indistinguishable from rendering such html document without CORB -
+ `img-html-correctly-labeled.sub.html`
+ * CORB shouldn't block responses that don't sniff as a CORB-protected document
+ type - `img-png-mislabeled-as-html.sub.html`
+* Helping document cases where CORB causes observable changes in behavior.
+ Examples:
+ * blocking of nosniff images labeled as non-image, CORB-protected
+ Content-Type - `img-png-mislabeled-as-html-nosniff.tentative.sub.html`
+ * blocking of CORB-protected documents can prevent triggering
+ syntax errors in scripts -
+ `script-html-via-cross-origin-blob-url.tentative.sub.html`
+* Helping verify which MIME types are protected by CORB.
+
+Examples of aspects that WPT tests cannot cover (these aspects have to be
+covered in other, browser-specific tests):
+* Verifying that CORB doesn't affect things that are only indirectly
+ observable by the web (like
+ [prefetch](https://html.spec.whatwg.org/#link-type-prefetch).
+* Verifying that CORB strips headers of blocked responses.
+* Verifying that CORB blocks responses before they reach the process hosting
+ a cross-origin execution context.
diff --git a/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html
new file mode 100644
index 0000000000..0e75596952
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<!-- Same-origin, so the HTTP response is not CORB-eligible -->
+<img src="resources/html-correctly-labeled.html">
diff --git a/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html
new file mode 100644
index 0000000000..844cd0c927
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-html-correctly-labeled.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- Test verifies that html fed to an <img> tag doesn't have any observable
+ difference with and without CORB (in both cases the resource body cannot be
+ rendered as an image - html cannot be rendered as an image and the empty body
+ from a CORB-blocked response also cannot be rendered as an image).
+-->
+<meta charset="utf-8">
+<!-- Reference page uses same-origin resources, which are not CORB-eligible. -->
+<link rel="match" href="img-html-correctly-labeled.sub-ref.html">
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html">
diff --git a/testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html b/testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html
new file mode 100644
index 0000000000..e2386de2f2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-mime-types-coverage.tentative.sub.html
@@ -0,0 +1,85 @@
+<!-- Test verifies that cross-origin, nosniff images are 1) blocked when their
+ MIME type is covered by CORB and 2) allowed otherwise.
+
+ This test is very similar to fetch/nosniff/images.html, except that
+ 1) it deals with cross-origin images (CORB ignores same-origin fetches),
+ 2) it focuses on MIME types relevant to CORB.
+ There are opportunities to unify the test here with nosniff tests *if*
+ we can also start blocking same-origin (or cors-allowed) images. We
+ should try to gather data to quantify the impact of such change.
+-->
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+ var passes = [
+ // Empty or non-sensical MIME types
+ null, "", "x", "x/x",
+
+ // MIME-types not protected by CORB
+ "image/gif", "image/png", "image/png;blah", "image/svg+xml",
+ "application/javascript", "application/jsonp",
+ "application/dash+xml", // video format
+ "image/gif;HI=THERE",
+
+ // Non-image MIME-types that in practice get used for images on the web.
+ //
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1302539
+ "application/octet-stream",
+ // https://crbug.com/990853
+ "application/x-www-form-urlencoded",
+
+ // MIME types that may seem to be JSON or XML, but really aren't - i.e.
+ // these MIME types are not covered by:
+ // - https://mimesniff.spec.whatwg.org/#json-mime-type
+ // - https://mimesniff.spec.whatwg.org/#xml-mime-type
+ // - https://tools.ietf.org/html/rfc6839
+ // - https://tools.ietf.org/html/rfc7303
+ "text/x-json", "text/json+blah", "application/json+blah",
+ "text/xml+blah", "application/xml+blah",
+ "application/blahjson", "text/blahxml"]
+
+ var fails = [
+ // CORB-protected MIME-types - i.e. ones covered by:
+ // - https://mimesniff.spec.whatwg.org/#html-mime-type
+ // - https://mimesniff.spec.whatwg.org/#json-mime-type
+ // - https://mimesniff.spec.whatwg.org/#xml-mime-type
+ "text/html",
+ "text/json", "application/json", "text/xml", "application/xml",
+ "application/blah+json", "text/blah+json",
+ "application/blah+xml", "text/blah+xml",
+ "TEXT/HTML", "TEXT/JSON", "TEXT/BLAH+JSON", "APPLICATION/BLAH+XML",
+ "text/json;does=it;matter", "text/HTML;NO=it;does=NOT"]
+
+ const get_url = (mime) => {
+ // www1 is cross-origin, so the HTTP response is CORB-eligible -->
+ url = "http://{{domains[www1]}}:{{ports[http][0]}}"
+ url = url + "/fetch/nosniff/resources/image.py"
+ if (mime != null) {
+ url += "?type=" + encodeURIComponent(mime)
+ }
+ return url
+ }
+
+ passes.forEach(function(mime) {
+ async_test(function(t) {
+ var img = document.createElement("img")
+ img.onerror = t.unreached_func("Unexpected error event")
+ img.onload = t.step_func_done(function(){
+ assert_equals(img.width, 96)
+ })
+ img.src = get_url(mime)
+ document.body.appendChild(img)
+ }, "CORB should allow the response if Content-Type is: '" + mime + "'. ")
+ })
+
+ fails.forEach(function(mime) {
+ async_test(function(t) {
+ var img = document.createElement("img")
+ img.onerror = t.step_func_done()
+ img.onload = t.unreached_func("Unexpected load event")
+ img.src = get_url(mime)
+ document.body.appendChild(img)
+ }, "CORB should block the response if Content-Type is: '" + mime + "'. ")
+ })
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html
new file mode 100644
index 0000000000..a771ed6a65
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<!-- Same-origin, so the HTTP response is not CORB-eligible -->
+<img src="resources/empty-labeled-as-png.png">
diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html
new file mode 100644
index 0000000000..82adc47b0c
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- Test verifies that CORB blocks an image mislabeled as text/html if
+ sniffing is disabled via `X-Content-Type-Options: nosniff` response header.
+ This has an observable effect (the image stops rendering), compared to the
+ behavior with no CORB.
+-->
+<meta charset="utf-8">
+<!-- Reference page uses same-origin resources, which are not CORB-eligible. -->
+<link rel="match" href="img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html">
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png">
diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html
new file mode 100644
index 0000000000..ebb337dba8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<!-- Same-origin, so the HTTP response is not CORB-eligible -->
+<img src="resources/png-correctly-labeled.png">
diff --git a/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html
new file mode 100644
index 0000000000..1ae4cfcaa7
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-png-mislabeled-as-html.sub.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<!-- Test verifies that CORB won't block an image after sniffing determines
+ that the text/html Content-Type response header doesn't match the response
+ body.
+-->
+<meta charset="utf-8">
+<!-- Reference page uses same-origin resources, which are not CORB-eligible. -->
+<link rel="match" href="img-png-mislabeled-as-html.sub-ref.html">
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html.png">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html
new file mode 100644
index 0000000000..3219feda17
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-empty.sub.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<!-- Verifies CORB/ORB SVG image blocking.
+ This image has no MIME type and an html DOCTYPE declaration and is
+ expected to be blocked-->
+<meta charset="utf-8">
+<link rel="match" href="img-svg-invalid.sub-ref.html">
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html
new file mode 100644
index 0000000000..efcfaa2737
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg-doctype-html-mimetype-svg.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- Verifies CORB/ORB SVG image blocking.
+ This image has an SVG MIME type and an html DOCTYPE declaration and is
+ expected to load.
+
+ This testcase is distilled from a bugreport and real web page. See:
+ https://crbug.com/1359788
+-->
+<meta charset="utf-8">
+<link rel="match" href="img-svg.sub-ref.html">
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html
new file mode 100644
index 0000000000..484cd0a4fd
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg-invalid.sub-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<!-- Same-origin, but invalid URL.
+ Serves as reference for tests that expect the image to be blocked. -->
+<img src="resources/invalid.svg">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html
new file mode 100644
index 0000000000..0578b835fe
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-dash.sub.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<!-- Verifies CORB/ORB SVG image blocking.
+ This image is served with a DASH MIME type, and is expected to be blocked. -->
+<meta charset="utf-8">
+<link rel="match" href="img-svg-invalid.sub-ref.html">
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-labeled-as-dash.svg">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html
new file mode 100644
index 0000000000..30a2eb3246
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg-labeled-as-svg-xml.sub.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<!-- Verifies CORB/ORB SVG image blocking.
+ This image is served with a proper SVG MIME type and is expected to load. -->
+<meta charset="utf-8">
+<link rel="match" href="img-svg.sub-ref.html">
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-labeled-as-svg-xml.svg">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html b/testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html
new file mode 100644
index 0000000000..0d3aeafb25
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg-xml-decl.sub.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<!-- Verifies CORB/ORB SVG image blocking.
+ This image has an XML declaration and is expected to load. -->
+<meta charset="utf-8">
+<link rel="match" href="img-svg.sub-ref.html">
+<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/svg-xml-decl.svg">
diff --git a/testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html b/testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html
new file mode 100644
index 0000000000..5462f685a0
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/img-svg.sub-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<!-- Same-origin, so the HTTP response is not CORB-eligible.
+ Serves as reference for cases the image is expected to be loaded. -->
+<img src="resources/svg.svg">
diff --git a/testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html b/testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html
new file mode 100644
index 0000000000..cea80f2f89
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!-- This test verifies observable CORB impact on <link rel="preload"> elements.
+-->
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<script>
+async_test(function(t) {
+ // With CORB the link.onerror event will be reached
+ // (because CORB will block the cross-origin preload).
+ window.preloadErrorEvent = t.step_func_done();
+
+ // Without CORB the link.onload event will be reached.
+ window.preloadLoadEvent = t.unreached_func("link/preload onload event reached.");
+});
+</script>
+
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<link rel="preload" as="image"
+ onerror="window.preloadErrorEvent()"
+ onload="window.preloadLoadEvent()"
+ href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png">
diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css
new file mode 100644
index 0000000000..afd2b92975
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css
@@ -0,0 +1 @@
+#header { color: red; }
diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers
new file mode 100644
index 0000000000..0f228f94ec
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html-nosniff.css.headers
@@ -0,0 +1,2 @@
+Content-Type: text/html
+X-Content-Type-Options: nosniff
diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css
new file mode 100644
index 0000000000..afd2b92975
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css
@@ -0,0 +1 @@
+#header { color: red; }
diff --git a/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers
new file mode 100644
index 0000000000..156209f9c8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/css-mislabeled-as-html.css.headers
@@ -0,0 +1 @@
+Content-Type: text/html
diff --git a/testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css b/testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css
new file mode 100644
index 0000000000..7db6f5c6d3
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/css-with-json-parser-breaker.css
@@ -0,0 +1,3 @@
+)]}'
+{}
+#header { color: red; }
diff --git a/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png
diff --git a/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers
new file mode 100644
index 0000000000..e7be84a714
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/empty-labeled-as-png.png.headers
@@ -0,0 +1 @@
+Content-Type: image/png
diff --git a/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html
new file mode 100644
index 0000000000..7bad71bfbd
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Page Title</title>
+ </head>
+ <body>
+ <p>Page body</p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers
new file mode 100644
index 0000000000..156209f9c8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/html-correctly-labeled.html.headers
@@ -0,0 +1 @@
+Content-Type: text/html
diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js
new file mode 100644
index 0000000000..db45bb4acc
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js
@@ -0,0 +1,9 @@
+<!--/*--><html><body><script type="text/javascript"><!--//*/
+
+// This is a regression test for https://crbug.com/839425
+// which found out that some script resources are served
+// with text/html content-type and with a body that is
+// both a valid html and a valid javascript.
+window['html-js-polyglot.js'] = true;
+
+//--></script></body></html>
diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers
new file mode 100644
index 0000000000..156209f9c8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot.js.headers
@@ -0,0 +1 @@
+Content-Type: text/html
diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js
new file mode 100644
index 0000000000..faae1b7682
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js
@@ -0,0 +1,10 @@
+<!-- comment --> <script type='text/javascript'>
+//<![CDATA[
+
+// This is a regression test for https://crbug.com/839945
+// which found out that some script resources are served
+// with text/html content-type and with a body that is
+// both a valid html and a valid javascript.
+window['html-js-polyglot2.js'] = true;
+
+//]]>--></script>
diff --git a/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers
new file mode 100644
index 0000000000..156209f9c8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/html-js-polyglot2.js.headers
@@ -0,0 +1 @@
+Content-Type: text/html
diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js
new file mode 100644
index 0000000000..a880a5bc72
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js
@@ -0,0 +1 @@
+window.has_executed_script = true;
diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers
new file mode 100644
index 0000000000..0f228f94ec
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html-nosniff.js.headers
@@ -0,0 +1,2 @@
+Content-Type: text/html
+X-Content-Type-Options: nosniff
diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js
new file mode 100644
index 0000000000..a880a5bc72
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js
@@ -0,0 +1 @@
+window.has_executed_script = true;
diff --git a/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers
new file mode 100644
index 0000000000..156209f9c8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/js-mislabeled-as-html.js.headers
@@ -0,0 +1 @@
+Content-Type: text/html
diff --git a/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png
new file mode 100644
index 0000000000..820f8cace2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png
Binary files differ
diff --git a/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers
new file mode 100644
index 0000000000..e7be84a714
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/png-correctly-labeled.png.headers
@@ -0,0 +1 @@
+Content-Type: image/png
diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png
new file mode 100644
index 0000000000..820f8cace2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png
Binary files differ
diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers
new file mode 100644
index 0000000000..0f228f94ec
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html-nosniff.png.headers
@@ -0,0 +1,2 @@
+Content-Type: text/html
+X-Content-Type-Options: nosniff
diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png
new file mode 100644
index 0000000000..820f8cace2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png
Binary files differ
diff --git a/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers
new file mode 100644
index 0000000000..156209f9c8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/png-mislabeled-as-html.png.headers
@@ -0,0 +1 @@
+Content-Type: text/html
diff --git a/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js
new file mode 100644
index 0000000000..9c3b87bcbd
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js
@@ -0,0 +1 @@
+alert(1); // Arbitrary JavaScript. Details don't matter for the test.
diff --git a/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers
new file mode 100644
index 0000000000..0d848b02c2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/response_block_probe.js.headers
@@ -0,0 +1 @@
+Content-Type: text/csv
diff --git a/testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py b/testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py
new file mode 100644
index 0000000000..f8150936ac
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/sniffable-resource.py
@@ -0,0 +1,11 @@
+def main(request, response):
+ body = request.GET.first(b"body", None)
+ type = request.GET.first(b"type", None)
+
+ response.add_required_headers = False
+ response.writer.write_status(200)
+ response.writer.write_header(b"content-length", len(body))
+ response.writer.write_header(b"content-type", type)
+ response.writer.end_headers()
+
+ response.writer.write(body)
diff --git a/testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html b/testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html
new file mode 100644
index 0000000000..67b3ad5a60
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+fetch('html-correctly-labeled.html')
+ .then(response => response.blob())
+ .then(blob => {
+ let msg = { blob_size: blob.size,
+ blob_type: blob.type,
+ blob_url: URL.createObjectURL(blob) };
+ window.parent.postMessage(msg, '*');
+ })
+ .catch(error => {
+ let msg = { error: error };
+ window.parent.postMessage(msg, '*');
+ });
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg
new file mode 100644
index 0000000000..fa2d29b3b0
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img">
+<rect width="100" height="100" style="fill:rgb(255,0,0)"/>
+</svg>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers
new file mode 100644
index 0000000000..29515ee7d4
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-empty.svg.headers
@@ -0,0 +1 @@
+Content-Type:
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg
new file mode 100644
index 0000000000..fa2d29b3b0
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img">
+<rect width="100" height="100" style="fill:rgb(255,0,0)"/>
+</svg>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers
new file mode 100644
index 0000000000..070de35fbe
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-doctype-html-mimetype-svg.svg.headers
@@ -0,0 +1 @@
+Content-Type: image/svg+xml
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg
new file mode 100644
index 0000000000..2b7d1016b1
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg
@@ -0,0 +1,3 @@
+<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img">
+<rect width="100" height="100" style="fill:rgb(255,0,0)"/>
+</svg>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers
new file mode 100644
index 0000000000..43ce612c9f
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-dash.svg.headers
@@ -0,0 +1 @@
+Content-Type: application/dash+xml
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg
new file mode 100644
index 0000000000..2b7d1016b1
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg
@@ -0,0 +1,3 @@
+<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img">
+<rect width="100" height="100" style="fill:rgb(255,0,0)"/>
+</svg>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers
new file mode 100644
index 0000000000..070de35fbe
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-labeled-as-svg-xml.svg.headers
@@ -0,0 +1 @@
+Content-Type: image/svg+xml
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg b/testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg
new file mode 100644
index 0000000000..3b39aff8e5
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg-xml-decl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img">
+<rect width="100" height="100" style="fill:rgb(255,0,0)"/>
+</svg>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg.svg b/testing/web-platform/tests/fetch/corb/resources/svg.svg
new file mode 100644
index 0000000000..2b7d1016b1
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg.svg
@@ -0,0 +1,3 @@
+<svg width="920" height="625" xmlns="http://www.w3.org/2000/svg" role="img">
+<rect width="100" height="100" style="fill:rgb(255,0,0)"/>
+</svg>
diff --git a/testing/web-platform/tests/fetch/corb/resources/svg.svg.headers b/testing/web-platform/tests/fetch/corb/resources/svg.svg.headers
new file mode 100644
index 0000000000..070de35fbe
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/resources/svg.svg.headers
@@ -0,0 +1 @@
+Content-Type: image/svg+xml
diff --git a/testing/web-platform/tests/fetch/corb/response_block.tentative.https.html b/testing/web-platform/tests/fetch/corb/response_block.tentative.https.html
new file mode 100644
index 0000000000..6b116000d4
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/response_block.tentative.https.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+<script>
+// A cross-origin response containing JavaScript, labelled as text/csv.
+const probeUrl = get_host_info().HTTPS_REMOTE_ORIGIN +
+ "/fetch/corb/resources/response_block_probe.js";
+
+// Test handling of blocked responses in CORB/ORB for <script> elements.
+function probe_script() {
+ // We will cross-origin load a script resource that should get blocked by all
+ // versions of CORB/ORB. Two things may happen:
+ //
+ // 1, An empty response is injected. (What CORB does.)
+ // 2, An error is injected and script loading aborts. (What ORB does.)
+
+ // Load the probe as a script.
+ const script = document.createElement("script");
+ script.src = probeUrl;
+ document.body.appendChild(script);
+
+ // Return a promise that will return a string description corresponding to the
+ // conditions above.
+ return new Promise((resolve, reject) => {
+ script.onload = _ => resolve("Resource loaded (expected for CORB)");
+ script.onerror = _ => resolve("ORB-style network error");
+ });
+}
+
+// Test handling of blocked responses in CORB/ORB for script-initiated fetches.
+function probe_fetch() {
+ return fetch(probeUrl, {mode: "no-cors"})
+ .then(response => response.text())
+ .then(text => {
+ assert_equals(text, "");
+ return "Resource loaded (expected for CORB)";
+ })
+ .catch(_ => "ORB-style network error");
+}
+
+// These tests check for ORB behaviour.
+promise_test(t => probe_script().then(
+ value => assert_equals(value, "ORB-style network error")),
+ "ORB: Expect error response from <script> fetch.");
+promise_test(t => probe_fetch().then(
+ value => assert_equals(value, "ORB-style network error")),
+ "ORB: Expect error response from fetch().");
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html b/testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html
new file mode 100644
index 0000000000..6d1947cea7
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-html-correctly-labeled.tentative.sub.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- Test verifies that html fed to a <script> tag won't report a syntax
+ error after CORB blocks the response (an empty response body injected
+ by CORB won't have any JavaScript syntax errors).
+-->
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception : true});
+async_test(function(t) {
+ var script = document.createElement("script")
+
+ // Without CORB, the html document would cause a syntax error when parsed as
+ // JavaScript, but with CORB there should be no errors (because CORB will
+ // replace the response body with an empty body). With ORB, the script loading
+ // itself will error out.
+ script.onload = t.step_func_done();
+ script.onerror = t.step_func_done();
+ addEventListener("error",function(e) {
+ t.step(function() {
+ assert_unreached("Empty body of a CORB-blocked response shouldn't trigger syntax errors.");
+ t.done();
+ })
+ });
+
+ // www1 is cross-origin, so the HTTP response is CORB-eligible.
+ script.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html';
+ document.body.appendChild(script)
+}, "CORB-blocked script has no syntax errors");
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html b/testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html
new file mode 100644
index 0000000000..9a272d63ff
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-html-js-polyglot.sub.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!-- Test verifies that CORB won't block a polyglot script that is
+ both a valid HTML document and also valid Javascript.
+-->
+<meta charset="utf-8">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+["html-js-polyglot.js", "html-js-polyglot2.js"].forEach(polyglot_name => {
+ async_test(function(t) {
+ window[polyglot_name] = false;
+ var script = document.createElement("script");
+
+ script.onload = t.step_func_done(function(){
+ // Verify that the script response wasn't blocked - that script
+ // should have set window[polyglot_name] to true.
+ assert_true(window[polyglot_name]);
+ })
+ addEventListener("error",function(e) {
+ t.step(function() {
+ assert_unreached("No errors are expected with or without CORB.");
+ t.done();
+ })
+ });
+
+ // www1 is cross-origin, so the HTTP response is CORB-eligible.
+ script.src = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/" + polyglot_name;
+ document.body.appendChild(script);
+ }, "CORB cannot block polyglot HTML/JS: " + polyglot_name);
+});
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html b/testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html
new file mode 100644
index 0000000000..c8a90c79b3
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-html-via-cross-origin-blob-url.sub.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- Test verifies that cross-origin blob URIs are blocked both with and
+ without CORB.
+-->
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ function step1_createSubframe() {
+ addEventListener("message", function(e) {
+ t.step(function() { step2_processSubframeMsg(e.data); })
+ });
+ var subframe = document.createElement("iframe")
+ // www1 is cross-origin, to ensure that the received blob will be cross-origin.
+ subframe.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/subframe-that-posts-html-containing-blob-url-to-parent.html';
+ document.body.appendChild(subframe);
+ }
+
+ function step2_processSubframeMsg(msg) {
+ assert_false(msg.hasOwnProperty('error'), 'unexpected property found: "error"');
+ assert_equals(msg.blob_type, 'text/html');
+ assert_equals(msg.blob_size, 147);
+
+ // With and without CORB loading of a cross-origin blob should be blocked
+ // (this is verified by expecting |script.onerror|, but not |script.onload|
+ // below).
+ var script = document.createElement("script")
+ script.src = msg.blob_url;
+ script.onerror = t.step_func_done(function(){})
+ script.onload = t.unreached_func("Unexpected load event")
+ document.body.appendChild(script)
+ }
+
+ step1_createSubframe();
+});
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html
new file mode 100644
index 0000000000..b6bc90964d
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html-nosniff.sub.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<!-- Test verifies that script mislabeled as html won't execute with and without CORB
+ if the nosniff response header is present.
+
+ The expected behavior is covered by the Fetch spec at
+ https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff?
+
+ See also the following tests:
+ - fetch/nosniff/importscripts.html
+ - fetch/nosniff/script.html
+ - fetch/nosniff/worker.html
+-->
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<script>
+setup({ single_test: true });
+window.has_executed_script = false;
+</script>
+
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<script src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/js-mislabeled-as-html-nosniff.js">
+</script>
+
+<script>
+// Verify what observable effects the <script> tag above had.
+// Assertion should hold with and without CORB:
+assert_false(window.has_executed_script,
+ 'The cross-origin script should not be executed');
+done();
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html
new file mode 100644
index 0000000000..44cb1f8659
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-js-mislabeled-as-html.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!-- Test verifies that script mislabeled as html will execute with and without
+ CORB (CORB should allow the script after sniffing).
+-->
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+
+<script>
+setup({ single_test: true });
+window.has_executed_script = false;
+</script>
+
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<script src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/js-mislabeled-as-html.js">
+</script>
+
+<script>
+// Verify what observable effects the <script> tag above had.
+// Assertion should hold with and without CORB:
+assert_true(window.has_executed_script,
+ 'The cross-origin script should execute');
+done();
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html b/testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html
new file mode 100644
index 0000000000..f0eb1f0ab1
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<!-- Test verifies CORB will block responses beginning with a JSON parser
+ breaker regardless of their MIME type (excluding text/css - see below).
+
+ A JSON parser breaker is a prefix added to resources with sensitive data to
+ prevent cross-site script inclusion (XSSI) and similar attacks. For example,
+ it may be included in JSON files to prevent them from leaking data via a
+ <script> tag, making the response only useful to a fetch or XmlHttpRequest.
+ See also https://chromium.googlesource.com/chromium/src/+/main/services/network/cross_origin_read_blocking_explainer.md#Protecting-JSON
+
+ The assumption is that all images, other media, scripts, fonts and other
+ resources that may be embedded cross-origin will never begin with a JSON
+ parser breaker. For example an JPEG image should always being with FF D8 FF,
+ a PNG image with 89 50 4E 47 0D 0A 1A 0A bytes and an SVG image with "<?xml"
+ substring.
+
+ The assumption above excludes text/css which (as shown by
+ style-css-with-json-parser-breaker.sub.html) can parse as valid stylesheet
+ even in presence of a JSON parser breaker.
+-->
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception : true});
+
+// A subset of JSON security prefixes (only ones that are parser breakers).
+json_parser_breakers = [
+ ")]}'",
+ "{}&&",
+ "{} &&",
+]
+
+// JSON parser breaker should trigger CORB blocking for any Content-Type - even
+// for resources that claim to be of a MIME type that is normally allowed to be
+// embedded in cross-origin documents (like images and/or scripts).
+mime_types = [
+ // CORB-protected MIME types
+ "text/html",
+ "text/xml",
+ "text/json",
+ "text/plain",
+
+ // MIME types that normally are allowed by CORB.
+ "application/javascript",
+ "image/png",
+ "image/svg+xml",
+
+ // Other types.
+ "application/pdf",
+ "application/zip",
+]
+
+function test(mime_type, body) {
+ // The test below depends on a global/shared event handler - we need to ensure
+ // that no tests run in parallel - this is achieved by using `promise_test`
+ // instead of `async_test`. See also
+ // https://web-platform-tests.org/writing-tests/testharness-api.html#promise-tests
+ promise_test(t => new Promise(function(resolve, reject) {
+ var script = document.createElement("script")
+
+ // Without CORB, the JSON parser breaker would cause a syntax error when
+ // parsed as JavaScript, but with CORB there should be no errors (because
+ // CORB will replace the response body with an empty body). With ORB,
+ // the script loading itself should error out.
+ script.onload = resolve;
+ script.onerror = resolve;
+ addEventListener("error", t.unreached_func(
+ "Empty body of a CORS-blocked response shouldn't trigger syntax errors."))
+
+ // www1 is cross-origin, so the HTTP response is CORB-eligible.
+ var src_prefix = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py";
+ script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body);
+ document.body.appendChild(script)
+ }), "CORB-blocks '" + mime_type + "' that starts with the following JSON parser breaker: " + body);
+}
+
+mime_types.forEach(function(type) {
+ json_parser_breakers.forEach(function(body) {
+ test(type, body);
+ });
+});
+
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html b/testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html
new file mode 100644
index 0000000000..6d490d55bc
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/script-resource-with-nonsniffable-types.tentative.sub.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<!-- Test verifies CORB will block responses with types that do not
+ require confirmation sniffing.
+
+ We assume that:
+ 1) it is unlikely that images, other media, scripts, etc. will be mislabelled
+ as the |protected_mime_types| below,
+ 2) the |protected_mime_types| below are likely to contain sensitive,
+ credentialled data.
+-->
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<div id=log></div>
+<script>
+setup({allow_uncaught_exception : true, single_test : true});
+
+function test(mime_type, is_blocking_expected) {
+ var action = is_blocking_expected ? "blocks" : "does not block";
+
+ async_test(function(t) {
+ var script = document.createElement("script")
+ var script_has_run_token = "script_has_run" + token();
+
+ // With and without CORB there should be no error, but without CORB the
+ // original script body will be preserved and |window.script_has_run| will
+ // be set.
+ window[script_has_run_token] = false;
+ script.onload = t.step_func_done(function(){
+ if (is_blocking_expected) {
+ assert_false(window[script_has_run_token]);
+ } else {
+ assert_true(window[script_has_run_token]);
+ }
+ });
+ addEventListener("error",function(e) {
+ t.step(function() {
+ assert_unreached("Unexpected error: " + e);
+ t.done();
+ })
+ });
+
+ // www1 is cross-origin, so the HTTP response is CORB-eligible.
+ var src_prefix = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py";
+ body = `window['${script_has_run_token}'] = true;`
+ script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body);
+ document.body.appendChild(script)
+ }, "CORB " + action + " '" + mime_type + "'");
+}
+
+// Some mime types should be protected by CORB without any kind
+// of confirmation sniffing.
+protected_mime_types = [
+ "application/gzip",
+ "application/pdf",
+ "application/x-gzip",
+ "application/x-protobuf",
+ "application/zip",
+ "multipart/byteranges",
+ "multipart/signed",
+ "text/csv",
+ "text/event-stream",
+]
+protected_mime_types.forEach(function(type) {
+ test(type, true /* is_blocking_expected */);
+});
+
+// Other mime types.
+other_mime_types = [
+ // These content types are legitimately allowed in 'no-cors' fetches.
+ "application/javascript",
+
+ // Confirmation sniffing will fail and prevent CORB from blocking the
+ // response.
+ "text/html",
+
+ // Unrecognized content types.
+ "application/blah"
+]
+other_mime_types.forEach(function(type) {
+ test(type, false /* is_blocking_expected */);
+});
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html
new file mode 100644
index 0000000000..8fef0dc59e
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html-nosniff.sub.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<!-- Test verifies that a stylesheet mislabeled as html won't execute with and
+ without CORB if the nosniff response header is present.
+
+ The expected behavior is covered by the Fetch spec at
+ https://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-nosniff?
+
+ See also the following tests:
+ - fetch/nosniff/stylesheet.html
+-->
+<meta charset="utf-8">
+<title>CSS is not applied (because of nosniff + non-text/css headers)</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<!-- Default style that will be applied if the external stylesheet resource
+ below won't load for any reason. This stylesheet will set h1's
+ color to green (see |default_color| below). -->
+<style>
+h1 { color: green; }
+</style>
+
+<!-- This stylesheet (if loaded) should set h1#header's color to red
+ (see |external_color| below). -->
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<link rel="stylesheet" type="text/css"
+ href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-mislabeled-as-html-nosniff.css">
+
+<body>
+ <h1 id="header">Header example</h1>
+ <p>Paragraph body</p>
+</body>
+
+<script>
+test(() => {
+ let style = getComputedStyle(document.getElementById('header'));
+ const external_color = 'rgb(255, 0, 0)'; // red
+ const default_color = 'rgb(0, 128, 0)'; // green
+ assert_equals(style.getPropertyValue('color'), default_color);
+ assert_not_equals(style.getPropertyValue('color'), external_color);
+});
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html
new file mode 100644
index 0000000000..4f0b4c22f5
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/style-css-mislabeled-as-html.sub.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<!-- Test verifies that CORB won't impact a cross-origin stylesheet mislabeled
+ as text/html (because even without CORB mislabeled CSS will be rejected).
+-->
+<meta charset="utf-8">
+<title>CSS is not applied (because of strict content-type enforcement for cross-origin stylesheets)</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<!-- Default style that will be applied if the external stylesheet resource
+ below won't load for any reason. This stylesheet will set h1's
+ color to green (see |default_color| below). -->
+<style>
+h1 { color: green; }
+</style>
+
+<!-- This stylesheet (if loaded) should set h1#header's color to red
+ (see |external_color| below). -->
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<link rel="stylesheet" type="text/css"
+ href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-mislabeled-as-html.css">
+
+<body>
+ <h1 id="header">Header example</h1>
+ <p>Paragraph body</p>
+</body>
+
+<script>
+test(() => {
+ let style = getComputedStyle(document.getElementById('header'));
+ const external_color = 'rgb(255, 0, 0)'; // red
+ const default_color = 'rgb(0, 128, 0)'; // green
+ assert_equals(style.getPropertyValue('color'), default_color);
+ assert_not_equals(style.getPropertyValue('color'), external_color);
+});
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html b/testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html
new file mode 100644
index 0000000000..29ed586a4f
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/style-css-with-json-parser-breaker.sub.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<!-- Test verifies that CORB won't block a stylesheet that
+ 1) is correctly labeled with text/css Content-Type and parsing fine as text/css
+ 2) starts with a JSON parser breaker (like )]}')
+-->
+<meta charset="utf-8">
+<title>CORB doesn't block a stylesheet that has a proper Content-Type and begins with a JSON parser breaker</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<!-- Default style that will be applied if the external stylesheet resource
+ below won't load for any reason. This stylesheet will set h1's
+ color to green (see |default_color| below). -->
+<style>
+h1 { color: green; }
+</style>
+
+<!-- This stylesheet (if loaded) should set h1#header's color to red
+ (see |external_color| below). -->
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<link rel="stylesheet" type="text/css"
+ href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/css-with-json-parser-breaker.css">
+
+<body>
+ <h1 id="header">Header example</h1>
+ <p>Paragraph body</p>
+</body>
+
+<script>
+test(() => {
+ // Verify that CSS got applied / did not get blocked by CORB.
+ let style = getComputedStyle(document.getElementById('header'));
+ const external_color = 'rgb(255, 0, 0)'; // red
+ const default_color = 'rgb(0, 128, 0)'; // green
+ assert_equals(style.getPropertyValue('color'), external_color);
+ assert_not_equals(style.getPropertyValue('color'), default_color);
+});
+</script>
diff --git a/testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html b/testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html
new file mode 100644
index 0000000000..cdefcd2d2c
--- /dev/null
+++ b/testing/web-platform/tests/fetch/corb/style-html-correctly-labeled.sub.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<!-- Test verifies that using a HTML document as a stylesheet has no observable
+ differences with and without CORB:
+ - The cross-origin stylesheet requires a correct text/css Content-Type
+ and therefore won't render even without CORB. This aspect of this test
+ is similar to the style-css-mislabeled-as-html.sub.html test.
+ - Even if the Content-Type requirements were relaxed for cross-origin stylesheets,
+ the HTML document is unlikely to parse as a stylesheet (unless a polyglot
+ HTML/CSS document is crafted as part of an attack) and therefore the
+ observable behavior should be indistinguishable from parsing the empty,
+ CORB-blocked response as a stylesheet.
+-->
+<meta charset="utf-8">
+<title>CSS is not applied (because of mismatched Content-Type header)</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<!-- Default style that will be applied if the external stylesheet resource
+ below won't load for any reason. This stylesheet will set h1's
+ color to green (see |default_color| below). -->
+<style>
+h1 { color: green; }
+</style>
+
+<!-- This is not really a stylesheet... -->
+<!-- www1 is cross-origin, so the HTTP response is CORB-eligible -->
+<link rel="stylesheet" type="text/css"
+ href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html">
+
+<body>
+ <h1 id="header">Header example</h1>
+ <p>Paragraph body</p>
+</body>
+
+<script>
+test(() => {
+ var style = getComputedStyle(document.getElementById('header'));
+ const default_color = 'rgb(0, 128, 0)'; // green
+ assert_equals(style.getPropertyValue('color'), default_color);
+});
+</script>