Automatic update from web-platform-tests Compression dictionary: Prioritize match-dest over pattern length This fixes an edge case where we weren't aligned with the RFC and added more web platform test coverage. The RFC explicitly states that dictionaries with a matching match-dest take priority over those that are wildcard matches. Web Platform Test updates: - Improved the test cases that have unknown values in match-dest. - Improved the testing around valid and invalid characters in "id". - Tested more edge cases for dictionary match prioritization. Bug: 521299806, 40255884 Change-Id: If8f544bfd5df70f6d2ffdd8870696ff1006361d8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7909546 Reviewed-by: Frédéric Wang Nélar <fwang@igalia.com> Reviewed-by: Tsuyoshi Horo <horo@chromium.org> Commit-Queue: Patrick Meenan <pmeenan@chromium.org> Cr-Commit-Position: refs/heads/main@{#1645339} -- wpt-commits: 21c3d7bf2c741fa4ef461f6a72ac6e8a63063fb7 wpt-pr: 60518
182 lines
8.0 KiB
HTML
182 lines
8.0 KiB
HTML
<!DOCTYPE html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="timeout" content="long"/>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/common/get-host-info.sub.js"></script>
|
|
<script src="/common/utils.js"></script>
|
|
<script src="./resources/compression-dictionary-util.sub.js"></script>
|
|
</head>
|
|
<body>
|
|
<script>
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_dest = encodeURIComponent('("asdf")');
|
|
const pattern = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/echo-headers.py');
|
|
await fetch(
|
|
`${kRegisterDictionaryPath}?id=id1&match-dest=${match_dest}&match=${pattern}`);
|
|
await registerAltDictionaryAndWait(t);
|
|
const headers = await (await fetch('./resources/echo-headers.py')).json();
|
|
assert_false("available-dictionary" in headers);
|
|
}, 'Dictionary with unknown match-dest is not used for fetch() API');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_dest = encodeURIComponent('()');
|
|
const dict = await (await fetch(`${kRegisterDictionaryPath}?id=test&match-dest=${match_dest}`)).text();
|
|
assert_equals(
|
|
await waitUntilAvailableDictionaryHeader(t, {}),
|
|
kDefaultDictionaryHashBase64);
|
|
assert_equals(await checkHeader('dictionary-id', {}), '"test"');
|
|
}, 'Dictionary registration with empty match-dest list acts as wildcard');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_dest = encodeURIComponent('("")');
|
|
const dict = await (await fetch(`${kRegisterDictionaryPath}?id=test&match-dest=${match_dest}`)).text();
|
|
assert_equals(
|
|
await waitUntilAvailableDictionaryHeader(t, {}),
|
|
kDefaultDictionaryHashBase64);
|
|
assert_equals(await checkHeader('dictionary-id', {}), '"test"');
|
|
}, 'Dictionary registration with matching fetch destination');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_dest = encodeURIComponent('("script")');
|
|
const pattern = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/echo-headers.py');
|
|
await fetch(
|
|
`${kRegisterDictionaryPath}?id=id1&match-dest=${match_dest}&match=${pattern}`);
|
|
await registerAltDictionaryAndWait(t);
|
|
const headers = await (await fetch('./resources/echo-headers.py')).json();
|
|
assert_false("available-dictionary" in headers);
|
|
}, 'Dictionary with non-matching match-dest is not used');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_dest = encodeURIComponent('("asdf" "")');
|
|
const dict = await (await fetch(`${kRegisterDictionaryPath}?id=test&match-dest=${match_dest}`)).text();
|
|
assert_equals(
|
|
await waitUntilAvailableDictionaryHeader(t, {}),
|
|
kDefaultDictionaryHashBase64);
|
|
assert_equals(await checkHeader('dictionary-id', {}), '"test"');
|
|
}, 'Dictionary registration with unknown match-dest and empty string matches fetch destination');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_specific = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/echo-headers.py');
|
|
const match_medium = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/*');
|
|
const match_general = encodeURIComponent(
|
|
'/fetch/compression-dictionary/*');
|
|
const dictionary_path_specific =
|
|
`${kRegisterDictionaryPath}?id=specific&content=specific&` +
|
|
`match=${match_specific}`;
|
|
const dictionary_path_medium =
|
|
`${kRegisterDictionaryPath}?id=medium&content=medium&` +
|
|
`match=${match_medium}`;
|
|
const dictionary_path_general =
|
|
`${kRegisterDictionaryPath}?id=general&content=general&` +
|
|
`match=${match_general}`;
|
|
const expected_specific_hash = await calculateDictionaryHash('specific');
|
|
const expected_medium_hash = await calculateDictionaryHash('medium');
|
|
await fetch(dictionary_path_specific);
|
|
await fetch(dictionary_path_medium);
|
|
await fetch(dictionary_path_general);
|
|
|
|
// echo-headers.py matches all 3, specific (length 55) is the most specific.
|
|
const hash_specific = await waitUntilAvailableDictionaryHeader(t, {
|
|
expected_header: expected_specific_hash
|
|
});
|
|
assert_equals(hash_specific, expected_specific_hash);
|
|
|
|
// echo-headers2.py matches medium (length 41) and general (length 31),
|
|
// medium is more specific.
|
|
const hash_medium = await waitUntilAvailableDictionaryHeader(t, {
|
|
expected_header: expected_medium_hash,
|
|
use_alt_path: true
|
|
});
|
|
assert_equals(hash_medium, expected_medium_hash);
|
|
}, 'Best match algorithm prioritizes dictionaries with longer match patterns');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_longer_nodest = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/echo-headers*.py');
|
|
const match_medium_dest = encodeURIComponent(
|
|
'/fetch/compression-dictionary/*/echo-headers2.py');
|
|
const match_shorter_dest = encodeURIComponent(
|
|
'/fetch/compression-dictionary/*');
|
|
const match_dest = encodeURIComponent('("")');
|
|
|
|
const dictionary_path_longer_nodest =
|
|
`${kRegisterDictionaryPath}?id=longer-nodest&content=longer-nodest&` +
|
|
`match=${match_longer_nodest}`;
|
|
const dictionary_path_medium_dest =
|
|
`${kRegisterDictionaryPath}?id=medium-dest&content=medium-dest&` +
|
|
`match-dest=${match_dest}&match=${match_medium_dest}`;
|
|
const dictionary_path_shorter_dest =
|
|
`${kRegisterDictionaryPath}?id=shorter-dest&content=shorter-dest&` +
|
|
`match-dest=${match_dest}&match=${match_shorter_dest}`;
|
|
|
|
const expected_longer_hash = await calculateDictionaryHash('longer-nodest');
|
|
const expected_medium_hash = await calculateDictionaryHash('medium-dest');
|
|
const expected_shorter_hash = await calculateDictionaryHash('shorter-dest');
|
|
|
|
await fetch(dictionary_path_longer_nodest);
|
|
await fetch(dictionary_path_medium_dest);
|
|
await fetch(dictionary_path_shorter_dest);
|
|
|
|
// echo-headers.py matches longer-nodest (no dest) and shorter-dest (with dest).
|
|
// shorter-dest wins because it has match-dest.
|
|
const hash_selected = await waitUntilAvailableDictionaryHeader(t, {
|
|
expected_header: expected_shorter_hash
|
|
});
|
|
assert_equals(hash_selected, expected_shorter_hash);
|
|
|
|
// echo-headers2.py matches all three. medium-dest and shorter-dest have dest.
|
|
// medium-dest wins because it has a longer match pattern.
|
|
const hash_medium = await waitUntilAvailableDictionaryHeader(t, {
|
|
expected_header: expected_medium_hash,
|
|
use_alt_path: true
|
|
});
|
|
assert_equals(hash_medium, expected_medium_hash);
|
|
}, 'match-dest presence takes priority over longer match patterns');
|
|
|
|
compression_dictionary_promise_test(async (t) => {
|
|
const match_specific_1 = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/echo-headers*.py');
|
|
const match_specific_2 = encodeURIComponent(
|
|
'/fetch/compression-dictionary/resources/echo-headers.py*');
|
|
const dictionary_path_first =
|
|
`${kRegisterDictionaryPath}?id=first-fetched&content=first-fetched-content&` +
|
|
`match=${match_specific_1}`;
|
|
const dictionary_path_second =
|
|
`${kRegisterDictionaryPath}?id=second-fetched&content=second-fetched-content&` +
|
|
`match=${match_specific_2}`;
|
|
const expected_first_hash = await calculateDictionaryHash('first-fetched-content');
|
|
const expected_second_hash = await calculateDictionaryHash('second-fetched-content');
|
|
|
|
await (await fetch(dictionary_path_first)).text();
|
|
assert_equals(
|
|
await waitUntilAvailableDictionaryHeader(t, {}), expected_first_hash);
|
|
|
|
// Wait a short delay to ensure different fetch times.
|
|
await new Promise(resolve => t.step_timeout(resolve, 50));
|
|
await (await fetch(dictionary_path_second)).text();
|
|
|
|
// We must wait until second-fetched is registered.
|
|
const hash_selected = await waitUntilAvailableDictionaryHeader(t, {
|
|
expected_header: expected_second_hash
|
|
});
|
|
assert_equals(hash_selected, expected_second_hash);
|
|
|
|
// The first dictionary should still be available for paths that only match it.
|
|
assert_equals(
|
|
await waitUntilAvailableDictionaryHeader(t, {
|
|
expected_header: expected_first_hash,
|
|
use_alt_path: true
|
|
}),
|
|
expected_first_hash);
|
|
}, 'Most recently fetched dictionary takes priority when match lengths are equal');
|
|
|
|
</script>
|
|
</body>
|