diff options
Diffstat (limited to 'test/wpt/tests/fetch/connection-pool/network-partition-key.html')
-rw-r--r-- | test/wpt/tests/fetch/connection-pool/network-partition-key.html | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/test/wpt/tests/fetch/connection-pool/network-partition-key.html b/test/wpt/tests/fetch/connection-pool/network-partition-key.html new file mode 100644 index 0000000..60a784c --- /dev/null +++ b/test/wpt/tests/fetch/connection-pool/network-partition-key.html @@ -0,0 +1,264 @@ +<!doctype html> +<html> +<head> + <meta charset="utf-8"> + <title>Connection partitioning by site</title> + <meta name="help" href="https://fetch.spec.whatwg.org/#network-partition-keys"> + <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> +<!-- Used to open about:blank tabs from opaque origins --> +<iframe id="iframe0" sandbox="allow-popups allow-scripts allow-popups-to-escape-sandbox"></iframe> +<iframe id="iframe1" sandbox="allow-popups allow-scripts allow-popups-to-escape-sandbox"></iframe> +<script> +const host = get_host_info(); + +// These two origins must correspond to different sites for this test to pass. +const POPUP_ORIGINS = [ + host.ORIGIN, + host.HTTP_NOTSAMESITE_ORIGIN +]; + +// This origin should ideally correspond to a different site from the two above, but the +// tests will still pass if it matches the site of one of the other two origins. +const OTHER_ORIGIN = host.REMOTE_ORIGIN; + +// Except for the csp_sandbox and about:blanks, each test opens up two windows, one at +// POPUP_ORIGINS[0], one at POPUP_ORIGINS[1], and has them request subresources from +// subresource_origin. All requests (HTML, JS, and fetch requests) for each window go +// through network-partition-key.py and have a partition_id parameter, which is used +// to check if any request for one window uses the same socket as a request for the +// other window. +// +// Whenever requests from the two different popup windows use the same connection, the +// fetch requests all start returning 400 errors, but other requests will continue to +// succeed, to make for clearer errors. +// +// include_credentials indicates whether the fetch requests use credentials or not, +// which is interesting as uncredentialed sockets have separate connection pools. +const tests = [ + { + name: 'With credentials', + subresource_origin: POPUP_ORIGINS[0], + include_credentials: true, + popup_params: [ + {type: 'main_frame'}, + {type: 'main_frame'} + ] + }, + { + name: 'Without credentials', + subresource_origin: POPUP_ORIGINS[0], + include_credentials: false, + popup_params: [ + {type: 'main_frame'}, + {type: 'main_frame'} + ] + }, + { + name: 'Cross-site resources with credentials', + subresource_origin: OTHER_ORIGIN, + include_credentials: true, + popup_params: [ + {type: 'main_frame'}, + {type: 'main_frame'} + ] + }, + { + name: 'Cross-site resources without credentials', + subresource_origin: OTHER_ORIGIN, + include_credentials: false, + popup_params: [ + {type: 'main_frame'}, + {type: 'main_frame'} + ] + }, + { + name: 'Iframes', + subresource_origin: OTHER_ORIGIN, + include_credentials: true, + popup_params: [ + { + type: 'iframe', + iframe_origin: OTHER_ORIGIN + }, + { + type: 'iframe', + iframe_origin: OTHER_ORIGIN + } + ] + }, + { + name: 'Workers', + subresource_origin: POPUP_ORIGINS[0], + include_credentials: true, + popup_params: [ + {type: 'worker'}, + {type: 'worker'} + ] + }, + { + name: 'Workers with cross-site resources', + subresource_origin: OTHER_ORIGIN, + include_credentials: true, + popup_params: [ + {type: 'worker'}, + {type: 'worker'} + ] + }, + { + name: 'CSP sandbox', + subresource_origin: POPUP_ORIGINS[0], + include_credentials: true, + popup_params: [ + {type: 'csp_sandbox'}, + {type: 'csp_sandbox'} + ] + }, + { + name: 'about:blank from opaque origin iframe', + subresource_origin: OTHER_ORIGIN, + include_credentials: true, + popup_params: [ + {type: 'opaque_about_blank'}, + {type: 'opaque_about_blank'} + ] + }, +]; + +const BASE_PATH = window.location.pathname.replace(/\/[^\/]*$/, '/'); + +function create_script_url(origin, uuid, partition_id, dispatch) { + return `${origin}${BASE_PATH}resources/network-partition-key.py?uuid=${uuid}&partition_id=${partition_id}&dispatch=${dispatch}` +} + +function run_test(test) { + var uuid = token(); + + // Used to track the opened popup windows, so they can be closed at the end of the test. + // They could be closed immediately after use, but safest to keep them open, as browsers + // could use closing a window as a hint to close idle sockets that the window used. + var popup_windows = []; + + // Creates a popup window at |url| and waits for a test result. Returns a promise. + function create_popup_and_wait_for_result(url) { + return new Promise(function(resolve, reject) { + popup_windows.push(window.open(url)); + // Listen for the result + function message_listener(event) { + if (event.data.result === 'success') { + resolve(); + } else if (event.data.result === 'error') { + reject(event.data.details); + } else { + reject('Unexpected message.'); + } + } + window.addEventListener('message', message_listener, {once: 'true'}); + }); + } + + // Navigates iframe to url and waits for a test result. Returns a promise. + function navigate_iframe_and_wait_for_result(iframe, url) { + return new Promise(function(resolve, reject) { + iframe.src = url; + // Listen for the result + function message_listener(event) { + if (event.data.result === 'success') { + resolve(); + } else if (event.data.result === 'error') { + reject(event.data.details); + } else { + reject('Unexpected message.'); + } + } + window.addEventListener('message', message_listener, {once: 'true'}); + }); + } + + function make_test_function(test, index) { + var popup_params = test.popup_params[index]; + return function() { + var popup_path; + var additional_url_params = ''; + var origin = POPUP_ORIGINS[index]; + var partition_id = POPUP_ORIGINS[index]; + if (popup_params.type == 'main_frame') { + popup_path = 'resources/network-partition-checker.html'; + } else if (popup_params.type == 'iframe') { + popup_path = 'resources/network-partition-iframe-checker.html'; + additional_url_params = `&other_origin=${popup_params.iframe_origin}`; + } else if (popup_params.type == 'worker') { + popup_path = 'resources/network-partition-worker-checker.html'; + // The origin of the dedicated worker must mutch the page that loads it. + additional_url_params = `&other_origin=${POPUP_ORIGINS[index]}`; + } else if (popup_params.type == 'csp_sandbox') { + // For the Content-Security-Policy sandbox test, all requests are from the same origin, but + // the origin should be treated as an opaque origin, so sockets should not be reused. + origin = test.subresource_origin; + partition_id = index; + popup_path = 'resources/network-partition-checker.html'; + // Don't check partition of root document, since the document isn't sandboxed until the + // root document is fetched. + additional_url_params = '&sandbox=true&nocheck_partition=true' + } else if (popup_params.type=='opaque_about_blank') { + popup_path = 'resources/network-partition-about-blank-checker.html'; + } else if (popup_params.type == 'iframe') { + throw 'Unrecognized popup_params.type.'; + } + var url = create_script_url(origin, uuid, partition_id, 'fetch_file'); + url += `&subresource_origin=${test.subresource_origin}` + url += `&include_credentials=${test.include_credentials}` + url += `&path=${BASE_PATH.substring(1)}${popup_path}`; + url += additional_url_params; + + if (popup_params.type=='opaque_about_blank') { + return navigate_iframe_and_wait_for_result(iframe = document.getElementById('iframe' + index), url); + } + + return create_popup_and_wait_for_result(url); + } + } + + // Takes a Promise, and cleans up state when the promise has completed, successfully or not, re-throwing + // any exception from the passed in Promise. + async function clean_up_when_done(promise) { + var error; + try { + await promise; + } catch (e) { + error = e; + } + + popup_windows.map(function (win) { win.close(); }); + + try { + var cleanup_url = create_script_url(host.ORIGIN, uuid, host.ORIGIN, 'clean_up'); + var response = await fetch(cleanup_url, {credentials: 'omit', mode: 'cors'}); + assert_equals(await response.text(), 'cleanup complete', `Sever state cleanup failed`); + } catch (e) { + // Prefer error from the passed in Promise over errors from the fetch request to clean up server state. + error = error || e; + } + if (error) + throw error; + } + + return clean_up_when_done( + make_test_function(test, 0)() + .then(make_test_function(test, 1))); +} + +tests.forEach(function (test) { + promise_test( + function() { return run_test(test); }, + test.name); +}) + +</script> +</body> +</html> |