summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html
blob: d62788cabac4886099185bc527e1a026d23e19a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
<!DOCTYPE html>
<title>Use for navigation the requested prefetched response annotated with No-Vary-Search hint, if
No-Vary-Search headers also match during navigation</title>
<meta charset="utf-8">

<meta name="variant" content="?1-1">
<meta name="variant" content="?2-2">
<meta name="variant" content="?3-3">
<meta name="variant" content="?4-4">
<meta name="variant" content="?5-5">
<meta name="variant" content="?6-6">
<meta name="variant" content="?7-7">
<meta name="variant" content="?8-8">
<meta name="variant" content="?9-9">
<meta name="variant" content="?10-10">
<meta name="variant" content="?11-11">
<meta name="variant" content="?12-12">
<meta name="variant" content="?13-13">
<meta name="variant" content="?14-14">
<meta name="variant" content="?15-15">
<meta name="variant" content="?16-16">
<meta name="variant" content="?17-17">
<meta name="variant" content="?18-18">
<meta name="variant" content="?19-19">
<meta name="variant" content="?20-20">
<meta name="variant" content="?21-21">
<meta name="variant" content="?22-22">
<meta name="variant" content="?23-23">
<meta name="variant" content="?24-24">
<meta name="variant" content="?25-last">

<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/dispatcher/dispatcher.js"></script>
<script src="/common/utils.js"></script>
<script src="../resources/utils.sub.js"></script>
<script src="/common/subset-tests.js"></script>

<script>
  function addNoVarySearchHeaderUsingQueryParam(url, value){
    // Use nvs_header query parameter to ask the wpt server
    // to populate No-Vary-Search response header.
    if(value){
      url.searchParams.append("nvs_header", value);
    }
  }

  /*
    remoteAgent: the RemoteContext instance used to communicate between the
      test and the window where prefetch/navigation is happening
    noVarySearchHeaderValue: the value of No-Vary-Search header to be populated
      for the prefetched response
    noVarySearchHintValue: the value of No-Vary-Search hint passed in
      as expects_no_vary_search hint in prefetch speculation rules.
    prefetchQuery: query params to be added to prefetchExecutor url and prefetched
    navigateQuery: query params to be added to prefetchExecutor url and navigated to
  */
  async function prefetchAndNavigate(remoteAgent, noVarySearchHeaderValue, noVarySearchHintValue, prefetchQuery, navigateQuery){
    /*
    Flow:
      * prefetch prefetch_nvs_hint.py?uuid=...&nvs_header=...&otherqueryparams
      * the prefetch request above includes no_vary_search_hint in the speculation
        rules
      * the server blocks progress on this prefetch request on the server side so
        from the browser perspective the server is "thinking"
      * the test starts navigation to
        prefetch_nvs_hint.py?uuid=...&nvs_header=...&otherdifferentqueryparams.
        This navigation matches by No-Vary-Search hint the above in
        progress prefetch.
      * the test fetches prefetch_nvs_hint.py?uuid=...&unblock="unblock"
        which unblocks the in progress prefetch so that the in-progress
        navigation can continue
    */
    const prefetch_nvs_hint_server_page = "prefetch_nvs_hint.py";
    const prefetchUrl = remoteAgent.getExecutorURL({executor:prefetch_nvs_hint_server_page});
    const navigateToUrl = new URL(prefetchUrl);
    // Add query params to the url to be prefetched.
    const additionalPrefetchedUrlSearchParams = new URLSearchParams(prefetchQuery);
    addNoVarySearchHeaderUsingQueryParam(prefetchUrl, noVarySearchHeaderValue);
    additionalPrefetchedUrlSearchParams.forEach((value, key) => {
      prefetchUrl.searchParams.append(key, value);
    });

    await remoteAgent.forceSinglePrefetch(prefetchUrl,
        {expects_no_vary_search:noVarySearchHintValue});

    // Add new query params to navigateToUrl to match No-Vary-Search test case.
    const additionalNavigateToUrlSearchParams = new URLSearchParams(navigateQuery);
    addNoVarySearchHeaderUsingQueryParam(navigateToUrl, noVarySearchHeaderValue);
    additionalNavigateToUrlSearchParams.forEach((value, key) => {
      navigateToUrl.searchParams.append(key, value);
    });
    // Url used by fetch in order to unblock the prefetched url
    const nvshint_unblock_url = remoteAgent.getExecutorURL(
      {executor:prefetch_nvs_hint_server_page, unblock:"unblock"});
    await remoteAgent.execute_script((unblock_url) => {
      onbeforeunload = (event) => {
          fetch(unblock_url);
      };
    }, [nvshint_unblock_url]);

    // Try navigating to a non-exact prefetched URL that matches by
    // No-Vary-Search hint
    // Wait for the navigation to finish
    await remoteAgent.navigate(navigateToUrl);
  }

  function prefetch_no_vary_search_test(description, noVarySearch, noVarySearchHint, prefetchQuery, navigateQuery, shouldUsePrefetch){
    promise_test(async t => {
      assert_implements(HTMLScriptElement.supports('speculationrules'), "Speculation Rules not supported");
      const agent = await spawnWindow(t, {});
      await prefetchAndNavigate(agent,
        noVarySearch,
        noVarySearchHint,
        prefetchQuery,
        navigateQuery);

      if(shouldUsePrefetch){
        assert_prefetched(await agent.getRequestHeaders(),
          "Navigation didn't use the prefetched response!");
      }
      else{
        assert_not_prefetched(await agent.getRequestHeaders(),
          "Navigation used the prefetched response!");
      }
     }, description);
  }

  // Test inputs:
  // - description: a description of the test.
  // - noVarySearch: No-Vary-Search header value for the response.
  // - noVarySearchHint: No-Vary-Search hint to include in prefetch
  //   speculation rules
  // - prefetchQuery: added to query part of prefetch-executor when prefetching
  // - navigateQuery: added to query part of prefetch-executor when navigating
  // - shouldUsePrefetch: if the test case expects the prefetched entry to be
  //   used or not.
  [{description:"Use in-flight prefetch as query parameter b has the same value.",
    noVarySearch: 'params=("a")',
    noVarySearchHint: 'params=("a")',
    prefetchQuery: "a=2&b=3",
    navigateQuery: "b=3",
    shouldUsePrefetch: true},

   {description:"Don't use in-flight prefetch as there is no No-Vary-Search hint.",
    noVarySearch: 'params=("a")',
    noVarySearchHint: '',
    prefetchQuery: "a=2&b=3",
    navigateQuery: "b=3",
    shouldUsePrefetch: false},

   {description:"Don't use in-flight prefetch as the prefetched URL has the extra \"a\" query parameter.",
    noVarySearch: 'params=("b")',
    noVarySearchHint: 'params=("b")',
    prefetchQuery: "a=2&b=3",
    navigateQuery: "b=2",
    shouldUsePrefetch: false},

   {description:"Use in-flight prefetch as the URLs do not vary by a and b.",
    noVarySearch: 'params=("a" "b")',
    noVarySearchHint: 'params=("a" "b")',
    prefetchQuery: "a=2&b=3",
    navigateQuery: "b=2",
    shouldUsePrefetch: true},

   {description:"Do not use in-flight prefetch as the navigation URL has" +
                " a different value for the \"b\" query parameter.",
    noVarySearch: 'params=("a" "b")',
    noVarySearchHint: 'params=("a")',
    prefetchQuery: "a=2&b=3",
    navigateQuery: "b=2",
    shouldUsePrefetch: false},

   {description:"Use in-flight prefetch as the URLs have the same values for all keys, only differing by order.",
    noVarySearch: "key-order",
    noVarySearchHint: "key-order",
    prefetchQuery: "b=5&a=3&a=4&d=6&c=5&b=3",
    navigateQuery: "d=6&a=3&b=5&b=3&c=5&a=4",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as the URLs have the same values for all keys, only differing by order and using ?1 for specifying a true value.",
    noVarySearch: "key-order=?1",
    noVarySearchHint: "key-order=?1",
    prefetchQuery: "b=5&a=3&a=4&d=6&c=5&b=3",
    navigateQuery: "d=6&a=3&b=5&b=3&c=5&a=4",
    shouldUsePrefetch: true},

   {description:"Don't use in-flight prefetch as key-order is set to false and the URLs are not identical.",
    noVarySearch: "key-order=?0",
    noVarySearchHint: "key-order=?1",
    prefetchQuery: "b=5&a=3&a=4&d=6&c=5&b=3",
    navigateQuery: "d=6&a=3&b=5&b=3&c=5&a=4",
    shouldUsePrefetch: false},

   {description:"Use in-flight prefetch as all query parameters except c can be ignored.",
    noVarySearch: 'params, except=("c")',
    noVarySearchHint: 'params, except=("c")',
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "a=1&b=2&c=3",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as all query parameters except c can be ignored." +
                " Only the last except matters.",
    noVarySearch: 'params, except=("b"), except=("c")',
    noVarySearchHint: 'params, except=("b"), except=("c")',
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "a=1&b=2&c=3",
    shouldUsePrefetch: true},

   {description:"Don't use in-flight prefetch as even though all query parameters" +
                " except c can be ignored, c has different value.",
    noVarySearch: 'params, except=("c")',
    noVarySearchHint: "params",
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "a=1&b=2&c=5",
    shouldUsePrefetch: false},

   {description:"Use in-flight prefetch as even though all query parameters" +
                " except c and d can be ignored, c value matches and d value matches.",
    noVarySearch: 'params, except=("c" "d")',
    noVarySearchHint: 'params, except=("c" "d")',
    prefetchQuery: "b=5&a=3&d=6&c=5",
    navigateQuery: "d=6&a=1&b=2&c=5",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as even though all query parameters except" +
                " c and d can be ignored, c value matches and d value matches." +
                " Some query parameters to be ignored appear multiple times in the query.",
    noVarySearch: 'params, except=("c" "d")',
    noVarySearchHint: 'params',
    prefetchQuery: "b=5&a=3&a=4&d=6&c=5",
    navigateQuery: "d=6&a=1&a=2&b=2&b=3&c=5",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as all query parameters except c can be ignored." +
                " Allow extension via parameters.",
    noVarySearch: 'params, except=("c";unknown)',
    noVarySearchHint: 'params, except=("c";unknown)',
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "a=1&b=2&c=3",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as query parameter c can be ignored." +
                " Allow extension via parameters.",
    noVarySearch: 'params=("c";unknown)',
    noVarySearchHint: 'params=("c";unknown)',
    prefetchQuery: "a=2&b=2&c=5",
    navigateQuery: "a=2&c=3&b=2",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as the URLs have the values in different order for a." +
                " Allow extension via parameters.",
    noVarySearch: "key-order;unknown",
    noVarySearchHint: "key-order;unknown",
    prefetchQuery: "b=5&a=3&a=4&d=6&c=5&b=3",
    navigateQuery: "d=6&a=3&b=5&b=3&c=5&a=4",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as the URLs do not vary on any query parameters." +
                " Allow extension via parameters.",
    noVarySearch: "params;unknown",
    noVarySearchHint: "params;unknown",
    prefetchQuery: "",
    navigateQuery: "b=4&c=5",
    shouldUsePrefetch: true},

   {description:"Use in-flight prefetch as all query parameters except c can be ignored." +
                " Allow extension via parameters.",
    noVarySearch: 'params;unknown, except=("c");unknown',
    noVarySearchHint: 'params;unknown, except=("c");unknown',
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "a=1&b=2&c=3",
    shouldUsePrefetch: true},

   {description:"Don't use the in-flight prefetched URL. Empty No-Vary-Search means default URL variance." +
                " The prefetched and the navigated URLs have to be the same.",
    noVarySearch: "",
    noVarySearchHint: "params",
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "a=1&b=2&c=3",
    shouldUsePrefetch: false},

   {description:"Use the in-flight prefetch. Empty No-Vary-Search means default URL variance." +
                " The prefetched and the navigated URLs have to be the same.",
    noVarySearch: "",
    noVarySearchHint: "",
    prefetchQuery: "b=5&a=3&d=6&c=3",
    navigateQuery: "b=5&a=3&d=6&c=3",
    shouldUsePrefetch: true},

   {description:"Use the in-flight prefetch. Empty No-Vary-Search means default URL variance." +
                " The prefetched and the navigated URLs have to be the same.",
    noVarySearch: "",
    noVarySearchHint: "",
    prefetchQuery: "",
    navigateQuery: "",
    shouldUsePrefetch: true},

   {description:"Use the in-flight prefetch. Non-ASCII key - 2 UTF-8 code units." +
                " Don't vary the response on the non-ASCII key.",
    noVarySearch: 'params=("%C2%A2")',
    noVarySearchHint: 'params=("%C2%A2")',
    prefetchQuery: "¢=3",
    navigateQuery: "¢=4",
    shouldUsePrefetch: true},

   {description:"Use the in-flight prefetch. Non-ASCII key - 2 UTF-8 code units." +
                " Don't vary the response on the non-ASCII key.",
    noVarySearch: 'params=("%C2%A2")',
    noVarySearchHint: 'params=("%C2%A2")',
    prefetchQuery: "a=2&¢=3",
    navigateQuery: "¢=4&a=2",
    shouldUsePrefetch: true},

   {description:"Don't use the in-flight prefetch. Non-ASCII key - 2 UTF-8 code units." +
                " Vary the response on the non-ASCII key.",
    noVarySearch: 'params, except=("%C2%A2")',
    noVarySearchHint: 'params',
    prefetchQuery: "¢=3",
    navigateQuery: "¢=4",
    shouldUsePrefetch: false},

   {description:"Use the in-flight prefetch. Non-ASCII key - 2 UTF-8 code units." +
                 " Vary the response on the non-ASCII key.",
    noVarySearch: 'params, except=("%C2%A2")',
    noVarySearchHint: 'params, except=("%C2%A2")',
    prefetchQuery: "¢=3&a=4",
    navigateQuery: "a=5&¢=3",
    shouldUsePrefetch: true},

  ].forEach(({description, noVarySearch, noVarySearchHint, prefetchQuery, navigateQuery, shouldUsePrefetch}) => {
    subsetTest(prefetch_no_vary_search_test,
      description, noVarySearch, noVarySearchHint, prefetchQuery, navigateQuery,
      shouldUsePrefetch);
  });

</script>