summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fetch/compression-dictionary/resources
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/fetch/compression-dictionary/resources')
-rw-r--r--testing/web-platform/tests/fetch/compression-dictionary/resources/clear-site-data.py4
-rw-r--r--testing/web-platform/tests/fetch/compression-dictionary/resources/compressed-data.py28
-rw-r--r--testing/web-platform/tests/fetch/compression-dictionary/resources/compression-dictionary-util.js120
-rw-r--r--testing/web-platform/tests/fetch/compression-dictionary/resources/echo-headers.py10
-rw-r--r--testing/web-platform/tests/fetch/compression-dictionary/resources/empty.html1
-rw-r--r--testing/web-platform/tests/fetch/compression-dictionary/resources/register-dictionary.py37
6 files changed, 200 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/compression-dictionary/resources/clear-site-data.py b/testing/web-platform/tests/fetch/compression-dictionary/resources/clear-site-data.py
new file mode 100644
index 0000000000..0db51bf797
--- /dev/null
+++ b/testing/web-platform/tests/fetch/compression-dictionary/resources/clear-site-data.py
@@ -0,0 +1,4 @@
+def main(request, response):
+ directive = request.GET.first(b"directive")
+ response.headers.set(b"Clear-Site-Data", b"\"" + directive + b"\"")
+ return b"OK"
diff --git a/testing/web-platform/tests/fetch/compression-dictionary/resources/compressed-data.py b/testing/web-platform/tests/fetch/compression-dictionary/resources/compressed-data.py
new file mode 100644
index 0000000000..4be4b55564
--- /dev/null
+++ b/testing/web-platform/tests/fetch/compression-dictionary/resources/compressed-data.py
@@ -0,0 +1,28 @@
+def main(request, response):
+ response.headers.set(b"Access-Control-Allow-Origin", b"*")
+ response.headers.set(b"Content-Type", b"text/plain")
+ response.headers.set(
+ b"Content-Dictionary",
+ b":U5abz16WDg7b8KS93msLPpOB4Vbef1uRzoORYkJw9BY=:")
+
+ # `br_d_data` and `zstd_d_data` are generated using the following commands:
+ #
+ # $ echo "This is a test dictionary." > /tmp/dict
+ # $ echo -n "This is compressed test data using a test dictionary" \
+ # > /tmp/data
+ # $ brotli -o /tmp/out.brd -D /tmp/dict /tmp/data
+ # $ xxd -p /tmp/out.brd | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ br_d_data = b"\xa1\x98\x01\x80\x62\xa4\x4c\x1d\xdf\x12\x84\x8c\xae\xc2\xca\x60\x22\x07\x6e\x81\x05\x14\xc9\xb7\xc3\x44\x8e\xbc\x16\xe0\x15\x0e\xec\xc1\xee\x34\x33\x3e\x0d"
+ # $ zstd -o /tmp/out.zstdd -D /tmp/dict /tmp/data
+ # $ xxd -p /tmp/out.zstdd | tr -d '\n' | sed 's/\(..\)/\\x\1/g'
+ zstd_d_data = b"\x28\xb5\x2f\xfd\x24\x34\xf5\x00\x00\x98\x63\x6f\x6d\x70\x72\x65\x73\x73\x65\x64\x61\x74\x61\x20\x75\x73\x69\x6e\x67\x03\x00\x59\xf9\x73\x54\x46\x27\x26\x10\x9e\x99\xf2\xbc"
+
+ if b'content_encoding' in request.GET:
+ content_encoding = request.GET.first(b"content_encoding")
+ response.headers.set(b"Content-Encoding", content_encoding)
+ if content_encoding == b"br-d":
+ # Send the pre compressed file
+ response.content = br_d_data
+ if content_encoding == b"zstd-d":
+ # Send the pre compressed file
+ response.content = zstd_d_data
diff --git a/testing/web-platform/tests/fetch/compression-dictionary/resources/compression-dictionary-util.js b/testing/web-platform/tests/fetch/compression-dictionary/resources/compression-dictionary-util.js
new file mode 100644
index 0000000000..46d95041d8
--- /dev/null
+++ b/testing/web-platform/tests/fetch/compression-dictionary/resources/compression-dictionary-util.js
@@ -0,0 +1,120 @@
+
+const kDefaultDictionaryContent = 'This is a test dictionary.\n';
+const kDefaultDictionaryHashBase64 =
+ ':U5abz16WDg7b8KS93msLPpOB4Vbef1uRzoORYkJw9BY=:';
+const kRegisterDictionaryPath = './resources/register-dictionary.py';
+const kCompressedDataPath = './resources/compressed-data.py';
+const kExpectedCompressedData =
+ `This is compressed test data using a test dictionary`;
+const kCheckAvailableDictionaryHeaderMaxRetry = 5;
+const kCheckAvailableDictionaryHeaderRetryTimeout = 100;
+const kCheckPreviousRequestHeadersMaxRetry = 5;
+const kCheckPreviousRequestHeadersRetryTimeout = 250;
+
+// Gets the remote URL corresponding to `relative_path`.
+function getRemoteHostUrl(relative_path) {
+ const remote_origin = new URL(get_host_info().HTTPS_REMOTE_ORIGIN);
+ let result = new URL(relative_path, location.href);
+ result.protocol = remote_origin.protocol;
+ result.hostname = remote_origin.hostname;
+ result.port = remote_origin.port;
+ return result.href;
+}
+
+// Calculates the Structured Field Byte Sequence containing the SHA-256 hash of
+// the contents of the dictionary text.
+async function calculateDictionaryHash(dictionary_text) {
+ const encoded = (new TextEncoder()).encode(dictionary_text);
+ const digest = await crypto.subtle.digest('SHA-256', encoded)
+ return ':' + btoa(String.fromCharCode(...new Uint8Array(digest))) + ':';
+}
+
+// Checks the HTTP request headers which is sent to the server.
+async function checkHeaders(check_remote = false) {
+ let url = './resources/echo-headers.py';
+ if (check_remote) {
+ url = getRemoteHostUrl(url);
+ }
+ return await (await fetch(url)).json();
+}
+
+// Checks the "available-dictionary" header in the HTTP request headers.
+async function checkAvailableDictionaryHeader(check_remote = false) {
+ return (await checkHeaders(check_remote))['available-dictionary'];
+}
+
+// Waits until the "available-dictionary" header is available in the HTTP
+// request headers, and returns the header. If the header is not available after
+// the specified number of retries, returns an error message. If the
+// `expected_header` is specified, this method waits until the header is
+// available and matches the `expected_header`.
+async function waitUntilAvailableDictionaryHeader(test, {
+ max_retry = kCheckAvailableDictionaryHeaderMaxRetry,
+ expected_header = undefined,
+ check_remote = false
+}) {
+ for (let retry_count = 0; retry_count <= max_retry; retry_count++) {
+ const header = await checkAvailableDictionaryHeader(check_remote);
+ if (header) {
+ if (expected_header === undefined || header == expected_header) {
+ return header;
+ }
+ }
+ await new Promise(
+ (resolve) => test.step_timeout(
+ resolve, kCheckAvailableDictionaryHeaderRetryTimeout));
+ }
+ return '"available-dictionary" header is not available';
+}
+
+// Checks the HTTP request headers which was sent to the server with `token`
+// to register a dictionary.
+async function checkPreviousRequestHeaders(token, check_remote = false) {
+ let url = `./resources/register-dictionary.py?get_previous_header=${token}`;
+ if (check_remote) {
+ url = getRemoteHostUrl(url);
+ }
+ return await (await fetch(url)).json();
+}
+
+// Waits until the HTTP request headers which was sent to the server with
+// `token` to register a dictionary is available, and returns the header. If the
+// header is not available after the specified number of retries, returns
+// `undefined`.
+async function waitUntilPreviousRequestHeaders(
+ test, token, check_remote = false) {
+ for (let retry_count = 0; retry_count <= kCheckPreviousRequestHeadersMaxRetry;
+ retry_count++) {
+ const header =
+ (await checkPreviousRequestHeaders(token, check_remote))['headers'];
+ if (header) {
+ return header;
+ }
+ await new Promise(
+ (resolve) => test.step_timeout(
+ resolve, kCheckPreviousRequestHeadersRetryTimeout));
+ }
+ return undefined;
+}
+
+// Clears the site data for the specified directive by sending a request to
+// `./resources/clear-site-data.py` which returns `Clear-Site-Data` response
+// header.
+// Note: When `directive` is 'cache' or 'cookies' is specified, registered
+// compression dictionaries should be also cleared.
+async function clearSiteData(directive = 'cache') {
+ return await (await fetch(
+ `./resources/clear-site-data.py?directive=${directive}`))
+ .text();
+}
+
+// A utility test method that adds the `clearSiteData()` method to the
+// testharness cleanup function. This is intended to ensure that registered
+// dictionaries are cleared in tests and that registered dictionaries do not
+// interfere with subsequent tests.
+function compression_dictionary_promise_test(func, name, properties) {
+ promise_test(async (test) => {
+ test.add_cleanup(clearSiteData);
+ await func(test);
+ }, name, properties);
+}
diff --git a/testing/web-platform/tests/fetch/compression-dictionary/resources/echo-headers.py b/testing/web-platform/tests/fetch/compression-dictionary/resources/echo-headers.py
new file mode 100644
index 0000000000..aabd99eb10
--- /dev/null
+++ b/testing/web-platform/tests/fetch/compression-dictionary/resources/echo-headers.py
@@ -0,0 +1,10 @@
+import json
+
+def main(request, response):
+ response.headers.set(b"Access-Control-Allow-Origin", b"*")
+ headers = {}
+ for header in request.headers:
+ key = header.decode('utf-8')
+ value = request.headers.get(header).decode('utf-8')
+ headers[key] = value
+ return json.dumps(headers)
diff --git a/testing/web-platform/tests/fetch/compression-dictionary/resources/empty.html b/testing/web-platform/tests/fetch/compression-dictionary/resources/empty.html
new file mode 100644
index 0000000000..0e76edd65b
--- /dev/null
+++ b/testing/web-platform/tests/fetch/compression-dictionary/resources/empty.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/testing/web-platform/tests/fetch/compression-dictionary/resources/register-dictionary.py b/testing/web-platform/tests/fetch/compression-dictionary/resources/register-dictionary.py
new file mode 100644
index 0000000000..0bd57225ef
--- /dev/null
+++ b/testing/web-platform/tests/fetch/compression-dictionary/resources/register-dictionary.py
@@ -0,0 +1,37 @@
+import json
+
+def main(request, response):
+ response.headers.set(b"Access-Control-Allow-Origin", b"*")
+ match = b"/fetch/compression-dictionary/resources/*"
+ content = b"This is a test dictionary.\n"
+ if b"match" in request.GET:
+ match = request.GET.first(b"match")
+ if b"content" in request.GET:
+ content = request.GET.first(b"content")
+
+ token = request.GET.first(b"save_header", None)
+ if token is not None:
+ headers = {}
+ for header in request.headers:
+ key = header.decode('utf-8')
+ value = request.headers.get(header).decode('utf-8')
+ headers[key] = value
+ with request.server.stash.lock:
+ request.server.stash.put(token, json.dumps(headers))
+
+ previous_token = request.GET.first(b"get_previous_header", None)
+ if previous_token is not None:
+ result = {}
+ with request.server.stash.lock:
+ store = request.server.stash.take(previous_token)
+ if store is not None:
+ headers = json.loads(store)
+ result["headers"] = headers
+ return json.dumps(result)
+
+ options = b"match=\"" + match + b"\""
+ if b"id" in request.GET:
+ options += b", id=\"" + request.GET.first(b"id") + b"\""
+ response.headers.set(b"Use-As-Dictionary", options)
+ response.headers.set(b"Cache-Control", b"max-age=3600")
+ return content