summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fetch/api/resources
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/fetch/api/resources')
-rw-r--r--testing/web-platform/tests/fetch/api/resources/authentication.py14
-rw-r--r--testing/web-platform/tests/fetch/api/resources/bad-chunk-encoding.py13
-rw-r--r--testing/web-platform/tests/fetch/api/resources/basic.html5
-rw-r--r--testing/web-platform/tests/fetch/api/resources/cache.py18
-rw-r--r--testing/web-platform/tests/fetch/api/resources/clean-stash.py6
-rw-r--r--testing/web-platform/tests/fetch/api/resources/cors-top.txt1
-rw-r--r--testing/web-platform/tests/fetch/api/resources/cors-top.txt.headers1
-rw-r--r--testing/web-platform/tests/fetch/api/resources/data.json1
-rw-r--r--testing/web-platform/tests/fetch/api/resources/dump-authorization-header.py14
-rw-r--r--testing/web-platform/tests/fetch/api/resources/echo-content.h2.py7
-rw-r--r--testing/web-platform/tests/fetch/api/resources/echo-content.py12
-rw-r--r--testing/web-platform/tests/fetch/api/resources/empty.txt0
-rw-r--r--testing/web-platform/tests/fetch/api/resources/infinite-slow-response.py35
-rw-r--r--testing/web-platform/tests/fetch/api/resources/inspect-headers.py24
-rw-r--r--testing/web-platform/tests/fetch/api/resources/keepalive-iframe.html25
-rw-r--r--testing/web-platform/tests/fetch/api/resources/keepalive-window.html34
-rw-r--r--testing/web-platform/tests/fetch/api/resources/method.py18
-rw-r--r--testing/web-platform/tests/fetch/api/resources/preflight.py78
-rw-r--r--testing/web-platform/tests/fetch/api/resources/redirect-empty-location.py3
-rw-r--r--testing/web-platform/tests/fetch/api/resources/redirect.h2.py14
-rw-r--r--testing/web-platform/tests/fetch/api/resources/redirect.py73
-rw-r--r--testing/web-platform/tests/fetch/api/resources/sandboxed-iframe.html34
-rw-r--r--testing/web-platform/tests/fetch/api/resources/script-with-header.py7
-rw-r--r--testing/web-platform/tests/fetch/api/resources/stash-put.py17
-rw-r--r--testing/web-platform/tests/fetch/api/resources/stash-take.py9
-rw-r--r--testing/web-platform/tests/fetch/api/resources/status.py11
-rw-r--r--testing/web-platform/tests/fetch/api/resources/sw-intercept-abort.js19
-rw-r--r--testing/web-platform/tests/fetch/api/resources/sw-intercept.js10
-rw-r--r--testing/web-platform/tests/fetch/api/resources/top.txt1
-rw-r--r--testing/web-platform/tests/fetch/api/resources/trickle.py15
-rw-r--r--testing/web-platform/tests/fetch/api/resources/utils.js105
31 files changed, 624 insertions, 0 deletions
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 0000000000..8b6b00b087
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/authentication.py
@@ -0,0 +1,14 @@
+def main(request, response):
+ user = request.auth.username
+ password = request.auth.password
+
+ if user == b"user" and password == b"password":
+ return b"Authentication done"
+
+ realm = b"test"
+ if b"realm" in request.GET:
+ realm = request.GET.first(b"realm")
+
+ return ((401, b"Unauthorized"),
+ [(b"WWW-Authenticate", b'Basic realm="' + realm + b'"')],
+ b"Please login with credentials 'user' and 'password'")
diff --git a/testing/web-platform/tests/fetch/api/resources/bad-chunk-encoding.py b/testing/web-platform/tests/fetch/api/resources/bad-chunk-encoding.py
new file mode 100644
index 0000000000..94a77adead
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/bad-chunk-encoding.py
@@ -0,0 +1,13 @@
+import time
+
+def main(request, response):
+ delay = float(request.GET.first(b"ms", 1000)) / 1E3
+ count = int(request.GET.first(b"count", 50))
+ time.sleep(delay)
+ response.headers.set(b"Transfer-Encoding", b"chunked")
+ response.write_status_headers()
+ time.sleep(delay)
+ for i in range(count):
+ response.writer.write_content(b"a\r\nTEST_CHUNK\r\n")
+ time.sleep(delay)
+ response.writer.write_content(b"garbage")
diff --git a/testing/web-platform/tests/fetch/api/resources/basic.html b/testing/web-platform/tests/fetch/api/resources/basic.html
new file mode 100644
index 0000000000..e23afd4bf6
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/basic.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<!--
+ Duplicating /common/blank.html to make service worker scoping simpler in
+ ../abort/serviceworker-intercepted.https.html
+-->
diff --git a/testing/web-platform/tests/fetch/api/resources/cache.py b/testing/web-platform/tests/fetch/api/resources/cache.py
new file mode 100644
index 0000000000..4de751e30b
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/cache.py
@@ -0,0 +1,18 @@
+ETAG = b'"123abc"'
+CONTENT_TYPE = b"text/plain"
+CONTENT = b"lorem ipsum dolor sit amet"
+
+
+def main(request, response):
+ # let caching kick in if possible (conditional GET)
+ etag = request.headers.get(b"If-None-Match", None)
+ if etag == ETAG:
+ response.headers.set(b"X-HTTP-STATUS", 304)
+ response.status = (304, b"Not Modified")
+ return b""
+
+ # cache miss, so respond with the actual content
+ response.status = (200, b"OK")
+ response.headers.set(b"ETag", ETAG)
+ response.headers.set(b"Content-Type", CONTENT_TYPE)
+ return CONTENT
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 0000000000..ee8c69ac44
--- /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(b"token")
+ if request.server.stash.take(token) is not None:
+ return b"1"
+ else:
+ return b"0"
diff --git a/testing/web-platform/tests/fetch/api/resources/cors-top.txt b/testing/web-platform/tests/fetch/api/resources/cors-top.txt
new file mode 100644
index 0000000000..83a3157d14
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/cors-top.txt
@@ -0,0 +1 @@
+top \ No newline at end of file
diff --git a/testing/web-platform/tests/fetch/api/resources/cors-top.txt.headers b/testing/web-platform/tests/fetch/api/resources/cors-top.txt.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/cors-top.txt.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
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 0000000000..76519fa8cc
--- /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/dump-authorization-header.py b/testing/web-platform/tests/fetch/api/resources/dump-authorization-header.py
new file mode 100644
index 0000000000..a651aeb4e8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/dump-authorization-header.py
@@ -0,0 +1,14 @@
+def main(request, response):
+ headers = [(b"Content-Type", "text/html"),
+ (b"Cache-Control", b"no-cache")]
+
+ if b"Origin" in request.headers:
+ headers.append((b"Access-Control-Allow-Origin", request.headers.get(b"Origin", b"")))
+ headers.append((b"Access-Control-Allow-Credentials", b"true"))
+ else:
+ headers.append((b"Access-Control-Allow-Origin", b"*"))
+ headers.append((b"Access-Control-Allow-Headers", b'Authorization'))
+
+ if b"authorization" in request.headers:
+ return 200, headers, request.headers.get(b"Authorization")
+ return 200, headers, "none"
diff --git a/testing/web-platform/tests/fetch/api/resources/echo-content.h2.py b/testing/web-platform/tests/fetch/api/resources/echo-content.h2.py
new file mode 100644
index 0000000000..0be3ece4a5
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/echo-content.h2.py
@@ -0,0 +1,7 @@
+def handle_headers(frame, request, response):
+ response.status = 200
+ response.headers.update([('Content-Type', 'text/plain')])
+ response.write_status_headers()
+
+def handle_data(frame, request, response):
+ response.writer.write_data(frame.data)
diff --git a/testing/web-platform/tests/fetch/api/resources/echo-content.py b/testing/web-platform/tests/fetch/api/resources/echo-content.py
new file mode 100644
index 0000000000..5e137e15d7
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/echo-content.py
@@ -0,0 +1,12 @@
+from wptserve.utils import isomorphic_encode
+
+def main(request, response):
+
+ headers = [(b"X-Request-Method", isomorphic_encode(request.method)),
+ (b"X-Request-Content-Length", request.headers.get(b"Content-Length", b"NO")),
+ (b"X-Request-Content-Type", request.headers.get(b"Content-Type", b"NO")),
+ # Avoid any kind of content sniffing on the response.
+ (b"Content-Type", b"text/plain")]
+ content = request.body
+
+ return headers, content
diff --git a/testing/web-platform/tests/fetch/api/resources/empty.txt b/testing/web-platform/tests/fetch/api/resources/empty.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/empty.txt
diff --git a/testing/web-platform/tests/fetch/api/resources/infinite-slow-response.py b/testing/web-platform/tests/fetch/api/resources/infinite-slow-response.py
new file mode 100644
index 0000000000..a26cd8064c
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/infinite-slow-response.py
@@ -0,0 +1,35 @@
+import time
+
+
+def url_dir(request):
+ return u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/'
+
+
+def stash_write(request, key, value):
+ """Write to the stash, overwriting any previous value"""
+ request.server.stash.take(key, url_dir(request))
+ request.server.stash.put(key, value, url_dir(request))
+
+
+def main(request, response):
+ stateKey = request.GET.first(b"stateKey", b"")
+ abortKey = request.GET.first(b"abortKey", b"")
+
+ if stateKey:
+ stash_write(request, stateKey, 'open')
+
+ response.headers.set(b"Content-type", b"text/plain")
+ response.write_status_headers()
+
+ # Writing an initial 2k so browsers realise it's there. *shrug*
+ response.writer.write(b"." * 2048)
+
+ while True:
+ if not response.writer.write(b"."):
+ break
+ if abortKey and request.server.stash.take(abortKey, url_dir(request)):
+ break
+ time.sleep(0.01)
+
+ if stateKey:
+ stash_write(request, stateKey, 'closed')
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 0000000000..9ed566e607
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/inspect-headers.py
@@ -0,0 +1,24 @@
+def main(request, response):
+ headers = []
+ if b"headers" in request.GET:
+ checked_headers = request.GET.first(b"headers").split(b"|")
+ for header in checked_headers:
+ if header in request.headers:
+ headers.append((b"x-request-" + header, request.headers.get(header, b"")))
+
+ if b"cors" in request.GET:
+ if b"Origin" in request.headers:
+ headers.append((b"Access-Control-Allow-Origin", request.headers.get(b"Origin", b"")))
+ else:
+ headers.append((b"Access-Control-Allow-Origin", b"*"))
+ headers.append((b"Access-Control-Allow-Credentials", b"true"))
+ headers.append((b"Access-Control-Allow-Methods", b"GET, POST, HEAD"))
+ exposed_headers = [b"x-request-" + header for header in checked_headers]
+ headers.append((b"Access-Control-Expose-Headers", b", ".join(exposed_headers)))
+ if b"allow_headers" in request.GET:
+ headers.append((b"Access-Control-Allow-Headers", request.GET[b'allow_headers']))
+ else:
+ headers.append((b"Access-Control-Allow-Headers", b", ".join(request.headers)))
+
+ headers.append((b"content-type", b"text/plain"))
+ return headers, b""
diff --git a/testing/web-platform/tests/fetch/api/resources/keepalive-iframe.html b/testing/web-platform/tests/fetch/api/resources/keepalive-iframe.html
new file mode 100644
index 0000000000..47de0da779
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/keepalive-iframe.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+const SEARCH_PARAMS = new URL(location.href).searchParams;
+const ORIGIN1 = SEARCH_PARAMS.get('origin1') || '';
+const ORIGIN2 = SEARCH_PARAMS.get('origin2') || '';
+const WITH_HEADERS = !!SEARCH_PARAMS.has('with-headers');
+const TOKEN = token();
+
+const url =
+ `${ORIGIN1}/fetch/api/resources/redirect.py?` +
+ `delay=500&` +
+ `allow_headers=foo&` +
+ `location=${ORIGIN2}/fetch/api/resources/stash-put.py?key=${TOKEN}%26value=on`;
+
+addEventListener('load', () => {
+ const headers = WITH_HEADERS ? {'foo': 'bar'} : undefined;
+ let p = fetch(url, {keepalive: true, headers});
+ window.parent.postMessage(TOKEN, '*');
+});
+</script>
+</html>
diff --git a/testing/web-platform/tests/fetch/api/resources/keepalive-window.html b/testing/web-platform/tests/fetch/api/resources/keepalive-window.html
new file mode 100644
index 0000000000..6ccf484644
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/keepalive-window.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+const TOKEN = token();
+const {
+ HTTP_NOTSAMESITE_ORIGIN,
+ HTTP_REMOTE_ORIGIN,
+ HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT
+} = get_host_info();
+const REDIRECT_DESTINATION =
+ `${HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT}/fetch/api/resources/stash-put.py` +
+ `?key=${TOKEN}&value=on`;
+const URL =
+ `${HTTP_REMOTE_ORIGIN}/fetch/api/resources/redirect.py?` +
+ `delay=500&` +
+ `allow_headers=foo&` +
+ `location=${encodeURIComponent(REDIRECT_DESTINATION)}`;
+
+addEventListener('load', () => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ iframe.contentWindow.addEventListener('unload', () => {
+ iframe.contentWindow.fetch(URL, {keepalive: true, headers: {foo: 'bar'}});
+ });
+
+ window.opener.postMessage(TOKEN, '*');
+ // Do NOT remove `iframe` here. We want to check the case where the nested
+ // frame is implicitly closed by window closure.
+});
+</script>
+</html>
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 0000000000..c1a111b4cd
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/method.py
@@ -0,0 +1,18 @@
+from wptserve.utils import isomorphic_encode
+
+def main(request, response):
+ headers = []
+ if b"cors" in request.GET:
+ headers.append((b"Access-Control-Allow-Origin", b"*"))
+ headers.append((b"Access-Control-Allow-Credentials", b"true"))
+ headers.append((b"Access-Control-Allow-Methods", b"GET, POST, PUT, FOO"))
+ headers.append((b"Access-Control-Allow-Headers", b"x-test, x-foo"))
+ headers.append((b"Access-Control-Expose-Headers", b"x-request-method"))
+
+ headers.append((b"x-request-method", isomorphic_encode(request.method)))
+ headers.append((b"x-request-content-type", request.headers.get(b"Content-Type", b"NO")))
+ headers.append((b"x-request-content-length", request.headers.get(b"Content-Length", b"NO")))
+ headers.append((b"x-request-content-encoding", request.headers.get(b"Content-Encoding", b"NO")))
+ headers.append((b"x-request-content-language", request.headers.get(b"Content-Language", b"NO")))
+ headers.append((b"x-request-content-location", request.headers.get(b"Content-Location", b"NO")))
+ 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 0000000000..f983ef9522
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/preflight.py
@@ -0,0 +1,78 @@
+def main(request, response):
+ headers = [(b"Content-Type", b"text/plain")]
+ stashed_data = {b'control_request_headers': b"", b'preflight': b"0", b'preflight_referrer': b""}
+
+ token = None
+ if b"token" in request.GET:
+ token = request.GET.first(b"token")
+
+ if b"origin" in request.GET:
+ for origin in request.GET[b'origin'].split(b", "):
+ headers.append((b"Access-Control-Allow-Origin", origin))
+ else:
+ headers.append((b"Access-Control-Allow-Origin", b"*"))
+
+ if b"clear-stash" in request.GET:
+ if request.server.stash.take(token) is not None:
+ return headers, b"1"
+ else:
+ return headers, b"0"
+
+ if b"credentials" in request.GET:
+ headers.append((b"Access-Control-Allow-Credentials", b"true"))
+
+ if request.method == u"OPTIONS":
+ if not b"Access-Control-Request-Method" in request.headers:
+ response.set_error(400, u"No Access-Control-Request-Method header")
+ return b"ERROR: No access-control-request-method in preflight!"
+
+ if request.headers.get(b"Accept", b"") != b"*/*":
+ response.set_error(400, u"Request does not have 'Accept: */*' header")
+ return b"ERROR: Invalid access in preflight!"
+
+ if b"control_request_headers" in request.GET:
+ stashed_data[b'control_request_headers'] = request.headers.get(b"Access-Control-Request-Headers", None)
+
+ if b"max_age" in request.GET:
+ headers.append((b"Access-Control-Max-Age", request.GET[b'max_age']))
+
+ if b"allow_headers" in request.GET:
+ headers.append((b"Access-Control-Allow-Headers", request.GET[b'allow_headers']))
+
+ if b"allow_methods" in request.GET:
+ headers.append((b"Access-Control-Allow-Methods", request.GET[b'allow_methods']))
+
+ preflight_status = 200
+ if b"preflight_status" in request.GET:
+ preflight_status = int(request.GET.first(b"preflight_status"))
+
+ stashed_data[b'preflight'] = b"1"
+ stashed_data[b'preflight_referrer'] = request.headers.get(b"Referer", b"")
+ stashed_data[b'preflight_user_agent'] = request.headers.get(b"User-Agent", b"")
+ if token:
+ request.server.stash.put(token, stashed_data)
+
+ return preflight_status, headers, b""
+
+
+ if token:
+ data = request.server.stash.take(token)
+ if data:
+ stashed_data = data
+
+ if b"checkUserAgentHeaderInPreflight" in request.GET and request.headers.get(b"User-Agent") != stashed_data[b'preflight_user_agent']:
+ return 400, headers, b"ERROR: No user-agent header in preflight"
+
+ #use x-* headers for returning value to bodyless responses
+ headers.append((b"Access-Control-Expose-Headers", b"x-did-preflight, x-control-request-headers, x-referrer, x-preflight-referrer, x-origin"))
+ headers.append((b"x-did-preflight", stashed_data[b'preflight']))
+ if stashed_data[b'control_request_headers'] != None:
+ headers.append((b"x-control-request-headers", stashed_data[b'control_request_headers']))
+ headers.append((b"x-preflight-referrer", stashed_data[b'preflight_referrer']))
+ headers.append((b"x-referrer", request.headers.get(b"Referer", b"")))
+ headers.append((b"x-origin", request.headers.get(b"Origin", b"")))
+
+ if token:
+ request.server.stash.put(token, stashed_data)
+
+ return headers, b""
diff --git a/testing/web-platform/tests/fetch/api/resources/redirect-empty-location.py b/testing/web-platform/tests/fetch/api/resources/redirect-empty-location.py
new file mode 100644
index 0000000000..1a5f7feb2a
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/redirect-empty-location.py
@@ -0,0 +1,3 @@
+def main(request, response):
+ headers = [(b"Location", b"")]
+ return 302, headers, b""
diff --git a/testing/web-platform/tests/fetch/api/resources/redirect.h2.py b/testing/web-platform/tests/fetch/api/resources/redirect.h2.py
new file mode 100644
index 0000000000..6937014587
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/redirect.h2.py
@@ -0,0 +1,14 @@
+from wptserve.utils import isomorphic_decode, isomorphic_encode
+
+def handle_headers(frame, request, response):
+ status = 302
+ if b'redirect_status' in request.GET:
+ status = int(request.GET[b'redirect_status'])
+ response.status = status
+
+ if b'location' in request.GET:
+ url = isomorphic_decode(request.GET[b'location'])
+ response.headers[b'Location'] = isomorphic_encode(url)
+
+ response.headers.update([('Content-Type', 'text/plain')])
+ response.write_status_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 0000000000..d52ab5f3ee
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/redirect.py
@@ -0,0 +1,73 @@
+import time
+
+from urllib.parse import urlencode, urlparse
+
+from wptserve.utils import isomorphic_decode, isomorphic_encode
+
+def main(request, response):
+ stashed_data = {b'count': 0, b'preflight': b"0"}
+ status = 302
+ headers = [(b"Content-Type", b"text/plain"),
+ (b"Cache-Control", b"no-cache"),
+ (b"Pragma", b"no-cache")]
+ if b"Origin" in request.headers:
+ headers.append((b"Access-Control-Allow-Origin", request.headers.get(b"Origin", b"")))
+ headers.append((b"Access-Control-Allow-Credentials", b"true"))
+ else:
+ headers.append((b"Access-Control-Allow-Origin", b"*"))
+
+ token = None
+ if b"token" in request.GET:
+ token = request.GET.first(b"token")
+ data = request.server.stash.take(token)
+ if data:
+ stashed_data = data
+
+ if request.method == u"OPTIONS":
+ if b"allow_headers" in request.GET:
+ headers.append((b"Access-Control-Allow-Headers", request.GET[b'allow_headers']))
+ stashed_data[b'preflight'] = b"1"
+ #Preflight is not redirected: return 200
+ if not b"redirect_preflight" in request.GET:
+ if token:
+ request.server.stash.put(request.GET.first(b"token"), stashed_data)
+ return 200, headers, u""
+
+ if b"redirect_status" in request.GET:
+ status = int(request.GET[b'redirect_status'])
+ elif b"redirect_status" in request.POST:
+ status = int(request.POST[b'redirect_status'])
+
+ stashed_data[b'count'] += 1
+
+ if b"location" in request.GET:
+ url = isomorphic_decode(request.GET[b'location'])
+ if b"simple" not in request.GET:
+ scheme = urlparse(url).scheme
+ if scheme == u"" or scheme == u"http" or scheme == u"https":
+ url += u"&" if u'?' in url else u"?"
+ #keep url parameters in location
+ url_parameters = {}
+ for item in request.GET.items():
+ url_parameters[isomorphic_decode(item[0])] = isomorphic_decode(item[1][0])
+ url += urlencode(url_parameters)
+ #make sure location changes during redirection loop
+ url += u"&count=" + str(stashed_data[b'count'])
+ headers.append((b"Location", isomorphic_encode(url)))
+
+ if b"redirect_referrerpolicy" in request.GET:
+ headers.append((b"Referrer-Policy", request.GET[b'redirect_referrerpolicy']))
+
+ if b"delay" in request.GET:
+ time.sleep(float(request.GET.first(b"delay", 0)) / 1E3)
+
+ if token:
+ request.server.stash.put(request.GET.first(b"token"), stashed_data)
+ if b"max_count" in request.GET:
+ max_count = int(request.GET[b'max_count'])
+ #stop redirecting and return count
+ if stashed_data[b'count'] > max_count:
+ # -1 because the last is not a redirection
+ return str(stashed_data[b'count'] - 1)
+
+ return status, headers, u""
diff --git a/testing/web-platform/tests/fetch/api/resources/sandboxed-iframe.html b/testing/web-platform/tests/fetch/api/resources/sandboxed-iframe.html
new file mode 100644
index 0000000000..6e5d506547
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/sandboxed-iframe.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<script>
+async function no_cors_should_be_rejected() {
+ let thrown = false;
+ try {
+ const resp = await fetch('top.txt');
+ } catch (e) {
+ thrown = true;
+ }
+ if (!thrown) {
+ throw Error('fetching "top.txt" should be rejected.');
+ }
+}
+
+async function null_origin_should_be_accepted() {
+ const url = 'top.txt?pipe=header(access-control-allow-origin,null)|' +
+ 'header(cache-control,no-store)';
+ const resp = await fetch(url);
+}
+
+async function test() {
+ try {
+ await no_cors_should_be_rejected();
+ await null_origin_should_be_accepted();
+ parent.postMessage('PASS', '*');
+ } catch (e) {
+ parent.postMessage(e.message, '*');
+ }
+}
+
+test();
+</script>
+</html>
diff --git a/testing/web-platform/tests/fetch/api/resources/script-with-header.py b/testing/web-platform/tests/fetch/api/resources/script-with-header.py
new file mode 100644
index 0000000000..9a9c70ef5c
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/script-with-header.py
@@ -0,0 +1,7 @@
+def main(request, response):
+ headers = [(b"Content-type", request.GET.first(b"mime"))]
+ if b"content" in request.GET and request.GET.first(b"content") == b"empty":
+ content = b''
+ else:
+ content = b"console.log('Script loaded')"
+ return 200, headers, content
diff --git a/testing/web-platform/tests/fetch/api/resources/stash-put.py b/testing/web-platform/tests/fetch/api/resources/stash-put.py
new file mode 100644
index 0000000000..dbc7ceebb8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/stash-put.py
@@ -0,0 +1,17 @@
+from wptserve.utils import isomorphic_decode
+
+def main(request, response):
+ if request.method == u'OPTIONS':
+ # CORS preflight
+ response.headers.set(b'Access-Control-Allow-Origin', b'*')
+ response.headers.set(b'Access-Control-Allow-Methods', b'*')
+ response.headers.set(b'Access-Control-Allow-Headers', b'*')
+ return 'done'
+
+ url_dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/'
+ key = request.GET.first(b"key")
+ value = request.GET.first(b"value")
+ # value here must be a text string. It will be json.dump()'ed in stash-take.py.
+ request.server.stash.put(key, isomorphic_decode(value), url_dir)
+ response.headers.set(b'Access-Control-Allow-Origin', b'*')
+ return "done"
diff --git a/testing/web-platform/tests/fetch/api/resources/stash-take.py b/testing/web-platform/tests/fetch/api/resources/stash-take.py
new file mode 100644
index 0000000000..e6db80dd86
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/stash-take.py
@@ -0,0 +1,9 @@
+from wptserve.handlers import json_handler
+
+
+@json_handler
+def main(request, response):
+ dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/'
+ key = request.GET.first(b"key")
+ response.headers.set(b'Access-Control-Allow-Origin', b'*')
+ return request.server.stash.take(key, dir)
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 0000000000..05a59d5a63
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/status.py
@@ -0,0 +1,11 @@
+from wptserve.utils import isomorphic_encode
+
+def main(request, response):
+ code = int(request.GET.first(b"code", 200))
+ text = request.GET.first(b"text", b"OMG")
+ content = request.GET.first(b"content", b"")
+ type = request.GET.first(b"type", b"")
+ status = (code, text)
+ headers = [(b"Content-Type", type),
+ (b"X-Request-Method", isomorphic_encode(request.method))]
+ return status, headers, content
diff --git a/testing/web-platform/tests/fetch/api/resources/sw-intercept-abort.js b/testing/web-platform/tests/fetch/api/resources/sw-intercept-abort.js
new file mode 100644
index 0000000000..19d4b189d8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/sw-intercept-abort.js
@@ -0,0 +1,19 @@
+async function messageClient(clientId, message) {
+ const client = await clients.get(clientId);
+ client.postMessage(message);
+}
+
+addEventListener('fetch', event => {
+ let resolve;
+ const promise = new Promise(r => resolve = r);
+
+ function onAborted() {
+ messageClient(event.clientId, event.request.signal.reason);
+ resolve();
+ }
+
+ messageClient(event.clientId, 'fetch event has arrived');
+
+ event.respondWith(promise.then(() => new Response('hello')));
+ event.request.signal.addEventListener('abort', onAborted);
+});
diff --git a/testing/web-platform/tests/fetch/api/resources/sw-intercept.js b/testing/web-platform/tests/fetch/api/resources/sw-intercept.js
new file mode 100644
index 0000000000..b8166b62a5
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/sw-intercept.js
@@ -0,0 +1,10 @@
+async function broadcast(msg) {
+ for (const client of await clients.matchAll()) {
+ client.postMessage(msg);
+ }
+}
+
+addEventListener('fetch', event => {
+ event.waitUntil(broadcast(event.request.url));
+ event.respondWith(fetch(event.request));
+});
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 0000000000..83a3157d14
--- /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 0000000000..99833f1b38
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/trickle.py
@@ -0,0 +1,15 @@
+import time
+
+def main(request, response):
+ delay = float(request.GET.first(b"ms", 500)) / 1E3
+ count = int(request.GET.first(b"count", 50))
+ # Read request body
+ request.body
+ time.sleep(delay)
+ if not b"notype" in request.GET:
+ response.headers.set(b"Content-type", b"text/plain")
+ response.write_status_headers()
+ time.sleep(delay)
+ for i in range(count):
+ response.writer.write_content(b"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 0000000000..3b20ecc834
--- /dev/null
+++ b/testing/web-platform/tests/fetch/api/resources/utils.js
@@ -0,0 +1,105 @@
+var RESOURCES_DIR = "../resources/";
+
+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 encode_utf8(str)
+{
+ if (self.TextEncoder)
+ return (new TextEncoder).encode(str);
+ return stringToArray(unescape(encodeURIComponent(str)));
+}
+
+function validateBufferFromString(buffer, expectedValue, message)
+{
+ return assert_array_equals(new Uint8Array(buffer !== undefined ? buffer : []), stringToArray(expectedValue), message);
+}
+
+function validateStreamFromString(reader, expectedValue, retrievedArrayBuffer) {
+ // Passing Uint8Array for byte streams; non-byte streams will simply ignore it
+ return reader.read(new Uint8Array(64)).then(function(data) {
+ if (!data.done) {
+ assert_true(data.value instanceof Uint8Array, "Fetch ReadableStream chunks should be Uint8Array");
+ var newBuffer;
+ if (retrievedArrayBuffer) {
+ newBuffer = new Uint8Array(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");
+ });
+}
+
+function validateStreamFromPartialString(reader, expectedValue, retrievedArrayBuffer) {
+ // Passing Uint8Array for byte streams; non-byte streams will simply ignore it
+ return reader.read(new Uint8Array(64)).then(function(data) {
+ if (!data.done) {
+ assert_true(data.value instanceof Uint8Array, "Fetch ReadableStream chunks should be Uint8Array");
+ var newBuffer;
+ if (retrievedArrayBuffer) {
+ newBuffer = new Uint8Array(data.value.length + retrievedArrayBuffer.length);
+ newBuffer.set(retrievedArrayBuffer, 0);
+ newBuffer.set(data.value, retrievedArrayBuffer.length);
+ } else {
+ newBuffer = data.value;
+ }
+ return validateStreamFromPartialString(reader, expectedValue, newBuffer);
+ }
+
+ var string = new TextDecoder("utf-8").decode(retrievedArrayBuffer);
+ return assert_true(string.search(expectedValue) != -1, "Retrieve and verify stream");
+ });
+}
+
+// From streams tests
+function delay(milliseconds)
+{
+ return new Promise(function(resolve) {
+ step_timeout(resolve, milliseconds);
+ });
+}