Skip to content

Commit

Permalink
Add WPTs for different Early Hints preload finish timings
Browse files Browse the repository at this point in the history
The test scenarios are:
* 103 -> start preload -> preload finished -> 200 -> response body.
* 103 -> start preload -> (preload inflight) -> 200 -> preload finished
  -> response body.

The purpose of these tests is to make sure the resource is added to the
preload map of the document [1]. Also refer to [2] for the motivation.

[1] whatwg/html#7675
[2] #33076 (comment)

Bug: 1305896
Change-Id: Id0ba4748f6493bc2c78be6de5769b4d16ce9092f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3552176
Reviewed-by: Yutaka Hirano <[email protected]>
Commit-Queue: Kenichi Ishibashi <[email protected]>
Cr-Commit-Position: refs/heads/main@{#985847}
  • Loading branch information
bashi authored and chromium-wpt-export-bot committed Mar 28, 2022
1 parent e9c5c4c commit 2139b60
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// META: script=/common/utils.js
// META: script=resources/early-hints-helpers.sub.js

test(() => {
const params = new URLSearchParams();
const id = token();
params.set("resource-url", SAME_ORIGIN_RESOURCES_URL + "/fetch-and-record-js.h2.py?id=" + id);
params.set("resource-id", id);
const test_url = "resources/preload-finished-before-final-response.h2.py?" + params.toString();
window.location.replace(new URL(test_url, window.location));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// META: script=/common/utils.js
// META: script=resources/early-hints-helpers.sub.js

test(() => {
const params = new URLSearchParams();
const id = token();
params.set("resource-url", SAME_ORIGIN_RESOURCES_URL + "/fetch-and-record-js.h2.py?id=" + id);
params.set("resource-id", id);
const test_url = "resources/preload-finished-while-receiving-final-response-body.h2.py?" + params.toString();
window.location.replace(new URL(test_url, window.location));
});
10 changes: 4 additions & 6 deletions loading/early-hints/resources/delayed-js.h2.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import time
import importlib

utils = importlib.import_module("loading.early-hints.resources.utils")


def main(request, response):
id = request.GET.first(b"id")
url_dir = u'/'.join(request.url_parts.path.split(u'/')[:-1]) + u'/'
# Wait until the id is set via resume-delayed-js.h2.py.
while True:
if request.server.stash.take(id, url_dir):
break
time.sleep(0.1)
utils.wait_for_preload_to_finish(request, id)

headers = [
("Content-Type", "text/javascript"),
Expand Down
3 changes: 3 additions & 0 deletions loading/early-hints/resources/fetch-and-record-js.h2.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import importlib
import time

utils = importlib.import_module("loading.early-hints.resources.utils")

Expand All @@ -10,4 +11,6 @@ def main(request, response):
("Cache-Control", "max-age=600"),
]
body = "/*empty script*/"
# Sleep to simulate loading time.
time.sleep(0.05)
return (200, "OK"), headers, body
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import importlib
import os

utils = importlib.import_module("loading.early-hints.resources.utils")


def handle_headers(frame, request, response):
resource_url = request.GET.first(b"resource-url").decode()
link_header_value = "<{}>; rel=preload; as=script".format(resource_url)
early_hints = [
(b":status", b"103"),
(b"link", link_header_value),
]
response.writer.write_raw_header_frame(headers=early_hints,
end_headers=True)

# Wait for preload to finish before sending the final response headers.
resource_id = request.GET.first(b"resource-id").decode()
utils.wait_for_preload_to_finish(request, resource_id)

response.status = 200
response.headers[b"content-type"] = "text/html"
response.write_status_headers()


def main(request, response):
current_dir = os.path.dirname(os.path.realpath(__file__))
file_path = os.path.join(current_dir, "preload-finished-before-final-response.html")
with open(file_path, "r") as f:
test_content = f.read()
response.writer.write_data(item=test_content, last=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="early-hints-helpers.sub.js"></script>
<body>
<script>
promise_test(async (t) => {
const params = new URLSearchParams(window.location.search);
const resource_url = params.get("resource-url");
await fetchScript(resource_url);
assert_true(isPreloadedByEarlyHints(resource_url));
}, "Early hints preload finished before the final response.");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import importlib
import os

utils = importlib.import_module("loading.early-hints.resources.utils")


def handle_headers(frame, request, response):
resource_url = request.GET.first(b"resource-url").decode()
link_header_value = "<{}>; rel=preload; as=script".format(resource_url)
early_hints = [
(b":status", b"103"),
(b"link", link_header_value),
]
response.writer.write_raw_header_frame(headers=early_hints,
end_headers=True)

response.status = 200
response.headers[b"content-type"] = "text/html"
response.write_status_headers()


def main(request, response):
# Wait for preload to finish before sending the response body.
resource_id = request.GET.first(b"resource-id").decode()
utils.wait_for_preload_to_finish(request, resource_id)

current_dir = os.path.dirname(os.path.realpath(__file__))
file_path = os.path.join(current_dir, "preload-finished-while-receiving-final-response-body.html")
with open(file_path, "r") as f:
test_content = f.read()
response.writer.write_data(item=test_content, last=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="early-hints-helpers.sub.js"></script>
<body>
<script>
promise_test(async (t) => {
const params = new URLSearchParams(window.location.search);
const resource_url = params.get("resource-url");
await fetchScript(resource_url);
assert_true(isPreloadedByEarlyHints(resource_url));
}, "Early hints preload finished while loading the final response body.");
</script>
</body>
20 changes: 16 additions & 4 deletions loading/early-hints/resources/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime
import json
import time


def _url_dir(request):
Expand All @@ -22,12 +23,23 @@ def store_request_timing_and_headers(request):
request.server.stash.put(id, value, url_dir)


def get_request_timing_and_headers(request):
def get_request_timing_and_headers(request, id=None):
"""Get previously stored timestamp and request headers associated with the
given request. The request must be a GET request and must have the "id"
parameter.
given "id". When "id" is not given the id is retrieved from "request".
"""
id = request.GET.first(b"id")
if id is None:
id = request.GET.first(b"id")
url_dir = _url_dir(request)
item = request.server.stash.take(id, url_dir)
if not item:
return None
return json.dumps(item)


def wait_for_preload_to_finish(request, id):
"""Wait until a preload associated with "id" is sent."""
while True:
if get_request_timing_and_headers(request, id):
break
time.sleep(0.1)
time.sleep(0.1)

0 comments on commit 2139b60

Please sign in to comment.