summaryrefslogtreecommitdiffstats
path: root/test/wpt/tests/fetch/connection-pool/network-partition-key.html
diff options
context:
space:
mode:
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.html264
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>