Skip to content

Commit

Permalink
Use the frame Accept header for prefetches.
Browse files Browse the repository at this point in the history
Special-casing prefetches makes it so that `Vary: Accept`
makes the browser erroneously reject the prefetched response.

Also changed the SXG ?q= value for the frame accept header, as it was
done for prefetch (and should have been done for the frame accept
header).

For now CORS prefetches remain untouched, as changing them to the
>128bytes frame accept headers would cause incompatibility due to a
CORS-preflight requirement.

This was previously unspecified,
See whatwg/fetch#1485

Bug: 626081
Change-Id: I2c99f4f1abd2556fdf456d877588b346a22fd677
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4069726
Reviewed-by: Matt Menke <[email protected]>
Commit-Queue: Noam Rosenthal <[email protected]>
Auto-Submit: Noam Rosenthal <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1083806}
  • Loading branch information
noamr authored and chromium-wpt-export-bot committed Dec 15, 2022
1 parent acf5819 commit 9eb3b18
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 0 deletions.
26 changes: 26 additions & 0 deletions preload/prefetch-accept.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<title>Ensures that prefetch works with documents</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="resources/prefetch-helper.js"></script>
<body>
<script>

promise_test(async t => {
const {href, uid} = await prefetch({
file: "prefetch-exec.html",
type: "text/html",
origin: document.origin});
const popup = window.open(href + "&cache_bust=" + token());
const remoteContext = new RemoteContext(uid);
t.add_cleanup(() => popup.close());
await remoteContext.execute_script(() => "OK");
const results = await get_prefetch_info(href);
assert_equals(results.length, 2);
assert_equals(results[0].headers.accept, results[1].headers.accept);
}, "Document prefetch should send the exact Accept header as navigation")

</script>
</body>
9 changes: 9 additions & 0 deletions preload/resources/prefetch-exec.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>Message BC</title>
<script src="/common/dispatcher/dispatcher.js"></script>
<script>
"use strict";
const params = new URLSearchParams(location.search);
window.executor = new Executor(params.get("key"));
</script>
21 changes: 21 additions & 0 deletions preload/resources/prefetch-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
async function get_prefetch_info(href) {
const response = await fetch(`${href}&mode=info`, {mode: "cors"});
return await response.json();
}

async function prefetch(p = {}, t) {
const link = document.createElement("link");
link.rel = "prefetch";
if (p.crossOrigin)
link.setAttribute("crossorigin", p.crossOrigin);
const uid = token();
const params = new URLSearchParams();
params.set("key", uid);
for (const key in p)
params.set(key, p[key]);
const origin = p.origin || '';
link.href = `${origin}/preload/resources/prefetch-info.py?${params.toString()}`;
document.head.appendChild(link);
while (!(await get_prefetch_info(link.href)).length) { }
return {href: link.href, uid};
}
37 changes: 37 additions & 0 deletions preload/resources/prefetch-info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
from wptserve.utils import isomorphic_encode
from json import dumps, loads

def main(request, response):
key = request.GET.first(b"key").decode("utf8")
mode = request.GET.first(b"mode", "content")
status = int(request.GET.first(b"status", b"200"))
stash = request.server.stash
cors = request.GET.first(b"cors", "true")
if cors == "true" or mode == b"info":
response.headers.set(b"Access-Control-Allow-Origin", b"*")

response.status = status
with stash.lock:
requests = loads(stash.take(key) or '[]')
if mode == b"info":
response.headers.set(b"Content-Type", "application/json")
json_reqs = dumps(requests)
response.content = json_reqs
stash.put(key, json_reqs)
return
else:
headers = {}
for header, value in request.headers.items():
headers[header.decode("utf8")] = value[0].decode("utf8")
path = request.url
requests.append({"headers": headers, "url": request.url})
stash.put(key, dumps(requests))

response.headers.set(b"Content-Type", request.GET.first(b"type", "text/plain"))
response.headers.set(b"Cache-Control", request.GET.first(b"cache-control", b"max-age: 604800"))
if b"file" in request.GET:
path = os.path.join(os.path.dirname(isomorphic_encode(__file__)), os.path.basename(request.GET.first(b"file")))
response.content = open(path, mode=u'rb').read()
else:
return request.GET.first(b"content", "123")

0 comments on commit 9eb3b18

Please sign in to comment.