diff options
Diffstat (limited to 'testing/web-platform/tests/fetch/nosniff')
13 files changed, 391 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/nosniff/image.html b/testing/web-platform/tests/fetch/nosniff/image.html new file mode 100644 index 0000000000..9dfdb94cf6 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/image.html @@ -0,0 +1,39 @@ +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + // Note: images get always sniffed, nosniff doesn't do anything + // (but note the tentative Cross-Origin Read Blocking (CORB) tests + // - for example wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html). + var passes = [ + // Empty or non-sensical MIME types + null, "", "x", "x/x", + + // Image MIME types + "image/gif", "image/png", "image/png;blah", "image/svg+xml", + + // CORB-protected MIME types (but note that CORB doesn't apply here, + // because CORB ignores same-origin requests). + "text/html", "application/xml", "application/blah+xml" + ] + + const get_url = (mime) => { + let url = "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) + }, "URL query: " + mime) + }) +</script> diff --git a/testing/web-platform/tests/fetch/nosniff/importscripts.html b/testing/web-platform/tests/fetch/nosniff/importscripts.html new file mode 100644 index 0000000000..920b6bdd40 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/importscripts.html @@ -0,0 +1,14 @@ +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + async_test(function(t) { + var w = new Worker("importscripts.js") + w.onmessage = t.step_func(function(e) { + if(e.data == "END") + t.done() + else + assert_equals(e.data, "PASS") + }) + }, "Test importScripts()") +</script> diff --git a/testing/web-platform/tests/fetch/nosniff/importscripts.js b/testing/web-platform/tests/fetch/nosniff/importscripts.js new file mode 100644 index 0000000000..18952805bb --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/importscripts.js @@ -0,0 +1,28 @@ +// Testing importScripts() +function log(w) { this.postMessage(w) } +function f() { log("FAIL") } +function p() { log("PASS") } + +const get_url = (mime, outcome) => { + let url = "resources/js.py" + if (mime != null) { + url += "?type=" + encodeURIComponent(mime) + } + if (outcome) { + url += "&outcome=p" + } + return url +} + +[null, "", "x", "x/x", "text/html", "text/json"].forEach(function(mime) { + try { + importScripts(get_url(mime)) + } catch(e) { + (e.name == "NetworkError") ? p() : log("FAIL (no NetworkError exception): " + mime) + } + +}) +importScripts(get_url("text/javascript", true)) +importScripts(get_url("text/ecmascript", true)) +importScripts(get_url("text/ecmascript;blah", true)) +log("END") diff --git a/testing/web-platform/tests/fetch/nosniff/parsing-nosniff.window.js b/testing/web-platform/tests/fetch/nosniff/parsing-nosniff.window.js new file mode 100644 index 0000000000..2a2648653c --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/parsing-nosniff.window.js @@ -0,0 +1,27 @@ +promise_test(() => fetch("resources/x-content-type-options.json").then(res => res.json()).then(runTests), "Loading JSONā¦"); + +function runTests(allTestData) { + for (let i = 0; i < allTestData.length; i++) { + const testData = allTestData[i], + input = encodeURIComponent(testData.input); + promise_test(t => { + let resolve; + const promise = new Promise(r => resolve = r); + const script = document.createElement("script"); + t.add_cleanup(() => script.remove()); + // A <script> element loading a classic script does not care about the MIME type, unless + // X-Content-Type-Options: nosniff is specified, in which case a JavaScript MIME type is + // enforced, which x/x is not. + if (testData.nosniff) { + script.onerror = resolve; + script.onload = t.unreached_func("Script should not have loaded"); + } else { + script.onerror = t.unreached_func("Script should have loaded"); + script.onload = resolve; + } + script.src = "resources/nosniff.py?nosniff=" + input; + document.body.appendChild(script); + return promise; + }, input); + } +} diff --git a/testing/web-platform/tests/fetch/nosniff/resources/css.py b/testing/web-platform/tests/fetch/nosniff/resources/css.py new file mode 100644 index 0000000000..8afb56991d --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/css.py @@ -0,0 +1,23 @@ +def main(request, response): + type = request.GET.first(b"type", None) + is_revalidation = request.headers.get(b"If-Modified-Since", None) + + content = b"/* nothing to see here */" + + response.add_required_headers = False + if is_revalidation is not None: + response.writer.write_status(304) + response.writer.write_header(b"x-content-type-options", b"nosniff") + response.writer.write_header(b"content-length", 0) + if(type != None): + response.writer.write_header(b"content-type", type) + response.writer.end_headers() + response.writer.write(b"") + else: + response.writer.write_status(200) + response.writer.write_header(b"x-content-type-options", b"nosniff") + response.writer.write_header(b"content-length", len(content)) + if(type != None): + response.writer.write_header(b"content-type", type) + response.writer.end_headers() + response.writer.write(content) diff --git a/testing/web-platform/tests/fetch/nosniff/resources/image.py b/testing/web-platform/tests/fetch/nosniff/resources/image.py new file mode 100644 index 0000000000..9fd367c85c --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/image.py @@ -0,0 +1,24 @@ +import os.path + +from wptserve.utils import isomorphic_decode + +def main(request, response): + type = request.GET.first(b"type", None) + + if type != None and b"svg" in type: + filename = u"green-96x96.svg" + else: + filename = u"blue96x96.png" + + path = os.path.join(os.path.dirname(isomorphic_decode(__file__)), u"../../../images", filename) + body = open(path, u"rb").read() + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header(b"x-content-type-options", b"nosniff") + response.writer.write_header(b"content-length", len(body)) + if(type != None): + response.writer.write_header(b"content-type", type) + response.writer.end_headers() + + response.writer.write(body) diff --git a/testing/web-platform/tests/fetch/nosniff/resources/js.py b/testing/web-platform/tests/fetch/nosniff/resources/js.py new file mode 100644 index 0000000000..784050a2ca --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/js.py @@ -0,0 +1,17 @@ +def main(request, response): + outcome = request.GET.first(b"outcome", b"f") + type = request.GET.first(b"type", b"Content-Type missing") + + content = b"// nothing to see here" + content += b"\n" + content += b"log('FAIL: " + type + b"')" if (outcome == b"f") else b"p()" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header(b"x-content-type-options", b"nosniff") + response.writer.write_header(b"content-length", len(content)) + if(type != b"Content-Type missing"): + response.writer.write_header(b"content-type", type) + response.writer.end_headers() + + response.writer.write(content) diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff.py b/testing/web-platform/tests/fetch/nosniff/resources/nosniff.py new file mode 100644 index 0000000000..bc85ea0ec9 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff.py @@ -0,0 +1,10 @@ +def main(request, response): + response.add_required_headers = False + output = b"HTTP/1.1 220 YOU HAVE NO POWER HERE\r\n" + output += b"Content-Length: 22\r\n" + output += b"Content-Type: x/x\r\n" + output += request.GET.first(b"nosniff") + b"\r\n" + output += b"\r\n" + output += b"// nothing to see here" + response.writer.write(output) + response.close_connection = True diff --git a/testing/web-platform/tests/fetch/nosniff/resources/worker.py b/testing/web-platform/tests/fetch/nosniff/resources/worker.py new file mode 100644 index 0000000000..2d7e3f6c90 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/worker.py @@ -0,0 +1,16 @@ +def main(request, response): + type = request.GET.first(b"type", None) + + content = b"// nothing to see here" + content += b"\n" + content += b"this.postMessage('hi')" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header(b"x-content-type-options", b"nosniff") + response.writer.write_header(b"content-length", len(content)) + if(type != None): + response.writer.write_header(b"content-type", type) + response.writer.end_headers() + + response.writer.write(content) diff --git a/testing/web-platform/tests/fetch/nosniff/resources/x-content-type-options.json b/testing/web-platform/tests/fetch/nosniff/resources/x-content-type-options.json new file mode 100644 index 0000000000..080fc1990b --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/x-content-type-options.json @@ -0,0 +1,62 @@ +[ + { + "input": "X-Content-Type-Options: NOSNIFF", + "nosniff": true + }, + { + "input": "x-content-type-OPTIONS: nosniff", + "nosniff": true + }, + { + "input": "X-Content-Type-Options: nosniff,,@#$#%%&^&^*()()11!", + "nosniff": true + }, + { + "input": "X-Content-Type-Options: @#$#%%&^&^*()()11!,nosniff", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: nosniff\r\nX-Content-Type-Options: no", + "nosniff": true + }, + { + "input": "X-Content-Type-Options: no\r\nX-Content-Type-Options: nosniff", + "nosniff": false + }, + { + "input": "X-Content-Type-Options:\r\nX-Content-Type-Options: nosniff", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: nosniff\r\nX-Content-Type-Options: nosniff", + "nosniff": true + }, + { + "input": "X-Content-Type-Options: ,nosniff", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: nosniff\u000C", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: nosniff\u000B", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: nosniff\u000B,nosniff", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: 'NosniFF'", + "nosniff": false + }, + { + "input": "X-Content-Type-Options: \"nosniFF\"", + "nosniff": false + }, + { + "input": "Content-Type-Options: nosniff", + "nosniff": false + } +] diff --git a/testing/web-platform/tests/fetch/nosniff/script.html b/testing/web-platform/tests/fetch/nosniff/script.html new file mode 100644 index 0000000000..e0b5dac709 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/script.html @@ -0,0 +1,43 @@ +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + var log = function() {}, // see comment below + p = function() {}, // see comment below + fails = [null, "", "x", "x/x", "text/html", "text/json"], + passes = ["text/javascript", "text/ecmascript", "text/ecmascript;blah", "text/javascript1.0"] + + // Ideally we'd also check whether the scripts in fact execute, but that would involve + // timers and might get a bit racy without cross-browser support for the execute events. + + const get_url = (mime, outcome) => { + let url = "resources/js.py" + if (mime != null) { + url += "?type=" + encodeURIComponent(mime) + } + if (outcome) { + url += "&outcome=p" + } + return url + } + + fails.forEach(function(mime) { + async_test(function(t) { + var script = document.createElement("script") + script.onerror = t.step_func_done(function(){}) + script.onload = t.unreached_func("Unexpected load event") + script.src = get_url(mime) + document.body.appendChild(script) + }, "URL query: " + mime) + }) + + passes.forEach(function(mime) { + async_test(function(t) { + var script = document.createElement("script") + script.onerror = t.unreached_func("Unexpected error event") + script.onload = t.step_func_done(function(){}) + script.src = get_url(mime, true) + document.body.appendChild(script) + }, "URL query: " + mime) + }) +</script> diff --git a/testing/web-platform/tests/fetch/nosniff/stylesheet.html b/testing/web-platform/tests/fetch/nosniff/stylesheet.html new file mode 100644 index 0000000000..8f2b5476e9 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/stylesheet.html @@ -0,0 +1,60 @@ +<!-- quirks mode is important, text/css is already required otherwise --> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + var fails = [null, "", "x", "x/x", "text/html", "text/json"], + passes = ["text/css", "text/css;charset=utf-8", "text/css;blah"] + + const get_url = (mime) => { + let url = "resources/css.py" + if (mime != null) { + url += "?type=" + encodeURIComponent(mime) + } + return url + } + + fails.forEach(function(mime) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.step_func_done() + link.onload = t.unreached_func("Unexpected load event") + link.href = get_url(mime) + document.body.appendChild(link) + }, "URL query: " + mime) + }) + + fails.forEach(function(mime) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.step_func_done() + link.onload = t.unreached_func("Unexpected load event") + link.href = get_url(mime) + document.body.appendChild(link) + }, "Revalidated URL query: " + mime) + }) + + passes.forEach(function(mime) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.unreached_func("Unexpected error event") + link.onload = t.step_func_done() + link.href = get_url(mime) + document.body.appendChild(link) + }, "URL query: " + mime) + }) + + passes.forEach(function(mime) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.unreached_func("Unexpected error event") + link.onload = t.step_func_done() + link.href = get_url(mime) + document.body.appendChild(link) + }, "Revalidated URL query: " + mime) + }) +</script> diff --git a/testing/web-platform/tests/fetch/nosniff/worker.html b/testing/web-platform/tests/fetch/nosniff/worker.html new file mode 100644 index 0000000000..c8c1076df5 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/worker.html @@ -0,0 +1,28 @@ +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + var workers = [], + fails = ["", "?type=", "?type=x", "?type=x/x", "?type=text/html", "?type=text/json"], + passes = ["?type=text/javascript", "?type=text/ecmascript", "?type=text/ecmascript;yay"] + + fails.forEach(function(urlpart) { + async_test(function(t) { + var w = new Worker("resources/worker.py" + urlpart) + w.onmessage = t.unreached_func("Unexpected message event") + w.onerror = t.step_func_done(function(){}) + workers.push(w) // avoid GC + }, "URL query: " + urlpart) + }) + + passes.forEach(function(urlpart) { + async_test(function(t) { + var w = new Worker("resources/worker.py" + urlpart) + w.onmessage = t.step_func_done(function(e){ + assert_equals(e.data, "hi") + }) + w.onerror = t.unreached_func("Unexpected error event") + workers.push(w) // avoid GC + }, "URL query: " + urlpart) + }) +</script> |