diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /testing/web-platform/tests/fetch | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'testing/web-platform/tests/fetch')
200 files changed, 7112 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/OWNERS b/testing/web-platform/tests/fetch/OWNERS new file mode 100644 index 000000000..fbeac366e --- /dev/null +++ b/testing/web-platform/tests/fetch/OWNERS @@ -0,0 +1,2 @@ +@jdm +@youennf diff --git a/testing/web-platform/tests/fetch/api/basic/accept-header-worker.html b/testing/web-platform/tests/fetch/api/basic/accept-header-worker.html new file mode 100644 index 000000000..4d5b32205 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/accept-header-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: accept header</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#fetching"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("accept-header.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/accept-header.html b/testing/web-platform/tests/fetch/api/basic/accept-header.html new file mode 100644 index 000000000..cd9550fb2 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/accept-header.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: accept header</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#fetching"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="accept-header.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/accept-header.js b/testing/web-platform/tests/fetch/api/basic/accept-header.js new file mode 100644 index 000000000..3cf9ba3b0 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/accept-header.js @@ -0,0 +1,38 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +promise_test(function() { + return fetch(RESOURCES_DIR + "inspect-headers.py?headers=Accept").then(function(response) { + assert_equals(response.status, 200, "HTTP status is 200"); + assert_equals(response.type , "basic", "Response's type is basic"); + assert_equals(response.headers.get("x-request-accept"), "*/*", "Request has accept header with value '*/*'"); + }); +}, "Request through fetch should have 'accept' header with value '*/*'"); + +promise_test(function() { + return fetch(RESOURCES_DIR + "inspect-headers.py?headers=Accept", {"headers": [["Accept", "custom/*"]]}).then(function(response) { + assert_equals(response.status, 200, "HTTP status is 200"); + assert_equals(response.type , "basic", "Response's type is basic"); + assert_equals(response.headers.get("x-request-accept"), "custom/*", "Request has accept header with value 'custom/*'"); + }); +}, "Request through fetch should have 'accept' header with value 'custom/*'"); + +promise_test(function() { + return fetch(RESOURCES_DIR + "inspect-headers.py?headers=Accept-Language").then(function(response) { + assert_equals(response.status, 200, "HTTP status is 200"); + assert_equals(response.type , "basic", "Response's type is basic"); + assert_true(response.headers.has("x-request-accept-language")); + }); +}, "Request through fetch should have a 'accept-language' header"); + +promise_test(function() { + return fetch(RESOURCES_DIR + "inspect-headers.py?headers=Accept-Language", {"headers": [["Accept-Language", "bzh"]]}).then(function(response) { + assert_equals(response.status, 200, "HTTP status is 200"); + assert_equals(response.type , "basic", "Response's type is basic"); + assert_equals(response.headers.get("x-request-accept-language"), "bzh", "Request has accept header with value 'bzh'"); + }); +}, "Request through fetch should have 'accept-language' header with value 'bzh'"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/integrity-sharedworker.html b/testing/web-platform/tests/fetch/api/basic/integrity-sharedworker.html new file mode 100644 index 000000000..fa90a60ce --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/integrity-sharedworker.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in sharedworker: integrity handling</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new SharedWorker("integrity.js?pipe=sub")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/integrity-worker.html b/testing/web-platform/tests/fetch/api/basic/integrity-worker.html new file mode 100644 index 000000000..9240bc632 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/integrity-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: integrity handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("integrity.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/integrity.html b/testing/web-platform/tests/fetch/api/basic/integrity.html new file mode 100644 index 000000000..150c9b71d --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/integrity.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: integrity handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="integrity.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/integrity.js b/testing/web-platform/tests/fetch/api/basic/integrity.js new file mode 100644 index 000000000..a436dabe4 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/integrity.js @@ -0,0 +1,45 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function integrity(desc, url, integrity, shouldPass) { + if (shouldPass) { + promise_test(function(test) { + return fetch(url, {'integrity': integrity}).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + }); + }, desc); + } else { + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url, {'integrity': integrity})); + }, desc); + } +} + +var topSha256 = "sha256-KHIDZcXnR2oBHk9DrAA+5fFiR6JjudYjqoXtMR1zvzk="; +var topSha384 = "sha384-MgZYnnAzPM/MjhqfOIMfQK5qcFvGZsGLzx4Phd7/A8fHTqqLqXqKo8cNzY3xEPTL"; +var topSha512 = "sha512-D6yns0qxG0E7+TwkevZ4Jt5t7Iy3ugmAajG/dlf6Pado1JqTyneKXICDiqFIkLMRExgtvg8PlxbKTkYfRejSOg=="; +var invalidSha256 = "sha256-dKUcPOn/AlUjWIwcHeHNqYXPlvyGiq+2dWOdFcE+24I="; +var invalidSha512 = "sha512-oUceBRNxPxnY60g/VtPCj2syT4wo4EZh2CgYdWy9veW8+OsReTXoh7dizMGZafvx9+QhMS39L/gIkxnPIn41Zg=="; + +var url = "../resources/top.txt"; +var corsUrl = "http://{{host}}:{{ports[http][1]}}" + dirname(location.pathname) + RESOURCES_DIR + "top.txt"; +/* Enable CORS*/ +corsUrl += "?pipe=header(Access-Control-Allow-Origin,*)"; + +integrity("Empty string integrity", url, "", true); +integrity("SHA-256 integrity", url, topSha256, true); +integrity("SHA-384 integrity", url, topSha384, true); +integrity("SHA-512 integrity", url, topSha512, true); +integrity("Invalid integrity", url, invalidSha256, false); +integrity("Multiple integrities: valid stronger than invalid", url, invalidSha256 + " " + topSha384, true); +integrity("Multiple integrities: invalid stronger than valid", url, invalidSha512 + " " + topSha384, false); +integrity("Multiple integrities: invalid as strong as valid", url, invalidSha512 + " " + topSha512, true); +integrity("Multiple integrities: both are valid", url, topSha384 + " " + topSha512, true); +integrity("Multiple integrities: both are invalid", url, invalidSha256 + " " + invalidSha512, false); +integrity("CORS empty integrity", corsUrl, "", true); +integrity("CORS SHA-512 integrity", corsUrl, topSha512, true); +integrity("CORS invalid integrity", corsUrl, invalidSha512, false); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/mode-no-cors-worker.html b/testing/web-platform/tests/fetch/api/basic/mode-no-cors-worker.html new file mode 100644 index 000000000..87376a130 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/mode-no-cors-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: no-cors mode and opaque filtering</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("mode-no-cors.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/mode-no-cors.html b/testing/web-platform/tests/fetch/api/basic/mode-no-cors.html new file mode 100644 index 000000000..7aee37909 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/mode-no-cors.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: no-cors mode and opaque filtering</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="mode-no-cors.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/mode-no-cors.js b/testing/web-platform/tests/fetch/api/basic/mode-no-cors.js new file mode 100644 index 000000000..53e849051 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/mode-no-cors.js @@ -0,0 +1,31 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function fetchNoCors(url, isOpaqueFiltered) { + var urlQuery = "?pipe=header(x-is-filtered,value)" + promise_test(function(test) { + if (isOpaqueFiltered) + return fetch(url + urlQuery, {"mode": "no-cors"}).then(function(resp) { + assert_equals(resp.status, 0, "Opaque filter: status is 0"); + assert_equals(resp.statusText, "", "Opaque filter: statusText is \"\""); + assert_equals(resp.type , "opaque", "Opaque filter: response's type is opaque"); + assert_equals(resp.headers.get("x-is-filtered"), null, "Header x-is-filtered is filtered"); + }); + else + return fetch(url + urlQuery, {"mode": "no-cors"}).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + assert_equals(resp.headers.get("x-is-filtered"), "value", "Header x-is-filtered is not filtered"); + }); + }, "Fetch "+ url + " with no-cors mode"); +} + +fetchNoCors(RESOURCES_DIR + "top.txt", false); +fetchNoCors("http://{{host}}:{{ports[http][0]}}/fetch/api/resources/top.txt", false); +fetchNoCors("https://{{host}}:{{ports[https][0]}}/fetch/api/resources/top.txt", true); +fetchNoCors("http://{{host}}:{{ports[http][1]}}/fetch/api/resources/top.txt", true); + +done(); + diff --git a/testing/web-platform/tests/fetch/api/basic/mode-same-origin-worker.html b/testing/web-platform/tests/fetch/api/basic/mode-same-origin-worker.html new file mode 100644 index 000000000..cc39af3cb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/mode-same-origin-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: same-origin mode</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("mode-same-origin.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/mode-same-origin.html b/testing/web-platform/tests/fetch/api/basic/mode-same-origin.html new file mode 100644 index 000000000..550053f30 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/mode-same-origin.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: same-origin mode</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="mode-same-origin.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/mode-same-origin.js b/testing/web-platform/tests/fetch/api/basic/mode-same-origin.js new file mode 100644 index 000000000..6418b22f5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/mode-same-origin.js @@ -0,0 +1,34 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js") +} + +function fetchSameOrigin(url, shouldPass) { + promise_test(function(test) { + if (shouldPass) + return fetch(url , {"mode": "same-origin"}).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type, "basic", "response type is basic"); + }); + else + return promise_rejects(test, new TypeError, fetch(url, {mode: "same-origin"})); + }, "Fetch "+ url + " with same-origin mode"); +} + +var host_info = get_host_info(); + +fetchSameOrigin(RESOURCES_DIR + "top.txt", true); +fetchSameOrigin(host_info.HTTP_ORIGIN + "/fetch/api/resources/top.txt", true); +fetchSameOrigin(host_info.HTTPS_ORIGIN + "/fetch/api/resources/top.txt", false); +fetchSameOrigin(host_info.HTTP_REMOTE_ORIGIN + "/fetch/api/resources/top.txt", false); + +var redirPath = dirname(location.pathname) + RESOURCES_DIR + "redirect.py?location="; + +fetchSameOrigin(redirPath + RESOURCES_DIR + "top.txt", true); +fetchSameOrigin(redirPath + host_info.HTTP_ORIGIN + "/fetch/api/resources/top.txt", true); +fetchSameOrigin(redirPath + host_info.HTTPS_ORIGIN + "/fetch/api/resources/top.txt", false); +fetchSameOrigin(redirPath + host_info.HTTP_REMOTE_ORIGIN + "/fetch/api/resources/top.txt", false); + +done(); + diff --git a/testing/web-platform/tests/fetch/api/basic/referrer-worker.html b/testing/web-platform/tests/fetch/api/basic/referrer-worker.html new file mode 100644 index 000000000..4b397de43 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/referrer-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: same-origin mode</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("referrer.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/referrer.html b/testing/web-platform/tests/fetch/api/basic/referrer.html new file mode 100644 index 000000000..1af3f75ba --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/referrer.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: same-origin mode</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="referrer.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/referrer.js b/testing/web-platform/tests/fetch/api/basic/referrer.js new file mode 100644 index 000000000..84cf980c7 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/referrer.js @@ -0,0 +1,35 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js") +} + +function runTest(url, init, expectedReferrer, title) { + promise_test(function(test) { + url += (url.indexOf('?') !== -1 ? '&' : '?') + "headers=referer&cors"; + + return fetch(url , init).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.headers.get("x-request-referer"), expectedReferrer, "Request's referrer is correct"); + }); + }, title); +} + +var fetchedUrl = RESOURCES_DIR + "inspect-headers.py"; +var corsFetchedUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py"; +var redirectUrl = RESOURCES_DIR + "redirect.py?location=" ; +var corsRedirectUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "redirect.py?location="; + +runTest(fetchedUrl, { referrerPolicy: "origin-when-cross-origin"}, location.toString(), "origin-when-cross-origin policy on a same-origin URL"); +runTest(corsFetchedUrl, { referrerPolicy: "origin-when-cross-origin"}, get_host_info().HTTP_ORIGIN + "/", "origin-when-cross-origin policy on a cross-origin URL"); +runTest(redirectUrl + corsFetchedUrl, { referrerPolicy: "origin-when-cross-origin"}, get_host_info().HTTP_ORIGIN + "/", "origin-when-cross-origin policy on a cross-origin URL after same-origin redirection"); +runTest(corsRedirectUrl + fetchedUrl, { referrerPolicy: "origin-when-cross-origin"}, get_host_info().HTTP_ORIGIN + "/", "origin-when-cross-origin policy on a same-origin URL after cross-origin redirection"); + + +var referrerUrlWithCredentials = get_host_info().HTTP_ORIGIN.replace("http://", "http://username:password@"); +runTest(fetchedUrl, {referrer: referrerUrlWithCredentials}, get_host_info().HTTP_ORIGIN + "/", "Referrer with credentials should be stripped"); +var referrerUrlWithFragmentIdentifier = get_host_info().HTTP_ORIGIN + "#fragmentIdentifier"; +runTest(fetchedUrl, {referrer: referrerUrlWithFragmentIdentifier}, get_host_info().HTTP_ORIGIN + "/", "Referrer with fragment ID should be stripped"); + +done(); + diff --git a/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers-worker.html b/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers-worker.html new file mode 100644 index 000000000..12e87f9e4 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: forbidden request header management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#forbidden-header-name"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("request-forbidden-headers.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers.html b/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers.html new file mode 100644 index 000000000..56ce2a65b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: forbidden request header management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#forbidden-header-name"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="request-forbidden-headers.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers.js b/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers.js new file mode 100644 index 000000000..72a8392a5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-forbidden-headers.js @@ -0,0 +1,48 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function requestForbiddenHeaders(desc, forbiddenHeaders) { + var url = RESOURCES_DIR + "inspect-headers.py"; + var requestInit = {"headers": forbiddenHeaders} + var urlParameters = "?headers=" + Object.keys(forbiddenHeaders).join("|"); + + promise_test(function(test){ + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + for (var header in forbiddenHeaders) + assert_not_equals(resp.headers.get("x-request-" + header), forbiddenHeaders[header], header + " does not have the value we defined"); + }); + }, desc); +} + +requestForbiddenHeaders("Accept-Charset is a forbidden request header", {"Accept-Charset": "utf-8"}); +requestForbiddenHeaders("Accept-Encoding is a forbidden request header", {"Accept-Encoding": ""}); + +requestForbiddenHeaders("Access-Control-Request-Headers is a forbidden request header", {"Access-Control-Request-Headers": ""}); +requestForbiddenHeaders("Access-Control-Request-Method is a forbidden request header", {"Access-Control-Request-Method": ""}); +requestForbiddenHeaders("Connection is a forbidden request header", {"Connection": "close"}); +requestForbiddenHeaders("Content-Length is a forbidden request header", {"Content-Length": "42"}); +requestForbiddenHeaders("Cookie is a forbidden request header", {"Cookie": "cookie=none"}); +requestForbiddenHeaders("Cookie2 is a forbidden request header", {"Cookie2": "cookie2=none"}); +requestForbiddenHeaders("Date is a forbidden request header", {"Date": "Wed, 04 May 1988 22:22:22 GMT"}); +requestForbiddenHeaders("DNT is a forbidden request header", {"DNT": "4"}); +requestForbiddenHeaders("Expect is a forbidden request header", {"Expect": "100-continue"}); +requestForbiddenHeaders("Host is a forbidden request header", {"Host": "http://wrong-host.com"}); +requestForbiddenHeaders("Keep-Alive is a forbidden request header", {"Keep-Alive": "timeout=15"}); +requestForbiddenHeaders("Origin is a forbidden request header", {"Origin": "http://wrong-origin.com"}); +requestForbiddenHeaders("Referer is a forbidden request header", {"Referer": "http://wrong-referer.com"}); +requestForbiddenHeaders("TE is a forbidden request header", {"TE": "trailers"}); +requestForbiddenHeaders("Trailer is a forbidden request header", {"Trailer": "Accept"}); +requestForbiddenHeaders("Transfer-Encoding is a forbidden request header", {"Transfer-Encoding": "chunked"}); +requestForbiddenHeaders("Upgrade is a forbidden request header", {"Upgrade": "HTTP/2.0"}); +requestForbiddenHeaders("Via is a forbidden request header", {"Via": "1.1 nowhere.com"}); +requestForbiddenHeaders("Proxy- is a forbidden request header", {"Proxy-": "value"}); +requestForbiddenHeaders("Proxy-Test is a forbidden request header", {"Proxy-Test": "value"}); +requestForbiddenHeaders("Sec- is a forbidden request header", {"Sec-": "value"}); +requestForbiddenHeaders("Sec-Test is a forbidden request header", {"Sec-Test": "value"}); + +done(); + diff --git a/testing/web-platform/tests/fetch/api/basic/request-head-worker.html b/testing/web-platform/tests/fetch/api/basic/request-head-worker.html new file mode 100644 index 000000000..3be7c99ad --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-head-worker.html @@ -0,0 +1,14 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: HEAD method</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("request-head.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/request-head.html b/testing/web-platform/tests/fetch/api/basic/request-head.html new file mode 100644 index 000000000..a9d8bef1f --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-head.html @@ -0,0 +1,12 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: HEAD method</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="request-head.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/request-head.js b/testing/web-platform/tests/fetch/api/basic/request-head.js new file mode 100644 index 000000000..f0d6b74f8 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-head.js @@ -0,0 +1,10 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); +} + +promise_test(function(test) { + var requestInit = {"method": "HEAD", "body": "test"}; + return promise_rejects(test, new TypeError(), fetch(".", requestInit)); +}, "Fetch with HEAD with body"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/request-headers-worker.html b/testing/web-platform/tests/fetch/api/basic/request-headers-worker.html new file mode 100644 index 000000000..85b4c4c70 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-headers-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: User agent add headers to request</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("request-headers.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/request-headers.html b/testing/web-platform/tests/fetch/api/basic/request-headers.html new file mode 100644 index 000000000..5236d29b1 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-headers.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: User agent add headers to request</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="request-headers.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/request-headers.js b/testing/web-platform/tests/fetch/api/basic/request-headers.js new file mode 100644 index 000000000..4c78ff0dc --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-headers.js @@ -0,0 +1,63 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function checkContentType(contentType, body) +{ + if (self.FormData && body instanceof self.FormData) { + assert_true(contentType.startsWith("multipart/form-data;boundary="), "Request should have header content-type starting with multipart/form-data;boundary=, but got " + contentType); + return; + } + + var expectedContentType = "text/plain;charset=UTF-8"; + if(body === null || body instanceof ArrayBuffer || body.buffer instanceof ArrayBuffer) + expectedContentType = null; + else if (body instanceof Blob) + expectedContentType = body.type ? body.type : null; + + assert_equals(contentType , expectedContentType, "Request should have header content-type: " + expectedContentType); +} + +function requestHeaders(desc, url, method, body, expectedOrigin, expectedContentLength) { + var urlParameters = "?headers=origin|user-agent|accept-charset|content-length|content-type"; + var requestInit = {"method": method} + promise_test(function(test){ + if (typeof body === "function") + body = body(); + if (body) + requestInit["body"] = body; + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + assert_true(resp.headers.has("x-request-user-agent"), "Request has header user-agent"); + assert_false(resp.headers.has("accept-charset"), "Request has header accept-charset"); + assert_equals(resp.headers.get("x-request-origin") , expectedOrigin, "Request should have header origin: " + expectedOrigin); + if (expectedContentLength !== undefined) + assert_equals(resp.headers.get("x-request-content-length") , expectedContentLength, "Request should have header content-length: " + expectedContentLength); + checkContentType(resp.headers.get("x-request-content-type"), body); + }); + }, desc); +} + +var url = RESOURCES_DIR + "inspect-headers.py" + +requestHeaders("Fetch with GET", url, "GET", null, location.origin, null); +requestHeaders("Fetch with HEAD", url, "HEAD", null, location.origin, null); +requestHeaders("Fetch with PUT without body", url, "POST", null, location.origin, "0"); +requestHeaders("Fetch with PUT with body", url, "PUT", "Request's body", location.origin, "14"); +requestHeaders("Fetch with POST without body", url, "POST", null, location.origin, "0"); +requestHeaders("Fetch with POST with text body", url, "POST", "Request's body", location.origin, "14"); +requestHeaders("Fetch with POST with FormData body", url, "POST", function() { return new FormData(); }, location.origin); +requestHeaders("Fetch with POST with Blob body", url, "POST", new Blob(["Test"]), location.origin, "4"); +requestHeaders("Fetch with POST with ArrayBuffer body", url, "POST", new ArrayBuffer(4), location.origin, "4"); +requestHeaders("Fetch with POST with Uint8Array body", url, "POST", new Uint8Array(4), location.origin, "4"); +requestHeaders("Fetch with POST with Int8Array body", url, "POST", new Int8Array(4), location.origin, "4"); +requestHeaders("Fetch with POST with Float32Array body", url, "POST", new Float32Array(1), location.origin, "4"); +requestHeaders("Fetch with POST with Float64Array body", url, "POST", new Float64Array(1), location.origin, "8"); +requestHeaders("Fetch with POST with DataView body", url, "POST", new DataView(new ArrayBuffer(8), 0, 4), location.origin, "4"); +requestHeaders("Fetch with POST with Blob body with mime type", url, "POST", new Blob(["Test"], { type: "text/maybe" }), location.origin, "4"); +requestHeaders("Fetch with Chicken", url, "Chicken", null, location.origin, null); +requestHeaders("Fetch with Chicken with body", url, "Chicken", "Request's body", location.origin, "14"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/request-referrer.html b/testing/web-platform/tests/fetch/api/basic/request-referrer.html new file mode 100644 index 000000000..dd895617b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-referrer.html @@ -0,0 +1,13 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: fetch() respects Request referrer value</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="request-referrer.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/request-referrer.js b/testing/web-platform/tests/fetch/api/basic/request-referrer.js new file mode 100644 index 000000000..cc5cc8e01 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/request-referrer.js @@ -0,0 +1,28 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function testReferrer(referrer, expected) { + promise_test(function(test) { + var url = RESOURCES_DIR + "inspect-headers.py?headers=referer" + var req = new Request(url, { referrer: referrer }); + return fetch(req).then(function(resp) { + var actual = resp.headers.get("x-request-referer"); + if (expected) { + assert_equals(actual, expected, "request's referer should be: " + expected); + return; + } + if (actual) { + assert_equals(actual, "", "request's referer should be empty"); + } + }); + }); +} + +testReferrer("about:client", window.location.href); + +var fooURL = new URL("./foo", window.location).href; +testReferrer(fooURL, fooURL); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/response-url-worker.html b/testing/web-platform/tests/fetch/api/basic/response-url-worker.html new file mode 100644 index 000000000..03374e0f6 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/response-url-worker.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: response url getter</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response-class"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("response-url.js?pipe=sub")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/response-url.html b/testing/web-platform/tests/fetch/api/basic/response-url.html new file mode 100644 index 000000000..dfe9d96c7 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/response-url.html @@ -0,0 +1,13 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: response url getter</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response-class"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="response-url.js?pipe=sub"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/basic/response-url.js b/testing/web-platform/tests/fetch/api/basic/response-url.js new file mode 100644 index 000000000..91b553aae --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/response-url.js @@ -0,0 +1,21 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); +} + +function checkResponseURL(fetchedURL, expectedURL) +{ + promise_test(function() { + return fetch(fetchedURL).then(function(response) { + assert_equals(response.url, expectedURL); + }); + }, "Testing response url getter with " +fetchedURL); +} + +var baseURL = "http://{{host}}:{{ports[http][0]}}"; +checkResponseURL(baseURL + "/ada", baseURL + "/ada"); +checkResponseURL(baseURL + "/#", baseURL + "/"); +checkResponseURL(baseURL + "/#ada", baseURL + "/"); +checkResponseURL(baseURL + "#ada", baseURL + "/"); + +done(); + diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-about-worker.html b/testing/web-platform/tests/fetch/api/basic/scheme-about-worker.html new file mode 100644 index 000000000..9c9d9a038 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-about-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: about scheme</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("scheme-about.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-about.html b/testing/web-platform/tests/fetch/api/basic/scheme-about.html new file mode 100644 index 000000000..8b6df2468 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-about.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: about scheme</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="scheme-about.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-about.js b/testing/web-platform/tests/fetch/api/basic/scheme-about.js new file mode 100644 index 000000000..ddf711bf0 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-about.js @@ -0,0 +1,39 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function checkFetchResponse(url, method, desc) { + if (!desc) { + var cut = (url.length >= 40) ? "[...]" : ""; + cut += " (" + method + ")" + desc = "Fetching " + url.substring(0, 40) + cut + " is OK" + } + promise_test(function(test) { + return fetch(url, { method: method }).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type, "basic", "response type is basic"); + assert_equals(resp.headers.get("Content-Type"), "text/html;charset=utf-8", "Content-Type is " + resp.headers.get("Content-Type")); + return resp.text(); + }) + }, desc); +} + +checkFetchResponse("about:blank", "GET"); +checkFetchResponse("about:blank", "PUT"); +checkFetchResponse("about:blank", "POST"); + +function checkKoUrl(url, desc) { + if (!desc) + desc = "Fetching " + url.substring(0, 45) + " is KO" + promise_test(function(test) { + var promise = fetch(url); + return promise_rejects(test, new TypeError(), promise); + }, desc); +} + +checkKoUrl("about:invalid.com"); +checkKoUrl("about:config"); +checkKoUrl("about:unicorn"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-blob-worker.html b/testing/web-platform/tests/fetch/api/basic/scheme-blob-worker.html new file mode 100644 index 000000000..961ecbd52 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-blob-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: blob scheme</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("scheme-blob.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-blob.html b/testing/web-platform/tests/fetch/api/basic/scheme-blob.html new file mode 100644 index 000000000..7787c3710 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-blob.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: blob scheme</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="scheme-blob.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-blob.js b/testing/web-platform/tests/fetch/api/basic/scheme-blob.js new file mode 100644 index 000000000..9bf73a693 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-blob.js @@ -0,0 +1,48 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function checkFetchResponse(url, data, mime, size, desc) { + promise_test(function(test) { + size = size.toString(); + return fetch(url).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type, "basic", "response type is basic"); + assert_equals(resp.headers.get("Content-Type"), mime, "Content-Type is " + resp.headers.get("Content-Type")); + assert_equals(resp.headers.get("Content-Length"), size, "Content-Length is " + resp.headers.get("Content-Length")); + return resp.text(); + }).then(function(bodyAsText) { + assert_equals(bodyAsText, data, "Response's body is " + data); + }); + }, desc); +} + +var blob = new Blob(["Blob's data"], { "type" : "text/plain" }); +checkFetchResponse(URL.createObjectURL(blob), "Blob's data", "text/plain", blob.size, + "Fetching [GET] URL.createObjectURL(blob) is OK"); + +function checkKoUrl(url, method, desc) { + promise_test(function(test) { + var promise = fetch(url, {"method": method}); + return promise_rejects(test, new TypeError(), promise); + }, desc); +} + +var blob2 = new Blob(["Blob's data"], { "type" : "text/plain" }); +checkKoUrl("blob:http://{{domains[www]}}:{{ports[http][0]}}/", "GET", + "Fetching [GET] blob:http://{{domains[www]}}:{{ports[http][0]}}/ is KO"); + +var invalidRequestMethods = [ + "POST", + "OPTIONS", + "HEAD", + "PUT", + "DELETE", + "INVALID", +]; +invalidRequestMethods.forEach(function(method) { + checkKoUrl(URL.createObjectURL(blob2), method, "Fetching [" + method + "] URL.createObjectURL(blob) is KO"); +}); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-data-worker.html b/testing/web-platform/tests/fetch/api/basic/scheme-data-worker.html new file mode 100644 index 000000000..42fc3f4a9 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-data-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: data scheme</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("scheme-data.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-data.html b/testing/web-platform/tests/fetch/api/basic/scheme-data.html new file mode 100644 index 000000000..0b41991c9 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-data.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: data scheme</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="scheme-data.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-data.js b/testing/web-platform/tests/fetch/api/basic/scheme-data.js new file mode 100644 index 000000000..61efd2b2d --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-data.js @@ -0,0 +1,48 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +<<<<<<< b45946c54935c6113fefb5199b3fe0e4bf087777 +function checkFetchResponse(url, data, mime, fetchMode, method) { + var cut = (url.length >= 40) ? "[...]" : ""; + desc = "Fetching " + (method ? "[" + method + "] " : "") + url.substring(0, 40) + cut + " is OK"; + var init = {"method": method || "GET"}; + if (fetchMode) { + init.mode = fetchMode; + desc += " (" + fetchMode + ")"; + } + promise_test(function(test) { + return fetch(url, init).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.statusText, "OK", "HTTP statusText is OK"); + assert_equals(resp.type, "basic", "response type is basic"); + assert_equals(resp.headers.get("Content-Type"), mime, "Content-Type is " + resp.headers.get("Content-Type")); + return resp.text(); + }).then(function(body) { + assert_equals(body, data, "Response's body is correct"); + }); + }, desc); +} + +checkFetchResponse("data:,response%27s%20body", "response's body", "text/plain;charset=US-ASCII"); +checkFetchResponse("data:,response%27s%20body", "response's body", "text/plain;charset=US-ASCII", "same-origin"); +checkFetchResponse("data:,response%27s%20body", "response's body", "text/plain;charset=US-ASCII", "cors"); +checkFetchResponse("data:text/plain;base64,cmVzcG9uc2UncyBib2R5", "response's body", "text/plain"); +checkFetchResponse("data:image/png;base64,cmVzcG9uc2UncyBib2R5", + "response's body", + "image/png"); +checkFetchResponse("data:,response%27s%20body", "response's body", "text/plain;charset=US-ASCII", null, "POST"); +checkFetchResponse("data:,response%27s%20body", "response's body", "text/plain;charset=US-ASCII", null, "HEAD"); + +function checkKoUrl(url, method, desc) { + var cut = (url.length >= 40) ? "[...]" : ""; + desc = "Fetching [" + method + "] " + url.substring(0, 45) + cut + " is KO" + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url, {"method": method})); + }, desc); +} + +checkKoUrl("data:notAdataUrl.com", "GET"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-others-worker.html b/testing/web-platform/tests/fetch/api/basic/scheme-others-worker.html new file mode 100644 index 000000000..397d9257b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-others-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: urls with unsupported schemes</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("scheme-others.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-others.html b/testing/web-platform/tests/fetch/api/basic/scheme-others.html new file mode 100644 index 000000000..dd37143b0 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-others.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: urls with unsupported schemes</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#basic-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="scheme-others.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/scheme-others.js b/testing/web-platform/tests/fetch/api/basic/scheme-others.js new file mode 100644 index 000000000..ce02ec134 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/scheme-others.js @@ -0,0 +1,33 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function checkKoUrl(url, desc) { + if (!desc) + desc = "Fetching " + url.substring(0, 45) + " is KO" + promise_test(function(test) { + var promise = fetch(url); + return promise_rejects(test, new TypeError(), promise); + }, desc); +} + +var urlWithoutScheme = "://{{host}}:{{ports[http][0]}}/"; +checkKoUrl("aaa" + urlWithoutScheme); +checkKoUrl("cap" + urlWithoutScheme); +checkKoUrl("cid" + urlWithoutScheme); +checkKoUrl("dav" + urlWithoutScheme); +checkKoUrl("dict" + urlWithoutScheme); +checkKoUrl("dns" + urlWithoutScheme); +checkKoUrl("geo" + urlWithoutScheme); +checkKoUrl("im" + urlWithoutScheme); +checkKoUrl("imap" + urlWithoutScheme); +checkKoUrl("ipp" + urlWithoutScheme); +checkKoUrl("ldap" + urlWithoutScheme); +checkKoUrl("mailto" + urlWithoutScheme); +checkKoUrl("nfs" + urlWithoutScheme); +checkKoUrl("pop" + urlWithoutScheme); +checkKoUrl("rtsp" + urlWithoutScheme); +checkKoUrl("snmp" + urlWithoutScheme); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/stream-response-worker.html b/testing/web-platform/tests/fetch/api/basic/stream-response-worker.html new file mode 100644 index 000000000..0be1c0d13 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/stream-response-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: retrieve response's body progressively</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("stream-response.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/stream-response.html b/testing/web-platform/tests/fetch/api/basic/stream-response.html new file mode 100644 index 000000000..eb6b1415a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/stream-response.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: retrieve response's body progressively</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="stream-response.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/basic/stream-response.js b/testing/web-platform/tests/fetch/api/basic/stream-response.js new file mode 100644 index 000000000..322b16455 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/stream-response.js @@ -0,0 +1,33 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function streamBody(reader, test, count) { + return reader.read().then(function(data) { + if (!data.done && count < 2) { + count += 1; + return streamBody(reader, test, count); + } else { + test.step(function() { + assert_true(count >= 2, "Retrieve body progressively"); + }); + } + }); +} + +//simulate streaming: +//count is large enough to let the UA deliver the body before it is completely retrieved +promise_test(function(test) { + return fetch(RESOURCES_DIR + "trickle.py?ms=30&count=100").then(function(resp) { + var count = 0; + if (resp.body) + return streamBody(resp.body.getReader(), test, count); + else + test.step(function() { + assert_unreached( "Body does not exist in response"); + }); + }); +}, "Stream response's body"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/basic/text-utf8.html b/testing/web-platform/tests/fetch/api/basic/text-utf8.html new file mode 100644 index 000000000..7499a474a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/basic/text-utf8.html @@ -0,0 +1,69 @@ +<!doctype html> +<meta charset=utf-8> +<title>Fetch: Request and Response text() should decode as UTF-8</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://fetch.spec.whatwg.org/#body-mixin" /> + +<script src="../resources/utils.js"></script> +<script> + +function testTextDecoding(body, expectedText, urlParameter, title) +{ + var arrayBuffer = stringToArray(body); + + promise_test(function(test) { + var request = new Request("", {method: "POST", body: arrayBuffer}); + return request.text().then(function(value) { + assert_equals(value, expectedText, "Request.text() should decode data as UTF-8"); + }); + }, title + " with Request.text()"); + + promise_test(function(test) { + var response = new Response(arrayBuffer); + return response.text().then(function(value) { + assert_equals(value, expectedText, "Response.text() should decode data as UTF-8"); + }); + }, title + " with Response.text()"); + + promise_test(function(test) { + return fetch("../resources/status.py?code=200&type=text%2Fplain%3Bcharset%3DUTF-8&content=" + urlParameter).then(function(response) { + return response.text().then(function(value) { + assert_equals(value, expectedText, "Fetched Response.text() should decode data as UTF-8"); + }); + }); + }, title + " with fetched data (UTF-8 charset)"); + + promise_test(function(test) { + return fetch("../resources/status.py?code=200&type=text%2Fplain%3Bcharset%3DUTF-16&content=" + urlParameter).then(function(response) { + return response.text().then(function(value) { + assert_equals(value, expectedText, "Fetched Response.text() should decode data as UTF-8"); + }); + }); + }, title + " with fetched data (UTF-16 charset)"); +} + +var utf8WithBOM = "\xef\xbb\xbf\xe4\xb8\x89\xe6\x9d\x91\xe3\x81\x8b\xe3\x81\xaa\xe5\xad\x90"; +var utf8WithBOMAsURLParameter = "%EF%BB%BF%E4%B8%89%E6%9D%91%E3%81%8B%E3%81%AA%E5%AD%90"; +var utf8WithoutBOM = "\xe4\xb8\x89\xe6\x9d\x91\xe3\x81\x8b\xe3\x81\xaa\xe5\xad\x90"; +var utf8WithoutBOMAsURLParameter = "%E4%B8%89%E6%9D%91%E3%81%8B%E3%81%AA%E5%AD%90"; +var utf8Decoded = "三村かな子"; +testTextDecoding(utf8WithBOM, utf8Decoded, utf8WithBOMAsURLParameter, "UTF-8 with BOM"); +testTextDecoding(utf8WithoutBOM, utf8Decoded, utf8WithoutBOMAsURLParameter, "UTF-8 without BOM"); + +var utf16BEWithBOM = "\xfe\xff\x4e\x09\x67\x51\x30\x4b\x30\x6a\x5b\x50"; +var utf16BEWithBOMAsURLParameter = "%fe%ff%4e%09%67%51%30%4b%30%6a%5b%50"; +var utf16BEWithBOMDecodedAsUTF8 = "��N\tgQ0K0j[P"; +testTextDecoding(utf16BEWithBOM, utf16BEWithBOMDecodedAsUTF8, utf16BEWithBOMAsURLParameter, "UTF-16BE with BOM decoded as UTF-8"); + +var utf16LEWithBOM = "\xff\xfe\x09\x4e\x51\x67\x4b\x30\x6a\x30\x50\x5b"; +var utf16LEWithBOMAsURLParameter = "%ff%fe%09%4e%51%67%4b%30%6a%30%50%5b"; +var utf16LEWithBOMDecodedAsUTF8 = "��\tNQgK0j0P["; +testTextDecoding(utf16LEWithBOM, utf16LEWithBOMDecodedAsUTF8, utf16LEWithBOMAsURLParameter, "UTF-16LE with BOM decoded as UTF-8"); + +var utf16WithoutBOM = "\xe6\x00\xf8\x00\xe5\x00\x0a\x00\xc6\x30\xb9\x30\xc8\x30\x0a\x00"; +var utf16WithoutBOMAsURLParameter = "%E6%00%F8%00%E5%00%0A%00%C6%30%B9%30%C8%30%0A%00"; +var utf16WithoutBOMDecoded = "\ufffd\u0000\ufffd\u0000\ufffd\u0000\u000a\u0000\ufffd\u0030\ufffd\u0030\ufffd\u0030\u000a\u0000"; +testTextDecoding(utf16WithoutBOM, utf16WithoutBOMDecoded, utf16WithoutBOMAsURLParameter, "UTF-16 without BOM decoded as UTF-8"); + +</script> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-basic-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-basic-worker.html new file mode 100644 index 000000000..2373bf710 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-basic-worker.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: basic CORS</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-cors"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-cors-check"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-basic.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-basic.html b/testing/web-platform/tests/fetch/api/cors/cors-basic.html new file mode 100644 index 000000000..feddf59d0 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-basic.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: basic CORS</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-cors"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-cors-check"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-basic.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-basic.js b/testing/web-platform/tests/fetch/api/cors/cors-basic.js new file mode 100644 index 000000000..354d8aaa9 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-basic.js @@ -0,0 +1,42 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js"); +} + +function cors(desc, origin) { + var url = origin + dirname(location.pathname); + var urlParameters = "?pipe=header(Access-Control-Allow-Origin,*)"; + + promise_test(function(test) { + return fetch(url + RESOURCES_DIR + "top.txt" + urlParameters, {"mode": "no-cors"} ).then(function(resp) { + assert_equals(resp.status, 0, "Opaque filter: status is 0"); + assert_equals(resp.statusText, "", "Opaque filter: statusText is \"\""); + assert_equals(resp.type , "opaque", "Opaque filter: response's type is opaque"); + return resp.text().then(function(value) { + assert_equals(value, "", "Opaque response should have an empty body"); + }); + }); + }, desc + " [no-cors mode]"); + + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url + RESOURCES_DIR + "top.txt", {"mode": "cors"})); + }, desc + " [server forbid CORS]"); + + promise_test(function(test) { + return fetch(url + RESOURCES_DIR + "top.txt" + urlParameters, {"mode": "cors"} ).then(function(resp) { + assert_equals(resp.status, 200, "Fetch's response's status is 200"); + assert_equals(resp.type , "cors", "CORS response's type is cors"); + }); + }, desc + " [cors mode]"); +} + +var host_info = get_host_info(); + +cors("Same domain different port", host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT); +cors("Same domain different protocol different port", host_info.HTTPS_ORIGIN); +cors("Cross domain basic usage", host_info.HTTP_REMOTE_ORIGIN); +cors("Cross domain different port", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT); +cors("Cross domain different protocol", host_info.HTTPS_REMOTE_ORIGIN); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-cookies-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-cookies-worker.html new file mode 100644 index 000000000..c0738e571 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-cookies-worker.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: cookies management for cors requests</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-cookies.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-cookies.html b/testing/web-platform/tests/fetch/api/cors/cors-cookies.html new file mode 100644 index 000000000..d9fa2e3ee --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-cookies.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: cookies management for cors requests</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-cookies.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-cookies.js b/testing/web-platform/tests/fetch/api/cors/cors-cookies.js new file mode 100644 index 000000000..6c8aa8df2 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-cookies.js @@ -0,0 +1,61 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js") +} + +function corsCookies(desc, baseURL1, baseURL2, credentialsMode, cookies) { + var urlSetCookie = baseURL1 + dirname(location.pathname) + RESOURCES_DIR + "top.txt"; + var urlCheckCookies = baseURL2 + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?cors&headers=cookie"; + //enable cors with credentials + var urlParameters = "?pipe=header(Access-Control-Allow-Origin," + location.origin + ")"; + urlParameters += "|header(Access-Control-Allow-Credentials,true)"; + + var urlCleanParameters = "?pipe=header(Access-Control-Allow-Origin," + location.origin + ")"; + urlCleanParameters += "|header(Access-Control-Allow-Credentials,true)"; + if (cookies) { + urlParameters += "|header(Set-Cookie,"; + urlParameters += cookies.join(",True)|header(Set-Cookie,") + ",True)"; + urlCleanParameters += "|header(Set-Cookie,"; + urlCleanParameters += cookies.join("%3B%20max-age=0,True)|header(Set-Cookie,") + "%3B%20max-age=0,True)"; + } + + var requestInit = {"credentials": credentialsMode, "mode": "cors"}; + + promise_test(function(test){ + return fetch(urlSetCookie + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + //check cookies sent + return fetch(urlCheckCookies, requestInit); + }).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_false(resp.headers.has("Cookie") , "Cookie header is not exposed in response"); + if (credentialsMode === "include" && baseURL1 === baseURL2) { + assert_equals(resp.headers.get("x-request-cookie") , cookies.join("; "), "Request includes cookie(s)"); + } + else { + assert_false(resp.headers.has("x-request-cookie") , "Request should have no cookie"); + } + //clean cookies + return fetch(urlSetCookie + urlCleanParameters, {"credentials": "include"}); + }).catch(function(e) { + return fetch(urlSetCookie + urlCleanParameters, {"credentials": "include"}).then(function(resp) { + throw e; + }) + }); + }, desc); +} + +var local = get_host_info().HTTP_ORIGIN; +var remote = get_host_info().HTTP_REMOTE_ORIGIN; +// FIXME: otherRemote might not be accessible on some test environments. +var otherRemote = local.replace("http://", "http://www."); + +corsCookies("Omit mode: no cookie sent", local, local, "omit", ["g=7"]); +corsCookies("Include mode: 1 cookie", remote, remote, "include", ["a=1"]); +corsCookies("Include mode: local cookies are not sent with remote request", local, remote, "include", ["c=3"]); +corsCookies("Include mode: remote cookies are not sent with local request", remote, local, "include", ["d=4"]); +corsCookies("Same-origin mode: cookies are discarded in cors request", remote, remote, "same-origin", ["f=6"]); +corsCookies("Include mode: remote cookies are not sent with other remote request", remote, otherRemote, "include", ["e=5"]); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-filtering-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-filtering-worker.html new file mode 100644 index 000000000..f15566fc5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-filtering-worker.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: filtered headers in CORS response</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-cors"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-filtering.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/cors/cors-filtering.html b/testing/web-platform/tests/fetch/api/cors/cors-filtering.html new file mode 100644 index 000000000..b7500ad16 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-filtering.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: filtered headers in CORS response</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-cors"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="cors-filtering.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/cors/cors-filtering.js b/testing/web-platform/tests/fetch/api/cors/cors-filtering.js new file mode 100644 index 000000000..d2c53e79f --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-filtering.js @@ -0,0 +1,66 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function corsFilter(corsUrl, headerName, headerValue, isFiltered) { + var url = corsUrl + "?pipe=header(" + headerName + "," + encodeURIComponent(headerValue) +")|header(Access-Control-Allow-Origin,*)"; + promise_test(function(test) { + return fetch(url).then(function(resp) { + assert_equals(resp.status, 200, "Fetch success with code 200"); + assert_equals(resp.type , "cors", "CORS fetch's response has cors type"); + if (!isFiltered) { + assert_equals(resp.headers.get(headerName), headerValue, + headerName + " header should be included in response with value: " + headerValue); + } else { + assert_false(resp.headers.has(headerName), "UA should exclude " + headerName + " header from response"); + } + test.done(); + }); + }, "CORS filter on " + headerName + " header"); +} + +function corsExposeFilter(corsUrl, headerName, headerValue, isForbidden) { + var url = corsUrl + "?pipe=header(" + headerName + "," + encodeURIComponent(headerValue) +")|" + + "header(Access-Control-Allow-Origin,*)" + + "header(Access-Control-Expose-Headers," + headerName + ")"; + + promise_test(function(test) { + return fetch(url).then(function(resp) { + assert_equals(resp.status, 200, "Fetch success with code 200"); + assert_equals(resp.type , "cors", "CORS fetch's response has cors type"); + if (!isForbidden) { + assert_equals(resp.headers.get(headerName), headerValue, + headerName + " header should be included in response with value: " + headerValue); + } else { + assert_false(resp.headers.has(headerName), "UA should exclude " + headerName + " header from response"); + } + test.done(); + }); + }, "CORS filter on " + headerName + " header, header is exposed"); +} + +var url = "http://{{host}}:{{ports[http][1]}}" + dirname(location.pathname) + RESOURCES_DIR + "top.txt"; + +corsFilter(url, "Cache-Control", "no-cache", false); +corsFilter(url, "Content-Language", "fr", false); +corsFilter(url, "Content-Type", "text/html", false); +corsFilter(url, "Expires","04 May 1988 22:22:22 GMT" , false); +corsFilter(url, "Last-Modified", "04 May 1988 22:22:22 GMT", false); +corsFilter(url, "Pragma", "no-cache", false); + +corsFilter(url, "Age", "27", true); +corsFilter(url, "Server", "wptServe" , true); +corsFilter(url, "Warning", "Mind the gap" , true); +corsFilter(url, "Content-Length", "0" , true); +corsFilter(url, "Set-Cookie", "name=value" , true); +corsFilter(url, "Set-Cookie2", "name=value" , true); + +corsExposeFilter(url, "Age", "27", false); +corsExposeFilter(url, "Server", "wptServe" , false); +corsExposeFilter(url, "Warning", "Mind the gap" , false); +corsExposeFilter(url, "Content-Length", "0" , false); +corsExposeFilter(url, "Set-Cookie", "name=value" , true); +corsExposeFilter(url, "Set-Cookie2", "name=value" , true); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins-worker.html new file mode 100644 index 000000000..a8e505732 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins-worker.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: check multiple Access-Control-Allow-Origin header management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-check"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-multiple-origins.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.html b/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.html new file mode 100644 index 000000000..9b12b0506 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: check multiple Access-Control-Allow-Origin header management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-check"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="cors-multiple-origins.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.js b/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.js new file mode 100644 index 000000000..e4cf7245d --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-multiple-origins.js @@ -0,0 +1,32 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function corsMultipleOrigins(desc, originList, shouldPass) { + var urlParameters = "?origin=" + encodeURIComponent(originList.join(", ")); + var url = "http://{{host}}:{{ports[http][1]}}" + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + + if (shouldPass) { + promise_test(function(test) { + return fetch(url + urlParameters).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + }); + }, desc); + } else { + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url + urlParameters)); + }, desc); + } +} +/* Actual origin */ +var origin = "http://{{host}}:{{ports[http][0]}}"; + +corsMultipleOrigins("3 origins allowed, match the 3rd (" + origin + ")", ["\"\"", "http://example.com", origin], true); +corsMultipleOrigins("3 origins allowed, match the 3rd (\"*\")", ["\"\"", "http://example.com", "*"], true); +corsMultipleOrigins("3 origins allowed, match twice (" + origin + ")", ["\"\"", origin, origin], true); +corsMultipleOrigins("3 origins allowed, match twice (\"*\")", ["*", "http://example.com", "*"], true); +corsMultipleOrigins("3 origins allowed, match twice (\"*\" and " + origin + ")", ["*", "http://example.com", origin], true); +corsMultipleOrigins("3 origins allowed, no match", ["", "http://example.com", "https://example2.com"], false); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-no-preflight-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-no-preflight-worker.html new file mode 100644 index 000000000..b65a73e07 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-no-preflight-worker.html @@ -0,0 +1,20 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: CORS request with simple methods and headers</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-method"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-header"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-no-preflight.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-no-preflight.html b/testing/web-platform/tests/fetch/api/cors/cors-no-preflight.html new file mode 100644 index 000000000..5426d5adb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-no-preflight.html @@ -0,0 +1,21 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: CORS request with simple methods and headers</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-method"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-header"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-no-preflight.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-no-preflight.js b/testing/web-platform/tests/fetch/api/cors/cors-no-preflight.js new file mode 100644 index 000000000..f2f3e200e --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-no-preflight.js @@ -0,0 +1,46 @@ +if (this.document === undefined) { + importScripts("/common/utils.js"); + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js") +} + +function corsNoPreflight(desc, baseURL, method, headerName, headerValue) { + + var uuid_token = token(); + var url = baseURL + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + var requestInit = {"mode": "cors", "method": method, "headers":{}}; + if (headerName) + requestInit["headers"][headerName] = headerValue; + + promise_test(function(test) { + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.headers.get("x-did-preflight"), "0", "No preflight request has been made"); + }); + }); + }, desc); +} + +var host_info = get_host_info(); + +corsNoPreflight("Cross domain basic usage [GET]", host_info.HTTP_REMOTE_ORIGIN, "GET"); +corsNoPreflight("Same domain different port [GET]", host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT, "GET"); +corsNoPreflight("Cross domain different port [GET]", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, "GET"); +corsNoPreflight("Cross domain different protocol [GET]", host_info.HTTPS_REMOTE_ORIGIN, "GET"); +corsNoPreflight("Same domain different protocol different port [GET]", host_info.HTTPS_ORIGIN, "GET"); +corsNoPreflight("Cross domain [POST]", host_info.HTTP_REMOTE_ORIGIN, "POST"); +corsNoPreflight("Cross domain [HEAD]", host_info.HTTP_REMOTE_ORIGIN, "HEAD"); +corsNoPreflight("Cross domain [GET] [Accept: */*]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Accept", "*/*"); +corsNoPreflight("Cross domain [GET] [Accept-Language: fr]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Accept-Language", "fr"); +corsNoPreflight("Cross domain [GET] [Content-Language: fr]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Language", "fr"); +corsNoPreflight("Cross domain [GET] [Content-Type: application/x-www-form-urlencoded]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "application/x-www-form-urlencoded"); +corsNoPreflight("Cross domain [GET] [Content-Type: multipart/form-data]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "multipart/form-data"); +corsNoPreflight("Cross domain [GET] [Content-Type: text/plain]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "text/plain"); +corsNoPreflight("Cross domain [GET] [Content-Type: text/plain;charset=utf-8]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "text/plain;charset=utf-8"); +corsNoPreflight("Cross domain [GET] [Content-Type: Text/Plain;charset=utf-8]", host_info.HTTP_REMOTE_ORIGIN, "GET" , "Content-Type", "Text/Plain;charset=utf-8"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-origin-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-origin-worker.html new file mode 100644 index 000000000..e59a0b0bd --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-origin-worker.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: check Access-Control-Allow-Origin header management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-check"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-origin.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-origin.html b/testing/web-platform/tests/fetch/api/cors/cors-origin.html new file mode 100644 index 000000000..87f0dff81 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-origin.html @@ -0,0 +1,20 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: check Access-Control-Allow-Origin header management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-check"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-origin.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-origin.js b/testing/web-platform/tests/fetch/api/cors/cors-origin.js new file mode 100644 index 000000000..c3601eeab --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-origin.js @@ -0,0 +1,56 @@ +if (this.document === undefined) { + importScripts("/common/utils.js"); + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js") +} + +/* If origin is undefined, it is set to fetched url's origin*/ +function corsOrigin(desc, baseURL, method, origin, shouldPass) { + if (!origin) + origin = baseURL; + + var uuid_token = token(); + var urlParameters = "?token=" + uuid_token + "&max_age=0&origin=" + encodeURIComponent(origin) + "&allow_methods=" + method; + var url = baseURL + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + var requestInit = {"mode": "cors", "method": method}; + + promise_test(function(test) { + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + if (shouldPass) { + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + }); + } else { + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + } + }); + }, desc); + +} + +var host_info = get_host_info(); + +/* Actual origin */ +var origin = host_info.HTTP_ORIGIN; + +corsOrigin("Cross domain different subdomain [origin OK]", host_info.HTTP_REMOTE_ORIGIN, "GET", origin, true); +corsOrigin("Cross domain different subdomain [origin KO]", host_info.HTTP_REMOTE_ORIGIN, "GET", undefined, false); +corsOrigin("Same domain different port [origin OK]", host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT, "GET", origin, true); +corsOrigin("Same domain different port [origin KO]", host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT, "GET", undefined, false); +corsOrigin("Cross domain different port [origin OK]", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, "GET", origin, true); +corsOrigin("Cross domain different port [origin KO]", host_info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT, "GET", undefined, false); +corsOrigin("Cross domain different protocol [origin OK]", host_info.HTTPS_REMOTE_ORIGIN, "GET", origin, true); +corsOrigin("Cross domain different protocol [origin KO]", host_info.HTTPS_REMOTE_ORIGIN, "GET", undefined, false); +corsOrigin("Same domain different protocol different port [origin OK]", host_info.HTTPS_ORIGIN, "GET", origin, true); +corsOrigin("Same domain different protocol different port [origin KO]", host_info.HTTPS_ORIGIN, "GET", undefined, false); +corsOrigin("Cross domain [POST] [origin OK]", host_info.HTTP_REMOTE_ORIGIN, "POST", origin, true); +corsOrigin("Cross domain [POST] [origin KO]", host_info.HTTP_REMOTE_ORIGIN, "POST", undefined, false); +corsOrigin("Cross domain [HEAD] [origin OK]", host_info.HTTP_REMOTE_ORIGIN, "HEAD", origin, true); +corsOrigin("Cross domain [HEAD] [origin KO]", host_info.HTTP_REMOTE_ORIGIN, "HEAD", undefined, false); +corsOrigin("CORS preflight [PUT] [origin OK]", host_info.HTTP_REMOTE_ORIGIN, "PUT", origin, true); +corsOrigin("CORS preflight [PUT] [origin KO]", host_info.HTTP_REMOTE_ORIGIN, "PUT", undefined, false); +corsOrigin("Allowed origin: \"\" [origin KO]", host_info.HTTP_REMOTE_ORIGIN, "GET", "" , false); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect-worker.html new file mode 100644 index 000000000..24066c08d --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect-worker.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: redirection handling for cors with preflight</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-preflight-redirect.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect.html new file mode 100644 index 000000000..8f2534037 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: redirection handling for cors with preflight</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-preflight-redirect.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect.js b/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect.js new file mode 100644 index 000000000..f375c0d6e --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-redirect.js @@ -0,0 +1,41 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/utils.js"); + importScripts("/common/get-host-info.sub.js"); +} + +function corsPreflightRedirect(desc, redirectUrl, redirectLocation, redirectStatus, redirectPreflight) { + var uuid_token = token(); + var url = redirectUrl; + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + urlParameters += "&redirect_status=" + redirectStatus; + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + if (redirectPreflight) + urlParameters += "&redirect_preflight"; + var requestInit = {"mode": "cors", "redirect": "follow"}; + + /* Force preflight */ + requestInit["headers"] = {"x-force-preflight": ""}; + urlParameters += "&allow_headers=x-force-preflight"; + + promise_test(function(test) { + fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + }); + }, desc); +} + +var redirectUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "redirect.py"; +var locationUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + +for (var code of [301, 302, 303, 307, 308]) { + /* preflight should not follow the redirection */ + corsPreflightRedirect("Redirection " + code + " on preflight failed", redirectUrl, locationUrl, code, true); + /* preflight is done before redirection: preflight force redirect to error */ + corsPreflightRedirect("Redirection " + code + " after preflight failed", redirectUrl, locationUrl, code, false); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer-worker.html new file mode 100644 index 000000000..6913c7e69 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer-worker.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: Referer header management in CORS request with preflight</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-preflight-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-preflight-referrer.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer.html new file mode 100644 index 000000000..62403caee --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer.html @@ -0,0 +1,19 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: Referer header management in CORS request with preflight</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-preflight-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-preflight-referrer.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer.js b/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer.js new file mode 100644 index 000000000..bb6505058 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-referrer.js @@ -0,0 +1,53 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("/common/utils.js"); + importScripts("/common/get-host-info.sub.js"); + importScripts("../resources/utils.js"); +} + +function corsPreflightReferrer(desc, corsUrl, referrerPolicy, referrer, expectedReferrer) { + var uuid_token = token(); + var url = corsUrl; + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + var requestInit = {"mode": "cors", "referrerPolicy": referrerPolicy}; + + if (referrer) + requestInit.referrer = referrer; + + /* Force preflight */ + requestInit["headers"] = {"x-force-preflight": ""}; + urlParameters += "&allow_headers=x-force-preflight"; + + promise_test(function(test) { + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made"); + assert_equals(resp.headers.get("x-preflight-referrer"), expectedReferrer, "Preflight's referrer is correct"); + assert_equals(resp.headers.get("x-referrer"), expectedReferrer, "Request's referrer is correct"); + assert_equals(resp.headers.get("x-control-request-headers"), "", "Access-Control-Allow-Headers value"); + }); + }); + }, desc + " and referrer: " + (referrer ? "'" + referrer + "'" : "default")); +} + +var corsUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; +var origin = get_host_info().HTTP_ORIGIN + "/"; + +corsPreflightReferrer("Referrer policy: no-referrer", corsUrl, "no-referrer", undefined, ""); +corsPreflightReferrer("Referrer policy: no-referrer", corsUrl, "no-referrer", "myreferrer", ""); + +corsPreflightReferrer("Referrer policy: \"\"", corsUrl, "", undefined, location.toString()) +corsPreflightReferrer("Referrer policy: \"\"", corsUrl, "", "myreferrer", new URL("myreferrer", location).toString()); + +corsPreflightReferrer("Referrer policy: origin", corsUrl, "origin", undefined, origin); +corsPreflightReferrer("Referrer policy: origin", corsUrl, "origin", "myreferrer", origin); + +corsPreflightReferrer("Referrer policy: origin-when-cross-origin", corsUrl, "origin-when-cross-origin", undefined, origin); +corsPreflightReferrer("Referrer policy: origin-when-cross-origin", corsUrl, "origin-when-cross-origin", "myreferrer", origin); + +corsPreflightReferrer("Referrer policy: unsafe-url", corsUrl, "unsafe-url", undefined, location.toString()); +corsPreflightReferrer("Referrer policy: unsafe-url", corsUrl, "unsafe-url", "myreferrer", new URL("myreferrer", location).toString()); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-status-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-status-worker.html new file mode 100644 index 000000000..281d77396 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-status-worker.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: preflight status code handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-preflight-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-preflight-status.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-status.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-status.html new file mode 100644 index 000000000..4b619d6d1 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-status.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: preflight status code handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#cors-preflight-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-preflight-status.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-status.js b/testing/web-platform/tests/fetch/api/cors/cors-preflight-status.js new file mode 100644 index 000000000..5b4b15a9a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-status.js @@ -0,0 +1,42 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/utils.js"); + importScripts("/common/get-host-info.sub.js"); +} + +/* Check preflight is ok if status is ok status (200 to 299)*/ +function corsPreflightStatus(desc, corsUrl, preflightStatus) { + var uuid_token = token(); + var url = corsUrl; + var requestInit = {"mode": "cors"}; + /* Force preflight */ + requestInit["headers"] = {"x-force-preflight": ""}; + + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + urlParameters += "&allow_headers=x-force-preflight"; + urlParameters += "&preflight_status=" + preflightStatus; + + promise_test(function(test) { + fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + if (200 <= preflightStatus && 299 >= preflightStatus) { + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made"); + }); + } else { + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + } + }); + }, desc); +} + +var corsUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; +for (status of [200, 201, 202, 203, 204, 205, 206, + 300, 301, 302, 303, 304, 305, 306, 307, 308, + 400, 401, 402, 403, 404, 405, + 501, 502, 503, 504, 505]) + corsPreflightStatus("Preflight answered with status " + status, corsUrl, status); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight-worker.html new file mode 100644 index 000000000..c80d1e989 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight-worker.html @@ -0,0 +1,20 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: Check cors fetches requiring prefligh</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-method"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-header"> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-preflight.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight.html b/testing/web-platform/tests/fetch/api/cors/cors-preflight.html new file mode 100644 index 000000000..036f2f515 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight.html @@ -0,0 +1,21 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: Check cors fetches requiring preflight</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-cors-protocol"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-method"> + <meta name="help" href="https://fetch.spec.whatwg.org/#simple-header"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="/common/utils.js"></script> + <script src="cors-preflight.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-preflight.js b/testing/web-platform/tests/fetch/api/cors/cors-preflight.js new file mode 100644 index 000000000..24366ff20 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-preflight.js @@ -0,0 +1,103 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("/common/utils.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js"); +} + +function headerNames(headers) +{ + let names = []; + for (let header of headers) + names.push(header[0].toLowerCase()); + return names +} + +/* + Check preflight is done + Control if server allows method and headers and check accordingly + Check control access headers added by UA (for method and headers) +*/ +function corsPreflight(desc, corsUrl, method, allowed, headers, safeHeaders) { + return promise_test(function(test) { + var uuid_token = token(); + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(response) { + var url = corsUrl; + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + var requestInit = {"mode": "cors", "method": method}; + var requestHeaders = []; + if (headers) + requestHeaders.push.apply(requestHeaders, headers); + if (safeHeaders) + requestHeaders.push.apply(requestHeaders, safeHeaders); + requestInit["headers"] = requestHeaders; + + if (allowed) { + urlParameters += "&allow_methods=" + method; + if (headers) { + //Let's check prefligh request. + //Server will send back headers from Access-Control-Request-Headers in x-control-request-headers + urlParameters += "&control_request_headers" + //Make the server allow the headers + urlParameters += "&allow_headers=" + headerNames(headers).join("%20%2C"); + } + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made"); + if (headers) { + var actualHeaders = resp.headers.get("x-control-request-headers").toLowerCase().split(","); + for (var i in actualHeaders) + actualHeaders[i] = actualHeaders[i].trim(); + for (var header of headers) + assert_in_array(header[0].toLowerCase(), actualHeaders, "Preflight asked permission for header: " + header); + + let accessControlAllowHeaders = headerNames(headers).sort().join(","); + assert_equals(resp.headers.get("x-control-request-headers"), accessControlAllowHeaders, "Access-Control-Allow-Headers value"); + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token); + } + }); + } else { + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)).then(function(){ + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token); + }); + } + }); + }, desc); +} + +var corsUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + +corsPreflight("CORS [DELETE], server allows", corsUrl, "DELETE", true); +corsPreflight("CORS [DELETE], server refuses", corsUrl, "DELETE", false); +corsPreflight("CORS [PUT], server allows", corsUrl, "PUT", true); +corsPreflight("CORS [PUT], server refuses", corsUrl, "PUT", false); +corsPreflight("CORS [PATCH], server allows", corsUrl, "PATCH", true); +corsPreflight("CORS [PATCH], server refuses", corsUrl, "PATCH", false); +corsPreflight("CORS [NEW], server allows", corsUrl, "NEW", true); +corsPreflight("CORS [NEW], server refuses", corsUrl, "NEW", false); + +corsPreflight("CORS [GET] [x-test-header: allowed], server allows", corsUrl, "GET", true, [["x-test-header1", "allowed"]]); +corsPreflight("CORS [GET] [x-test-header: refused], server refuses", corsUrl, "GET", false, [["x-test-header1", "refused"]]); + +var headers = [ + ["x-test-header1", "allowedOrRefused"], + ["x-test-header2", "allowedOrRefused"], + ["X-test-header3", "allowedOrRefused"], + ["x-test-header-b", "allowedOrRefused"], + ["x-test-header-D", "allowedOrRefused"], + ["x-test-header-C", "allowedOrRefused"], + ["x-test-header-a", "allowedOrRefused"], + ["Content-Type", "allowedOrRefused"], +]; +var safeHeaders= [ + ["Accept", "*"], + ["Accept-Language", "bzh"], + ["Content-Language", "eu"], +]; + +corsPreflight("CORS [GET] [several headers], server allows", corsUrl, "GET", true, headers, safeHeaders); +corsPreflight("CORS [GET] [several headers], server refuses", corsUrl, "GET", false, headers, safeHeaders); +corsPreflight("CORS [PUT] [several headers], server allows", corsUrl, "PUT", true, headers, safeHeaders); +corsPreflight("CORS [PUT] [several headers], server refuses", corsUrl, "PUT", false, headers, safeHeaders); + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials-worker.html new file mode 100644 index 000000000..38e3e78ac --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: redirection url has credentials</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-redirect-credentials.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials.html b/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials.html new file mode 100644 index 000000000..410c0e491 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: redirection url has credentials</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-redirect-credentials.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials.js b/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials.js new file mode 100644 index 000000000..1b3fe5d4b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-credentials.js @@ -0,0 +1,50 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js") +} + +function corsRedirectCredentials(desc, redirectUrl, redirectLocation, redirectStatus, locationCredentials) { + + var url = redirectUrl + var urlParameters = "?redirect_status=" + redirectStatus; + urlParameters += "&location=" + encodeURIComponent(redirectLocation.replace("://", "://" + locationCredentials + "@")); + + var requestInit = {"mode": "cors", "redirect": "follow", "credentials":"include"}; + + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + }, desc); +} + +var redirPath = dirname(location.pathname) + RESOURCES_DIR + "redirect.py"; +var preflightPath = dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + +var host_info = get_host_info(); + +var localRedirect = host_info.HTTP_ORIGIN + redirPath; +var remoteRedirect = host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT + redirPath; + +var localLocation = host_info.HTTP_ORIGIN + preflightPath; +var remoteLocation = host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT + preflightPath; +var remoteLocation2 = host_info.HTTP_REMOTE_ORIGIN + preflightPath; + +for (var code of [301, 302, 303, 307, 308]) { + corsRedirectCredentials("Redirect " + code + " from same origin to remote with user and password", localRedirect, remoteLocation, code, "user:password"); + corsRedirectCredentials("Redirect " + code + " from same origin to remote with user", localRedirect, remoteLocation, code, "user:"); + corsRedirectCredentials("Redirect " + code + " from same origin to remote with password", localRedirect, remoteLocation, code, ":password"); + + corsRedirectCredentials("Redirect " + code + " from remote to same origin with user and password", remoteRedirect, localLocation, code, "user:password"); + corsRedirectCredentials("Redirect " + code + " from remote to same origin with user", remoteRedirect, localLocation, code, "user:"); + corsRedirectCredentials("Redirect " + code + " from remote to same origin with password", remoteRedirect, localLocation, code, ":password"); + + corsRedirectCredentials("Redirect " + code + " from remote to same remote with user and password", remoteRedirect, remoteLocation, code, "user:password"); + corsRedirectCredentials("Redirect " + code + " from remote to same remote with user", remoteRedirect, remoteLocation, code, "user:"); + corsRedirectCredentials("Redirect " + code + " from remote to same remote with password", remoteRedirect, remoteLocation, code, ":password"); + + corsRedirectCredentials("Redirect " + code + " from remote to another remote with user and password", remoteRedirect, remoteLocation2, code, "user:password"); + corsRedirectCredentials("Redirect " + code + " from remote to another remote with user", remoteRedirect, remoteLocation2, code, "user:"); + corsRedirectCredentials("Redirect " + code + " from remote to another remote with password", remoteRedirect, remoteLocation2, code, ":password"); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight-worker.html new file mode 100644 index 000000000..d7d83a510 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight-worker.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: CORS preflight after redirection</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-redirect-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-redirect-preflight.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight.html b/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight.html new file mode 100644 index 000000000..172f52e79 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: CORS preflight after redirection</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-redirect-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="../resources/utils.js"></script> + <script src="cors-redirect-preflight.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight.js b/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight.js new file mode 100644 index 000000000..9b9f8b92f --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-preflight.js @@ -0,0 +1,50 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("/common/utils.js"); + importScripts("/common/get-host-info.sub.js"); + importScripts("../resources/utils.js"); +} + +function corsRedirect(desc, redirectUrl, redirectLocation, redirectStatus, expectSuccess) { + var urlBaseParameters = "&redirect_status=" + redirectStatus; + var urlParametersSuccess = urlBaseParameters + "&allow_headers=x-w3c&location=" + encodeURIComponent(redirectLocation + "?allow_headers=x-w3c"); + var urlParametersFailure = urlBaseParameters + "&location=" + encodeURIComponent(redirectLocation); + + var requestInit = {"mode": "cors", "redirect": "follow", "headers" : [["x-w3c", "test"]]}; + + promise_test(function(test) { + var uuid_token = token(); + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + return fetch(redirectUrl + "?token=" + uuid_token + "&max_age=0" + urlParametersSuccess, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made"); + }); + }); + }, desc + " (preflight after redirection success case)"); + promise_test(function(test) { + var uuid_token = token(); + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + return promise_rejects(test, new TypeError(), fetch(redirectUrl + "?token=" + uuid_token + "&max_age=0" + urlParametersFailure, requestInit)); + }); + }, desc + " (preflight after redirection failure case)"); +} + +var redirPath = dirname(location.pathname) + RESOURCES_DIR + "redirect.py"; +var preflightPath = dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + +var host_info = get_host_info(); + +var localRedirect = host_info.HTTP_ORIGIN + redirPath; +var remoteRedirect = host_info.HTTP_REMOTE_ORIGIN + redirPath; + +var localLocation = host_info.HTTP_ORIGIN + preflightPath; +var remoteLocation = host_info.HTTP_REMOTE_ORIGIN + preflightPath; +var remoteLocation2 = host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT + preflightPath; + +for (var code of [301, 302, 303, 307, 308]) { + corsRedirect("Redirect " + code + ": same origin to cors", localRedirect, remoteLocation, code); + corsRedirect("Redirect " + code + ": cors to same origin", remoteRedirect, localLocation, code); + corsRedirect("Redirect " + code + ": cors to another cors", remoteRedirect, remoteLocation2, code); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect-worker.html b/testing/web-platform/tests/fetch/api/cors/cors-redirect-worker.html new file mode 100644 index 000000000..9f8dfb022 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: CORS Redirection with several origins</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cors-redirect.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect.html b/testing/web-platform/tests/fetch/api/cors/cors-redirect.html new file mode 100644 index 000000000..87424f432 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: CORS Redirection with several origins</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="cors-redirect.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/cors/cors-redirect.js b/testing/web-platform/tests/fetch/api/cors/cors-redirect.js new file mode 100644 index 000000000..75f67e7ee --- /dev/null +++ b/testing/web-platform/tests/fetch/api/cors/cors-redirect.js @@ -0,0 +1,47 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("/common/utils.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js"); +} + +function corsRedirect(desc, redirectUrl, redirectLocation, redirectStatus, expectedOrigin) { + var uuid_token = token(); + var url = redirectUrl; + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + urlParameters += "&redirect_status=" + redirectStatus; + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + var requestInit = {"mode": "cors", "redirect": "follow"}; + + return promise_test(function(test) { + fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.headers.get("x-did-preflight"), "0", "No preflight request has been made"); + assert_equals(resp.headers.get("x-origin"), expectedOrigin, "Origin is correctly set after redirect"); + }); + }); + }, desc); +} + +var redirPath = dirname(location.pathname) + RESOURCES_DIR + "redirect.py"; +var preflightPath = dirname(location.pathname) + RESOURCES_DIR + "preflight.py"; + +var host_info = get_host_info(); + +var localRedirect = host_info.HTTP_ORIGIN + redirPath; +var remoteRedirect = host_info.HTTP_REMOTE_ORIGIN + redirPath; + +var localLocation = host_info.HTTP_ORIGIN + preflightPath; +var remoteLocation = host_info.HTTP_REMOTE_ORIGIN + preflightPath; +var remoteLocation2 = host_info.HTTP_ORIGIN_WITH_DIFFERENT_PORT + preflightPath; + +for (var code of [301, 302, 303, 307, 308]) { + corsRedirect("Redirect " + code + ": cors to same cors", remoteRedirect, remoteLocation, code, location.origin); + corsRedirect("Redirect " + code + ": cors to another cors", remoteRedirect, remoteLocation2, code, "null"); + corsRedirect("Redirect " + code + ": same origin to cors", localRedirect, remoteLocation, code, location.origin); + corsRedirect("Redirect " + code + ": cors to same origin", remoteRedirect, localLocation, code, "null"); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/credentials/authentication-basic-worker.html b/testing/web-platform/tests/fetch/api/credentials/authentication-basic-worker.html new file mode 100644 index 000000000..e9ced4f10 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/credentials/authentication-basic-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: Authorisation header management for basic authentication</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("authentication-basic.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/credentials/authentication-basic.html b/testing/web-platform/tests/fetch/api/credentials/authentication-basic.html new file mode 100644 index 000000000..cba1ecd4a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/credentials/authentication-basic.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: Authorisation header management for basic authentication</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="authentication-basic.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/credentials/authentication-basic.js b/testing/web-platform/tests/fetch/api/credentials/authentication-basic.js new file mode 100644 index 000000000..ce93e9d7b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/credentials/authentication-basic.js @@ -0,0 +1,21 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function basicAuth(desc, user, pass, mode, status) { + promise_test(function(test) { + var headers = { "Authorization": "Basic " + btoa(user + ":" + pass)}; + var requestInit = {"credentials": mode, "headers": headers}; + return fetch(RESOURCES_DIR + "authentication.py?realm=test", requestInit).then(function(resp) { + assert_equals(resp.status, status, "HTTP status is " + status); + assert_equals(resp.type , "basic", "Response's type is basic"); + }); + }, desc); +} + +basicAuth("User-added Authorization header with include mode", "user", "password", "include", 200); +basicAuth("User-added Authorization header with same-origin mode", "user", "password", "same-origin", 200); +basicAuth("User-added Authorization header with omit mode", "user", "password", "omit", 200); + +done(); diff --git a/testing/web-platform/tests/fetch/api/credentials/cookies-worker.html b/testing/web-platform/tests/fetch/api/credentials/cookies-worker.html new file mode 100644 index 000000000..86febf10b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/credentials/cookies-worker.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: cookies management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("cookies.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/credentials/cookies.html b/testing/web-platform/tests/fetch/api/credentials/cookies.html new file mode 100644 index 000000000..72913029a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/credentials/cookies.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: cookies management</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="cookies.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/credentials/cookies.js b/testing/web-platform/tests/fetch/api/credentials/cookies.js new file mode 100644 index 000000000..c63505349 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/credentials/cookies.js @@ -0,0 +1,53 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function cookies(desc, credentials1, credentials2 ,cookies) { + var url = RESOURCES_DIR + "top.txt" + var urlParameters = ""; + var urlCleanParameters = ""; + if (cookies) { + urlParameters +="?pipe=header(Set-Cookie,"; + urlParameters += cookies.join(",True)|header(Set-Cookie,") + ",True)"; + urlCleanParameters +="?pipe=header(Set-Cookie,"; + urlCleanParameters += cookies.join("%3B%20max-age=0,True)|header(Set-Cookie,") + "%3B%20max-age=0,True)"; + } + + var requestInit = {"credentials": credentials1} + promise_test(function(test){ + var requestInit = {"credentials": credentials1} + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + //check cookies sent + return fetch(RESOURCES_DIR + "inspect-headers.py?headers=cookie" , {"credentials": credentials2}); + }).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + assert_false(resp.headers.has("Cookie") , "Cookie header is not exposed in response"); + if (credentials1 != "omit" && credentials2 != "omit") { + assert_equals(resp.headers.get("x-request-cookie") , cookies.join("; "), "Request include cookie(s)"); + } + else { + assert_false(resp.headers.has("x-request-cookie") , "Request does not have cookie(s)"); + } + //clean cookies + return fetch(url + urlCleanParameters, {"credentials": "include"}); + }).catch(function(e) { + return fetch(url + urlCleanParameters, {"credentials": "include"}).then(function() { + return Promise.reject(e); + }); + }); + }, desc); +} + +cookies("Include mode: 1 cookie", "include", "include", ["a=1"]); +cookies("Include mode: 2 cookies", "include", "include", ["b=2", "c=3"]); +cookies("Omit mode: discard cookies", "omit", "omit", ["d=4"]); +cookies("Omit mode: no cookie is stored", "omit", "include", ["e=5"]); +cookies("Omit mode: no cookie is sent", "include", "omit", ["f=6"]); +cookies("Same-origin mode: 1 cookie", "same-origin", "same-origin", ["a=1"]); +cookies("Same-origin mode: 2 cookies", "same-origin", "same-origin", ["b=2", "c=3"]); + +done(); diff --git a/testing/web-platform/tests/fetch/api/headers/headers-basic.html b/testing/web-platform/tests/fetch/api/headers/headers-basic.html new file mode 100644 index 000000000..98d71acad --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-basic.html @@ -0,0 +1,221 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers structure</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#headers"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + test(function() { + new Headers(); + }, "Create headers from no parameter"); + + test(function() { + new Headers(undefined); + }, "Create headers from undefined parameter"); + + test(function() { + new Headers({}); + }, "Create headers from empty object"); + + var parameters = [null, 1]; + parameters.forEach(function(parameter) { + test(function() { + assert_throws(new TypeError(), function() { new Headers(parameter) }); + }, "Create headers with " + parameter + " should throw"); + }); + + var headerDict = {"name1": "value1", + "name2": "value2", + "name3": "value3", + "name4": null, + "name5": undefined, + "name6": 1, + "Content-Type": "value4" + }; + + var headerSeq = []; + for (var name in headerDict) + headerSeq.push([name, headerDict[name]]); + + test(function() { + var headers = new Headers(headerSeq); + for (name in headerDict) { + assert_equals(headers.get(name), String(headerDict[name]), + "name: " + name + " has value: " + headerDict[name]); + } + assert_equals(headers.get("length"), null, "init should be treated as a sequence, not as a dictionary"); + }, "Create headers with sequence"); + + test(function() { + var headers = new Headers(headerDict); + for (name in headerDict) { + assert_equals(headers.get(name), String(headerDict[name]), + "name: " + name + " has value: " + headerDict[name]); + } + }, "Create headers with OpenEndedDictionary"); + + test(function() { + var headers = new Headers(headerDict); + var headers2 = new Headers(headers); + for (name in headerDict) { + assert_equals(headers2.get(name), String(headerDict[name]), + "name: " + name + " has value: " + headerDict[name]); + } + }, "Create headers with existing headers"); + + test(function() { + var headers = new Headers(); + for (name in headerDict) { + headers.append(name, headerDict[name]); + assert_equals(headers.get(name), String(headerDict[name]), + "name: " + name + " has value: " + headerDict[name]); + } + }, "Check append method"); + + test(function() { + var headers = new Headers(); + for (name in headerDict) { + headers.set(name, headerDict[name]); + assert_equals(headers.get(name), String(headerDict[name]), + "name: " + name + " has value: " + headerDict[name]); + } + }, "Check set method"); + + test(function() { + var headers = new Headers(headerDict); + for (name in headerDict) + assert_true(headers.has(name),"headers has name " + name); + + assert_false(headers.has("nameNotInHeaders"),"headers do not have header: nameNotInHeaders"); + }, "Check has method"); + + test(function() { + var headers = new Headers(headerDict); + for (name in headerDict) { + assert_true(headers.has(name),"headers have a header: " + name); + headers.delete(name) + assert_true(!headers.has(name),"headers do not have anymore a header: " + name); + } + }, "Check delete method"); + + test(function() { + var headers = new Headers(headerDict); + for (name in headerDict) + assert_equals(headers.get(name), String(headerDict[name]), + "name: " + name + " has value: " + headerDict[name]); + + assert_equals(headers.get("nameNotInHeaders"), null, "header: nameNotInHeaders has no value"); + }, "Check get method"); + + var headerEntriesDict = {"name1": "value1", + "Name2": "value2", + "name": "value3", + "content-Type": "value4", + "Content-Typ": "value5", + "Content-Types": "value6" + }; + var sortedHeaderDict = {}; + var headerValues = []; + var sortedHeaderKeys = Object.keys(headerEntriesDict).map(function(value) { + sortedHeaderDict[value.toLowerCase()] = headerEntriesDict[value]; + headerValues.push(headerEntriesDict[value]); + return value.toLowerCase(); + }).sort(); + + var iteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); + function checkIteratorProperties(iterator) { + var prototype = Object.getPrototypeOf(iterator); + assert_equals(Object.getPrototypeOf(prototype), iteratorPrototype); + + var descriptor = Object.getOwnPropertyDescriptor(prototype, "next"); + assert_true(descriptor.configurable, "configurable"); + assert_true(descriptor.enumerable, "enumerable"); + assert_true(descriptor.writable, "writable"); + } + + test(function() { + var headers = new Headers(headerEntriesDict); + var actual = headers.keys(); + checkIteratorProperties(actual); + + sortedHeaderKeys.forEach(function(key) { + entry = actual.next(); + assert_false(entry.done); + assert_equals(entry.value, key); + }); + assert_true(actual.next().done); + assert_true(actual.next().done); + + for (key of headers.keys()) + assert_true(sortedHeaderKeys.indexOf(key) != -1); + }, "Check keys method"); + + test(function() { + var headers = new Headers(headerEntriesDict); + var actual = headers.values(); + checkIteratorProperties(actual); + + sortedHeaderKeys.forEach(function(key) { + entry = actual.next(); + assert_false(entry.done); + assert_equals(entry.value, sortedHeaderDict[key]); + }); + assert_true(actual.next().done); + assert_true(actual.next().done); + + for (value of headers.values()) + assert_true(headerValues.indexOf(value) != -1); + }, "Check values method"); + + test(function() { + var headers = new Headers(headerEntriesDict); + var actual = headers.entries(); + checkIteratorProperties(actual); + + sortedHeaderKeys.forEach(function(key) { + entry = actual.next(); + assert_false(entry.done); + assert_equals(entry.value[0], key); + assert_equals(entry.value[1], sortedHeaderDict[key]); + }); + assert_true(actual.next().done); + assert_true(actual.next().done); + + for (entry of headers.entries()) + assert_equals(entry[1], sortedHeaderDict[entry[0]]); + }, "Check entries method"); + + test(function() { + var headers = new Headers(headerEntriesDict); + var actual = headers[Symbol.iterator](); + + sortedHeaderKeys.forEach(function(key) { + entry = actual.next(); + assert_false(entry.done); + assert_equals(entry.value[0], key); + assert_equals(entry.value[1], sortedHeaderDict[key]); + }); + assert_true(actual.next().done); + assert_true(actual.next().done); + }, "Check Symbol.iterator method"); + + test(function() { + var headers = new Headers(headerEntriesDict); + var reference = sortedHeaderKeys[Symbol.iterator](); + headers.forEach(function(value, key, container) { + assert_equals(headers, container); + entry = reference.next(); + assert_false(entry.done); + assert_equals(key, entry.value); + assert_equals(value, sortedHeaderDict[entry.value]); + }); + assert_true(reference.next().done); + }, "Check forEach method"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/headers/headers-casing.html b/testing/web-platform/tests/fetch/api/headers/headers-casing.html new file mode 100644 index 000000000..1e505d81c --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-casing.html @@ -0,0 +1,64 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers case management</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-header-list-append"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var headerDictCase = {"UPPERCASE": "value1", + "lowercase": "value2", + "mixedCase": "value3", + "Content-TYPE": "value4" + }; + + function checkHeadersCase(originalName, headersToCheck, expectedDict) { + var lowCaseName = originalName.toLowerCase(); + var upCaseName = originalName.toUpperCase(); + var expectedValue = expectedDict[originalName]; + assert_equals(headersToCheck.get(originalName), expectedValue, + "name: " + originalName + " has value: " + expectedValue); + assert_equals(headersToCheck.get(lowCaseName), expectedValue, + "name: " + lowCaseName + " has value: " + expectedValue); + assert_equals(headersToCheck.get(upCaseName), expectedValue, + "name: " + upCaseName + " has value: " + expectedValue); + } + + test(function() { + var headers = new Headers(headerDictCase); + for (name in headerDictCase) + checkHeadersCase(name, headers, headerDictCase) + }, "Create headers, names use characters with different case"); + + test(function() { + var headers = new Headers(); + for (name in headerDictCase) { + headers.append(name, headerDictCase[name]); + checkHeadersCase(name, headers, headerDictCase); + } + }, "Check append method, names use characters with different case"); + + test(function() { + var headers = new Headers(); + for (name in headerDictCase) { + headers.set(name, headerDictCase[name]); + checkHeadersCase(name, headers, headerDictCase); + } + }, "Check set method, names use characters with different case"); + + test(function() { + var headers = new Headers(); + for (name in headerDictCase) + headers.set(name, headerDictCase[name]); + for (name in headerDictCase) + headers.delete(name.toLowerCase()); + for (name in headerDictCase) + assert_false(headers.has(name), "header " + name + " should have been deleted"); + }, "Check delete method, names use characters with different case"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/headers/headers-combine.html b/testing/web-platform/tests/fetch/api/headers/headers-combine.html new file mode 100644 index 000000000..a0c15b0fe --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-combine.html @@ -0,0 +1,60 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers nameshake</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#headers"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var headerSeqCombine = [["single", "singleValue"], + ["double", "doubleValue1"], + ["double", "doubleValue2"], + ["triple", "tripleValue1"], + ["triple", "tripleValue2"], + ["triple", "tripleValue3"] + ]; + var expectedDict = {"single": "singleValue", + "double": "doubleValue1,doubleValue2", + "triple": "tripleValue1,tripleValue2,tripleValue3" + }; + + test(function() { + var headers = new Headers(headerSeqCombine); + for (name in expectedDict) + assert_equals(headers.get(name), expectedDict[name], + "name: " + name + " has value: " + expectedDict[name]); + }, "Create headers using same name for different values"); + + test(function() { + var headers = new Headers(headerSeqCombine); + for (name in expectedDict) { + assert_true(headers.has(name), "name: " + name + " has value(s)"); + headers.delete(name); + assert_false(headers.has(name), "name: " + name + " has no value(s) anymore"); + } + }, "Check delete and has methods when using same name for different values"); + + test(function() { + var headers = new Headers(headerSeqCombine); + for (name in expectedDict) { + headers.set(name,"newSingleValue"); + assert_equals(headers.get(name), "newSingleValue", "name: " + name + " has value: newSingleValue"); + } + }, "Check set methods when called with already used name"); + + test(function() { + var headers = new Headers(headerSeqCombine); + for (name in expectedDict) { + var value = headers.get(name); + headers.append(name,"newSingleValue"); + assert_equals(headers.get(name), (value + "," + "newSingleValue"), + "name: " + name + " has value: " + headers.get(name)); + } + }, "Check append methods when called with already used name"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/headers/headers-errors.html b/testing/web-platform/tests/fetch/api/headers/headers-errors.html new file mode 100644 index 000000000..194ff32f1 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-errors.html @@ -0,0 +1,107 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers errors</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#headers"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + + test(function() { + assert_throws(new TypeError() , function() { new Headers([["name"]]); }); + }, "Create headers giving an array having one string as init argument"); + + test(function() { + assert_throws(new TypeError() , function() { new Headers([["invalid", "invalidValue1", "invalidValue2"]]); }); + }, "Create headers giving an array having three strings as init argument"); + + test(function() { + assert_throws(new TypeError() , function() { new Headers([["invalidĀ", "Value1"]]); }); + }, "Create headers giving bad header name as init argument"); + + test(function() { + assert_throws(new TypeError() , function() { new Headers([["name", "invalidValueĀ"]]); }); + }, "Create headers giving bad header value as init argument"); + + var badNames = ["invalidĀ", {}]; + var badValues = ["invalidĀ"]; + + badNames.forEach(function(name) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.get(name); }); + }, "Check headers get with an invalid name " + name); + }); + + badNames.forEach(function(name) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.delete(name); }); + }, "Check headers delete with an invalid name " + name); + }); + + badNames.forEach(function(name) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.has(name); }); + }, "Check headers has with an invalid name " + name); + }); + + badNames.forEach(function(name) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.set(name, "Value1"); }); + }, "Check headers set with an invalid name " + name); + }); + + badValues.forEach(function(value) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.set("name", value); }); + }, "Check headers set with an invalid value " + value); + }); + + badNames.forEach(function(name) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.append("invalidĀ", "Value1"); }); + }, "Check headers append with an invalid name " + name); + }); + + badValues.forEach(function(value) { + test(function() { + var headers = new Headers(); + assert_throws(new TypeError() , function() { headers.append("name", value); }); + }, "Check headers append with an invalid value " + value); + }); + + test(function() { + var headers = new Headers([["name", "value"]]); + assert_throws(new TypeError() , function() { headers.forEach(); }); + assert_throws(new TypeError() , function() { headers.forEach(undefined); }); + assert_throws(new TypeError() , function() { headers.forEach(1); }); + }, "Headers forEach throws if argument is not callable"); + + test(function() { + var headers = new Headers([["name1", "value1"], ["name2", "value2"], ["name3", "value3"]]); + var counter = 0; + try { + headers.forEach(function(value, name) { + counter++; + if (name == "name2") + throw "error"; + }); + } catch (e) { + assert_equals(counter, 2); + assert_equals(e, "error"); + return; + } + assert_unreached(); + }, "Headers forEach loop should stop if callback is throwing exception"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/headers/headers-idl.html b/testing/web-platform/tests/fetch/api/headers/headers-idl.html new file mode 100644 index 000000000..2aaa1ceea --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-idl.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers idl interface</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/WebIDLParser.js"></script> + <script src="/resources/idlharness.js"></script> + </head> + <body> + <script id="headers-idl" type="text/plain"> + typedef (Headers or sequence<sequence<ByteString>> or OpenEndedDictionary<ByteString>) HeadersInit; + + [Constructor(optional HeadersInit init), + Exposed=(Window,Worker)] + interface Headers { + void append(ByteString name, ByteString value); + void delete(ByteString name); + ByteString? get(ByteString name); + boolean has(ByteString name); + void set(ByteString name, ByteString value); + iterable<ByteString, ByteString>; + }; + </script> + <script> + var idlsArray = new IdlArray(); + var idl = document.getElementById("headers-idl").innerHTML + idlsArray.add_idls(idl); + idlsArray.add_objects({ Headers: ['new Headers()'] }); + idlsArray.test(); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/headers/headers-normalize.html b/testing/web-platform/tests/fetch/api/headers/headers-normalize.html new file mode 100644 index 000000000..6dfcf9d81 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-normalize.html @@ -0,0 +1,47 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers normalize values</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-header-value-normalize"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var headerDictWS = {"name1": " space ", + "name2": "\ttab\t", + "name3": " spaceAndTab\t", + "name4": "\r\n newLine", //obs-fold cases + "name5": "newLine\r\n ", + "name6": "\r\n\tnewLine", + }; + + test(function() { + var headers = new Headers(headerDictWS); + for (name in headerDictWS) + assert_equals(headers.get(name), headerDictWS[name].trim(), + "name: " + name + " has normalized value: " + headerDictWS[name].trim()); + }, "Create headers with not normalized values"); + + test(function() { + var headers = new Headers(); + for (name in headerDictWS) { + headers.append(name, headerDictWS[name]); + assert_equals(headers.get(name), headerDictWS[name].trim(), + "name: " + name + " has value: " + headerDictWS[name].trim()); + } + }, "Check append method with not normalized values"); + + test(function() { + var headers = new Headers(); + for (name in headerDictWS) { + headers.set(name, headerDictWS[name]); + assert_equals(headers.get(name), headerDictWS[name].trim(), + "name: " + name + " has value: " + headerDictWS[name].trim()); + } + }, "Check set method with not normalized values"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/headers/headers-structure.html b/testing/web-platform/tests/fetch/api/headers/headers-structure.html new file mode 100644 index 000000000..9448e450c --- /dev/null +++ b/testing/web-platform/tests/fetch/api/headers/headers-structure.html @@ -0,0 +1,31 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Headers basic</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#headers"> + <meta name="help" href="https://heycam.github.io/webidl/#idl-iterable"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var headers = new Headers(); + var methods = ["append", + "delete", + "get", + "has", + "set", + //Headers is iterable + "entries", + "keys", + "values" + ]; + for (var idx in methods) + test(function() { + assert_true(methods[idx] in headers, "headers has " + methods[idx] + " method"); + }, "Headers has " + methods[idx] + " method"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/policies/csp-blocked-worker.html b/testing/web-platform/tests/fetch/api/policies/csp-blocked-worker.html new file mode 100644 index 000000000..e8660dffa --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/csp-blocked-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: blocked by CSP</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("csp-blocked.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/csp-blocked.html b/testing/web-platform/tests/fetch/api/policies/csp-blocked.html new file mode 100644 index 000000000..99e90dfcd --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/csp-blocked.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: blocked by CSP</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="csp-blocked.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/csp-blocked.html.headers b/testing/web-platform/tests/fetch/api/policies/csp-blocked.html.headers new file mode 100644 index 000000000..c8c1e9ffb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/csp-blocked.html.headers @@ -0,0 +1 @@ +Content-Security-Policy: connect-src 'none';
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/csp-blocked.js b/testing/web-platform/tests/fetch/api/policies/csp-blocked.js new file mode 100644 index 000000000..0395304b8 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/csp-blocked.js @@ -0,0 +1,13 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +//Content-Security-Policy: connect-src 'none'; cf .headers file +cspViolationUrl = RESOURCES_DIR + "top.txt"; + +promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(cspViolationUrl)); +}, "Fetch is blocked by CSP, got a TypeError"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/policies/csp-blocked.js.headers b/testing/web-platform/tests/fetch/api/policies/csp-blocked.js.headers new file mode 100644 index 000000000..c8c1e9ffb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/csp-blocked.js.headers @@ -0,0 +1 @@ +Content-Security-Policy: connect-src 'none';
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer-worker.html b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer-worker.html new file mode 100644 index 000000000..dbef9bb65 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: referrer with no-referrer policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("referrer-no-referrer.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.html b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.html new file mode 100644 index 000000000..22a6f34c5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: referrer with no-referrer policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="referrer-no-referrer.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.html.headers b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.html.headers new file mode 100644 index 000000000..7ffbf17d6 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.html.headers @@ -0,0 +1 @@ +Referrer-Policy: no-referrer diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.js b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.js new file mode 100644 index 000000000..60600bf08 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.js @@ -0,0 +1,19 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +var fetchedUrl = RESOURCES_DIR + "inspect-headers.py?headers=origin"; + +promise_test(function(test) { + return fetch(fetchedUrl).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + var referrer = resp.headers.get("x-request-referer"); + //Either no referrer header is sent or it is empty + if (referrer) + assert_equals(referrer, "", "request's referrer is empty"); + }); +}, "Request's referrer is empty"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.js.headers b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.js.headers new file mode 100644 index 000000000..7ffbf17d6 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-no-referrer.js.headers @@ -0,0 +1 @@ +Referrer-Policy: no-referrer diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin-worker.html b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin-worker.html new file mode 100644 index 000000000..f95ae8cf0 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: referrer with origin-when-cross-origin policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("referrer-origin-when-cross-origin.js?pipe=sub")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.html b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.html new file mode 100644 index 000000000..18de73646 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: referrer with origin-when-cross-origin policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="referrer-origin-when-cross-origin.js?pipe=sub"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.html.headers b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.html.headers new file mode 100644 index 000000000..ad768e632 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.html.headers @@ -0,0 +1 @@ +Referrer-Policy: origin-when-cross-origin diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.js b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.js new file mode 100644 index 000000000..2baf7d125 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.js @@ -0,0 +1,16 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +var referrerOrigin = "http://{{host}}:{{ports[http][0]}}/"; +var fetchedUrl = "http://{{host}}:{{ports[http][1]}}" + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?cors&headers=referer"; + +promise_test(function(test) { + return fetch(fetchedUrl).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.headers.get("x-request-referer"), referrerOrigin, "request's referrer is " + referrerOrigin); + }); +}, "Request's referrer is origin"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.js.headers b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.js.headers new file mode 100644 index 000000000..ad768e632 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin-when-cross-origin.js.headers @@ -0,0 +1 @@ +Referrer-Policy: origin-when-cross-origin diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin-worker.html b/testing/web-platform/tests/fetch/api/policies/referrer-origin-worker.html new file mode 100644 index 000000000..bb80dd54f --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: referrer with origin policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("referrer-origin.js?pipe=sub")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin.html b/testing/web-platform/tests/fetch/api/policies/referrer-origin.html new file mode 100644 index 000000000..92baed79b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: referrer with origin policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="referrer-origin.js?pipe=sub"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin.html.headers b/testing/web-platform/tests/fetch/api/policies/referrer-origin.html.headers new file mode 100644 index 000000000..5b29739bb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin.html.headers @@ -0,0 +1 @@ +Referrer-Policy: origin diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin.js b/testing/web-platform/tests/fetch/api/policies/referrer-origin.js new file mode 100644 index 000000000..8f63072ff --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin.js @@ -0,0 +1,22 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +var referrerOrigin = "http://{{host}}:{{ports[http][0]}}/"; +var fetchedUrl = RESOURCES_DIR + "inspect-headers.py?headers=referer"; + +promise_test(function(test) { + return fetch(fetchedUrl).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + assert_equals(resp.headers.get("x-request-referer"), referrerOrigin, "request's referrer is " + referrerOrigin); + }); +}, "Request's referrer is origin"); + +promise_test(function(test) { + var referrerUrl = "http://{{domains[www]}}:{{ports[http][0]}}/"; + return promise_rejects(test, new TypeError(), fetch(fetchedUrl, { "referrer": referrerUrl})); +}, "Throw a TypeError referrer is not same-origin with origin"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-origin.js.headers b/testing/web-platform/tests/fetch/api/policies/referrer-origin.js.headers new file mode 100644 index 000000000..5b29739bb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-origin.js.headers @@ -0,0 +1 @@ +Referrer-Policy: origin diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url-worker.html b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url-worker.html new file mode 100644 index 000000000..42045776b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: referrer with unsafe-url policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("referrer-unsafe-url.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.html b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.html new file mode 100644 index 000000000..10dd79e3d --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: referrer with unsafe-url policy</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="referrer-unsafe-url.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.html.headers b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.html.headers new file mode 100644 index 000000000..8e23770bd --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.html.headers @@ -0,0 +1 @@ +Referrer-Policy: unsafe-url diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.js b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.js new file mode 100644 index 000000000..b593fad5a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.js @@ -0,0 +1,17 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +var referrerUrl = location.href; +var fetchedUrl = RESOURCES_DIR + "inspect-headers.py?headers=referer"; + +promise_test(function(test) { + return fetch(fetchedUrl).then(function(resp) { + assert_equals(resp.status, 200, "HTTP status is 200"); + assert_equals(resp.type , "basic", "Response's type is basic"); + assert_equals(resp.headers.get("x-request-referer"), referrerUrl, "request's referrer is " + referrerUrl); + }); +}, "Request's referrer is the full url of current document/worker"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.js.headers b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.js.headers new file mode 100644 index 000000000..8e23770bd --- /dev/null +++ b/testing/web-platform/tests/fetch/api/policies/referrer-unsafe-url.js.headers @@ -0,0 +1 @@ +Referrer-Policy: unsafe-url diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-count-worker.html b/testing/web-platform/tests/fetch/api/redirect/redirect-count-worker.html new file mode 100644 index 000000000..1ce33b7c4 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-count-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: rediraction loop</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("redirect-count.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-count.html b/testing/web-platform/tests/fetch/api/redirect/redirect-count.html new file mode 100644 index 000000000..d6a66e6eb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-count.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: redirection loop</title> + <meta name="timeout" content="long"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="redirect-count.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-count.js b/testing/web-platform/tests/fetch/api/redirect/redirect-count.js new file mode 100644 index 000000000..ffa521a5c --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-count.js @@ -0,0 +1,42 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/utils.js"); +} + +function redirectCount(desc, redirectUrl, redirectLocation, redirectStatus, maxCount, shouldPass) { + var uuid_token = token(); + + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + urlParameters += "&redirect_status=" + redirectStatus; + urlParameters += "&max_count=" + maxCount; + if (redirectLocation) + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + var url = redirectUrl; + var requestInit = {"redirect": "follow"}; + + promise_test(function(test) { + fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + + if (!shouldPass) + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + }); + }).then(function(body) { + assert_equals(body, maxCount.toString(), "Redirected " + maxCount + "times"); + }); + }, desc); +} + +var redirUrl = RESOURCES_DIR + "redirect.py"; + +for (var statusCode of [301, 302, 303, 307, 308]) { + redirectCount("Redirect " + statusCode + " 20 times", redirUrl, redirUrl, statusCode, 20, true); + redirectCount("Redirect " + statusCode + " 21 times", redirUrl, redirUrl, statusCode, 21, false); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-location-worker.html b/testing/web-platform/tests/fetch/api/redirect/redirect-location-worker.html new file mode 100644 index 000000000..e2970811c --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-location-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: handling Location header during redirection</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("redirect-location.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-location.html b/testing/web-platform/tests/fetch/api/redirect/redirect-location.html new file mode 100644 index 000000000..ac35dea54 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-location.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: handling Location header during redirection</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="redirect-location.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-location.js b/testing/web-platform/tests/fetch/api/redirect/redirect-location.js new file mode 100644 index 000000000..0297250b5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-location.js @@ -0,0 +1,50 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function redirectLocation(desc, redirectUrl, redirectLocation, redirectStatus, redirectMode, shouldPass) { + var url = redirectUrl; + var urlParameters = "?redirect_status=" + redirectStatus; + if (redirectLocation) + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + var requestInit = {"redirect": redirectMode}; + + promise_test(function(test) { + if (redirectMode === "error" || !shouldPass) + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + if (redirectLocation && redirectMode === "manual") + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 0, "Response's status is 0"); + assert_equals(resp.type, "opaqueredirect", "Response's type is opaqueredirect"); + assert_equals(resp.statusText, "", "Response's statusText is \"\""); + assert_true(resp.headers.entries().next().done, "Headers should be empty"); + }); + + if (redirectMode === "manual" || redirectMode === "follow") + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, redirectStatus, "Response's status is " + redirectStatus); + }); + assert_unreached(redirectMode + " is not a valid redirect mode"); + }, desc); +} + +var redirUrl = RESOURCES_DIR + "redirect.py"; +var locationUrl = "top.txt"; +var invalidLocationUrl = "#invalidurl:"; +var dataLocationUrl = "data:,data%20url"; +// FIXME: We may want to mix redirect-mode and cors-mode. +// FIXME: Add tests for "error" redirect-mode. +for (var statusCode of [301, 302, 303, 307, 308]) { + redirectLocation("Redirect " + statusCode + " in \"follow\" mode without location", redirUrl, undefined, statusCode, "follow", true); + redirectLocation("Redirect " + statusCode + " in \"manual\" mode without location", redirUrl, undefined, statusCode, "manual", true); + + redirectLocation("Redirect " + statusCode + " in \"follow\" mode with invalid location", redirUrl, invalidLocationUrl, statusCode, "follow", false); + redirectLocation("Redirect " + statusCode + " in \"manual\" mode with invalid location", redirUrl, invalidLocationUrl, statusCode, "manual", true); + + redirectLocation("Redirect " + statusCode + " in \"follow\" mode with data location", redirUrl, dataLocationUrl, statusCode, "follow", false); + redirectLocation("Redirect " + statusCode + " in \"manual\" mode with data location", redirUrl, dataLocationUrl, statusCode, "manual", true); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-method-worker.html b/testing/web-platform/tests/fetch/api/redirect/redirect-method-worker.html new file mode 100644 index 000000000..fc0bc5e52 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-method-worker.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: request method handling when redirected</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("redirect-method.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-method.html b/testing/web-platform/tests/fetch/api/redirect/redirect-method.html new file mode 100644 index 000000000..028842dbe --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-method.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: request method handling when redirected</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script src="redirect-method.js"></script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-method.js b/testing/web-platform/tests/fetch/api/redirect/redirect-method.js new file mode 100644 index 000000000..13433a1bb --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-method.js @@ -0,0 +1,55 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); +} + +function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, method, expectedMethod) { + var url = redirectUrl; + var urlParameters = "?redirect_status=" + redirectStatus; + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + var requestInit = {"method": method, "redirect": "follow"}; + if (method != "GET" && method != "HEAD") + requestInit.body = "this is my body"; + + promise_test(function(test) { + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_equals(resp.type, "basic", "Response's type basic"); + assert_equals(resp.headers.get("x-request-method"), expectedMethod, "Request method after redirection is " + expectedMethod); + assert_true(resp.redirected); + return resp.text().then(function(text) { + assert_equals(text, expectedMethod == "POST" ? requestInit.body : ""); + }); + }); + }, desc); +} + +promise_test(function(test) { + assert_false(new Response().redirected); + return fetch(RESOURCES_DIR + "method.py").then(function(resp) { + assert_equals(resp.status, 200, "Response's status is 200"); + assert_false(resp.redirected); + }); +}, "Response.redirected should be false on not-redirected responses"); + +var redirUrl = RESOURCES_DIR + "redirect.py"; +var locationUrl = "method.py"; + +redirectMethod("Redirect 301 with GET", redirUrl, locationUrl, 301, "GET", "GET"); +redirectMethod("Redirect 301 with POST", redirUrl, locationUrl, 301, "POST", "GET"); +redirectMethod("Redirect 301 with HEAD", redirUrl, locationUrl, 301, "HEAD", "HEAD"); + +redirectMethod("Redirect 302 with GET", redirUrl, locationUrl, 302, "GET", "GET"); +redirectMethod("Redirect 302 with POST", redirUrl, locationUrl, 302, "POST", "GET"); +redirectMethod("Redirect 302 with HEAD", redirUrl, locationUrl, 302, "HEAD", "HEAD"); + +redirectMethod("Redirect 303 with GET", redirUrl, locationUrl, 303, "GET", "GET"); +redirectMethod("Redirect 303 with POST", redirUrl, locationUrl, 303, "POST", "GET"); +redirectMethod("Redirect 303 with HEAD", redirUrl, locationUrl, 303, "HEAD", "HEAD"); + +redirectMethod("Redirect 307 with GET", redirUrl, locationUrl, 307, "GET", "GET"); +redirectMethod("Redirect 307 with POST", redirUrl, locationUrl, 307, "POST", "POST"); +redirectMethod("Redirect 307 with HEAD", redirUrl, locationUrl, 307, "HEAD", "HEAD"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-mode-worker.html b/testing/web-platform/tests/fetch/api/redirect/redirect-mode-worker.html new file mode 100644 index 000000000..32d219f76 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-mode-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: redirect mode handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("redirect-mode.js")); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-mode.html b/testing/web-platform/tests/fetch/api/redirect/redirect-mode.html new file mode 100644 index 000000000..20a0cd68a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-mode.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: redirect mode handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/get-host-info.sub.js"></script> + <script src="redirect-mode.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-mode.js b/testing/web-platform/tests/fetch/api/redirect/redirect-mode.js new file mode 100644 index 000000000..b59a8d57b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-mode.js @@ -0,0 +1,41 @@ +if (this.document === undefined) { + importScripts("/resources/testharness.js"); + importScripts("/common/get-host-info.sub.js") +} + +function redirectMode(desc, redirectUrl, redirectLocation, redirectStatus, redirectMode) { + var url = redirectUrl; + var urlParameters = "?redirect_status=" + redirectStatus; + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + var requestInit = {"redirect": redirectMode}; + + promise_test(function(test) { + if (redirectMode === "error") + return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)); + if (redirectMode === "manual") + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_equals(resp.status, 0, "Response's status is 0"); + assert_equals(resp.type, "opaqueredirect", "Response's type is opaqueredirect"); + assert_equals(resp.statusText, "", "Response's statusText is \"\""); + assert_equals(resp.url, url + urlParameters, "Response URL should be the original one"); + }); + if (redirectMode === "follow") + return fetch(url + urlParameters, requestInit).then(function(resp) { + assert_true(new URL(resp.url).pathname.endsWith(locationUrl), "Response's url should be the redirected one"); + assert_equals(resp.status, 200, "Response's status is 200"); + }); + assert_unreached(redirectMode + " is no a valid redirect mode"); + }, desc); +} + +var redirUrl = get_host_info().HTTP_ORIGIN + "/fetch/api/resources/redirect.py"; +var locationUrl = "top.txt"; + +for (var statusCode of [301, 302, 303, 307, 308]) { + redirectMode("Redirect " + statusCode + " in \"error\" mode ", redirUrl, locationUrl, statusCode, "error"); + redirectMode("Redirect " + statusCode + " in \"follow\" mode ", redirUrl, locationUrl, statusCode, "follow"); + redirectMode("Redirect " + statusCode + " in \"manual\" mode ", redirUrl, locationUrl, statusCode, "manual"); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-origin-worker.html b/testing/web-platform/tests/fetch/api/redirect/redirect-origin-worker.html new file mode 100644 index 000000000..fdb542237 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-origin-worker.html @@ -0,0 +1,17 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: redirect mode handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("redirect-origin.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-origin.html b/testing/web-platform/tests/fetch/api/redirect/redirect-origin.html new file mode 100644 index 000000000..4cbe1c07d --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-origin.html @@ -0,0 +1,18 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: redirect mode handling</title> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect"> + <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/utils.js"></script> + <script src="../resources/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + <script src="redirect-origin.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-origin.js b/testing/web-platform/tests/fetch/api/redirect/redirect-origin.js new file mode 100644 index 000000000..77f841e94 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-origin.js @@ -0,0 +1,40 @@ +if (this.document === undefined) { + importScripts("/common/utils.js"); + importScripts("/resources/testharness.js"); + importScripts("../resources/utils.js"); + importScripts("/common/get-host-info.sub.js"); +} + +function testOriginAfterRedirection(desc, redirectUrl, redirectLocation, redirectStatus, expectedOrigin) { + var uuid_token = token(); + var url = redirectUrl; + var urlParameters = "?token=" + uuid_token + "&max_age=0"; + urlParameters += "&redirect_status=" + redirectStatus; + urlParameters += "&location=" + encodeURIComponent(redirectLocation); + + var requestInit = {"mode": "cors", "redirect": "follow"}; + + promise_test(function(test) { + return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(resp) { + assert_equals(resp.status, 200, "Clean stash response's status is 200"); + return fetch(url + urlParameters, requestInit).then(function(response) { + assert_equals(response.status, 200, "Inspect header response's status is 200"); + assert_equals(response.headers.get("x-request-origin"), expectedOrigin, "Check origin header"); + }); + }); + }, desc); +} + +var redirectUrl = RESOURCES_DIR + "redirect.py"; +var corsRedirectUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "redirect.py"; +var locationUrl = get_host_info().HTTP_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?headers=origin"; +var corsLocationUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?cors&headers=origin"; + +for (var code of [301, 302, 303, 307, 308]) { + testOriginAfterRedirection("Same origin to same origin redirection " + code, redirectUrl, locationUrl, code, null); + testOriginAfterRedirection("Same origin to other origin redirection " + code, redirectUrl, corsLocationUrl, code, get_host_info().HTTP_ORIGIN); + testOriginAfterRedirection("Other origin to other origin redirection " + code, corsRedirectUrl, corsLocationUrl, code, get_host_info().HTTP_ORIGIN); + testOriginAfterRedirection("Other origin to same origin redirection " + code, corsRedirectUrl, locationUrl + "&cors", code, "null"); +} + +done(); diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-schemes.html b/testing/web-platform/tests/fetch/api/redirect/redirect-schemes.html new file mode 100644 index 000000000..cffec19d5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-schemes.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Fetch: handling different schemes in redirects</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> + // All non-HTTP(S) schemes cannot survive redirects + var url = "../resources/redirect.py?location="; + var tests = [ + url + "mailto:a@a.com", + url + "data:,HI", + url + "facetime:a@a.org", + url + "about:blank", + url + "about:unicorn", + url + "blob:djfksfjs" + ]; + tests.forEach(function(url) { + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url)) + }) + }) +</script> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl-worker.html b/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl-worker.html new file mode 100644 index 000000000..428f5135e --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl-worker.html @@ -0,0 +1,14 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch in worker: data URL loading after redirections</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + fetch_tests_from_worker(new Worker("redirect-to-dataurl.js")); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.html b/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.html new file mode 100644 index 000000000..ed7159f41 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.html @@ -0,0 +1,13 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Fetch: data URL loading after redirections</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="/common/get-host-info.sub.js"></script> + <script src="redirect-to-dataurl.js"></script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.js b/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.js new file mode 100644 index 000000000..c3bae3f6b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/redirect/redirect-to-dataurl.js @@ -0,0 +1,30 @@ +if (this.document === undefined) { + importScripts("/common/get-host-info.sub.js") + importScripts("/resources/testharness.js"); +} + +var dataURL = "data:text/plain;base64,cmVzcG9uc2UncyBib2R5"; +var body = "response's body"; +var contentType = "text/plain"; + +function redirectDataURL(desc, redirectUrl, mode) { + var url = redirectUrl + "?cors&location=" + encodeURIComponent(dataURL); + + var requestInit = {"mode": mode}; + + promise_test(function(test) { + return promise_rejects(test, new TypeError(), fetch(url, requestInit)); + }, desc); +} + +var redirUrl = get_host_info().HTTP_ORIGIN + "/fetch/api/resources/redirect.py"; +var corsRedirUrl = get_host_info().HTTP_REMOTE_ORIGIN + "/fetch/api/resources/redirect.py"; + +redirectDataURL("Testing data URL loading after same-origin redirection (cors mode)", redirUrl, "cors"); +redirectDataURL("Testing data URL loading after same-origin redirection (no-cors mode)", redirUrl, "no-cors"); +redirectDataURL("Testing data URL loading after same-origin redirection (same-origin mode)", redirUrl, "same-origin"); + +redirectDataURL("Testing data URL loading after cross-origin redirection (cors mode)", corsRedirUrl, "cors"); +redirectDataURL("Testing data URL loading after cross-origin redirection (no-cors mode)", corsRedirUrl, "no-cors"); + +done(); diff --git a/testing/web-platform/tests/fetch/api/request/request-cache.html b/testing/web-platform/tests/fetch/api/request/request-cache.html new file mode 100644 index 000000000..f2c442a54 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-cache.html @@ -0,0 +1,626 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request cache</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="timeout" content="long"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/common/utils.js"></script> + <script src="/common/get-host-info.sub.js"></script> + </head> + <body> + <script> + var now = new Date(); + /** + * Each test is run twice: once using etag/If-None-Match and once with + * date/If-Modified-Since. Each test run gets its own URL and randomized + * content and operates independently. + * + * The test steps are run with request_cache.length fetch requests issued + * and their immediate results sanity-checked. The cache.py server script + * stashes an entry containing any If-None-Match, If-Modified-Since, Pragma, + * and Cache-Control observed headers for each request it receives. When + * the test fetches have run, this state is retrieved from cache.py and the + * expected_* lists are checked, including their length. + * + * This means that if a request_* fetch is expected to hit the cache and not + * touch the network, then there will be no entry for it in the expect_* + * lists. AKA (request_cache.length - expected_validation_headers.length) + * should equal the number of cache hits that didn't touch the network. + * + * Test dictionary keys: + * - state: required string that determines whether the Expires response for + * the fetched document should be set in the future ("fresh") or past + * ("stale"). + * - vary: optional string to be passed to the server for it to quote back + * in a Vary header on the response to us. + * - cache_control: optional string to be passed to the server for it to + * quote back in a Cache-Control header on the response to us. + * - redirect: optional string "same-origin" or "cross-origin". If + * provided, the server will issue an absolute redirect to the script on + * the same or a different origin, as appropriate. The redirected + * location is the script with the redirect parameter removed, so the + * content/state/etc. will be as if you hadn't specified a redirect. + * - request_cache: required array of cache modes to use (via `cache`). + * - request_headers: optional array of explicit fetch `headers` arguments. + * If provided, the server will log an empty dictionary for each request + * instead of the request headers it would normally log. + * - response: optional array of specialized response handling. Right now, + * "error" array entries indicate a network error response is expected + * which will reject with a TypeError. + * - expected_validation_headers: required boolean array indicating whether + * the server should have seen an If-None-Match/If-Modified-Since header + * in the request. + * - expected_no_cache_headers: required boolean array indicating whether + * the server should have seen Pragma/Cache-control:no-cache headers in + * the request. + * - expected_max_age_headers: optional boolean array indicating whether + * the server should have seen a Cache-Control:max-age=0 header in the + * request. + */ + var tests = [ + { + name: 'RequestCache "default" mode checks the cache for previously cached content and goes to the network for stale responses', + state: "stale", + request_cache: ["default", "default"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "default" mode checks the cache for previously cached content and avoids going to the network if a fresh response exists', + state: "fresh", + request_cache: ["default", "default"], + expected_validation_headers: [false], + expected_no_cache_headers: [false], + }, + { + name: 'RequestCache "no-cache" mode revalidates stale responses found in the cache', + state: "stale", + request_cache: ["default", "no-cache"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [false, false], + expected_max_age_headers: [false, true], + }, + { + name: 'RequestCache "no-cache" mode revalidates fresh responses found in the cache', + state: "fresh", + request_cache: ["default", "no-cache"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [false, false], + expected_max_age_headers: [false, true], + }, + { + name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for stale responses', + state: "stale", + request_cache: ["default", "force-cache"], + expected_validation_headers: [false], + expected_no_cache_headers: [false], + }, + { + name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for fresh responses', + state: "fresh", + request_cache: ["default", "force-cache"], + expected_validation_headers: [false], + expected_no_cache_headers: [false], + }, + { + name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found', + state: "stale", + request_cache: ["force-cache"], + expected_validation_headers: [false], + expected_no_cache_headers: [false], + }, + { + name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found', + state: "fresh", + request_cache: ["force-cache"], + expected_validation_headers: [false], + expected_no_cache_headers: [false], + }, + { + name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary', + state: "stale", + vary: "*", + request_cache: ["default", "force-cache"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary', + state: "fresh", + vary: "*", + request_cache: ["default", "force-cache"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network', + state: "stale", + request_cache: ["force-cache", "default"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network', + state: "fresh", + request_cache: ["force-cache", "default"], + expected_validation_headers: [false], + expected_no_cache_headers: [false], + }, + { + name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and avoids revalidation for stale responses', + state: "stale", + request_cache: ["default", "only-if-cached"], + expected_validation_headers: [false], + expected_no_cache_headers: [false] + }, + { + name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and avoids revalidation for fresh responses', + state: "fresh", + request_cache: ["default", "only-if-cached"], + expected_validation_headers: [false], + expected_no_cache_headers: [false] + }, + { + name: 'RequestCache "only-if-cached" mode checks the cache for previously cached content and does not go to the network if a cached response is not found', + state: "fresh", + request_cache: ["only-if-cached"], + response: ["error"], + expected_validation_headers: [], + expected_no_cache_headers: [] + }, + { + name: 'RequestCache "only-if-cached" (with "same-origin") uses cached same-origin redirects to same-origin content', + state: "fresh", + request_cache: ["default", "only-if-cached"], + redirect: "same-origin", + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "only-if-cached" (with "same-origin") uses cached same-origin redirects to same-origin content', + state: "stale", + request_cache: ["default", "only-if-cached"], + redirect: "same-origin", + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "only-if-cached" (with "same-origin") does not follow redirects across origins and rejects', + state: "fresh", + request_cache: ["default", "only-if-cached"], + redirect: "cross-origin", + response: [null, "error"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "only-if-cached" (with "same-origin") does not follow redirects across origins and rejects', + state: "stale", + request_cache: ["default", "only-if-cached"], + redirect: "cross-origin", + response: [null, "error"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless', + state: "stale", + request_cache: ["default", "no-store"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless', + state: "fresh", + request_cache: ["default", "no-store"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "no-store" mode does not store the response in the cache', + state: "stale", + request_cache: ["no-store", "default"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "no-store" mode does not store the response in the cache', + state: "fresh", + request_cache: ["no-store", "default"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Modified-Since": now.toGMTString()}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Modified-Since": now.toGMTString()}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{"If-Modified-Since": now.toGMTString()}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{"If-Modified-Since": now.toGMTString()}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{}, {"If-None-Match": '"foo"'}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{}, {"If-None-Match": '"foo"'}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{"If-None-Match": '"foo"'}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{"If-None-Match": '"foo"'}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Match": '"foo"'}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Match": '"foo"'}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{"If-Match": '"foo"'}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{"If-Match": '"foo"'}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Range": '"foo"'}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{}, {"If-Range": '"foo"'}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"', + state: "stale", + request_cache: ["default", "default"], + request_headers: [{"If-Range": '"foo"'}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"', + state: "fresh", + request_cache: ["default", "default"], + request_headers: [{"If-Range": '"foo"'}, {}], + expected_validation_headers: [false, false], + expected_no_cache_headers: [true, false], + }, + { + name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache', + state: "stale", + cache_control: "no-store", + request_cache: ["default", "default"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, false], + }, + { + name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache', + state: "fresh", + cache_control: "no-store", + request_cache: ["default", "default"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, false], + }, + { + name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless', + state: "stale", + request_cache: ["default", "reload"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless', + state: "fresh", + request_cache: ["default", "reload"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + { + name: 'RequestCache "reload" mode does store the response in the cache', + state: "stale", + request_cache: ["reload", "default"], + expected_validation_headers: [false, true], + expected_no_cache_headers: [true, false], + }, + { + name: 'RequestCache "reload" mode does store the response in the cache', + state: "fresh", + request_cache: ["reload", "default"], + expected_validation_headers: [false], + expected_no_cache_headers: [true], + }, + { + name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored', + state: "stale", + request_cache: ["default", "reload", "default"], + expected_validation_headers: [false, false, true], + expected_no_cache_headers: [false, true, false], + }, + { + name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored', + state: "fresh", + request_cache: ["default", "reload", "default"], + expected_validation_headers: [false, false], + expected_no_cache_headers: [false, true], + }, + ]; + function base_path() { + return location.pathname.replace(/\/[^\/]*$/, '/'); + } + function make_url(uuid, id, value, content, info) { + var dates = { + fresh: new Date(now.getFullYear() + 1, now.getMonth(), now.getDay()).toGMTString(), + stale: new Date(now.getFullYear() - 1, now.getMonth(), now.getDay()).toGMTString(), + }; + var vary = ""; + if ("vary" in info) { + vary = "&vary=" + info.vary; + } + var cache_control = ""; + if ("cache_control" in info) { + cache_control = "&cache_control=" + info.cache_control; + } + var redirect = ""; + + var ignore_request_headers = ""; + if ("request_headers" in info) { + // Ignore the request headers that we send since they may be synthesized by the test. + ignore_request_headers = "&ignore"; + } + var url_sans_redirect = "resources/cache.py?token=" + uuid + + "&content=" + content + + "&" + id + "=" + value + + "&expires=" + dates[info.state] + + vary + cache_control + ignore_request_headers; + // If there's a redirect, the target is the script without any redirect at + // either the same domain or a different domain. + if ("redirect" in info) { + var host_info = get_host_info(); + var origin; + switch (info.redirect) { + case "same-origin": + origin = host_info['HTTP_ORIGIN']; + break; + case "cross-origin": + origin = host_info['HTTP_REMOTE_ORIGIN']; + break; + } + var redirected_url = origin + base_path() + url_sans_redirect; + return url_sans_redirect + "&redirect=" + encodeURIComponent(redirected_url); + } else { + return url_sans_redirect; + } + } + function expected_status(type, identifier, init) { + if (type == "date" && + init.headers && + init.headers["If-Modified-Since"] == identifier) { + // The server will respond with a 304 in this case. + return [304, "Not Modified"]; + } + return [200, "OK"]; + } + function expected_response_text(type, identifier, init, content) { + if (type == "date" && + init.headers && + init.headers["If-Modified-Since"] == identifier) { + // The server will respond with a 304 in this case. + return ""; + } + return content; + } + function server_state(uuid) { + return fetch("resources/cache.py?querystate&token=" + uuid) + .then(function(response) { + return response.text(); + }).then(function(text) { + // null will be returned if the server never received any requests + // for the given uuid. Normalize that to an empty list consistent + // with our representation. + return JSON.parse(text) || []; + }); + } + function make_test(type, info) { + return function(test) { + var uuid = token(); + var identifier = (type == "tag" ? Math.random() : now.toGMTString()); + var content = Math.random().toString(); + var url = make_url(uuid, type, identifier, content, info); + var fetch_functions = []; + for (var i = 0; i < info.request_cache.length; ++i) { + fetch_functions.push(function(idx) { + var init = {cache: info.request_cache[idx]}; + if ("request_headers" in info) { + init.headers = info.request_headers[idx]; + } + if (init.cache === "only-if-cached") { + // only-if-cached requires we use same-origin mode. + init.mode = "same-origin"; + } + return fetch(url, init) + .then(function(response) { + if ("response" in info && info.response[idx] === "error") { + assert_true(false, "fetch should have been an error"); + return; + } + assert_array_equals([response.status, response.statusText], + expected_status(type, identifier, init)); + return response.text(); + }).then(function(text) { + assert_equals(text, expected_response_text(type, identifier, init, content)); + }, function(reason) { + if ("response" in info && info.response[idx] === "error") { + assert_throws(new TypeError(), function() { throw reason; }); + } else { + throw reason; + } + }); + }); + } + var i = 0; + function run_next_step() { + if (fetch_functions.length) { + return fetch_functions.shift()(i++) + .then(run_next_step); + } else { + return Promise.resolve(); + } + } + return run_next_step() + .then(function() { + // Now, query the server state + return server_state(uuid); + }).then(function(state) { + var expectedState = []; + info.expected_validation_headers.forEach(function (validate) { + if (validate) { + if (type == "tag") { + expectedState.push({"If-None-Match": '"' + identifier + '"'}); + } else { + expectedState.push({"If-Modified-Since": identifier}); + } + } else { + expectedState.push({}); + } + }); + for (var i = 0; i < info.expected_no_cache_headers.length; ++i) { + if (info.expected_no_cache_headers[i]) { + expectedState[i]["Pragma"] = "no-cache"; + expectedState[i]["Cache-Control"] = "no-cache"; + } + } + if ("expected_max_age_headers" in info) { + for (var i = 0; i < info.expected_max_age_headers.length; ++i) { + if (info.expected_max_age_headers[i]) { + expectedState[i]["Cache-Control"] = "max-age=0"; + } + } + } + assert_equals(state.length, expectedState.length); + for (var i = 0; i < state.length; ++i) { + for (var header in state[i]) { + assert_equals(state[i][header], expectedState[i][header]); + delete expectedState[i][header]; + } + for (var header in expectedState[i]) { + assert_false(header in state[i]); + } + } + }); + }; + } + tests.forEach(function(info) { + promise_test(make_test("tag", info), info.name + " with Etag and " + info.state + " response"); + promise_test(make_test("date", info), info.name + " with date and " + info.state + " response"); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-clone.sub.html b/testing/web-platform/tests/fetch/api/request/request-clone.sub.html new file mode 100644 index 000000000..c690bb3dc --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-clone.sub.html @@ -0,0 +1,63 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request clone</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="../resources/utils.js"></script> + </head> + <body> + <script> + var headers = new Headers({"name" : "value"}); + var emptyHeaders = new Headers(); + + var initValuesDict = {"method" : "POST", + "referrer" : "http://{{host}}:{{ports[http][0]}}/", + "referrerPolicy" : "origin", + "mode" : "same-origin", + "credentials" : "include", + "cache" : "no-cache", + "redirect" : "error", + "integrity" : "Request's Integrity", + "headers" : headers, + "body" : "Request's body" + }; + + var expectedInitialized = {"method" : "POST", + "referrer" : "http://{{host}}:{{ports[http][0]}}/", + "referrerPolicy" : "origin", + "mode" : "same-origin", + "credentials" : "include", + "cache" : "no-cache", + "redirect" : "error", + "integrity" : "Request's Integrity", + "headers" : headers, + "body" : "Request's body" + }; + + test(function() { + var RequestInitialized = new Request("", initValuesDict); + var requestToCheck = RequestInitialized.clone(); + checkRequest(requestToCheck, expectedInitialized); + }, "Check cloning a request"); + + test(function() { + var initialRequest = new Request("", {"headers" : new Headers({"a": "1", "b" : "2"})}); + var request = initialRequest.clone(); + assert_equals(request.headers.get("a"), "1", "cloned request should have header 'a'"); + assert_equals(request.headers.get("b"), "2", "cloned request should have header 'b'"); + + initialRequest.headers.delete("a"); + assert_equals(request.headers.get("a"), "1", "cloned request should still have header 'a'"); + + request.headers.delete("a"); + assert_equals(initialRequest.headers.get("b"), "2", "initial request should have header 'b'"); + + }, "Check cloning a request copies the headers"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-consume-empty.html b/testing/web-platform/tests/fetch/api/request/request-consume-empty.html new file mode 100644 index 000000000..a2bb3e2a9 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-consume-empty.html @@ -0,0 +1,103 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request consume empty bodies</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + function checkBodyText(request) { + return request.text().then(function(bodyAsText) { + assert_equals(bodyAsText, "", "Resolved value should be empty"); + assert_false(request.bodyUsed); + }); + } + + function checkBodyBlob(request) { + return request.blob().then(function(bodyAsBlob) { + var promise = new Promise(function(resolve, reject) { + var reader = new FileReader(); + reader.onload = function(evt) { + resolve(reader.result) + }; + reader.onerror = function() { + reject("Blob's reader failed"); + }; + reader.readAsText(bodyAsBlob); + }); + return promise.then(function(body) { + assert_equals(body, "", "Resolved value should be empty"); + assert_false(request.bodyUsed); + }); + }); + } + + function checkBodyArrayBuffer(request) { + return request.arrayBuffer().then(function(bodyAsArrayBuffer) { + assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty"); + assert_false(request.bodyUsed); + }); + } + + function checkBodyJSON(request) { + return request.json().then( + function(bodyAsJSON) { + assert_unreached("JSON parsing should fail"); + }, + function() { + assert_false(request.bodyUsed); + }); + } + + function checkBodyFormData(request) { + return request.formData().then(function(bodyAsFormData) { + assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData"); + assert_false(request.bodyUsed); + }); + } + + function checkRequestWithNoBody(bodyType, checkFunction) { + promise_test(function(test) { + var request = new Request("", {"method": "POST"}); + assert_false(request.bodyUsed); + return checkFunction(request); + }, "Consume request's body as " + bodyType); + } + + var formData = new FormData(); + checkRequestWithNoBody("text", checkBodyText); + checkRequestWithNoBody("blob", checkBodyBlob); + checkRequestWithNoBody("arrayBuffer", checkBodyArrayBuffer); + checkRequestWithNoBody("json", checkBodyJSON); + checkRequestWithNoBody("formData", checkBodyFormData); + + function checkRequestWithEmptyBody(bodyType, body, asText) { + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": body}); + assert_false(request.bodyUsed, "bodyUsed is false at init"); + if (asText) { + return request.text().then(function(bodyAsString) { + assert_equals(bodyAsString.length, 0, "Resolved value should be empty"); + assert_true(request.bodyUsed, "bodyUsed is true after being consumed"); + }); + } + return request.arrayBuffer().then(function(bodyAsArrayBuffer) { + assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty"); + assert_true(request.bodyUsed, "bodyUsed is true after being consumed"); + }); + }, "Consume empty " + bodyType + " request body as " + (asText ? "text" : "arrayBuffer")); + } + + // FIXME: Add BufferSource, FormData and URLSearchParams. + checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), false); + checkRequestWithEmptyBody("text", "", false); + checkRequestWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true); + checkRequestWithEmptyBody("text", "", true); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-consume.html b/testing/web-platform/tests/fetch/api/request/request-consume.html new file mode 100644 index 000000000..9ac70412a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-consume.html @@ -0,0 +1,158 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request consume</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="../resources/utils.js"></script> + </head> + <body> + <script> + function checkBodyText(request, expectedBody) { + return request.text().then(function(bodyAsText) { + assert_equals(bodyAsText, expectedBody, "Retrieve and verify request's body"); + assert_true(request.bodyUsed, "body as text: bodyUsed turned true"); + }); + } + + function checkBodyBlob(request, expectedBody, checkContentType) { + return request.blob().then(function(bodyAsBlob) { + if (checkContentType) + assert_equals(bodyAsBlob.type, "text/plain", "Blob body type should be computed from the request Content-Type"); + + var promise = new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.onload = function(evt) { + resolve(reader.result) + }; + reader.onerror = function() { + reject("Blob's reader failed"); + }; + reader.readAsText(bodyAsBlob); + }); + return promise.then(function(body) { + assert_equals(body, expectedBody, "Retrieve and verify request's body"); + assert_true(request.bodyUsed, "body as blob: bodyUsed turned true"); + }); + }); + } + + function checkBodyArrayBuffer(request, expectedBody) { + return request.arrayBuffer().then(function(bodyAsArrayBuffer) { + validateBufferFromString(bodyAsArrayBuffer, expectedBody, "Retrieve and verify request's body"); + assert_true(request.bodyUsed, "body as arrayBuffer: bodyUsed turned true"); + }); + } + + function checkBodyJSON(request, expectedBody) { + return request.json().then(function(bodyAsJSON) { + var strBody = JSON.stringify(bodyAsJSON) + assert_equals(strBody, expectedBody, "Retrieve and verify request's body"); + assert_true(request.bodyUsed, "body as json: bodyUsed turned true"); + }); + } + + function checkBodyFormData(request, expectedBody) { + return request.formData().then(function(bodyAsFormData) { + assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData"); + assert_true(request.bodyUsed, "body as formData: bodyUsed turned true"); + }); + } + + function checkRequestBody(body, expected, bodyType) { + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": body, "headers": [["Content-Type", "text/PLAIN"]] }); + assert_false(request.bodyUsed, "bodyUsed is false at init"); + return checkBodyText(request, expected); + }, "Consume " + bodyType + " request's body as text"); + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": body }); + assert_false(request.bodyUsed, "bodyUsed is false at init"); + return checkBodyBlob(request, expected); + }, "Consume " + bodyType + " request's body as blob"); + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": body }); + assert_false(request.bodyUsed, "bodyUsed is false at init"); + return checkBodyArrayBuffer(request, expected); + }, "Consume " + bodyType + " request's body as arrayBuffer"); + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": body }); + assert_false(request.bodyUsed, "bodyUsed is false at init"); + return checkBodyJSON(request, expected); + }, "Consume " + bodyType + " request's body as JSON"); + } + + var textData = JSON.stringify("This is response's body"); + var blob = new Blob([textData], { "type" : "text/plain" }); + + checkRequestBody(textData, textData, "String"); + + var string = "\"123456\""; + function getArrayBuffer() { + var arrayBuffer = new ArrayBuffer(8); + var int8Array = new Int8Array(arrayBuffer); + for (var cptr = 0; cptr < 8; cptr++) + int8Array[cptr] = string.charCodeAt(cptr); + return arrayBuffer; + } + + function getArrayBufferWithZeros() { + var arrayBuffer = new ArrayBuffer(10); + var int8Array = new Int8Array(arrayBuffer); + for (var cptr = 0; cptr < 8; cptr++) + int8Array[cptr + 1] = string.charCodeAt(cptr); + return arrayBuffer; + } + + checkRequestBody(getArrayBuffer(), string, "ArrayBuffer"); + checkRequestBody(new Uint8Array(getArrayBuffer()), string, "Uint8Array"); + checkRequestBody(new Int8Array(getArrayBufferWithZeros(), 1, 8), string, "Int8Array"); + checkRequestBody(new Float32Array(getArrayBuffer()), string, "Float32Array"); + checkRequestBody(new DataView(getArrayBufferWithZeros(), 1, 8), string, "DataView"); + + promise_test(function(test) { + var formData = new FormData(); + formData.append("name", "value") + var request = new Request("", {"method": "POST", "body": formData }); + assert_false(request.bodyUsed, "bodyUsed is false at init"); + return checkBodyFormData(request, formData); + }, "Consume FormData request's body as FormData"); + + function checkBlobResponseBody(blobBody, blobData, bodyType, checkFunction) { + promise_test(function(test) { + var response = new Response(blobBody); + assert_false(response.bodyUsed, "bodyUsed is false at init"); + return checkFunction(response, blobData); + }, "Consume blob response's body as " + bodyType); + } + + checkBlobResponseBody(blob, textData, "blob", checkBodyBlob); + checkBlobResponseBody(blob, textData, "text", checkBodyText); + checkBlobResponseBody(blob, textData, "json", checkBodyJSON); + checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer); + checkBlobResponseBody(new Blob([""]), "", "blob (empty blob as input)", checkBodyBlob); + + var goodJSONValues = ["null", "1", "true", "\"string\""]; + goodJSONValues.forEach(function(value) { + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": value}); + return request.json().then(function(v) { + assert_equals(v, JSON.parse(value)); + }); + }, "Consume JSON from text: '" + JSON.stringify(value) + "'"); + }); + + var badJSONValues = ["undefined", "{", "a", "["]; + badJSONValues.forEach(function(value) { + promise_test(function(test) { + var request = new Request("", {"method": "POST", "body": value}); + return promise_rejects(test, new SyntaxError(), request.json()); + }, "Trying to consume bad JSON text as JSON: '" + value + "'"); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-disturbed.html b/testing/web-platform/tests/fetch/api/request/request-disturbed.html new file mode 100644 index 000000000..dbc218e50 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-disturbed.html @@ -0,0 +1,77 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request disturbed</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var initValuesDict = {"method" : "POST", + "body" : "Request's body" + }; + + var noBodyConsumed = new Request(""); + noBodyConsumed.blob(); + var bodyConsumed = new Request("", initValuesDict); + bodyConsumed.blob(); + + test(function() { + assert_false(noBodyConsumed.bodyUsed , "bodyUsed is false when request is not disturbed"); + try { + noBodyConsumed.clone(); + } catch (e) { + assert_unreached("Can use request not disturbed for creating or cloning request"); + } + }, "Request without body cannot be disturbed"); + + test(function() { + assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed"); + assert_throws(new TypeError(), function() { bodyConsumed.clone(); }); + }, "Check cloning a disturbed request"); + + test(function() { + assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed"); + assert_throws(new TypeError(), function() { new Request(bodyConsumed); }); + }, "Check creating a new request from a disturbed request"); + + test(function() { + var bodyRequest = new Request("", initValuesDict); + assert_false(bodyRequest.bodyUsed , "bodyUsed is false when request is not disturbed"); + var requestFromRequest = new Request(bodyRequest); + assert_true(bodyRequest.bodyUsed , "bodyUsed is true when request is disturbed"); + }, "Input request used for creating new request became disturbed"); + + promise_test(function(test) { + assert_true(bodyConsumed.bodyUsed , "bodyUsed is true when request is disturbed"); + return promise_rejects(test, new TypeError(), bodyConsumed.blob()); + }, "Check consuming a disturbed request"); + + test(function() { + var req = new Request(URL, {method: 'POST', body: 'hello'}); + assert_false(req.bodyUsed, + 'Request should not be flagged as used if it has not been ' + + 'consumed.'); + assert_throws(new TypeError(), + function() { new Request(req, {method: 'GET'}); }, + 'A get request may not have body.'); + + assert_false(req.bodyUsed, 'After the GET case'); + + assert_throws(new TypeError(), + function() { new Request(req, {method: 'CONNECT'}); }, + 'Request() with a forbidden method must throw.'); + + assert_false(req.bodyUsed, 'After the forbidden method case'); + + var req2 = new Request(req); + assert_true(req.bodyUsed, + 'Request should be flagged as used if it has been consumed.'); + }, 'Request construction failure should not set "bodyUsed"'); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-error.html b/testing/web-platform/tests/fetch/api/request/request-error.html new file mode 100644 index 000000000..c87429e76 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-error.html @@ -0,0 +1,110 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request error</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"window" : "http://test.url"}); }, + "Expect TypeError exception"); + },"RequestInit's window is not null"); + + test(function() { + assert_throws(new TypeError() , function() { new Request("http://:not a valid URL"); }, + "Expect TypeError exception"); + },"Input URL is not valid") + + test(function() { + assert_throws(new TypeError() , function() { new Request("http://user:pass@test.url"); }, + "Expect TypeError exception"); + },"Input URL has credentials"); + + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"mode" : "navigate"}); }, + "Expect TypeError exception"); + },"RequestInit's mode is navigate"); + + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"referrer" : "http://:not a valid URL"}); }, + "Expect TypeError exception"); + },"RequestInit's referrer is invalid"); + + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"referrer" : "http://test.url"}); }, + "Expect TypeError exception"); + },"RequestInit's referrer has invalid origin") + + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"method" : "IN VALID"}); }, + "Expect TypeError exception"); + }, "RequestInit's method is invalid"); + + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"method" : "TRACE"}); }, + "Expect TypeError exception"); + }, "RequestInit's method is forbidden"); + + test(function() { + assert_throws(new TypeError() , function() { new Request("", {"mode" : "no-cors", "method" : "PUT"}); }, + "Expect TypeError exception"); + },"RequestInit's mode is no-cors and method is not simple"); + + test(function() { + assert_throws(new TypeError() , + function() { new Request("", {"mode" : "no-cors", "integrity" : "not an empty string"}); }, + "Expect TypeError exception"); + },"RequestInit's mode is no-cors and integrity is not empty"); + + test(function() { + assert_throws(new TypeError() , + function() { new Request("", {"mode" : "cors", "cache" : "only-if-cached"}); }, + "Expect TypeError exception"); + },"RequestInit's cache mode is only-if-cached and mode is not same-origin"); + + test(function() { + var initialHeaders = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders}); + var request = new Request(initialRequest); + assert_equals(request.headers.get("Content-Type"), "potato"); + }, "Request should get its content-type from the init request"); + + test(function() { + var initialHeaders = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders}); + var headers = new Headers([]); + var request = new Request(initialRequest, {"headers" : headers}); + assert_false(request.headers.has("Content-Type")); + }, "Request should not get its content-type from the init request if init headers are provided"); + + test(function() { + var initialHeaders = new Headers([["Content-Type-Extra", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"}); + var request = new Request(initialRequest); + assert_equals(request.headers.get("Content-Type"), "text/plain;charset=UTF-8"); + }, "Request should get its content-type from the body if none is provided"); + + test(function() { + var initialHeaders = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"}); + var request = new Request(initialRequest); + assert_equals(request.headers.get("Content-Type"), "potato"); + }, "Request should get its content-type from init headers if one is provided"); + + var parameters = ["referrerPolicy", "mode", "credentials", "cache", "redirect"]; + parameters.forEach(function(parameter) { + test(function() { + var options = { }; + options[parameter] = "BAD"; + assert_throws(new TypeError(), function() { new Request("", options); }); + },"Bad " + parameter +" init parameter value"); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-headers.html b/testing/web-platform/tests/fetch/api/request/request-headers.html new file mode 100644 index 000000000..1d54728b7 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-headers.html @@ -0,0 +1,173 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request Headers</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var validRequestHeaders = [ + ["Content-Type", "OK"], + ["Potato", "OK"], + ["proxy", "OK"], + ["proxya", "OK"], + ["sec", "OK"], + ["secb", "OK"], + ]; + var invalidRequestHeaders = [ + ["Accept-Charset", "KO"], + ["accept-charset", "KO"], + ["ACCEPT-ENCODING", "KO"], + ["Accept-Encoding", "KO"], + ["Access-Control-Request-Headers", "KO"], + ["Access-Control-Request-Method", "KO"], + ["Connection", "KO"], + ["Content-Length", "KO"], + ["Cookie", "KO"], + ["Cookie2", "KO"], + ["Date", "KO"], + ["DNT", "KO"], + ["Expect", "KO"], + ["Host", "KO"], + ["Keep-Alive", "KO"], + ["Origin", "KO"], + ["Referer", "KO"], + ["TE", "KO"], + ["Trailer", "KO"], + ["Transfer-Encoding", "KO"], + ["Upgrade", "KO"], + ["Via", "KO"], + ["Proxy-", "KO"], + ["proxy-a", "KO"], + ["Sec-", "KO"], + ["sec-b", "KO"], + ]; + + var validRequestNoCorsHeaders = [ + ["Accept", "OK"], + ["Accept-Language", "OK"], + ["content-language", "OK"], + ["content-type", "application/x-www-form-urlencoded"], + ["content-type", "application/x-www-form-urlencoded;charset=UTF-8"], + ["content-type", "multipart/form-data"], + ["content-type", "multipart/form-data;charset=UTF-8"], + ["content-TYPE", "text/plain"], + ["CONTENT-type", "text/plain;charset=UTF-8"], + ]; + var invalidRequestNoCorsHeaders = [ + ["Content-Type", "KO"], + ["Potato", "KO"], + ["proxy", "KO"], + ["proxya", "KO"], + ["sec", "KO"], + ["secb", "KO"], + ]; + + validRequestHeaders.forEach(function(header) { + test(function() { + var request = new Request(""); + request.headers.set(header[0], header[1]); + assert_equals(request.headers.get(header[0]), header[1]); + }, "Adding valid request header \"" + header[0] + ": " + header[1] + "\""); + }); + invalidRequestHeaders.forEach(function(header) { + test(function() { + var request = new Request(""); + request.headers.set(header[0], header[1]); + assert_equals(request.headers.get(header[0]), null); + }, "Adding invalid request header \"" + header[0] + ": " + header[1] + "\""); + }); + + validRequestNoCorsHeaders.forEach(function(header) { + test(function() { + var requestNoCors = new Request("", {"mode": "no-cors"}); + requestNoCors.headers.set(header[0], header[1]); + assert_equals(requestNoCors.headers.get(header[0]), header[1]); + }, "Adding valid no-cors request header \"" + header[0] + ": " + header[1] + "\""); + }); + invalidRequestNoCorsHeaders.forEach(function(header) { + test(function() { + var requestNoCors = new Request("", {"mode": "no-cors"}); + requestNoCors.headers.set(header[0], header[1]); + assert_equals(requestNoCors.headers.get(header[0]), null); + }, "Adding invalid no-cors request header \"" + header[0] + ": " + header[1] + "\""); + }); + + test(function() { + var headers = new Headers([["Cookie2", "potato"]]); + var request = new Request("", {"headers": headers}); + assert_equals(request.headers.get("Cookie2"), null); + }, "Check that request constructor is filtering headers provided as init parameter"); + + test(function() { + var headers = new Headers([["Content-Type", "potato"]]); + var request = new Request("", {"headers": headers, "mode": "no-cors"}); + assert_equals(request.headers.get("Content-Type"), null); + }, "Check that no-cors request constructor is filtering headers provided as init parameter"); + + test(function() { + var headers = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers": headers}); + var request = new Request(initialRequest, {"mode": "no-cors"}); + assert_equals(request.headers.get("Content-Type"), null); + }, "Check that no-cors request constructor is filtering headers provided as part of request parameter"); + + test(function() { + var initialHeaders = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders}); + var request = new Request(initialRequest); + assert_equals(request.headers.get("Content-Type"), "potato"); + }, "Request should get its content-type from the init request"); + + test(function() { + var initialHeaders = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders}); + var headers = new Headers([]); + var request = new Request(initialRequest, {"headers" : headers}); + assert_false(request.headers.has("Content-Type")); + }, "Request should not get its content-type from the init request if init headers are provided"); + + test(function() { + var initialHeaders = new Headers([["Content-Type-Extra", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"}); + var request = new Request(initialRequest); + assert_equals(request.headers.get("Content-Type"), "text/plain;charset=UTF-8"); + }, "Request should get its content-type from the body if none is provided"); + + test(function() { + var initialHeaders = new Headers([["Content-Type", "potato"]]); + var initialRequest = new Request("", {"headers" : initialHeaders, "body" : "this is my plate", "method" : "POST"}); + var request = new Request(initialRequest); + assert_equals(request.headers.get("Content-Type"), "potato"); + }, "Request should get its content-type from init headers if one is provided"); + + test(function() { + var array = [["hello", "worldAHH"]]; + var object = {"hello": 'worldOOH'}; + var headers = new Headers(array); + + assert_equals(headers.get("hello"), "worldAHH"); + + var request1 = new Request("", {"headers": headers}); + var request2 = new Request("", {"headers": array}); + var request3 = new Request("", {"headers": object}); + + assert_equals(request1.headers.get("hello"), "worldAHH"); + assert_equals(request2.headers.get("hello"), "worldAHH"); + assert_equals(request3.headers.get("hello"), "worldOOH"); + }, "Testing request header creations with various objects"); + + promise_test(function(test) { + var request = new Request("", {"headers" : [["Content-Type", ""]], "body" : "this is my plate", "method" : "POST"}); + return request.blob().then(function(blob) { + assert_equals(blob.type, "", "Blob type should be the empty string"); + }); + }, "Testing empty Request Content-Type header"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-idl.html b/testing/web-platform/tests/fetch/api/request/request-idl.html new file mode 100644 index 000000000..4f1590c75 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-idl.html @@ -0,0 +1,86 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request idl interface</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/WebIDLParser.js"></script> + <script src="/resources/idlharness.js"></script> + </head> + <body> + <script id="body-idl" type="text/plain"> + typedef any JSON; + typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) BodyInit; + + [NoInterfaceObject, + Exposed=(Window,Worker)] + interface Body { + readonly attribute boolean bodyUsed; + [NewObject] Promise<ArrayBuffer> arrayBuffer(); + [NewObject] Promise<Blob> blob(); + [NewObject] Promise<FormData> formData(); + [NewObject] Promise<JSON> json(); + [NewObject] Promise<USVString> text(); + }; + </script> + <script id="request-idl" type="text/plain"> + typedef (Request or USVString) RequestInfo; + + [Constructor(RequestInfo input, optional RequestInit init), + Exposed=(Window,Worker)] + interface Request { + readonly attribute ByteString method; + readonly attribute USVString url; + [SameObject] readonly attribute Headers headers; + + readonly attribute RequestType type; + readonly attribute RequestDestination destination; + readonly attribute USVString referrer; + readonly attribute ReferrerPolicy referrerPolicy; + readonly attribute RequestMode mode; + readonly attribute RequestCredentials credentials; + readonly attribute RequestCache cache; + readonly attribute RequestRedirect redirect; + readonly attribute DOMString integrity; + + [NewObject] Request clone(); + }; + Request implements Body; + + dictionary RequestInit { + ByteString method; + HeadersInit headers; + BodyInit? body; + USVString referrer; + ReferrerPolicy referrerPolicy; + RequestMode mode; + RequestCredentials credentials; + RequestCache cache; + RequestRedirect redirect; + DOMString integrity; + any window; // can only be set to null + }; + + enum RequestType { "", "audio", "font", "image", "script", "style", "track", "video" }; + enum RequestDestination { "", "document", "sharedworker", "subresource", "unknown", "worker" }; + enum RequestMode { "navigate", "same-origin", "no-cors", "cors" }; + enum RequestCredentials { "omit", "same-origin", "include" }; + enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached" }; + enum RequestRedirect { "follow", "error", "manual" }; + enum ReferrerPolicy { "", "no-referrer", "no-referrer-when-downgrade", "origin-only", "origin-when-cross-origin", "unsafe-url" }; + </script> + <script> + var idlsArray = new IdlArray(); + var idl = document.getElementById("body-idl").innerHTML + idl += document.getElementById("request-idl").innerHTML + + idlsArray.add_idls(idl); + idlsArray.add_untested_idls("interface Headers {};"); + idlsArray.add_objects({ Request: ['new Request("")'] }); + idlsArray.test(); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-init-001.sub.html b/testing/web-platform/tests/fetch/api/request/request-init-001.sub.html new file mode 100644 index 000000000..b41f6f0fe --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-init-001.sub.html @@ -0,0 +1,92 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request init: simple cases</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var methods = {"givenValues" : ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "head"], + "expectedValues" : ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"] + }; + var referrers = {"givenValues" : ["/relative/ressource", + "http://{{host}}:{{ports[http][0]}}/relative/ressource?query=true#fragment", + "http://{{host}}:{{ports[http][0]}}/", + "about:client", + "" + ], + "expectedValues" : ["http://{{host}}:{{ports[http][0]}}/relative/ressource", + "http://{{host}}:{{ports[http][0]}}/relative/ressource?query=true#fragment", + "http://{{host}}:{{ports[http][0]}}/", + "about:client", + "" + ] + }; + var referrerPolicies = {"givenValues" : [ "", + "no-referrer", + "no-referrer-when-downgrade", + "origin", + "origin-when-cross-origin", + "unsafe-url" + ], + "expectedValues" : ["", + "no-referrer", + "no-referrer-when-downgrade", + "origin", + "origin-when-cross-origin", + "unsafe-url" + ] + }; + var modes = {"givenValues" : ["same-origin", "no-cors", "cors"], + "expectedValues" : ["same-origin", "no-cors", "cors"] + }; + var credentials = {"givenValues" : ["omit", "same-origin", "include"], + "expectedValues" : ["omit", "same-origin", "include"] + }; + var caches = {"givenValues" : [ "default", "no-store", "reload", "no-cache", "force-cache"], + "expectedValues" : [ "default", "no-store", "reload", "no-cache", "force-cache"] + }; + var redirects = {"givenValues" : ["follow", "error", "manual"], + "expectedValues" : ["follow", "error", "manual"] + }; + var integrities = {"givenValues" : ["", "AZERTYUIOP1234567890" ], + "expectedValues" : ["", "AZERTYUIOP1234567890"] + }; + + //there is no getter for window, init's window might be null + var windows = {"givenValues" : [ null ], + "expectedValues" : [undefined] + }; + + var initValuesDict = { "method" : methods, + "referrer" : referrers, + "referrerPolicy" : referrerPolicies, + "mode" : modes, + "credentials" : credentials, + "cache" : caches, + "redirect" : redirects, + "integrity" : integrities, + "window" : windows + }; + + for (var attributeName in initValuesDict) { + var valuesToTest = initValuesDict[attributeName]; + for (var valueIdx in valuesToTest["givenValues"]) { + var givenValue = valuesToTest["givenValues"][valueIdx]; + var expectedValue = valuesToTest["expectedValues"][valueIdx]; + test(function() { + var requestInit = {}; + requestInit[attributeName] = givenValue + var request = new Request("", requestInit); + assert_equals(request[attributeName], expectedValue, + "Expect request's " + attributeName + " is " + expectedValue + " when initialized with " + givenValue); + }, "Check " + attributeName + " init value of " + givenValue + " and associated getter"); + } + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-init-002.html b/testing/web-platform/tests/fetch/api/request/request-init-002.html new file mode 100644 index 000000000..5d92b09c5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-init-002.html @@ -0,0 +1,71 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request init: headers and body</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + test(function() { + var headerDict = {"name1": "value1", + "name2": "value2", + "name3": "value3" + }; + var headers = new Headers(headerDict); + var request = new Request("", { "headers" : headers }) + for (var name in headerDict) { + assert_equals(request.headers.get(name), headerDict[name], + "request's headers has " + name + " : " + headerDict[name]); + } + }, "Initialize Request with headers values"); + + function makeRequestInit(body, method) { + return {"method": method, "body": body}; + } + + function checkRequestInit(body, bodyType, expectedTextBody) { + promise_test(function(test) { + var request = new Request("", makeRequestInit(body, "POST")); + if (body) { + assert_throws(new TypeError(), function() { new Request("", makeRequestInit(body, "GET")); }); + assert_throws(new TypeError(), function() { new Request("", makeRequestInit(body, "HEAD")); }); + } else { + new Request("", makeRequestInit(body, "GET")); // should not throw + } + var reqHeaders = request.headers; + var mime = reqHeaders.get("Content-Type"); + assert_true(!body || (mime && mime.search(bodyType) > -1), "Content-Type header should be \"" + bodyType + "\", not \"" + mime + "\""); + return request.text().then(function(bodyAsText) { + //not equals: cannot guess formData exact value + assert_true( bodyAsText.search(expectedTextBody) > -1, "Retrieve and verify request body"); + }); + }, "Initialize Request's body with " + bodyType); + } + + var blob = new Blob(["This is a blob"], {type: "application/octet-binary"}); + var formaData = new FormData(); + formaData.append("name", "value"); + var usvString = "This is a USVString" + + checkRequestInit(undefined, undefined, ""); + checkRequestInit(null, null, ""); + checkRequestInit(blob, "application/octet-binary", "This is a blob"); + checkRequestInit(formaData, "multipart/form-data", "name=\"name\"\r\n\r\nvalue"); + checkRequestInit(usvString, "text/plain;charset=UTF-8", "This is a USVString"); + + // Ensure test does not time out in case of missing URLSearchParams support. + if (window.URLSearchParams) { + var urlSearchParams = new URLSearchParams("name=value"); + checkRequestInit(urlSearchParams, "application/x-www-form-urlencoded;charset=UTF-8", "name=value"); + } else { + promise_test(function(test) { + return Promise.reject("URLSearchParams not supported"); + }, "Initialize Request's body with application/x-www-form-urlencoded;charset=UTF-8"); + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-init-003.sub.html b/testing/web-platform/tests/fetch/api/request/request-init-003.sub.html new file mode 100644 index 000000000..8860d6074 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-init-003.sub.html @@ -0,0 +1,84 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request: init with request or url</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="help" href="https://url.spec.whatwg.org/#concept-url-serializer"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script> + var headers = new Headers( {"name":"value"} ); + var emptyHeaders = new Headers(); + + var initValuesDict = {"method" : "POST", + "referrer" : "http://{{host}}:{{ports[http][0]}}/", + "referrerPolicy" : "origin", + "mode" : "same-origin", + "credentials" : "include", + "cache" : "no-cache", + "redirect" : "error", + "integrity" : "Request's Integrity", + "headers" : headers, + "body" : "Request's body" + }; + + var expectedInitialized = {"method" : "POST", + "referrer" : "http://{{host}}:{{ports[http][0]}}/", + "referrerPolicy" : "origin", + "mode" : "same-origin", + "credentials" : "include", + "cache" : "no-cache", + "redirect" : "error", + "integrity" : "Request's Integrity", + "headers" : headers, + "body" : "Request's body" + }; + + var expectedDefault = {"method" : "GET", + "url" : location.href, + "referrer" : "http://{{host}}:{{ports[http][0]}}/", + "referrerPolicy" : "", + "mode" : "cors", + "credentials" : "omit", + "cache" : "default", + "redirect" : "follow", + "integrity" : "", + "headers" : emptyHeaders + }; + + var requestDefault = new Request(""); + var requestInitialized = new Request("", initValuesDict); + + test(function() { + var requestToCheck = new Request(requestInitialized); + checkRequest(requestToCheck, expectedInitialized); + }, "Check request values when initialized from Request"); + + test(function() { + var requestToCheck = new Request(requestDefault, initValuesDict); + checkRequest(requestToCheck, expectedInitialized); + }, "Check request values when initialized from Request and init values"); + + test(function() { + var url = "http://url.test:1234/path/subpath?query=true"; + url += "#fragment"; + expectedDefault["url"] = url; + var requestToCheck = new Request(url); + checkRequest(requestToCheck, expectedDefault); + }, "Check request values when initialized from url string"); + + test(function() { + var url = "http://url.test:1234/path/subpath?query=true"; + url += "#fragment"; + expectedInitialized["url"] = url; + var requestToCheck = new Request(url , initValuesDict); + checkRequest(requestToCheck, expectedInitialized); + }, "Check request values when initialized from url and init values"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/request-structure.html b/testing/web-platform/tests/fetch/api/request/request-structure.html new file mode 100644 index 000000000..cbe6cee99 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/request-structure.html @@ -0,0 +1,134 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Request structure</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#request"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var request = new Request(""); + var methods = ["clone", + //Request implements Body + "arrayBuffer", + "blob", + "formData", + "json", + "text" + ]; + var attributes = ["method", + "url", + "headers", + "type", + "destination", + "referrer", + "referrerPolicy", + "mode", + "credentials", + "cache", + "redirect", + "integrity", + //Request implements Body + "bodyUsed" + ]; + + function IsreadOnly(request, attributeToCheck) { + var defaultValue = undefined; + var newValue = undefined; + switch (attributeToCheck) { + case "method": + defaultValue = "GET"; + newValue = "POST"; + break; + + case "url": + //default value is base url + //i.e http://web-platform.test:8000/fetch/api/request-structure.html + newValue = "http://url.test"; + break; + + case "headers": + request.headers = new Headers ({"name":"value"}); + assert_false(request.headers.has("name"), "Headers attribute is read only"); + return; + break; + + case "type": + defaultValue = ""; + newValue = "style"; + break; + + case "destination": + defaultValue = ""; + newValue = "worker"; + break; + + case "referrer": + defaultValue = "about:client"; + newValue = "http://url.test"; + break; + + case "referrerPolicy": + defaultValue = ""; + newValue = "unsafe-url"; + break; + + case "mode": + defaultValue = "cors"; + newValue = "navigate"; + break; + + case "credentials": + defaultValue = "omit"; + newValue = "cors"; + break; + + case "cache": + defaultValue = "default"; + newValue = "reload"; + break; + + case "redirect": + defaultValue = "follow"; + newValue = "manual"; + break; + + case "integrity": + newValue = "CannotWriteIntegrity"; + break; + + case "bodyUsed": + defaultValue = false; + newValue = true; + break; + + default: + return; + } + + request[attributeToCheck] = newValue; + if (defaultValue === undefined) + assert_not_equals(request[attributeToCheck], newValue, "Attribute " + attributeToCheck + " is read only"); + else + assert_equals(request[attributeToCheck], defaultValue, + "Attribute " + attributeToCheck + " is read only. Default value is " + defaultValue); + } + + for (var idx in methods) { + test(function() { + assert_true(methods[idx] in request, "request has " + methods[idx] + " method"); + }, "Request has " + methods[idx] + " method"); + } + + for (var idx in attributes) { + test(function() { + assert_true(attributes[idx] in request, "request has " + attributes[idx] + " attribute"); + IsreadOnly(request, attributes[idx]); + }, "Check " + attributes[idx] + " attribute"); + } + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/request/resources/cache.py b/testing/web-platform/tests/fetch/api/request/resources/cache.py new file mode 100644 index 000000000..85265679a --- /dev/null +++ b/testing/web-platform/tests/fetch/api/request/resources/cache.py @@ -0,0 +1,62 @@ +def main(request, response): + token = request.GET.first("token", None) + if "querystate" in request.GET: + from json import JSONEncoder + response.headers.set("Content-Type", "text/plain") + return JSONEncoder().encode(request.server.stash.take(token)) + content = request.GET.first("content", None) + tag = request.GET.first("tag", None) + date = request.GET.first("date", None) + expires = request.GET.first("expires", None) + vary = request.GET.first("vary", None) + cc = request.GET.first("cache_control", None) + redirect = request.GET.first("redirect", None) + inm = request.headers.get("If-None-Match", None) + ims = request.headers.get("If-Modified-Since", None) + pragma = request.headers.get("Pragma", None) + cache_control = request.headers.get("Cache-Control", None) + ignore = "ignore" in request.GET + + server_state = request.server.stash.take(token) + if not server_state: + server_state = [] + state = dict() + if not ignore: + if inm: + state["If-None-Match"] = inm + if ims: + state["If-Modified-Since"] = ims + if pragma: + state["Pragma"] = pragma + if cache_control: + state["Cache-Control"] = cache_control + server_state.append(state) + request.server.stash.put(token, server_state) + + if tag: + response.headers.set("ETag", '"%s"' % tag) + elif date: + response.headers.set("Last-Modified", date) + if expires: + response.headers.set("Expires", expires) + if vary: + response.headers.set("Vary", vary) + if cc: + response.headers.set("Cache-Control", cc) + + # The only-if-cached redirect tests wants CORS to be okay, the other tests + # are all same-origin anyways and don't care. + response.headers.set("Access-Control-Allow-Origin", "*"); + + if redirect: + response.headers.set("Location", redirect); + response.status = (302, "Redirect") + return "" + elif ((inm is not None and inm == tag) or + (ims is not None and ims == date)): + response.status = (304, "Not Modified") + return "" + else: + response.status = (200, "OK") + response.headers.set("Content-Type", "text/plain") + return content diff --git a/testing/web-platform/tests/fetch/api/resources/authentication.py b/testing/web-platform/tests/fetch/api/resources/authentication.py new file mode 100644 index 000000000..a06d179e5 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/authentication.py @@ -0,0 +1,15 @@ +def main(request, response): + user = request.auth.username + password = request.auth.password + + if user == "user" and password == "password": + return "Authentication done" + + realm = "test" + if "realm" in request.GET: + realm = request.GET.first("realm") + + return ((401, "Unauthorized"), + [("WWW-Authenticate", 'Basic realm="' + realm + '"')], + "Please login with credentials 'user' and 'password'") + diff --git a/testing/web-platform/tests/fetch/api/resources/clean-stash.py b/testing/web-platform/tests/fetch/api/resources/clean-stash.py new file mode 100644 index 000000000..3ae731052 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/clean-stash.py @@ -0,0 +1,6 @@ +def main(request, response): + token = request.GET.first("token") + if request.server.stash.take(token) is not None: + return "1" + else: + return "0" diff --git a/testing/web-platform/tests/fetch/api/resources/data.json b/testing/web-platform/tests/fetch/api/resources/data.json new file mode 100644 index 000000000..76519fa8c --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/data.json @@ -0,0 +1 @@ +{"key": "value"} diff --git a/testing/web-platform/tests/fetch/api/resources/inspect-headers.py b/testing/web-platform/tests/fetch/api/resources/inspect-headers.py new file mode 100644 index 000000000..c4ace18ab --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/inspect-headers.py @@ -0,0 +1,22 @@ +def main(request, response): + headers = [] + request_headers = [] + if "headers" in request.GET: + checked_headers = request.GET.first("headers").split("|") + for header in checked_headers: + if header in request.headers: + headers.append(("x-request-" + header, request.headers.get(header, "") )) + + if "cors" in request.GET: + if "Origin" in request.headers: + headers.append(("Access-Control-Allow-Origin", request.headers.get("Origin", ""))) + else: + headers.append(("Access-Control-Allow-Origin", "*")) + headers.append(("Access-Control-Allow-Credentials", "true")) + headers.append(("Access-Control-Allow-Methods", "GET, POST, HEAD")) + exposed_headers = ["x-request-" + header for header in checked_headers] + headers.append(("Access-Control-Expose-Headers", ", ".join(exposed_headers))) + headers.append(("Access-Control-Allow-Headers", ", ".join(request.headers))) + + headers.append(("content-type", "text/plain")) + return headers, "" diff --git a/testing/web-platform/tests/fetch/api/resources/method.py b/testing/web-platform/tests/fetch/api/resources/method.py new file mode 100644 index 000000000..db234f9d1 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/method.py @@ -0,0 +1,11 @@ +def main(request, response): + headers = [] + if "cors" in request.GET: + headers.append(("Access-Control-Allow-Origin", "*")) + headers.append(("Access-Control-Allow-Credentials", "true")) + headers.append(("Access-Control-Allow-Methods", "GET, POST, PUT, FOO")) + headers.append(("Access-Control-Allow-Headers", "x-test, x-foo")) + headers.append(("Access-Control-Expose-Headers", "x-request-method")) + + headers.append(("x-request-method", request.method)) + return headers, request.body diff --git a/testing/web-platform/tests/fetch/api/resources/preflight.py b/testing/web-platform/tests/fetch/api/resources/preflight.py new file mode 100644 index 000000000..72dceba68 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/preflight.py @@ -0,0 +1,56 @@ +def main(request, response): + headers = [("Content-Type", "text/plain")] + stashed_data = {'control_request_headers': "", 'preflight': "0", 'preflight_referrer': ""} + + if "origin" in request.GET: + for origin in request.GET['origin'].split(", "): + headers.append(("Access-Control-Allow-Origin", origin)) + else: + headers.append(("Access-Control-Allow-Origin", "*")) + + if request.method == "OPTIONS": + if not "Access-Control-Request-Method" in request.headers: + response.set_error(400, "No Access-Control-Request-Method header") + return "ERROR: No access-control-request-method in preflight!" + + if "control_request_headers" in request.GET: + stashed_data['control_request_headers'] = request.headers.get("Access-Control-Request-Headers", "") + + if "max_age" in request.GET: + headers.append(("Access-Control-Max-Age", request.GET['max_age'])) + + if "allow_headers" in request.GET: + headers.append(("Access-Control-Allow-Headers", request.GET['allow_headers'])) + + if "allow_methods" in request.GET: + headers.append(("Access-Control-Allow-Methods", request.GET['allow_methods'])) + + preflight_status = 200 + if "preflight_status" in request.GET: + preflight_status = int(request.GET.first("preflight_status")) + + stashed_data['preflight'] = "1" + stashed_data['preflight_referrer'] = request.headers.get("Referer", "") + request.server.stash.put(request.GET.first("token"), stashed_data) + + return preflight_status, headers, "" + + token = None + if "token" in request.GET: + token = request.GET.first("token") + data = request.server.stash.take(token) + if data: + stashed_data = data + + #use x-* headers for returning value to bodyless responses + headers.append(("Access-Control-Expose-Headers", "x-did-preflight, x-control-request-headers, x-referrer, x-preflight-referrer, x-origin")) + headers.append(("x-did-preflight", stashed_data['preflight'])) + headers.append(("x-control-request-headers", stashed_data['control_request_headers'])) + headers.append(("x-preflight-referrer", stashed_data['preflight_referrer'])) + headers.append(("x-referrer", request.headers.get("Referer", "") )) + headers.append(("x-origin", request.headers.get("Origin", "") )) + + if token: + request.server.stash.put(token, stashed_data) + + return headers, "" diff --git a/testing/web-platform/tests/fetch/api/resources/redirect.py b/testing/web-platform/tests/fetch/api/resources/redirect.py new file mode 100644 index 000000000..46beade1f --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/redirect.py @@ -0,0 +1,54 @@ +from urllib import urlencode +from urlparse import urlparse + +def main(request, response): + stashed_data = {'count': 0, 'preflight': "0"} + status = 302 + headers = [("Content-Type", "text/plain"), + ("Cache-Control", "no-cache"), + ("Pragma", "no-cache"), + ("Access-Control-Allow-Origin", "*")] + token = None + + if "token" in request.GET: + token = request.GET.first("token") + data = request.server.stash.take(token) + if data: + stashed_data = data + + if request.method == "OPTIONS": + if "allow_headers" in request.GET: + headers.append(("Access-Control-Allow-Headers", request.GET['allow_headers'])) + stashed_data['preflight'] = "1" + #Preflight is not redirected: return 200 + if not "redirect_preflight" in request.GET: + if token: + request.server.stash.put(request.GET.first("token"), stashed_data) + return 200, headers, "" + + if "redirect_status" in request.GET: + status = int(request.GET['redirect_status']) + + stashed_data['count'] += 1 + + if "location" in request.GET: + url = request.GET['location'] + scheme = urlparse(url).scheme + if scheme == "" or scheme == "http" or scheme == "https": + url += "&" if '?' in url else "?" + #keep url parameters in location + url += urlencode({key: request.GET.first(key) for key in request.GET.keys()}) + #make sure location changes during redirection loop + url += "&count=" + str(stashed_data['count']) + headers.append(("Location", url)) + + if token: + request.server.stash.put(request.GET.first("token"), stashed_data) + if "max_count" in request.GET: + max_count = int(request.GET['max_count']) + #stop redirecting and return count + if stashed_data['count'] > max_count: + # -1 because the last is not a redirection + return str(stashed_data['count'] - 1) + + return status, headers, "" diff --git a/testing/web-platform/tests/fetch/api/resources/status.py b/testing/web-platform/tests/fetch/api/resources/status.py new file mode 100644 index 000000000..5d72e10b2 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/status.py @@ -0,0 +1,9 @@ +def main(request, response): + code = int(request.GET.first("code", 200)) + text = request.GET.first("text", "OMG") + content = request.GET.first("content", "") + type = request.GET.first("type", "") + status = (code, text) + headers = [("Content-Type", type), + ("X-Request-Method", request.method)] + return status, headers, content diff --git a/testing/web-platform/tests/fetch/api/resources/top.txt b/testing/web-platform/tests/fetch/api/resources/top.txt new file mode 100644 index 000000000..83a3157d1 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/top.txt @@ -0,0 +1 @@ +top
\ No newline at end of file diff --git a/testing/web-platform/tests/fetch/api/resources/trickle.py b/testing/web-platform/tests/fetch/api/resources/trickle.py new file mode 100644 index 000000000..0e709445c --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/trickle.py @@ -0,0 +1,12 @@ +import time + +def main(request, response): + delay = float(request.GET.first("ms", 500)) / 1E3 + count = int(request.GET.first("count", 50)) + time.sleep(delay) + response.headers.set("Content-type", "text/plain") + response.write_status_headers() + time.sleep(delay); + for i in xrange(count): + response.writer.write_content("TEST_TRICKLE\n") + time.sleep(delay) diff --git a/testing/web-platform/tests/fetch/api/resources/utils.js b/testing/web-platform/tests/fetch/api/resources/utils.js new file mode 100644 index 000000000..86542c7bc --- /dev/null +++ b/testing/web-platform/tests/fetch/api/resources/utils.js @@ -0,0 +1,83 @@ +var inWorker = false; +var RESOURCES_DIR = "../resources/"; + +try { + inWorker = !(self instanceof Window); +} catch (e) { + inWorker = true; +} + +function dirname(path) { + return path.replace(/\/[^\/]*$/, '/') +} + +function checkRequest(request, ExpectedValuesDict) { + for (var attribute in ExpectedValuesDict) { + switch(attribute) { + case "headers": + for (var key in ExpectedValuesDict["headers"].keys()) { + assert_equals(request["headers"].get(key), ExpectedValuesDict["headers"].get(key), + "Check headers attribute has " + key + ":" + ExpectedValuesDict["headers"].get(key)); + } + break; + + case "body": + //for checking body's content, a dedicated asyncronous/promise test should be used + assert_true(request["headers"].has("Content-Type") , "Check request has body using Content-Type header") + break; + + case "method": + case "referrer": + case "referrerPolicy": + case "credentials": + case "cache": + case "redirect": + case "integrity": + case "url": + case "destination": + assert_equals(request[attribute], ExpectedValuesDict[attribute], "Check " + attribute + " attribute") + break; + + default: + break; + } + } +} + +function stringToArray(str) { + var array = new Uint8Array(str.length); + for (var i=0, strLen = str.length; i < strLen; i++) + array[i] = str.charCodeAt(i); + return array; +} + +function validateBufferFromString(buffer, expectedValue, message) +{ + return assert_array_equals(new Uint8Array(buffer !== undefined ? buffer : []), stringToArray(expectedValue), message); +} + +function validateStreamFromString(reader, expectedValue, retrievedArrayBuffer) { + return reader.read().then(function(data) { + if (!data.done) { + assert_true(data.value instanceof Uint8Array, "Fetch ReadableStream chunks should be Uint8Array"); + var newBuffer; + if (retrievedArrayBuffer) { + newBuffer = new ArrayBuffer(data.value.length + retrievedArrayBuffer.length); + newBuffer.set(retrievedArrayBuffer, 0); + newBuffer.set(data.value, retrievedArrayBuffer.length); + } else { + newBuffer = data.value; + } + return validateStreamFromString(reader, expectedValue, newBuffer); + } + validateBufferFromString(retrievedArrayBuffer, expectedValue, "Retrieve and verify stream"); + }); +} + +// From streams tests +function delay(milliseconds) +{ + return new Promise(function(resolve) { + step_timeout(resolve, milliseconds); + }); +} diff --git a/testing/web-platform/tests/fetch/api/response/response-cancel-stream.html b/testing/web-platform/tests/fetch/api/response/response-cancel-stream.html new file mode 100644 index 000000000..2a02e1f60 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-cancel-stream.html @@ -0,0 +1,66 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response consume blob and http bodies</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script> + +promise_test(function(test) { + return new Response(new Blob([], { "type" : "text/plain" })).body.cancel(); +}, "Cancelling a starting blob Response stream"); + +promise_test(function(test) { + var response = new Response(new Blob(["This is data"], { "type" : "text/plain" })); + var reader = response.body.getReader(); + reader.read(); + return reader.cancel(); +}, "Cancelling a loading blob Response stream"); + +promise_test(function(test) { + var response = new Response(new Blob(["T"], { "type" : "text/plain" })); + var reader = response.body.getReader(); + + var closedPromise = reader.closed.then(function() { + return reader.cancel(); + }); + reader.read(); + return closedPromise; +}, "Cancelling a closed blob Response stream"); + +promise_test(function(test) { + return fetch(RESOURCES_DIR + "trickle.py?ms=30&count=100").then(function(response) { + return response.body.cancel(); + }); +}, "Cancelling a starting Response stream"); + +promise_test(function() { + return fetch(RESOURCES_DIR + "trickle.py?ms=30&count=100").then(function(response) { + var reader = response.body.getReader(); + return reader.read().then(function() { + return reader.cancel(); + }); + }); +}, "Cancelling a loading Response stream"); + +promise_test(function() { + return fetch(RESOURCES_DIR + "top.txt").then(function(response) { + var reader = response.body.getReader(); + var closedPromise = reader.closed.then(function() { + return reader.cancel(); + }); + reader.read(); + return closedPromise; + }); +}, "Cancelling a closed Response stream"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-clone.html b/testing/web-platform/tests/fetch/api/response/response-clone.html new file mode 100644 index 000000000..1efb4da5e --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-clone.html @@ -0,0 +1,98 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response clone</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script> + var defaultValues = { "type" : "default", + "url" : "", + "ok" : true, + "status" : 200, + "statusText" : "OK" + }; + + var response = new Response(); + var clonedResponse = response.clone(); + test(function() { + for (var attributeName in defaultValues) { + var expectedValue = defaultValues[attributeName]; + assert_equals(clonedResponse[attributeName], expectedValue, + "Expect default response." + attributeName + " is " + expectedValue); + } + }, "Check Response's clone with default values, without body"); + + var body = "This is response body"; + var headersInit = { "name" : "value" }; + var responseInit = { "status" : 200, + "statusText" : "GOOD", + "headers" : headersInit + }; + var response = new Response(body, responseInit); + var clonedResponse = response.clone(); + test(function() { + assert_equals(clonedResponse.status, responseInit["status"], + "Expect response.status is " + responseInit["status"]); + assert_equals(clonedResponse.statusText, responseInit["statusText"], + "Expect response.statusText is " + responseInit["statusText"]); + assert_equals(clonedResponse.headers.get("name"), "value", + "Expect response.headers has name:value header"); + }, "Check Response's clone has the expected attribute values"); + + promise_test(function(test) { + return validateStreamFromString(response.body.getReader(), body); + }, "Check orginal response's body after cloning"); + + promise_test(function(test) { + return validateStreamFromString(clonedResponse.body.getReader(), body); + }, "Check cloned response's body"); + + promise_test(function(test) { + var disturbedResponse = new Response("data"); + return disturbedResponse.text().then(function() { + assert_true(disturbedResponse.bodyUsed, "response is disturbed"); + assert_throws(new TypeError() , function() { disturbedResponse.clone(); }, + "Expect TypeError exception"); + }); + }, "Cannot clone a disturbed response"); + + promise_test(function(t) { + var clone; + var result; + var response; + return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) { + clone = res.clone(); + response = res; + return clone.arrayBuffer(); + }).then(function(r) { + assert_equals(r.byteLength, 26); + result = r; + return response.arrayBuffer(); + }).then(function(r) { + assert_array_equals(r, result, "cloned responses should provide the same data"); + }); + }, 'Cloned responses should provide the same data'); + + promise_test(function(t) { + var clone; + return fetch('../resources/trickle.py?count=2&delay=100').then(function(res) { + clone = res.clone(); + res.body.cancel(); + assert_true(res.bodyUsed); + assert_false(clone.bodyUsed); + return clone.arrayBuffer(); + }).then(function(r) { + assert_equals(r.byteLength, 26); + assert_true(clone.bodyUsed); + }); + }, 'Cancelling stream should not affect cloned one'); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-consume-empty.html b/testing/web-platform/tests/fetch/api/response/response-consume-empty.html new file mode 100644 index 000000000..788384699 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-consume-empty.html @@ -0,0 +1,103 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response consume empty bodies</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + function checkBodyText(response) { + return response.text().then(function(bodyAsText) { + assert_equals(bodyAsText, "", "Resolved value should be empty"); + assert_false(response.bodyUsed); + }); + } + + function checkBodyBlob(response) { + return response.blob().then(function(bodyAsBlob) { + var promise = new Promise(function(resolve, reject) { + var reader = new FileReader(); + reader.onload = function(evt) { + resolve(reader.result) + }; + reader.onerror = function() { + reject("Blob's reader failed"); + }; + reader.readAsText(bodyAsBlob); + }); + return promise.then(function(body) { + assert_equals(body, "", "Resolved value should be empty"); + assert_false(response.bodyUsed); + }); + }); + } + + function checkBodyArrayBuffer(response) { + return response.arrayBuffer().then(function(bodyAsArrayBuffer) { + assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty"); + assert_false(response.bodyUsed); + }); + } + + function checkBodyJSON(response) { + return response.json().then( + function(bodyAsJSON) { + assert_unreached("JSON parsing should fail"); + }, + function() { + assert_false(response.bodyUsed); + }); + } + + function checkBodyFormData(response) { + return response.formData().then(function(bodyAsFormData) { + assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData"); + assert_false(response.bodyUsed); + }); + } + + function checkResponseWithNoBody(bodyType, checkFunction) { + promise_test(function(test) { + var response = new Response(); + assert_false(response.bodyUsed); + return checkFunction(response); + }, "Consume response's body as " + bodyType); + } + + var formData = new FormData(); + checkResponseWithNoBody("text", checkBodyText); + checkResponseWithNoBody("blob", checkBodyBlob); + checkResponseWithNoBody("arrayBuffer", checkBodyArrayBuffer); + checkResponseWithNoBody("json", checkBodyJSON); + checkResponseWithNoBody("formData", checkBodyFormData); + + function checkResponseWithEmptyBody(bodyType, body, asText) { + promise_test(function(test) { + var response = new Response(body); + assert_false(response.bodyUsed, "bodyUsed is false at init"); + if (asText) { + return response.text().then(function(bodyAsString) { + assert_equals(bodyAsString.length, 0, "Resolved value should be empty"); + assert_true(response.bodyUsed, "bodyUsed is true after being consumed"); + }); + } + return response.arrayBuffer().then(function(bodyAsArrayBuffer) { + assert_equals(bodyAsArrayBuffer.byteLength, 0, "Resolved value should be empty"); + assert_true(response.bodyUsed, "bodyUsed is true after being consumed"); + }); + }, "Consume empty " + bodyType + " response body as " + (asText ? "text" : "arrayBuffer")); + } + + // FIXME: Add BufferSource, FormData and URLSearchParams. + checkResponseWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), false); + checkResponseWithEmptyBody("text", "", false); + checkResponseWithEmptyBody("blob", new Blob([], { "type" : "text/plain" }), true); + checkResponseWithEmptyBody("text", "", true); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-consume-stream.html b/testing/web-platform/tests/fetch/api/response/response-consume-stream.html new file mode 100644 index 000000000..f96192fa9 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-consume-stream.html @@ -0,0 +1,66 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response consume</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="../resources/utils.js"></script> + </head> + <body> + <script> + +promise_test(function(test) { + var body = ""; + var response = new Response(""); + return validateStreamFromString(response.body.getReader(), ""); +}, "Read empty text response's body as readableStream"); + +promise_test(function(test) { + var response = new Response(new Blob([], { "type" : "text/plain" })); + return validateStreamFromString(response.body.getReader(), ""); +}, "Read empty blob response's body as readableStream"); + +var formData = new FormData(); +formData.append("name", "value"); +var textData = JSON.stringify("This is response's body"); +var blob = new Blob([textData], { "type" : "text/plain" }); + +promise_test(function(test) { + var response = new Response(blob); + return validateStreamFromString(response.body.getReader(), textData); +}, "Read blob response's body as readableStream"); + +promise_test(function(test) { + var response = new Response(textData); + return validateStreamFromString(response.body.getReader(), textData); +}, "Read text response's body as readableStream"); + +promise_test(function(test) { + var arrayBuffer = new ArrayBuffer(textData.length); + var int8Array = new Int8Array(arrayBuffer); + for (var cptr = 0; cptr < textData.length; cptr++) + int8Array[cptr] = textData.charCodeAt(cptr); + + return validateStreamFromString(new Response(arrayBuffer).body.getReader(), textData); +}, "Read array buffer response's body as readableStream"); + +promise_test(function(test) { + var response = new Response(formData); + return validateStreamFromString(response.body.getReader(), "name=value"); +}, "Read form data response's body as readableStream"); + +test(function() { + assert_equals(Response.error().body, null); +}, "Getting an error Response stream"); + +promise_test(function(test) { + assert_equals(Response.redirect(301).body, null); +}, "Getting a redirect Response stream"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-consume.html b/testing/web-platform/tests/fetch/api/response/response-consume.html new file mode 100644 index 000000000..56e234248 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-consume.html @@ -0,0 +1,131 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response consume</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="../resources/utils.js"></script> + </head> + <body> + <script> + function checkBodyText(response, expectedBody) { + return response.text().then( function(bodyAsText) { + assert_equals(bodyAsText, expectedBody, "Retrieve and verify response's body"); + assert_true(response.bodyUsed, "body as text: bodyUsed turned true"); + }); + } + + function checkBodyBlob(response, expectedBody, checkContentType) { + return response.blob().then(function(bodyAsBlob) { + if (checkContentType) + assert_equals(bodyAsBlob.type, "text/plain", "Blob body type should be computed from the response Content-Type"); + + var promise = new Promise( function (resolve, reject) { + var reader = new FileReader(); + reader.onload = function(evt) { + resolve(reader.result) + }; + reader.onerror = function () { + reject("Blob's reader failed"); + }; + reader.readAsText(bodyAsBlob); + }); + return promise.then(function(body) { + assert_equals(body, expectedBody, "Retrieve and verify response's body"); + assert_true(response.bodyUsed, "body as blob: bodyUsed turned true"); + }); + }); + } + + function checkBodyArrayBuffer(response, expectedBody) { + return response.arrayBuffer().then( function(bodyAsArrayBuffer) { + validateBufferFromString(bodyAsArrayBuffer, expectedBody, "Retrieve and verify response's body"); + assert_true(response.bodyUsed, "body as arrayBuffer: bodyUsed turned true"); + }); + } + + function checkBodyJSON(response, expectedBody) { + return response.json().then(function(bodyAsJSON) { + var strBody = JSON.stringify(bodyAsJSON) + assert_equals(strBody, expectedBody, "Retrieve and verify response's body"); + assert_true(response.bodyUsed, "body as json: bodyUsed turned true"); + }); + } + + function checkBodyFormData(response, expectedBody) { + return response.formData().then(function(bodyAsFormData) { + assert_true(bodyAsFormData instanceof FormData, "Should receive a FormData"); + assert_true(response.bodyUsed, "body as formData: bodyUsed turned true"); + }); + } + + function checkResponseBody(body, bodyType, checkFunction) { + promise_test(function(test) { + var response = new Response(body, { "headers": [["Content-Type", "text/PLAIN"]] }); + assert_false(response.bodyUsed, "bodyUsed is false at init"); + return checkFunction(response, body); + }, "Consume response's body as " + bodyType); + } + + var formData = new FormData(); + formData.append("name", "value"); + var textData = JSON.stringify("This is response's body"); + var blob = new Blob([textData], { "type" : "text/plain" }); + + checkResponseBody(textData, "text", checkBodyText); + checkResponseBody(textData, "blob", function(response, body) { checkBodyBlob(response, body, true); }); + checkResponseBody(textData, "arrayBuffer", checkBodyArrayBuffer); + checkResponseBody(textData, "json", checkBodyJSON); + checkResponseBody(formData, "formData", checkBodyFormData); + + function checkBlobResponseBody(blobBody, blobData, bodyType, checkFunction) { + promise_test(function(test) { + var response = new Response(blobBody); + assert_false(response.bodyUsed, "bodyUsed is false at init"); + return checkFunction(response, blobData); + }, "Consume blob response's body as " + bodyType); + } + + checkBlobResponseBody(blob, textData, "blob", checkBodyBlob); + checkBlobResponseBody(blob, textData, "text", checkBodyText); + checkBlobResponseBody(blob, textData, "json", checkBodyJSON); + checkBlobResponseBody(blob, textData, "arrayBuffer", checkBodyArrayBuffer); + + function checkReadableStreamResponseBody(streamData, bodyType, checkFunction) { + promise_test(function(test) { + var stream = new ReadableStream({ + start: function(controller) { + controller.enqueue((stringToArray(streamData))); + controller.close(); + } + }); + var response = new Response(stream); + assert_false(response.bodyUsed, "bodyUsed is false at init"); + return checkFunction(response, streamData); + }, "Consume stream response's body as " + bodyType); + } + + checkReadableStreamResponseBody(textData, "blob", checkBodyBlob); + checkReadableStreamResponseBody(textData, "text", checkBodyText); + checkReadableStreamResponseBody(textData, "json", checkBodyJSON); + checkReadableStreamResponseBody(textData, "arrayBuffer", checkBodyArrayBuffer); + + function checkFetchedResponseBody(bodyType, checkFunction) { + return promise_test(function(test) { + return fetch("../resources/top.txt").then(function(response) { + assert_false(response.bodyUsed, "bodyUsed is false at init"); + return checkFunction(response, "top"); + }); + }, "Consume fetched response's body as " + bodyType); + } + checkFetchedResponseBody("blob", checkBodyBlob); + checkFetchedResponseBody("text", checkBodyText); + checkFetchedResponseBody("arrayBuffer", checkBodyArrayBuffer); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-error.html b/testing/web-platform/tests/fetch/api/response/response-error.html new file mode 100644 index 000000000..1e68f6d01 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-error.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response error</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var invalidStatus = [0, 100, 199, 600, 1000]; + invalidStatus.forEach(function(status) { + test(function() { + assert_throws(new RangeError() , function() { new Response("", { "status" : status }); }, + "Expect RangeError exception when status is " + status); + },"Throws RangeError when responseInit's status is " + status); + }); + + var invalidStatusText = ["\n", "Ā"]; + invalidStatusText.forEach(function(statusText) { + test(function() { + assert_throws(new TypeError() , function() { new Response("", { "statusText" : statusText }); }, + "Expect TypeError exception " + statusText); + },"Throws TypeError when responseInit's statusText is " + statusText); + }); + + var nullBodyStatus = [204, 205, 304]; + nullBodyStatus.forEach(function(status) { + test(function() { + assert_throws(new TypeError() , + function() { new Response("body", {"status" : status }); }, + "Expect TypeError exception "); + },"Throws TypeError when building a response with body and a body status of " + status); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-idl.html b/testing/web-platform/tests/fetch/api/response/response-idl.html new file mode 100644 index 000000000..e849856ce --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-idl.html @@ -0,0 +1,69 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response idl interface</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/WebIDLParser.js"></script> + <script src="/resources/idlharness.js"></script> + </head> + <body> + <script id="body-idl" type="text/plain"> + typedef any JSON; + typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) BodyInit; + + [NoInterfaceObject, + Exposed=(Window,Worker)] + interface Body { + readonly attribute boolean bodyUsed; + [NewObject] Promise<ArrayBuffer> arrayBuffer(); + [NewObject] Promise<Blob> blob(); + [NewObject] Promise<FormData> formData(); + [NewObject] Promise<JSON> json(); + [NewObject] Promise<USVString> text(); + }; + </script> + <script id="response-idl" type="text/plain"> + [Constructor(optional BodyInit body, optional ResponseInit init), + Exposed=(Window,Worker)] + interface Response { + [NewObject] static Response error(); + [NewObject] static Response redirect(USVString url, optional unsigned short status = 302); + + readonly attribute ResponseType type; + + readonly attribute USVString url; + readonly attribute unsigned short status; + readonly attribute boolean ok; + readonly attribute ByteString statusText; + [SameObject] readonly attribute Headers headers; + readonly attribute ReadableStream? body; + + [NewObject] Response clone(); + }; + Response implements Body; + + dictionary ResponseInit { + unsigned short status = 200; + ByteString statusText = "OK"; + HeadersInit headers; + }; + + enum ResponseType { "basic", "cors", "default", "error", "opaque", "opaqueredirect" }; + </script> + <script> + var idlsArray = new IdlArray(); + var idl = document.getElementById("body-idl").innerHTML + idl += document.getElementById("response-idl").innerHTML + + idlsArray.add_idls(idl); + idlsArray.add_untested_idls("interface Headers {};"); + idlsArray.add_untested_idls("interface ReadableStream {};"); + idlsArray.add_objects({ Response: ['new Response()'] }); + idlsArray.test(); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-init-001.html b/testing/web-platform/tests/fetch/api/response/response-init-001.html new file mode 100644 index 000000000..4a8a7bd80 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-init-001.html @@ -0,0 +1,63 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response init: simple cases</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var defaultValues = { "type" : "default", + "url" : "", + "ok" : true, + "status" : 200, + "statusText" : "OK", + "body" : null + }; + + var statusCodes = { "givenValues" : [200, 300, 400, 500, 599], + "expectedValues" : [200, 300, 400, 500, 599] + }; + var statusTexts = { "givenValues" : ["OK", "with space", String.fromCharCode(0x80)], + "expectedValues" : ["OK", "with space", String.fromCharCode(0x80)] + }; + var initValuesDict = { "status" : statusCodes, + "statusText" : statusTexts + }; + + function isOkStatus(status) { + return 200 <= status && 299 >= status; + } + + var response = new Response(); + for (var attributeName in defaultValues) { + test(function() { + var expectedValue = defaultValues[attributeName]; + assert_equals(response[attributeName], expectedValue, + "Expect default response." + attributeName + " is " + expectedValue); + }, "Check default value for " + attributeName + " attribute"); + } + + for (var attributeName in initValuesDict) + test(function() { + var valuesToTest = initValuesDict[attributeName]; + for (var valueIdx in valuesToTest["givenValues"]) { + var givenValue = valuesToTest["givenValues"][valueIdx]; + var expectedValue = valuesToTest["expectedValues"][valueIdx]; + var responseInit = {}; + responseInit[attributeName] = givenValue; + var response = new Response("", responseInit); + assert_equals(response[attributeName], expectedValue, + "Expect response." + attributeName + " is " + expectedValue + + " when initialized with " + givenValue); + assert_equals(response.ok, isOkStatus(response.status), + "Expect response.ok is " + isOkStatus(response.status)); + } + }, "Check " + attributeName + " init values and associated getter"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-init-002.html b/testing/web-platform/tests/fetch/api/response/response-init-002.html new file mode 100644 index 000000000..0bb2e8d0b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-init-002.html @@ -0,0 +1,70 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response init: body and headers</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-response"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script src="../resources/utils.js"></script> + <script> + test(function() { + var headerDict = {"name1": "value1", + "name2": "value2", + "name3": "value3" + }; + var headers = new Headers(headerDict); + var response = new Response("", { "headers" : headers }) + for (var name in headerDict) { + assert_equals(response.headers.get(name), headerDict[name], + "response's headers has " + name + " : " + headerDict[name]); + } + }, "Initialize Response with headers values"); + + function checkResponseInit(body, bodyType, expectedTextBody) { + promise_test(function(test) { + var response = new Response(body); + var resHeaders = response.headers; + var mime = resHeaders.get("Content-Type"); + assert_true(mime && mime.search(bodyType) > -1, "Content-Type header should be \"" + bodyType + "\" "); + return response.text().then(function(bodyAsText) { + //not equals: cannot guess formData exact value + assert_true(bodyAsText.search(expectedTextBody) > -1, "Retrieve and verify response body"); + }); + }, "Initialize Response's body with " + bodyType); + } + + var blob = new Blob(["This is a blob"], {type: "application/octet-binary"}); + var formaData = new FormData(); + formaData.append("name", "value"); + var urlSearchParams = "URLSearchParams are not supported"; + //avoid test timeout if not implemented + if (window.URLSearchParams) + urlSearchParams = new URLSearchParams("name=value"); + var usvString = "This is a USVString" + + checkResponseInit(blob, "application/octet-binary", "This is a blob"); + checkResponseInit(formaData, "multipart/form-data", "name=\"name\"\r\n\r\nvalue"); + checkResponseInit(urlSearchParams, "application/x-www-form-urlencoded;charset=UTF-8", "name=value"); + checkResponseInit(usvString, "text/plain;charset=UTF-8", "This is a USVString"); + + promise_test(function(test) { + var body = "This is response body"; + var response = new Response(body); + return validateStreamFromString(response.body.getReader(), body); + }, "Read Response's body as readableStream"); + + promise_test(function(test) { + var response = new Response("This is my fork", {"headers" : [["Content-Type", ""]]}); + return response.blob().then(function(blob) { + assert_equals(blob.type, "", "Blob type should be the empty string"); + }); + }, "Testing empty Response Content-Type header"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-static-error.html b/testing/web-platform/tests/fetch/api/response/response-static-error.html new file mode 100644 index 000000000..6e927a8bf --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-static-error.html @@ -0,0 +1,25 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response: error static method</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#concept-network-error"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + test(function() { + var responseError = Response.error(); + assert_equals(responseError.type, "error", "Network error response's type is error"); + assert_equals(responseError.status, 0, "Network error response's status is 0"); + assert_equals(responseError.statusText, "", "Network error response's statusText is empty"); + assert_equals(responseError.body, null, "Network error response's body is null"); + + assert_true(responseError.headers.entries().next().done, "Headers should be empty"); + }, "Check response returned by static method error()"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-static-redirect.html b/testing/web-platform/tests/fetch/api/response/response-static-redirect.html new file mode 100644 index 000000000..e09c66611 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-static-redirect.html @@ -0,0 +1,45 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Response: redirect static method</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#redirect-status"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + var url = "http://test.url:1234/"; + test(function() { + redirectResponse = Response.redirect(url); + assert_equals(redirectResponse.status, 302, "Default redirect status is 302"); + assert_equals(redirectResponse.headers.get("Location"), url, + "redirected response has Location header with the correct url"); + }, "Check default redirect response"); + + var redirectStatus = [301, 302, 303, 307, 308]; + redirectStatus.forEach(function(status) { + test(function() { + redirectResponse = Response.redirect(url, status); + assert_equals(redirectResponse.status, status, "Redirect status is " + status); + }, "Check response returned by static method redirect(), status = " + status); + }); + + test(function() { + var invalidUrl = "http://:This is not an url"; + assert_throws(new TypeError(), function() { Response.redirect(invalidUrl); }, + "Expect TypeError exception"); + }, "Check error returned when giving invalid url to redirect()"); + + var invalidRedirectStatus = [200, 309, 400, 500]; + invalidRedirectStatus.forEach(function(invalidStatus) { + test(function() { + assert_throws(new RangeError() , function() { Response.redirect(url, invalidStatus); }, + "Expect RangeError exception"); + }, "Check error returned when giving invalid status to redirect(), status = " + invalidStatus); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-1.html b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-1.html new file mode 100644 index 000000000..e9db8f77b --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-1.html @@ -0,0 +1,57 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Consuming Response body after getting a ReadableStream</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + +function createResponseWithReadableStream(callback) { + return fetch("../resources/data.json").then(function(response) { + var reader = response.body.getReader(); + reader.releaseLock(); + return callback(response); + }); +} + +promise_test(function() { + return createResponseWithReadableStream(function(response) { + return response.blob().then(function(blob) { + assert_true(blob instanceof Blob); + }); + }); +}, "Getting blob after getting the Response body - not disturbed, not locked"); + +promise_test(function() { + return createResponseWithReadableStream(function(response) { + return response.text().then(function(text) { + assert_true(text.length > 0); + }); + }); +}, "Getting text after getting the Response body - not disturbed, not locked"); + +promise_test(function() { + return createResponseWithReadableStream(function(response) { + return response.json().then(function(json) { + assert_true(typeof json === "object"); + }); + }); +}, "Getting json after getting the Response body - not disturbed, not locked"); + +promise_test(function() { + return createResponseWithReadableStream(function(response) { + return response.arrayBuffer().then(function(arrayBuffer) { + assert_true(arrayBuffer.byteLength > 0); + }); + }); +}, "Getting arrayBuffer after getting the Response body - not disturbed, not locked"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-2.html b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-2.html new file mode 100644 index 000000000..a1e2f3f24 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-2.html @@ -0,0 +1,48 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Consuming Response body after getting a ReadableStream</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + +function createResponseWithLockedReadableStream(callback) { + return fetch("../resources/data.json").then(function(response) { + var reader = response.body.getReader(); + return callback(response); + }); +} + +promise_test(function(test) { + return createResponseWithLockedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.blob()); + }); +}, "Getting blob after getting a locked Response body"); + +promise_test(function(test) { + return createResponseWithLockedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.text()); + }); +}, "Getting text after getting a locked Response body"); + +promise_test(function(test) { + return createResponseWithLockedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.json()); + }); +}, "Getting json after getting a locked Response body"); + +promise_test(function(test) { + return createResponseWithLockedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.arrayBuffer()); + }); +}, "Getting arrayBuffer after getting a locked Response body"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-3.html b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-3.html new file mode 100644 index 000000000..8d9212514 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-3.html @@ -0,0 +1,49 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Consuming Response body after getting a ReadableStream</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + +function createResponseWithDisturbedReadableStream(callback) { + return fetch("../resources/data.json").then(function(response) { + var reader = response.body.getReader(); + reader.read(); + return callback(response); + }); +} + +promise_test(function(test) { + return createResponseWithDisturbedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.blob()); + }); +}, "Getting blob after reading the Response body"); + +promise_test(function(test) { + return createResponseWithDisturbedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.text()); + }); +}, "Getting text after reading the Response body"); + +promise_test(function(test) { + return createResponseWithDisturbedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.json()); + }); +}, "Getting json after reading the Response body"); + +promise_test(function(test) { + return createResponseWithDisturbedReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.arrayBuffer()); + }); +}, "Getting arrayBuffer after reading the Response body"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-4.html b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-4.html new file mode 100644 index 000000000..e74699211 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-4.html @@ -0,0 +1,48 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Consuming Response body after getting a ReadableStream</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + +function createResponseWithCancelledReadableStream(callback) { + return fetch("../resources/data.json").then(function(response) { + response.body.cancel(); + return callback(response); + }); +} + +promise_test(function(test) { + return createResponseWithCancelledReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.blob()); + }); +}, "Getting blob after cancelling the Response body"); + +promise_test(function(test) { + return createResponseWithCancelledReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.text()); + }); +}, "Getting text after cancelling the Response body"); + +promise_test(function(test) { + return createResponseWithCancelledReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.json()); + }); +}, "Getting json after cancelling the Response body"); + +promise_test(function(test) { + return createResponseWithCancelledReadableStream(function(response) { + return promise_rejects(test, new TypeError(), response.arrayBuffer()); + }); +}, "Getting arrayBuffer after cancelling the Response body"); + + </script> + </body> +</html> diff --git a/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-5.html b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-5.html new file mode 100644 index 000000000..546b7b888 --- /dev/null +++ b/testing/web-platform/tests/fetch/api/response/response-stream-disturbed-5.html @@ -0,0 +1,49 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <title>Consuming Response body after getting a ReadableStream</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#response"> + <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> + <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + +promise_test(function() { + return fetch("../resources/data.json").then(function(response) { + response.blob(); + assert_not_equals(response.body, null); + assert_throws(new TypeError(), function() { response.body.getReader(); }); + }); +}, "Getting a body reader after consuming as blob"); + +promise_test(function() { + return fetch("../resources/data.json").then(function(response) { + response.text(); + assert_not_equals(response.body, null); + assert_throws(new TypeError(), function() { response.body.getReader(); }); + }); +}, "Getting a body reader after consuming as text"); + +promise_test(function() { + return fetch("../resources/data.json").then(function(response) { + response.json(); + assert_not_equals(response.body, null); + assert_throws(new TypeError(), function() { response.body.getReader(); }); + }); +}, "Getting a body reader after consuming as json"); + +promise_test(function() { + return fetch("../resources/data.json").then(function(response) { + response.arrayBuffer(); + assert_not_equals(response.body, null); + assert_throws(new TypeError(), function() { response.body.getReader(); }); + }); +}, "Getting a body reader after consuming as arrayBuffer"); + + </script> + </body> +</html> 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 000000000..e5869d94e --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/image.html @@ -0,0 +1,29 @@ +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + var fails = ["", "?type=", "?type=x", "?type=x/x"], + passes = ["?type=image/gif", "?type=image/png", "?type=image/png;blah"] + + fails.forEach(function(urlpart) { + async_test(function(t) { + var img = document.createElement("img") + img.onerror = t.step_func_done(function(){}) + img.onload = t.unreached_func("Unexpected load event") + img.src = "resources/image.py" + urlpart + document.body.appendChild(img) + }, "URL query: " + urlpart) + }) + + passes.forEach(function(urlpart) { + 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 = "resources/image.py" + urlpart + document.body.appendChild(img) + }, "URL query: " + urlpart) + }) +</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 000000000..920b6bdd4 --- /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 000000000..aeb615487 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/importscripts.js @@ -0,0 +1,17 @@ +// Testing importScripts() +function log(w) { this.postMessage(w) } +function f() { log("FAIL") } +function p() { log("PASS") } + +["", "?type=", "?type=x", "?type=x/x"].forEach(function(urlpart) { + try { + importScripts("resources/js.py" + urlpart) + } catch(e) { + (e.name == "NetworkError") ? p() : log("FAIL (no NetworkError exception): " + urlpart) + } + +}) +importScripts("resources/js.py?type=text/javascript&outcome=p") +importScripts("resources/js.py?type=text/ecmascript&outcome=p") +importScripts("resources/js.py?type=text/ecmascript;blah&outcome=p") +log("END") diff --git a/testing/web-platform/tests/fetch/nosniff/parsing-nosniff.html b/testing/web-platform/tests/fetch/nosniff/parsing-nosniff.html new file mode 100644 index 000000000..10c5cadfc --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/parsing-nosniff.html @@ -0,0 +1,28 @@ +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> + var fails = ["first", "uppercase"], + passes = ["last", "quoted", "quoted-single", "no-x"] + + fails.forEach(function(urlpart) { + 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 = "resources/nosniff-" + urlpart + ".asis" + document.body.appendChild(script) + }, "URL query: " + urlpart) + }) + + passes.forEach(function(urlpart) { + 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 = "resources/nosniff-" + urlpart + ".asis" + document.body.appendChild(script) + }, "URL query: " + urlpart) + }) + +</script> 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 000000000..7c4c63b59 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/css.py @@ -0,0 +1,15 @@ +def main(request, response): + outcome = request.GET.first("outcome", "f") + type = request.GET.first("type", None) + + content = "/* nothing to see here */" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != None): + response.writer.write_header("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 000000000..8fb05edc6 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/image.py @@ -0,0 +1,16 @@ +import os.path + +def main(request, response): + type = request.GET.first("type", None) + + body = open(os.path.join(os.path.dirname(__file__), "../../../images/blue96x96.png"), "rb").read() + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(body)) + if(type != None): + response.writer.write_header("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 000000000..0c06d9cd2 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/js.py @@ -0,0 +1,17 @@ +def main(request, response): + outcome = request.GET.first("outcome", "f") + type = request.GET.first("type", "Content-Type missing") + + content = "// nothing to see here" + content += "\n" + content += "log('FAIL: " + type + "')" if (outcome == "f") else "p()" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != "Content-Type missing"): + response.writer.write_header("content-type", type) + response.writer.end_headers() + + response.writer.write(content) diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff-first.asis b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-first.asis new file mode 100644 index 000000000..bccc53eef --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-first.asis @@ -0,0 +1,7 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-options: nosniff +X-Content-Type-Options: no + +// nothing to see here diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff-last.asis b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-last.asis new file mode 100644 index 000000000..e3de0733e --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-last.asis @@ -0,0 +1,7 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: no +X-Content-Type-options: nosniff + +// nothing to see here diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff-no-x.asis b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-no-x.asis new file mode 100644 index 000000000..329d0f721 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-no-x.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +Content-Type-Options: nosniff + +// nothing to see here diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff-quoted-single.asis b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-quoted-single.asis new file mode 100644 index 000000000..501f18999 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-quoted-single.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: 'NosniFF' + +// nothing to see here diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff-quoted.asis b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-quoted.asis new file mode 100644 index 000000000..c6de62b68 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-quoted.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: "nosniFF" + +// nothing to see here diff --git a/testing/web-platform/tests/fetch/nosniff/resources/nosniff-uppercase.asis b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-uppercase.asis new file mode 100644 index 000000000..8097fddce --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/nosniff-uppercase.asis @@ -0,0 +1,6 @@ +HTTP/1.1 200 YOU HAVE NO POWER HERE +Content-Length: 22 +Content-Type: x/x +X-Content-Type-Options: NOSNIFF + +// nothing to see here 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 000000000..3903ba349 --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/resources/worker.py @@ -0,0 +1,16 @@ +def main(request, response): + type = request.GET.first("type", None) + + content = "// nothing to see here" + content += "\n" + content += "this.postMessage('hi')" + + response.add_required_headers = False + response.writer.write_status(200) + response.writer.write_header("x-content-type-options", "nosniff") + response.writer.write_header("content-length", len(content)) + if(type != None): + response.writer.write_header("content-type", type) + response.writer.end_headers() + + response.writer.write(content) 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 000000000..667f3c99a --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/script.html @@ -0,0 +1,32 @@ +<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 = ["", "?type=", "?type=x", "?type=x/x"], + passes = ["?type=text/javascript", "?type=text/ecmascript", "?type=text/ecmascript;blah"] + + // 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. + + fails.forEach(function(urlpart) { + 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 = "resources/js.py" + urlpart + document.body.appendChild(script) + }, "URL query: " + urlpart) + }) + + passes.forEach(function(urlpart) { + 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 = "resources/js.py" + urlpart + "&outcome=p" + document.body.appendChild(script) + }, "URL query: " + urlpart) + }) +</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 000000000..0ad04038e --- /dev/null +++ b/testing/web-platform/tests/fetch/nosniff/stylesheet.html @@ -0,0 +1,30 @@ +<!-- 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 = ["", "?type=", "?type=x", "?type=x/x"], + passes = ["?type=text/css", "?type=text/css;blah"] + + fails.forEach(function(urlpart) { + async_test(function(t) { + var link = document.createElement("link") + link.rel = "stylesheet" + link.onerror = t.step_func_done(function(){}) + link.onload = t.unreached_func("Unexpected load event") + link.href = "resources/css.py" + urlpart + document.body.appendChild(link) + }, "URL query: " + urlpart) + }) + + passes.forEach(function(urlpart) { + 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(function(){}) + link.href = "resources/css.py" + urlpart + document.body.appendChild(link) + }, "URL query: " + urlpart) + }) +</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 000000000..466b2075e --- /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"], + 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> |