Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.

Commit 2423b61

Browse files
takahiroxmoz-wptsync-bot
authored andcommitted
Bug 1753998 [wpt PR 32728] - Support SRI on link preload font destination, a=testonly
Automatic update from web-platform-tests Support SRI on link preload font destination Changes 1. Set integrity metadata for font destination 2. Check SRI failure in RemoteFontFaceSource::NotifyFinished() 3. Add WPT for preload+SRI+font Regarding the WPT test, preload+SRI+font test doesn't really fit to the existing SRI WPT test subresource-integrity.html because 1. Fonts have to always be fetched with anonymous-mode CORS even for the same origin fetch 2. The main load uses FaceFont.load() (or @font-face in CSS), not HTMLElement. Separated preload+SRI+font test file from the existing SRI test would keep the tests simple. Bug: 981419 Change-Id: Id98c6152dfb67614c731516952bc3c5150e82462 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3428582 Reviewed-by: Hiroshige Hayashizaki <hiroshige@chromium.org> Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org> Cr-Commit-Position: refs/heads/main@{#996424} -- wpt-commits: 937311ebfd3f7a4eb9f4daa4aa2082d619fc51e9 wpt-pr: 32728
1 parent c02b681 commit 2423b61

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<!DOCTYPE html>
2+
<title>Subresource Integrity for font
3+
</title>
4+
<script src="/resources/testharness.js"></script>
5+
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/preload/resources/preload_helper.js"></script>
7+
<script src="/common/utils.js"></script>
8+
<script src="/common/get-host-info.sub.js"></script>
9+
<body>
10+
<script>
11+
const integrities = {
12+
sha256: 'sha256-xkrni1nquuAzPoWieTZ22i9RONF4y11sJyWgYQDVlxE=',
13+
sha384: 'sha384-Vif8vpq+J5UhnTqtncDDyol01dZx9nurRqQcSGtlCf0L1G8P+YeTyUYyZn4LMGrl',
14+
sha512: 'sha512-CVkJJeS4/8zBdqBHmpzMvbI987MEWpTVd1Y/w20UFU0+NWlJAQpl1d3lIyCF97CQ/N+t/gn4IkWP4pjuWWrg6A==',
15+
incorrect_sha256: 'sha256-wrongwrongwrongwrongwrongwrongwrongvalue====',
16+
incorrect_sha512: 'sha512-wrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrongwrong===',
17+
unknown_algo: 'foo666-8aBiAJl3ukQwSJ6eTs5wl6hGjnOtyXjcTRdAf89uIfY='
18+
};
19+
20+
const run_test = (preload_success, main_load_success, name,
21+
resource_url, extra_attributes, number_of_requests) => {
22+
const test = async_test(name);
23+
const link = document.createElement('link');
24+
link.rel = 'preload';
25+
link.as = 'font';
26+
link.href = resource_url;
27+
28+
for (const attribute_name in extra_attributes) {
29+
link[attribute_name] = extra_attributes[attribute_name];
30+
}
31+
32+
const valid_preload_failed = test.step_func(() => {
33+
assert_unreached('Valid preload fired error handler.');
34+
});
35+
const invalid_preload_succeeded = test.step_func(() => {
36+
assert_unreached('Invalid preload load succeeded.');
37+
});
38+
const valid_main_load_failed = test.step_func(() => {
39+
assert_unreached('Valid main load fired error handler.');
40+
});
41+
const invalid_main_load_succeeded = test.step_func(() => {
42+
assert_unreached('Invalid main load succeeded.');
43+
});
44+
const main_load_pass = test.step_func(() => {
45+
verifyNumberOfResourceTimingEntries(resource_url, number_of_requests);
46+
test.done();
47+
});
48+
49+
const preload_pass = test.step_func(async () => {
50+
try {
51+
await new FontFace('CanvasTest', `url("${resource_url}")`).load();
52+
} catch (error) {
53+
if (main_load_success) {
54+
valid_main_load_failed();
55+
} else {
56+
main_load_pass();
57+
}
58+
}
59+
60+
if (main_load_success) {
61+
main_load_pass();
62+
} else {
63+
invalid_main_load_succeeded();
64+
}
65+
});
66+
67+
if (preload_success) {
68+
link.onload = preload_pass;
69+
link.onerror = valid_preload_failed;
70+
} else {
71+
link.onload = invalid_preload_succeeded;
72+
link.onerror = preload_pass;
73+
}
74+
75+
document.body.appendChild(link);
76+
};
77+
78+
verifyPreloadAndRTSupport();
79+
80+
const anonymous = '&pipe=header(Access-Control-Allow-Origin,*)';
81+
const use_credentials = '&pipe=header(Access-Control-Allow-Credentials,true)|' +
82+
'header(Access-Control-Allow-Origin,' + location.origin + ')';
83+
const cross_origin_prefix = get_host_info().REMOTE_ORIGIN;
84+
const file_path = '/fonts/CanvasTest.ttf';
85+
86+
// Note: About preload + font + CORS
87+
//
88+
// The CSS Font spec defines that font files always have to be fetched using
89+
// anonymous-mode CORS.
90+
//
91+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#cors-enabled_fetches
92+
// https://www.w3.org/TR/css-fonts-3/#font-fetching-requirements
93+
//
94+
// So that font loading (@font-face in CSS and FontFace.load()) always
95+
// sends requests with anonymous-mode CORS. The crossOrigin attribute of
96+
// <link rel="preload" as="font"> should be set as anonymout mode,
97+
// too, even for same origin fetch. Otherwise, main font loading
98+
// doesn't match the corresponding preloading due to credentials
99+
// mode mismatch and the main font loading invokes another request.
100+
101+
// Needs CORS request even for same origin preload.
102+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with correct sha256 hash.',
103+
file_path + '?' + token(),
104+
{integrity: integrities.sha256, crossOrigin: 'anonymous'}, 1);
105+
106+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with correct sha384 hash.',
107+
file_path + '?' + token(),
108+
{integrity: integrities.sha384, crossOrigin: 'anonymous'}, 1);
109+
110+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with correct sha512 hash.',
111+
file_path + '?' + token(),
112+
{integrity: integrities.sha512, crossOrigin: 'anonymous'}, 1);
113+
114+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with empty integrity.',
115+
file_path + '?' + token(),
116+
{integrity: '', crossOrigin: 'anonymous'}, 1);
117+
118+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with no integrity.',
119+
file_path + '?' + token(),
120+
{crossOrigin: 'anonymous'}, 1);
121+
122+
run_test(false, false, '<crossorigin="anonymous"> Same-origin with incorrect hash.',
123+
file_path + '?' + token(),
124+
{integrity: integrities.incorrect_sha256, crossOrigin: 'anonymous'}, 1);
125+
126+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with correct sha256 hash, options.',
127+
file_path + '?' + token(),
128+
{integrity: `${integrities.sha256}?foo=bar?spam=eggs`, crossOrigin: 'anonymous'}, 1);
129+
130+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with unknown algorithm only.',
131+
file_path + '?' + token(),
132+
{integrity: integrities.unknown_algo, crossOrigin: 'anonymous'}, 1);
133+
134+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with multiple sha256 hashes, including correct.',
135+
file_path + '?' + token(),
136+
{integrity: `${integrities.sha256} ${integrities.incorrect_sha256}`, crossOrigin: 'anonymous'}, 1);
137+
138+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with multiple sha256 hashes, including unknown algorithm.',
139+
file_path + '?' + token(),
140+
{integrity: `${integrities.sha256} ${integrities.unknown_algo}`, crossOrigin: 'anonymous'}, 1);
141+
142+
run_test(true, true, '<crossorigin="anonymous"> Same-origin with sha256 mismatch, sha512 match.',
143+
file_path + '?' + token(),
144+
{integrity: `${integrities.incorrect_sha256} ${integrities.sha512}`, crossOrigin: 'anonymous'}, 1);
145+
146+
run_test(false, false, '<crossorigin="anonymous"> Same-origin with sha256 match, sha512 mismatch.',
147+
file_path + '?' + token(),
148+
{integrity: `${integrities.sha256} ${integrities.incorrect_sha512}`, crossOrigin: 'anonymous'}, 1);
149+
150+
// Main loading shouldn't match preloading due to credentials mode mismatch
151+
// so the number of requests should be two.
152+
run_test(true, true, 'Same-origin, not CORS request, with correct sha256 hash.',
153+
file_path + '?' + token(),
154+
{integrity: integrities.sha256}, 2);
155+
156+
// Main loading shouldn't match preloading due to credentials mode mismatch
157+
// and the main loading should invoke another request. The main font loading
158+
// always sends CORS request and doesn't support SRI by itself, so it should succeed.
159+
run_test(false, true, 'Same-origin, not CORS request, with incorrect sha256 hash.',
160+
file_path + '?' + token(),
161+
{integrity: integrities.incorrect_sha256}, 2);
162+
163+
run_test(true, true, '<crossorigin="anonymous"> Cross-origin with correct sha256 hash, ACAO: *.',
164+
cross_origin_prefix + file_path + '?' + token() + anonymous,
165+
{integrity: integrities.sha256, crossOrigin: 'anonymous'}, 1);
166+
167+
run_test(false, false, '<crossorigin="anonymous"> Cross-origin with incorrect sha256 hash, ACAO: *.',
168+
cross_origin_prefix + file_path + '?' + token() + anonymous,
169+
{integrity: integrities.incorrect_sha256, crossOrigin: 'anonymous'}, 1);
170+
171+
run_test(false, false, '<crossorigin="anonymous"> Cross-origin with correct sha256 hash, with CORS-ineligible resource.',
172+
cross_origin_prefix + file_path + '?' + token(),
173+
{integrity: integrities.sha256, crossOrigin: 'anonymous'}, 1);
174+
175+
run_test(false, true, 'Cross-origin, not CORS request, with correct sha256.',
176+
cross_origin_prefix + file_path + '?' + token() + anonymous,
177+
{integrity: integrities.sha256}, 2);
178+
179+
run_test(false, true, 'Cross-origin, not CORS request, with incorrect sha256.',
180+
cross_origin_prefix + file_path + '?' + token() + anonymous,
181+
{integrity: integrities.incorrect_sha256}, 2);
182+
183+
run_test(true, true, '<crossorigin="anonymous"> Cross-origin with empty integrity.',
184+
cross_origin_prefix + file_path + '?' + token() + anonymous,
185+
{integrity: '', crossOrigin: 'anonymous'}, 1);
186+
187+
run_test(true, true, 'Cross-origin, not CORS request, with empty integrity.',
188+
cross_origin_prefix + file_path + '?' + token() + anonymous,
189+
{integrity: ''}, 2);
190+
191+
// Non-anonymous mode CORS preload request should mismatch the main load.
192+
run_test(true, true, '<crossorigin="use-credentials"> Cross-origin with correct sha256 hash, CORS-eligible.',
193+
cross_origin_prefix + file_path + '?' + token() + use_credentials,
194+
{integrity: integrities.sha256, crossOrigin: 'use-credentials'}, 2);
195+
196+
run_test(false, true, '<crossorigin="use-credentials"> Cross-origin with incorrect sha256 hash, CORS-eligible.',
197+
cross_origin_prefix + file_path + '?' + token() + use_credentials,
198+
{integrity: integrities.incorrect_sha256, crossOrigin: 'use-credentials'}, 2);
199+
</script>
200+
</body>
201+
</html>

0 commit comments

Comments
 (0)