| |
| 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 = 10; |
| const kCheckAvailableDictionaryHeaderRetryTimeout = 200; |
| 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); |
| } |