[ResourceTiming] Refactor connection-reuse tests
This CL migrates the connection reuse WPTs to the new style. See
wpt/resource-timing/CodingConventions.md for details.
These tests exist to verify that the Resource Timing API yields correct
PerformanceResourceTiming values when the underlying TCP connection is
reused across multiple subresources.
Bug: 1171767
Change-Id: I5acdb6bf8a5e71bb34c7d2236cdb9d0209d3d04d
GithubIssue: https://github.com/w3c/resource-timing/issues/254
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2950880
Commit-Queue: Tom McKee <tommckee@chromium.org>
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Cr-Commit-Position: refs/heads/master@{#891368}
diff --git a/resource-timing/connection-reuse.html b/resource-timing/connection-reuse.html
index e82b7bc..a1bc927 100644
--- a/resource-timing/connection-reuse.html
+++ b/resource-timing/connection-reuse.html
@@ -7,8 +7,46 @@
<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
<script src="resources/entry-invariants.js"></script>
<script src="resources/connection-reuse-test.js"></script>
+<script>
+ const {HTTPS_ORIGIN} = get_host_info();
+
+ // Fetches the given subresource a couple times with the same connection.
+ const http_path = "resources/fake_responses.py";
+ connection_reuse_test(http_path,
+ {
+ 'on_200': invariants.assert_tao_pass_no_redirect_http,
+ 'on_304': invariants.assert_tao_pass_304_not_modified_http,
+ }, "Reuse HTTP connection");
+
+ // Like above, but the subresource is fetched over HTTPS while this page is
+ // fetched over HTTP.
+ const https_url = `${HTTPS_ORIGIN}/resource-timing/${http_path}`;
+ connection_reuse_test(https_url,
+ {
+ 'on_200': invariants.assert_tao_pass_no_redirect_https,
+ 'on_304': invariants.assert_tao_pass_304_not_modified_https,
+ }, "Reuse HTTPS connection from HTTP page");
+
+ // Like the above mixed-content test but the final resource is behind an HTTP
+ // redirect response.
+ const redirect_path = (() => {
+ // The resource behind the redirect is the same fake_responses.py handler
+ // on the HTTPS origin. Pass it through encodeURIComponent so that it can
+ // be passed through a query-parameter.
+ const redirect_url = encodeURIComponent(https_url)
+ // The request is made to the HTTPS origin with a query parameter that will
+ // cause a 302 response.
+ return `${https_url}?redirect=${redirect_url}`;
+ })();
+ connection_reuse_test(redirect_path,
+ {
+ 'on_200': invariants.assert_tao_enabled_cross_origin_redirected_resource,
+ 'on_304': invariants.assert_tao_enabled_cross_origin_redirected_resource,
+ }, "Reuse HTTPS connection with redirects from an HTTP page");
+</script>
</head>
<body>
<h1>Description</h1>
diff --git a/resource-timing/connection-reuse.https.html b/resource-timing/connection-reuse.https.html
index e82b7bc..3461eed 100644
--- a/resource-timing/connection-reuse.https.html
+++ b/resource-timing/connection-reuse.https.html
@@ -9,6 +9,13 @@
<script src="/resources/testharnessreport.js"></script>
<script src="resources/entry-invariants.js"></script>
<script src="resources/connection-reuse-test.js"></script>
+<script>
+ connection_reuse_test("resources/fake_responses.py",
+ {
+ 'on_200': invariants.assert_tao_pass_no_redirect_https,
+ 'on_304': invariants.assert_tao_pass_304_not_modified_https,
+ }, "Reuse an HTTPS connection");
+</script>
</head>
<body>
<h1>Description</h1>
diff --git a/resource-timing/resources/connection-reuse-test.js b/resource-timing/resources/connection-reuse-test.js
index 4def16c..453fbd3 100644
--- a/resource-timing/resources/connection-reuse-test.js
+++ b/resource-timing/resources/connection-reuse-test.js
@@ -1,70 +1,63 @@
// This script is loaded in HTTP and HTTPS contexts to validate
// PerformanceResourceTiming entries' attributes when reusing connections.
-
-// Make the first request before calling 'attribute_test' so that only the
-// second request's PerformanceResourceTiming entry will be interrogated.
-// We don't check the first request's PerformanceResourceTiming entry because
-// that's not what this test is trying to validate.
//
-// Note: to ensure that we reuse the connection to fetch multiple resources,
-// we use the same XMLHttpRequest object for each request. Although it doesn't
-// seem to be specified, each browser tested by WPT will reuse the underlying
-// TCP connection with this approach. Pre-establishing the XHR's connection
-// helps us to test connection reuse also in browsers that may key their
-// connections on the related request's credentials mode.
-const client = new XMLHttpRequest();
-const identifier = Math.random();
-const path = `resources/fake_responses.py?tag=${identifier}`;
-client.open("GET", path, false);
-client.send();
+// Note: to ensure that we reuse the connection to fetch multiple resources, we
+// use the same XMLHttpRequest object throughout an individual test. Although
+// it doesn't seem to be specified, each browser tested by WPT will reuse the
+// underlying TCP connection with this approach. Pre-establishing the XHR's
+// connection helps us to test connection reuse also in browsers that may key
+// their connections on the related request's credentials mode.
-attribute_test(
- async () => {
- client.open("GET", path + "&same_resource=false", false);
- client.send();
+const connection_reuse_test = (path, follow_on_assertions, test_label) => {
+ const {on_200, on_304} = follow_on_assertions;
- // We expect to get a 200 Ok response because we've requested a different
- // resource than previous requests.
- if (client.status != 200) {
- throw new Error(`Got something other than a 200 response. ` +
- `client.status: ${client.status}`);
- }
- }, path, entry => {
- invariants.assert_connection_reused(entry);
+ // Make the first request before calling 'attribute_test' so that only the
+ // second request's PerformanceResourceTiming entry will be interrogated. We
+ // don't check the first request's PerformanceResourceTiming entry because
+ // that's not what this test is trying to validate.
+ const client = new XMLHttpRequest();
+ const identifier = Math.random();
+ path = `${path}?tag=${identifier}`;
+ client.open("GET", path, false);
+ client.send();
- // The entry must also follow the specification for any entry corresponding
- // to a 'typical' 200 Ok response.
- if (self.location.protocol == 'https:') {
- invariants.assert_tao_pass_no_redirect_https(entry);
- } else {
- invariants.assert_tao_pass_no_redirect_http(entry);
- }
- },
- "PerformanceResrouceTiming entries need to conform to the spec when a " +
- "distinct resource is fetched over a persistent connection");
+ attribute_test(
+ async () => {
+ client.open("GET", path + "&same_resource=false", false);
+ client.send();
-attribute_test(
- async () => {
- client.open("GET", path, false);
- client.setRequestHeader("If-None-Match", identifier);
- client.send();
+ // We expect to get a 200 Ok response because we've requested a different
+ // resource than previous requests.
+ if (client.status != 200) {
+ throw new Error(`Got something other than a 200 response. ` +
+ `client.status: ${client.status}`);
+ }
+ }, path, entry => {
+ invariants.assert_connection_reused(entry);
+ on_200(entry);
+ },
+ `PerformanceResrouceTiming entries need to conform to the spec when a ` +
+ `distinct resource is fetched over a persistent connection ` +
+ `(${test_label})`);
- // We expect to get a 304 Not Modified response because we've used a
- // matching 'identifier' for the If-None-Match header.
- if (client.status != 304) {
- throw new Error(`Got something other than a 304 response. ` +
- `client.status: ${client.status}`);
- }
- }, path, entry => {
- invariants.assert_connection_reused(entry);
+ attribute_test(
+ async () => {
+ client.open("GET", path, false);
+ client.setRequestHeader("If-None-Match", identifier);
+ client.send();
- // The entry must also follow the specification for any entry corresponding
- // to a 'typical' 304 Not Modified response.
- if (self.location.protocol == 'https:') {
- invariants.assert_tao_pass_304_not_modified_https(entry);
- } else {
- invariants.assert_tao_pass_304_not_modified_http(entry);
- }
- },
- "PerformanceResrouceTiming entries need to conform to the spec when the " +
- "resource is cache-revalidated over a persistent connection");
+ // We expect to get a 304 Not Modified response because we've used a
+ // matching 'identifier' for the If-None-Match header.
+ if (client.status != 304) {
+ throw new Error(`Got something other than a 304 response. ` +
+ `client.status: ${client.status}, response: ` +
+ `'${client.responseText}'`);
+ }
+ }, path, entry => {
+ invariants.assert_connection_reused(entry);
+ on_304(entry);
+ },
+ `PerformanceResrouceTiming entries need to conform to the spec when the ` +
+ `resource is cache-revalidated over a persistent connection ` +
+ `(${test_label})`);
+}
diff --git a/resource-timing/resources/fake_responses.py b/resource-timing/resources/fake_responses.py
index 828748a..e33adbf 100644
--- a/resource-timing/resources/fake_responses.py
+++ b/resource-timing/resources/fake_responses.py
@@ -1,6 +1,12 @@
# /xhr/resources/conditional.py -- to fake a 304 response
def main(request, response):
+ if request.method == "OPTIONS":
+ # Assume this is a CORS preflight
+ response.headers.set(b"Access-Control-Allow-Headers", "*")
+ response.headers.set(b"Access-Control-Allow-Origin", "*")
+ response.status = (204, "No Content")
+ return b""
tag = request.GET.first(b"tag", None)
redirect = request.GET.first(b"redirect", None)
match = request.headers.get(b"If-None-Match", None)