1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/http_no_vary_search_data.h"
6
7 #include <string>
8 #include <string_view>
9
10 #include "base/containers/flat_map.h"
11 #include "base/containers/flat_set.h"
12 #include "base/memory/scoped_refptr.h"
13 #include "base/strings/string_util.h"
14 #include "base/test/gmock_expected_support.h"
15 #include "base/types/expected.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/http/http_util.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "url/gurl.h"
21
22 namespace net {
23
24 namespace {
25
26 using testing::IsEmpty;
27 using testing::UnorderedElementsAreArray;
28
TEST(HttpNoVarySearchCreateTest,CreateFromNoVaryParamsNonEmptyVaryOnKeyOrder)29 TEST(HttpNoVarySearchCreateTest, CreateFromNoVaryParamsNonEmptyVaryOnKeyOrder) {
30 const auto no_vary_search =
31 HttpNoVarySearchData::CreateFromNoVaryParams({"a"}, true);
32 EXPECT_THAT(no_vary_search.no_vary_params(),
33 UnorderedElementsAreArray({"a"}));
34 EXPECT_THAT(no_vary_search.vary_params(), IsEmpty());
35 EXPECT_TRUE(no_vary_search.vary_on_key_order());
36 EXPECT_TRUE(no_vary_search.vary_by_default());
37 }
38
TEST(HttpNoVarySearchCreateTest,CreateFromNoVaryParamsNonEmptyNoVaryOnKeyOrder)39 TEST(HttpNoVarySearchCreateTest,
40 CreateFromNoVaryParamsNonEmptyNoVaryOnKeyOrder) {
41 const auto no_vary_search =
42 HttpNoVarySearchData::CreateFromNoVaryParams({"a"}, false);
43 EXPECT_THAT(no_vary_search.no_vary_params(),
44 UnorderedElementsAreArray({"a"}));
45 EXPECT_THAT(no_vary_search.vary_params(), IsEmpty());
46 EXPECT_FALSE(no_vary_search.vary_on_key_order());
47 EXPECT_TRUE(no_vary_search.vary_by_default());
48 }
49
TEST(HttpNoVarySearchCreateTest,CreateFromNoVaryParamsEmptyNoVaryOnKeyOrder)50 TEST(HttpNoVarySearchCreateTest, CreateFromNoVaryParamsEmptyNoVaryOnKeyOrder) {
51 const auto no_vary_search =
52 HttpNoVarySearchData::CreateFromNoVaryParams({}, false);
53 EXPECT_THAT(no_vary_search.no_vary_params(), IsEmpty());
54 EXPECT_THAT(no_vary_search.vary_params(), IsEmpty());
55 EXPECT_FALSE(no_vary_search.vary_on_key_order());
56 EXPECT_TRUE(no_vary_search.vary_by_default());
57 }
58
TEST(HttpNoVarySearchCreateTest,CreateFromNoVaryParamsEmptyVaryOnKeyOrder)59 TEST(HttpNoVarySearchCreateTest, CreateFromNoVaryParamsEmptyVaryOnKeyOrder) {
60 const auto no_vary_search =
61 HttpNoVarySearchData::CreateFromNoVaryParams({}, true);
62 EXPECT_THAT(no_vary_search.no_vary_params(), IsEmpty());
63 EXPECT_THAT(no_vary_search.vary_params(), IsEmpty());
64 EXPECT_TRUE(no_vary_search.vary_on_key_order());
65 EXPECT_TRUE(no_vary_search.vary_by_default());
66 }
67
TEST(HttpNoVarySearchCreateTest,CreateFromVaryParamsNonEmptyVaryOnKeyOrder)68 TEST(HttpNoVarySearchCreateTest, CreateFromVaryParamsNonEmptyVaryOnKeyOrder) {
69 const auto no_vary_search =
70 HttpNoVarySearchData::CreateFromVaryParams({"a"}, true);
71 EXPECT_THAT(no_vary_search.no_vary_params(), IsEmpty());
72 EXPECT_THAT(no_vary_search.vary_params(), UnorderedElementsAreArray({"a"}));
73 EXPECT_TRUE(no_vary_search.vary_on_key_order());
74 EXPECT_FALSE(no_vary_search.vary_by_default());
75 }
76
TEST(HttpNoVarySearchCreateTest,CreateFromVaryParamsNonEmptyNoVaryOnKeyOrder)77 TEST(HttpNoVarySearchCreateTest, CreateFromVaryParamsNonEmptyNoVaryOnKeyOrder) {
78 const auto no_vary_search =
79 HttpNoVarySearchData::CreateFromVaryParams({"a"}, false);
80 EXPECT_THAT(no_vary_search.no_vary_params(), IsEmpty());
81 EXPECT_THAT(no_vary_search.vary_params(), UnorderedElementsAreArray({"a"}));
82 EXPECT_FALSE(no_vary_search.vary_on_key_order());
83 EXPECT_FALSE(no_vary_search.vary_by_default());
84 }
85
TEST(HttpNoVarySearchCreateTest,CreateFromVaryParamsEmptyNoVaryOnKeyOrder)86 TEST(HttpNoVarySearchCreateTest, CreateFromVaryParamsEmptyNoVaryOnKeyOrder) {
87 const auto no_vary_search =
88 HttpNoVarySearchData::CreateFromVaryParams({}, false);
89 EXPECT_THAT(no_vary_search.no_vary_params(), IsEmpty());
90 EXPECT_THAT(no_vary_search.vary_params(), IsEmpty());
91 EXPECT_FALSE(no_vary_search.vary_on_key_order());
92 EXPECT_FALSE(no_vary_search.vary_by_default());
93 }
94
TEST(HttpNoVarySearchCreateTest,CreateFromVaryParamsEmptyVaryOnKeyOrder)95 TEST(HttpNoVarySearchCreateTest, CreateFromVaryParamsEmptyVaryOnKeyOrder) {
96 const auto no_vary_search =
97 HttpNoVarySearchData::CreateFromVaryParams({}, true);
98 EXPECT_THAT(no_vary_search.no_vary_params(), IsEmpty());
99 EXPECT_THAT(no_vary_search.vary_params(), IsEmpty());
100 EXPECT_TRUE(no_vary_search.vary_on_key_order());
101 EXPECT_FALSE(no_vary_search.vary_by_default());
102 }
103
104 struct TestData {
105 const char* raw_headers;
106 const base::flat_set<std::string> expected_no_vary_params;
107 const base::flat_set<std::string> expected_vary_params;
108 const bool expected_vary_on_key_order;
109 const bool expected_vary_by_default;
110 };
111
112 class HttpNoVarySearchResponseHeadersTest
113 : public ::testing::Test,
114 public ::testing::WithParamInterface<TestData> {};
115
TEST_P(HttpNoVarySearchResponseHeadersTest,ParsingSuccess)116 TEST_P(HttpNoVarySearchResponseHeadersTest, ParsingSuccess) {
117 const TestData test = GetParam();
118
119 const std::string raw_headers =
120 net::HttpUtil::AssembleRawHeaders(test.raw_headers);
121
122 const auto parsed = base::MakeRefCounted<HttpResponseHeaders>(raw_headers);
123 ASSERT_OK_AND_ASSIGN(const auto no_vary_search_data,
124 HttpNoVarySearchData::ParseFromHeaders(*parsed));
125
126 EXPECT_EQ(no_vary_search_data.vary_on_key_order(),
127 test.expected_vary_on_key_order);
128 EXPECT_EQ(no_vary_search_data.vary_by_default(),
129 test.expected_vary_by_default);
130
131 EXPECT_EQ(no_vary_search_data.no_vary_params(), test.expected_no_vary_params);
132 EXPECT_EQ(no_vary_search_data.vary_params(), test.expected_vary_params);
133 }
134
135 struct FailureData {
136 const char* raw_headers;
137 const HttpNoVarySearchData::ParseErrorEnum expected_error;
138 };
139
140 class HttpNoVarySearchResponseHeadersParseFailureTest
141 : public ::testing::Test,
142 public ::testing::WithParamInterface<FailureData> {};
143
TEST_P(HttpNoVarySearchResponseHeadersParseFailureTest,ParsingFailureOrDefaultValue)144 TEST_P(HttpNoVarySearchResponseHeadersParseFailureTest,
145 ParsingFailureOrDefaultValue) {
146 const std::string raw_headers =
147 net::HttpUtil::AssembleRawHeaders(GetParam().raw_headers);
148
149 const auto parsed = base::MakeRefCounted<HttpResponseHeaders>(raw_headers);
150 const auto no_vary_search_data =
151 HttpNoVarySearchData::ParseFromHeaders(*parsed);
152
153 EXPECT_THAT(no_vary_search_data,
154 base::test::ErrorIs(GetParam().expected_error))
155 << "Headers = " << GetParam().raw_headers;
156 }
157
158 FailureData response_header_failed[] = {
159 {// No No-Vary-Search Header case
160 "HTTP/1.1 200 OK\r\n"
161 "Set-Cookie: a\r\n"
162 "Set-Cookie: b\r\n\r\n",
163 HttpNoVarySearchData::ParseErrorEnum::kOk},
164
165 {// No-Vary-Search Header doesn't parse as a dictionary.
166 "HTTP/1.1 200 OK\r\n"
167 R"(No-Vary-Search: "a")"
168 "\r\n\r\n",
169 HttpNoVarySearchData::ParseErrorEnum::kNotDictionary},
170
171 {// No-Vary-Search Header doesn't parse as a dictionary.
172 "HTTP/1.1 200 OK\r\n"
173 "No-Vary-Search: (a)\r\n\r\n",
174 HttpNoVarySearchData::ParseErrorEnum::kNotDictionary},
175
176 {// When except is specified, params cannot be a list of strings.
177 "HTTP/1.1 200 OK\r\n"
178 R"(No-Vary-Search: params=("b"),except=("a"))"
179 "\r\n\r\n",
180 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
181
182 {// An unknown dictionary key should behave as if the header was not
183 // specified.
184 "HTTP/1.1 200 OK\r\n"
185 "No-Vary-Search: unknown-key\r\n\r\n",
186 HttpNoVarySearchData::ParseErrorEnum::kUnknownDictionaryKey},
187
188 {// params not a boolean or a list of strings.
189 "HTTP/1.1 200 OK\r\n"
190 R"(No-Vary-Search: params="a")"
191 "\r\n\r\n",
192 HttpNoVarySearchData::ParseErrorEnum::kParamsNotStringList},
193
194 {// params not a boolean or a list of strings.
195 "HTTP/1.1 200 OK\r\n"
196 "No-Vary-Search: params=a\r\n\r\n",
197 HttpNoVarySearchData::ParseErrorEnum::kParamsNotStringList},
198
199 {// params as an empty list of strings should behave as if the header was
200 // not specified.
201 "HTTP/1.1 200 OK\r\n"
202 "No-Vary-Search: params=()\r\n\r\n",
203 HttpNoVarySearchData::ParseErrorEnum::kDefaultValue},
204
205 {// params not a boolean or a list of strings.
206 "HTTP/1.1 200 OK\r\n"
207 R"(No-Vary-Search: params=("a" b))"
208 "\r\n\r\n",
209 HttpNoVarySearchData::ParseErrorEnum::kParamsNotStringList},
210
211 {// params defaulting to ?0 which is the same as no header.
212 "HTTP/1.1 200 OK\r\n"
213 R"(No-Vary-Search: params=("a"))"
214 "\r\n"
215 "No-Vary-Search: params=?0\r\n\r\n",
216 HttpNoVarySearchData::ParseErrorEnum::kDefaultValue},
217
218 {// except without params.
219 "HTTP/1.1 200 OK\r\n"
220 "No-Vary-Search: except=()\r\n\r\n",
221 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
222
223 {// except without params.
224 "HTTP/1.1 200 OK\r\n"
225 "No-Vary-Search: except=()\r\n"
226 R"(No-Vary-Search: except=("a"))"
227 "\r\n\r\n",
228 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
229
230 {// except without params.
231 "HTTP/1.1 200 OK\r\n"
232 R"(No-Vary-Search: except=("a" "b"))"
233 "\r\n\r\n",
234 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
235
236 {// except with params set to a list of strings is incorrect.
237 "HTTP/1.1 200 OK\r\n"
238 R"(No-Vary-Search: params=("a"))"
239 "\r\n"
240 "No-Vary-Search: except=()\r\n\r\n",
241 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
242
243 {// except with params set to a list of strings is incorrect.
244 "HTTP/1.1 200 OK\r\n"
245 "No-Vary-Search: params=(),except=()\r\n\r\n",
246 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
247
248 {// except with params set to a list of strings is incorrect.
249 "HTTP/1.1 200 OK\r\n"
250 R"(No-Vary-Search: params,except=(),params=())"
251 "\r\n\r\n",
252 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
253
254 {// except with params set to a list of strings is incorrect.
255 "HTTP/1.1 200 OK\r\n"
256 R"(No-Vary-Search: except=("a" "b"))"
257 "\r\n"
258 R"(No-Vary-Search: params=("a"))"
259 "\r\n\r\n",
260 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
261
262 {// except with params set to a list of strings is incorrect.
263 "HTTP/1.1 200 OK\r\n"
264 R"(No-Vary-Search: params=("a"),except=("b"))"
265 "\r\n"
266 "No-Vary-Search: except=()\r\n\r\n",
267 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
268
269 {// except with params set to false is incorrect.
270 "HTTP/1.1 200 OK\r\n"
271 R"(No-Vary-Search: params=?0,except=("a"))"
272 "\r\n\r\n",
273 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
274
275 {// except with params set to a list of strings is incorrect.
276 "HTTP/1.1 200 OK\r\n"
277 R"(No-Vary-Search: params,except=("a" "b"))"
278 "\r\n"
279 R"(No-Vary-Search: params=("a"))"
280 "\r\n\r\n",
281 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
282
283 {// key-order not a boolean
284 "HTTP/1.1 200 OK\r\n"
285 R"(No-Vary-Search: key-order="a")"
286 "\r\n\r\n",
287 HttpNoVarySearchData::ParseErrorEnum::kNonBooleanKeyOrder},
288
289 {// key-order not a boolean
290 "HTTP/1.1 200 OK\r\n"
291 "No-Vary-Search: key-order=a\r\n\r\n",
292 HttpNoVarySearchData::ParseErrorEnum::kNonBooleanKeyOrder},
293
294 {// key-order not a boolean
295 "HTTP/1.1 200 OK\r\n"
296 "No-Vary-Search: key-order=()\r\n\r\n",
297 HttpNoVarySearchData::ParseErrorEnum::kNonBooleanKeyOrder},
298
299 {// key-order not a boolean
300 "HTTP/1.1 200 OK\r\n"
301 "No-Vary-Search: key-order=(a)\r\n\r\n",
302 HttpNoVarySearchData::ParseErrorEnum::kNonBooleanKeyOrder},
303
304 {// key-order not a boolean
305 "HTTP/1.1 200 OK\r\n"
306 R"(No-Vary-Search: key-order=("a"))"
307 "\r\n\r\n",
308 HttpNoVarySearchData::ParseErrorEnum::kNonBooleanKeyOrder},
309
310 {// key-order not a boolean
311 "HTTP/1.1 200 OK\r\n"
312 "No-Vary-Search: key-order=(?1)\r\n\r\n",
313 HttpNoVarySearchData::ParseErrorEnum::kNonBooleanKeyOrder},
314
315 {// key-order set to false should behave as if the
316 // header was not specified at all
317 "HTTP/1.1 200 OK\r\n"
318 "No-Vary-Search: key-order=?0\r\n\r\n",
319 HttpNoVarySearchData::ParseErrorEnum::kDefaultValue},
320
321 {// params set to false should behave as if the
322 // header was not specified at all
323 "HTTP/1.1 200 OK\r\n"
324 "No-Vary-Search: params=?0\r\n\r\n",
325 HttpNoVarySearchData::ParseErrorEnum::kDefaultValue},
326
327 {// params set to false should behave as if the
328 // header was not specified at all. except set to
329 // a list of tokens is incorrect.
330 "HTTP/1.1 200 OK\r\n"
331 "No-Vary-Search: params=?0\r\n"
332 "No-Vary-Search: except=(a)\r\n\r\n",
333 HttpNoVarySearchData::ParseErrorEnum::kExceptWithoutTrueParams},
334
335 {// except set to a list of tokens is incorrect.
336 "HTTP/1.1 200 OK\r\n"
337 "No-Vary-Search: params=?1\r\n"
338 "No-Vary-Search: except=(a)\r\n\r\n",
339 HttpNoVarySearchData::ParseErrorEnum::kExceptNotStringList},
340
341 {// except set to true
342 "HTTP/1.1 200 OK\r\n"
343 "No-Vary-Search: params=?1\r\n"
344 "No-Vary-Search: except\r\n\r\n",
345 HttpNoVarySearchData::ParseErrorEnum::kExceptNotStringList},
346
347 {// Fail parsing if an unknown key is in the dictionary.
348 "HTTP/1.1 200 OK\r\n"
349 "No-Vary-Search: params,except=(a)\r\n"
350 "No-Vary-Search: unknown-key\r\n"
351 R"(No-Vary-Search: except=("a"))"
352 "\r\n\r\n",
353 HttpNoVarySearchData::ParseErrorEnum::kUnknownDictionaryKey},
354 };
355
356 const TestData response_headers_tests[] = {
357 // params set to a list of strings with one element.
358 {
359 "HTTP/1.1 200 OK\r\n"
360 R"(No-Vary-Search: params=("a"))"
361 "\r\n\r\n", // raw_headers
362 {"a"}, // expected_no_vary_params
363 {}, // expected_vary_params
364 true, // expected_vary_on_key_order
365 true, // expected_vary_by_default
366 },
367 // params set to a list of strings with one non-ASCII character.
368 {
369 "HTTP/1.1 200 OK\r\n"
370 R"(No-Vary-Search: params=("%C2%A2"))"
371 "\r\n\r\n", // raw_headers
372 {"¢"}, // expected_no_vary_params
373 {}, // expected_vary_params
374 true, // expected_vary_on_key_order
375 true, // expected_vary_by_default
376 },
377 // params set to a list of strings with one ASCII and one non-ASCII
378 // character.
379 {
380 "HTTP/1.1 200 OK\r\n"
381 R"(No-Vary-Search: params=("c%C2%A2"))"
382 "\r\n\r\n", // raw_headers
383 {"c¢"}, // expected_no_vary_params
384 {}, // expected_vary_params
385 true, // expected_vary_on_key_order
386 true, // expected_vary_by_default
387 },
388 // params set to a list of strings with one space and one non-ASCII
389 // character.
390 {
391 "HTTP/1.1 200 OK\r\n"
392 R"(No-Vary-Search: params=("+%C2%A2"))"
393 "\r\n\r\n", // raw_headers
394 {" ¢"}, // expected_no_vary_params
395 {}, // expected_vary_params
396 true, // expected_vary_on_key_order
397 true, // expected_vary_by_default
398 },
399 // params set to true.
400 {
401 "HTTP/1.1 200 OK\r\n"
402 "No-Vary-Search: params\r\n\r\n", // raw_headers
403 {}, // expected_no_vary_params
404 {}, // expected_vary_params
405 true, // expected_vary_on_key_order
406 false, // expected_vary_by_default
407 },
408 // params set to true.
409 {
410 "HTTP/1.1 200 OK\r\n"
411 "No-Vary-Search: params=?1\r\n\r\n", // raw_headers
412 {}, // expected_no_vary_params
413 {}, // expected_vary_params
414 true, // expected_vary_on_key_order
415 false, // expected_vary_by_default
416 },
417 // params overridden by a list of strings.
418 {
419 "HTTP/1.1 200 OK\r\n"
420 R"(No-Vary-Search: params=("a" b))"
421 "\r\n"
422 R"(No-Vary-Search: params=("c"))"
423 "\r\n\r\n", // raw_headers
424 {"c"}, // expected_no_vary_params
425 {}, // expected_vary_params
426 true, // expected_vary_on_key_order
427 true, // expected_vary_by_default
428 },
429 // Vary on all with one excepted search param.
430 {
431 "HTTP/1.1 200 OK\r\n"
432 "No-Vary-Search: params\r\n"
433 "No-Vary-Search: except=()\r\n\r\n", // raw_headers
434 {}, // expected_no_vary_params
435 {}, // expected_vary_params
436 true, // expected_vary_on_key_order
437 false, // expected_vary_by_default
438 },
439 // Vary on all with one excepted search param.
440 {
441 "HTTP/1.1 200 OK\r\n"
442 "No-Vary-Search: params\r\n"
443 R"(No-Vary-Search: except=("a"))"
444 "\r\n\r\n", // raw_headers
445 {}, // expected_no_vary_params
446 {"a"}, // expected_vary_params
447 true, // expected_vary_on_key_order
448 false, // expected_vary_by_default
449 },
450 // Vary on all with one excepted non-ASCII search param.
451 {
452 "HTTP/1.1 200 OK\r\n"
453 "No-Vary-Search: params\r\n"
454 R"(No-Vary-Search: except=("%C2%A2"))"
455 "\r\n\r\n", // raw_headers
456 {}, // expected_no_vary_params
457 {"¢"}, // expected_vary_params
458 true, // expected_vary_on_key_order
459 false, // expected_vary_by_default
460 },
461 // Vary on all with one excepted search param that includes non-ASCII
462 // character.
463 {
464 "HTTP/1.1 200 OK\r\n"
465 "No-Vary-Search: params\r\n"
466 R"(No-Vary-Search: except=("c+%C2%A2"))"
467 "\r\n\r\n", // raw_headers
468 {}, // expected_no_vary_params
469 {"c ¢"}, // expected_vary_params
470 true, // expected_vary_on_key_order
471 false, // expected_vary_by_default
472 },
473 // Vary on all with one excepted search param. Set params as
474 // part of the same header line.
475 {
476 "HTTP/1.1 200 OK\r\n"
477 R"(No-Vary-Search: params,except=("a"))"
478 "\r\n\r\n", // raw_headers
479 {}, // expected_no_vary_params
480 {"a"}, // expected_vary_params
481 true, // expected_vary_on_key_order
482 false, // expected_vary_by_default
483 },
484 // Vary on all with one excepted search param. Override except
485 // on different header line.
486 {
487 "HTTP/1.1 200 OK\r\n"
488 R"(No-Vary-Search: params,except=("a" b))"
489 "\r\n"
490 R"(No-Vary-Search: except=("c"))"
491 "\r\n\r\n", // raw_headers
492 {}, // expected_no_vary_params
493 {"c"}, // expected_vary_params
494 true, // expected_vary_on_key_order
495 false, // expected_vary_by_default
496 },
497 // Vary on all with more than one excepted search param.
498 {
499 "HTTP/1.1 200 OK\r\n"
500 "No-Vary-Search: params\r\n"
501 R"(No-Vary-Search: except=("a" "b"))"
502 "\r\n\r\n", // raw_headers
503 {}, // expected_no_vary_params
504 {"a", "b"}, // expected_vary_params
505 true, // expected_vary_on_key_order
506 false, // expected_vary_by_default
507 },
508 // Vary on all with more than one excepted search param. params appears
509 // after except in header definition.
510 {
511 "HTTP/1.1 200 OK\r\n"
512 R"(No-Vary-Search: except=("a" "b"))"
513 "\r\n"
514 "No-Vary-Search: params\r\n\r\n", // raw_headers
515 {}, // expected_no_vary_params
516 {"a", "b"}, // expected_vary_params
517 true, // expected_vary_on_key_order
518 false, // expected_vary_by_default
519 },
520 // Vary on all with more than one excepted search param. Set params as
521 // part of the same header line.
522 {
523 "HTTP/1.1 200 OK\r\n"
524 R"(No-Vary-Search: params,except=("a" "b"))"
525 "\r\n\r\n", // raw_headers
526 {}, // expected_no_vary_params
527 {"a", "b"}, // expected_vary_params
528 true, // expected_vary_on_key_order
529 false, // expected_vary_by_default
530 },
531 // Don't vary on two search params.
532 {
533 "HTTP/1.1 200 OK\r\n"
534 R"(No-Vary-Search: params=("a" "b"))"
535 "\r\n\r\n", // raw_headers
536 {"a", "b"}, // expected_no_vary_params
537 {}, // expected_vary_params
538 true, // expected_vary_on_key_order
539 true, // expected_vary_by_default
540 },
541 // Don't vary on search params order.
542 {
543 "HTTP/1.1 200 OK\r\n"
544 "No-Vary-Search: key-order\r\n\r\n", // raw_headers
545 {}, // expected_no_vary_params
546 {}, // expected_vary_params
547 false, // expected_vary_on_key_order
548 true, // expected_vary_by_default
549 },
550 // Don't vary on search params order.
551 {
552 "HTTP/1.1 200 OK\r\n"
553 "No-Vary-Search: key-order=?1\r\n\r\n", // raw_headers
554 {}, // expected_no_vary_params
555 {}, // expected_vary_params
556 false, // expected_vary_on_key_order
557 true, // expected_vary_by_default
558 },
559 // Don't vary on search params order and on two specific search params.
560 {
561 "HTTP/1.1 200 OK\r\n"
562 R"(No-Vary-Search: params=("a" "b"))"
563 "\r\n"
564 "No-Vary-Search: key-order\r\n\r\n", // raw_headers
565 {"a", "b"}, // expected_no_vary_params
566 {}, // expected_vary_params
567 false, // expected_vary_on_key_order
568 true, // expected_vary_by_default
569 },
570 // Don't vary on search params order and on two specific search params.
571 {
572 "HTTP/1.1 200 OK\r\n"
573 R"(No-Vary-Search: params=("a" "b"))"
574 "\r\n"
575 "No-Vary-Search: key-order=?1\r\n\r\n", // raw_headers
576 {"a", "b"}, // expected_no_vary_params
577 {}, // expected_vary_params
578 false, // expected_vary_on_key_order
579 true, // expected_vary_by_default
580 },
581 // Vary on search params order and do not vary on two specific search
582 // params.
583 {
584 "HTTP/1.1 200 OK\r\n"
585 R"(No-Vary-Search: params=("a" "b"))"
586 "\r\n"
587 "No-Vary-Search: key-order=?0\r\n\r\n", // raw_headers
588 {"a", "b"}, // expected_no_vary_params
589 {}, // expected_vary_params
590 true, // expected_vary_on_key_order
591 true, // expected_vary_by_default
592 },
593 // Vary on all search params except one, and do not vary on search params
594 // order.
595 {
596 "HTTP/1.1 200 OK\r\n"
597 "No-Vary-Search: params\r\n"
598 R"(No-Vary-Search: except=("a"))"
599 "\r\n"
600 "No-Vary-Search: key-order\r\n\r\n", // raw_headers
601 {}, // expected_no_vary_params
602 {"a"}, // expected_vary_params
603 false, // expected_vary_on_key_order
604 false, // expected_vary_by_default
605 },
606 // Vary on all search params except one, and do not vary on search params
607 // order.
608 {
609 "HTTP/1.1 200 OK\r\n"
610 "No-Vary-Search: params=?1\r\n"
611 R"(No-Vary-Search: except=("a"))"
612 "\r\n"
613 "No-Vary-Search: key-order\r\n\r\n", // raw_headers
614 {}, // expected_no_vary_params
615 {"a"}, // expected_vary_params
616 false, // expected_vary_on_key_order
617 false, // expected_vary_by_default
618 },
619 // Vary on all search params except one, and do not vary on search params
620 // order.
621 {
622 "HTTP/1.1 200 OK\r\n"
623 "No-Vary-Search: params\r\n"
624 R"(No-Vary-Search: except=("a"))"
625 "\r\n"
626 "No-Vary-Search: key-order=?1\r\n\r\n", // raw_headers
627 {}, // expected_no_vary_params
628 {"a"}, // expected_vary_params
629 false, // expected_vary_on_key_order
630 false, // expected_vary_by_default
631 },
632 // Vary on all search params except one, and vary on search params order.
633 {
634 "HTTP/1.1 200 OK\r\n"
635 "No-Vary-Search: params=?1\r\n"
636 R"(No-Vary-Search: except=("a"))"
637 "\r\n"
638 "No-Vary-Search: key-order=?0\r\n\r\n", // raw_headers
639 {}, // expected_no_vary_params
640 {"a"}, // expected_vary_params
641 true, // expected_vary_on_key_order
642 false, // expected_vary_by_default
643 },
644 // Vary on all search params except two, and do not vary on search params
645 // order.
646 {
647 "HTTP/1.1 200 OK\r\n"
648 "No-Vary-Search: params\r\n"
649 R"(No-Vary-Search: except=("a" "b"))"
650 "\r\n"
651 "No-Vary-Search: key-order\r\n\r\n", // raw_headers
652 {}, // expected_no_vary_params
653 {"a", "b"}, // expected_vary_params
654 false, // expected_vary_on_key_order
655 false, // expected_vary_by_default
656 },
657 // Do not vary on one search params. Override params on a different header
658 // line.
659 {
660 "HTTP/1.1 200 OK\r\n"
661 R"(No-Vary-Search: params=("a"))"
662 "\r\n"
663 R"(No-Vary-Search: params=("b"))"
664 "\r\n\r\n", // raw_headers
665 {"b"}, // expected_no_vary_params
666 {}, // expected_vary_params
667 true, // expected_vary_on_key_order
668 true, // expected_vary_by_default
669 },
670 // Do not vary on any search params. Override params on a different header
671 // line.
672 {
673 "HTTP/1.1 200 OK\r\n"
674 R"(No-Vary-Search: params=("a"))"
675 "\r\n"
676 "No-Vary-Search: params\r\n\r\n", // raw_headers
677 {}, // expected_no_vary_params
678 {}, // expected_vary_params
679 true, // expected_vary_on_key_order
680 false, // expected_vary_by_default
681 },
682 // Do not vary on any search params except one. Override except on a
683 // different header line.
684 {
685 "HTTP/1.1 200 OK\r\n"
686 "No-Vary-Search: params\r\n"
687 R"(No-Vary-Search: except=("a"))"
688 "\r\n"
689 R"(No-Vary-Search: except=("b"))"
690 "\r\n\r\n", // raw_headers
691 {}, // expected_no_vary_params
692 {"b"}, // expected_vary_params
693 true, // expected_vary_on_key_order
694 false, // expected_vary_by_default
695 },
696 // Allow extension via parameters.
697 {
698 "HTTP/1.1 200 OK\r\n"
699 "No-Vary-Search: params;unknown\r\n\r\n", // raw_headers
700 {}, // expected_no_vary_params
701 {}, // expected_vary_params
702 true, // expected_vary_on_key_order
703 false, // expected_vary_by_default
704 },
705 // Allow extension via parameters.
706 {
707 "HTTP/1.1 200 OK\r\n"
708 R"(No-Vary-Search: params=("a");unknown)"
709 "\r\n\r\n", // raw_headers
710 {"a"}, // expected_no_vary_params
711 {}, // expected_vary_params
712 true, // expected_vary_on_key_order
713 true, // expected_vary_by_default
714 },
715 // Allow extension via parameters.
716 {
717 "HTTP/1.1 200 OK\r\n"
718 R"(No-Vary-Search: params;unknown,except=("a");unknown)"
719 "\r\n\r\n", // raw_headers
720 {}, // expected_no_vary_params
721 {"a"}, // expected_vary_params
722 true, // expected_vary_on_key_order
723 false, // expected_vary_by_default
724 },
725 // Allow extension via parameters.
726 {
727 "HTTP/1.1 200 OK\r\n"
728 "No-Vary-Search: key-order;unknown\r\n\r\n", // raw_headers
729 {}, // expected_no_vary_params
730 {}, // expected_vary_params
731 false, // expected_vary_on_key_order
732 true, // expected_vary_by_default
733 },
734 // Allow extension via parameters.
735 {
736 "HTTP/1.1 200 OK\r\n"
737 R"(No-Vary-Search: params=("a";unknown))"
738 "\r\n\r\n", // raw_headers
739 {"a"}, // expected_no_vary_params
740 {}, // expected_vary_params
741 true, // expected_vary_on_key_order
742 true, // expected_vary_by_default
743 },
744 // Allow extension via parameters.
745 {
746 "HTTP/1.1 200 OK\r\n"
747 "No-Vary-Search: params\r\n"
748 R"(No-Vary-Search: except=("a";unknown))"
749 "\r\n\r\n", // raw_headers
750 {}, // expected_no_vary_params
751 {"a"}, // expected_vary_params
752 true, // expected_vary_on_key_order
753 false, // expected_vary_by_default
754 },
755 // Vary on all search params except one. Override except on a different
756 // header line.
757 {
758 "HTTP/1.1 200 OK\r\n"
759 "No-Vary-Search: params,except=(a)\r\n"
760 R"(No-Vary-Search: except=("a"))"
761 "\r\n\r\n", // raw_headers
762 {}, // expected_no_vary_params
763 {"a"}, // expected_vary_params
764 true, // expected_vary_on_key_order
765 false, // expected_vary_by_default
766 }};
767
768 INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchResponseHeadersTest,
769 HttpNoVarySearchResponseHeadersTest,
770 testing::ValuesIn(response_headers_tests));
771
772 INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchResponseHeadersParseFailureTest,
773 HttpNoVarySearchResponseHeadersParseFailureTest,
774 testing::ValuesIn(response_header_failed));
775
776 struct NoVarySearchCompareTestData {
777 const GURL request_url;
778 const GURL cached_url;
779 const std::string_view raw_headers;
780 const bool expected_match;
781 };
782
TEST(HttpNoVarySearchCompare,CheckUrlEqualityWithSpecialCharacters)783 TEST(HttpNoVarySearchCompare, CheckUrlEqualityWithSpecialCharacters) {
784 // Use special characters in both `keys` and `values`.
785 const base::flat_map<std::string, std::string> percent_encoding = {
786 {"!", "%21"}, {"#", "%23"}, {"$", "%24"}, {"%", "%25"},
787 {"&", "%26"}, {"'", "%27"}, {"(", "%28"}, {")", "%29"},
788 {"*", R"(%2A)"}, {"+", R"(%2B)"}, {",", R"(%2C)"}, {"-", R"(%2D)"},
789 {".", R"(%2E)"}, {"/", R"(%2F)"}, {":", R"(%3A)"}, {";", "%3B"},
790 {"<", R"(%3C)"}, {"=", R"(%3D)"}, {">", R"(%3E)"}, {"?", R"(%3F)"},
791 {"@", "%40"}, {"[", "%5B"}, {"]", R"(%5D)"}, {"^", R"(%5E)"},
792 {"_", R"(%5F)"}, {"`", "%60"}, {"{", "%7B"}, {"|", R"(%7C)"},
793 {"}", R"(%7D)"}, {"~", R"(%7E)"}, {"", ""}};
794 const std::string_view raw_headers =
795 "HTTP/1.1 200 OK\r\n"
796 R"(No-Vary-Search: params=("c"))"
797 "\r\n\r\n";
798 const std::string headers = net::HttpUtil::AssembleRawHeaders(raw_headers);
799 const auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
800
801 const auto no_vary_search_data =
802 HttpNoVarySearchData::ParseFromHeaders(*parsed).value();
803
804 for (const auto& [key, value] : percent_encoding) {
805 std::string request_url_template =
806 R"(https://a.test/index.html?$key=$value)";
807 std::string cached_url_template =
808 R"(https://a.test/index.html?c=3&$key=$value)";
809
810 base::ReplaceSubstringsAfterOffset(&request_url_template, 0, "$key", value);
811 base::ReplaceSubstringsAfterOffset(&request_url_template, 0, "$value",
812 value);
813 base::ReplaceSubstringsAfterOffset(&cached_url_template, 0, "$key", value);
814 base::ReplaceSubstringsAfterOffset(&cached_url_template, 0, "$value",
815 value);
816
817 EXPECT_TRUE(no_vary_search_data.AreEquivalent(GURL(request_url_template),
818 GURL(cached_url_template)));
819
820 std::string header_template =
821 "HTTP/1.1 200 OK\r\n"
822 R"(No-Vary-Search: params, except=("$key"))"
823 "\r\n\r\n";
824 base::ReplaceSubstringsAfterOffset(&header_template, 0, "$key", key);
825
826 const auto parsed_header = base::MakeRefCounted<HttpResponseHeaders>(
827 net::HttpUtil::AssembleRawHeaders(header_template));
828 const auto no_vary_search_data_special_char =
829 HttpNoVarySearchData::ParseFromHeaders(*parsed_header).value();
830
831 EXPECT_TRUE(no_vary_search_data_special_char.AreEquivalent(
832 GURL(request_url_template), GURL(cached_url_template)));
833 }
834 }
835
836 constexpr std::pair<std::string_view, std::string_view>
837 kPercentEncodedNonAsciiKeys[] = {
838 {"¢", R"(%C2%A2)"},
839 {"¢ ¢", R"(%C2%A2+%C2%A2)"},
840 {"é 気", R"(%C3%A9+%E6%B0%97)"},
841 {"é", R"(%C3%A9)"},
842 {"気", R"(%E6%B0%97)"},
843 {"ぁ", R"(%E3%81%81)"},
844 {"", R"(%F0%90%A8%80)"},
845 };
846
TEST(HttpNoVarySearchCompare,CheckUrlEqualityWithPercentEncodedNonASCIICharactersExcept)847 TEST(HttpNoVarySearchCompare,
848 CheckUrlEqualityWithPercentEncodedNonASCIICharactersExcept) {
849 for (const auto& [key, value] : kPercentEncodedNonAsciiKeys) {
850 std::string request_url_template = R"(https://a.test/index.html?$key=c)";
851 std::string cached_url_template = R"(https://a.test/index.html?c=3&$key=c)";
852 base::ReplaceSubstringsAfterOffset(&request_url_template, 0, "$key", key);
853 base::ReplaceSubstringsAfterOffset(&cached_url_template, 0, "$key", key);
854 std::string header_template =
855 "HTTP/1.1 200 OK\r\n"
856 R"(No-Vary-Search: params, except=("$key"))"
857 "\r\n\r\n";
858 base::ReplaceSubstringsAfterOffset(&header_template, 0, "$key", value);
859
860 const auto parsed_header = base::MakeRefCounted<HttpResponseHeaders>(
861 net::HttpUtil::AssembleRawHeaders(header_template));
862 const auto no_vary_search_data_special_char =
863 HttpNoVarySearchData::ParseFromHeaders(*parsed_header).value();
864
865 EXPECT_TRUE(no_vary_search_data_special_char.AreEquivalent(
866 GURL(request_url_template), GURL(cached_url_template)))
867 << "request_url = " << request_url_template
868 << " cached_url = " << cached_url_template
869 << " headers = " << header_template;
870 }
871 }
872
TEST(HttpNoVarySearchCompare,CheckUrlEqualityWithPercentEncodedNonASCIICharacters)873 TEST(HttpNoVarySearchCompare,
874 CheckUrlEqualityWithPercentEncodedNonASCIICharacters) {
875 for (const auto& [key, value] : kPercentEncodedNonAsciiKeys) {
876 std::string request_url_template =
877 R"(https://a.test/index.html?a=2&$key=c)";
878 std::string cached_url_template = R"(https://a.test/index.html?$key=d&a=2)";
879 base::ReplaceSubstringsAfterOffset(&request_url_template, 0, "$key", key);
880 base::ReplaceSubstringsAfterOffset(&cached_url_template, 0, "$key", key);
881 std::string header_template =
882 "HTTP/1.1 200 OK\r\n"
883 R"(No-Vary-Search: params=("$key"))"
884 "\r\n\r\n";
885 base::ReplaceSubstringsAfterOffset(&header_template, 0, "$key", value);
886
887 const auto parsed_header = base::MakeRefCounted<HttpResponseHeaders>(
888 net::HttpUtil::AssembleRawHeaders(header_template));
889 const auto no_vary_search_data_special_char =
890 HttpNoVarySearchData::ParseFromHeaders(*parsed_header).value();
891
892 EXPECT_TRUE(no_vary_search_data_special_char.AreEquivalent(
893 GURL(request_url_template), GURL(cached_url_template)))
894 << "request_url = " << request_url_template
895 << " cached_url = " << cached_url_template
896 << " headers = " << header_template;
897 }
898 }
899
900 class HttpNoVarySearchCompare
901 : public ::testing::Test,
902 public ::testing::WithParamInterface<NoVarySearchCompareTestData> {};
903
TEST_P(HttpNoVarySearchCompare,CheckUrlEqualityByNoVarySearch)904 TEST_P(HttpNoVarySearchCompare, CheckUrlEqualityByNoVarySearch) {
905 const auto& test_data = GetParam();
906
907 const std::string headers =
908 net::HttpUtil::AssembleRawHeaders(test_data.raw_headers);
909 const auto parsed = base::MakeRefCounted<HttpResponseHeaders>(headers);
910 const auto no_vary_search_data =
911 HttpNoVarySearchData::ParseFromHeaders(*parsed).value();
912
913 EXPECT_EQ(no_vary_search_data.AreEquivalent(test_data.request_url,
914 test_data.cached_url),
915 test_data.expected_match)
916 << "request_url = " << test_data.request_url
917 << " cached_url = " << test_data.cached_url
918 << " headers = " << test_data.raw_headers
919 << " match = " << test_data.expected_match;
920 }
921
922 const NoVarySearchCompareTestData no_vary_search_compare_tests[] = {
923 // Url's for same page with same username but different passwords.
924 {GURL("https://owner:[email protected]/index.html?a=2&b=3"),
925 GURL("https://owner:[email protected]/index.html?a=2&b=3"),
926 "HTTP/1.1 200 OK\r\n"
927 "No-Vary-Search: params\r\n\r\n",
928 false},
929 // Url's for same page with different username.
930 {GURL("https://[email protected]/index.html?a=2&b=3"),
931 GURL("https://[email protected]/index.html?a=2&b=3"),
932 "HTTP/1.1 200 OK\r\n"
933 "No-Vary-Search: params\r\n\r\n",
934 false},
935 // Url's for same origin with different path.
936 {GURL("https://a.test/index.html?a=2&b=3"),
937 GURL("https://a.test/home.html?a=2&b=3"),
938 "HTTP/1.1 200 OK\r\n"
939 "No-Vary-Search: params\r\n\r\n",
940 false},
941 // Url's for same page with different protocol.
942 {GURL("http://a.test/index.html?a=2&b=3"),
943 GURL("https://a.test/index.html?a=2&b=3"),
944 "HTTP/1.1 200 OK\r\n"
945 "No-Vary-Search: params\r\n\r\n",
946 false},
947 // Url's for different pages without the query and reference part
948 // are not equivalent.
949 {GURL("https://a.test/index.html?a=2&b=3"),
950 GURL("https://b.test/index.html?b=4&c=5"),
951 "HTTP/1.1 200 OK\r\n"
952 "No-Vary-Search: params\r\n\r\n",
953 false},
954 // Cached page requested again with different order of query parameters with
955 // the same values.
956 {GURL("https://a.test/index.html?a=2&b=3"),
957 GURL("https://a.test/index.html?b=3&a=2"),
958 "HTTP/1.1 200 OK\r\n"
959 "No-Vary-Search: key-order\r\n\r\n",
960 true},
961 // Cached page requested again with different order of query parameters but
962 // with different values.
963 {GURL("https://a.test/index.html?a=2&c=5&b=3"),
964 GURL("https://a.test/index.html?c=4&b=3&a=2"),
965 "HTTP/1.1 200 OK\r\n"
966 "No-Vary-Search: key-order\r\n\r\n",
967 false},
968 // Cached page requested again with values in different order for the query
969 // parameters with the same name. Key order is ignored.
970 {GURL("https://a.test/index.html?d=6&a=4&b=5&b=3&c=5&a=3"),
971 GURL("https://a.test/index.html?b=5&a=3&a=4&d=6&c=5&b=3"),
972 "HTTP/1.1 200 OK\r\n"
973 "No-Vary-Search: key-order"
974 "\r\n\r\n",
975 false},
976 // Cached page requested again with values in the same order for the query
977 // parameters with the same name. Key order is ignored.
978 {GURL("https://a.test/index.html?d=6&a=3&b=5&b=3&c=5&a=4"),
979 GURL("https://a.test/index.html?b=5&a=3&a=4&d=6&c=5&b=3"),
980 "HTTP/1.1 200 OK\r\n"
981 "No-Vary-Search: key-order"
982 "\r\n\r\n",
983 true},
984 // Cached page requested again with different order of query parameters but
985 // with one of the query parameters marked to be ignored.
986 {GURL("https://a.test/index.html?a=2&c=3&b=2"),
987 GURL("https://a.test/index.html?a=2&b=2&c=5"),
988 "HTTP/1.1 200 OK\r\n"
989 R"(No-Vary-Search: params=("c"))"
990 "\r\n\r\n",
991 true},
992 // Cached page requested again without any query parameters, but
993 // the cached URL's query parameter marked to be ignored.
994 {GURL("https://a.test/index.html"), GURL("https://a.test/index.html?a=2"),
995 "HTTP/1.1 200 OK\r\n"
996 R"(No-Vary-Search: params=("a"))"
997 "\r\n\r\n",
998 true},
999 // Cached page requested again with different values for the query
1000 // parameters that are marked to be ignored. Same value for the query
1001 // parameter that is marked as to vary.
1002 {GURL("https://a.test/index.html?a=1&b=2&c=3"),
1003 GURL("https://a.test/index.html?b=5&a=3&d=6&c=3"),
1004 "HTTP/1.1 200 OK\r\n"
1005 R"(No-Vary-Search: params, except=("c"))"
1006 "\r\n\r\n",
1007 true},
1008 // Cached page requested again with different values for the query
1009 // parameters that are marked to be ignored. Different value for the query
1010 // parameter that is marked as to vary.
1011 {GURL("https://a.test/index.html?a=1&b=2&c=5"),
1012 GURL("https://a.test/index.html?b=5&a=3&d=6&c=3"),
1013 "HTTP/1.1 200 OK\r\n"
1014 R"(No-Vary-Search: params, except=("c"))"
1015 "\r\n\r\n",
1016 false},
1017 // Cached page requested again with different values for the query
1018 // parameters that are marked to be ignored. Same values for the query
1019 // parameters that are marked as to vary.
1020 {GURL("https://a.test/index.html?d=6&a=1&b=2&c=5"),
1021 GURL("https://a.test/index.html?b=5&a=3&d=6&c=5"),
1022 "HTTP/1.1 200 OK\r\n"
1023 R"(No-Vary-Search: params, except=("c" "d"))"
1024 "\r\n\r\n",
1025 true},
1026 // Cached page requested again with different values for the query
1027 // parameters that are marked to be ignored. Same values for the query
1028 // parameters that are marked as to vary. Some query parameters to be
1029 // ignored appear multiple times in the query.
1030 {GURL("https://a.test/index.html?d=6&a=1&a=2&b=2&b=3&c=5"),
1031 GURL("https://a.test/index.html?b=5&a=3&a=4&d=6&c=5"),
1032 "HTTP/1.1 200 OK\r\n"
1033 R"(No-Vary-Search: params, except=("c" "d"))"
1034 "\r\n\r\n",
1035 true},
1036 // Cached page requested again with query parameters. All query parameters
1037 // are marked as to be ignored.
1038 {GURL("https://a.test/index.html?a=1&b=2&c=5"),
1039 GURL("https://a.test/index.html"),
1040 "HTTP/1.1 200 OK\r\n"
1041 "No-Vary-Search: params\r\n\r\n",
1042 true},
1043 // Cached page requested again with query parameters. All query parameters
1044 // are marked as to be ignored. Both request url and cached url have query
1045 // parameters.
1046 {GURL("https://a.test/index.html?a=1&b=2&c=5"),
1047 GURL("https://a.test/index.html?a=5&b=6&c=8&d=1"),
1048 "HTTP/1.1 200 OK\r\n"
1049 "No-Vary-Search: params\r\n\r\n",
1050 true},
1051 // Add test for when the keys are percent encoded.
1052 {GURL(R"(https://a.test/index.html?c+1=3&b+%202=2&a=1&%63%201=2&a=5)"),
1053 GURL(R"(https://a.test/index.html?a=1&b%20%202=2&%63%201=3&a=5&c+1=2)"),
1054 "HTTP/1.1 200 OK\r\n"
1055 "No-Vary-Search: key-order\r\n\r\n",
1056 true},
1057 // Add test for when there are different representations of a character
1058 {GURL(R"(https://a.test/index.html?%C3%A9=f&a=2&c=4&é=b)"),
1059 GURL(R"(https://a.test/index.html?a=2&é=f&c=4&d=7&é=b)"),
1060 "HTTP/1.1 200 OK\r\n"
1061 R"(No-Vary-Search: params=("d"), key-order)"
1062 "\r\n\r\n",
1063 true},
1064 // Add test for when there are triple code point
1065 {GURL(R"(https://a.test/index.html?%E3%81%81=f&a=2&c=4&%E3%81%81=b)"),
1066 GURL(R"(https://a.test/index.html?a=2&%E3%81%81=f&c=4&d=7&%E3%81%81=b)"),
1067 "HTTP/1.1 200 OK\r\n"
1068 R"(No-Vary-Search: params=("d"), key-order)"
1069 "\r\n\r\n",
1070 true},
1071 // Add test for when there are quadruple code point
1072 {GURL(
1073 R"(https://a.test/index.html?%F0%90%A8%80=%F0%90%A8%80&a=2&c=4&%F0%90%A8%80=b)"),
1074 GURL(
1075 R"(https://a.test/index.html?a=2&%F0%90%A8%80=%F0%90%A8%80&c=4&d=7&%F0%90%A8%80=b)"),
1076 "HTTP/1.1 200 OK\r\n"
1077 R"(No-Vary-Search: params=("d"), key-order)"
1078 "\r\n\r\n",
1079 true},
1080 // Add test for when there are params with empty values / keys.
1081 {GURL("https://a.test/index.html?a&b&c&a=2&d&=5&=1&=3"),
1082 GURL("https://a.test/index.html?c&d&b&a&=5&=1&a=2&=3"),
1083 "HTTP/1.1 200 OK\r\n"
1084 "No-Vary-Search: key-order\r\n\r\n",
1085 true},
1086 // Add test for when there are params with empty values / keys, an empty
1087 // key pair missing.
1088 {GURL("https://a.test/index.html?a&b&c&a=2&d&=5&=1&=3"),
1089 GURL("https://a.test/index.html?c&d&b&a&=5&a=2&=3"),
1090 "HTTP/1.1 200 OK\r\n"
1091 "No-Vary-Search: key-order\r\n\r\n",
1092 false},
1093 // Add test when there are params with keys / values that are wrongly
1094 // escaped.
1095 {GURL(R"(https://a.test/index.html?a=%3&%3=b)"),
1096 GURL(R"(https://a.test/index.html?a=%3&c=3&%3=b)"),
1097 "HTTP/1.1 200 OK\r\n"
1098 R"(No-Vary-Search: params=("c"))"
1099 "\r\n\r\n",
1100 true},
1101 // Add test when there is a param with key starting with a percent encoded
1102 // space (+).
1103 {GURL(R"(https://a.test/index.html?+a=3)"),
1104 GURL(R"(https://a.test/index.html?+a=2)"),
1105 "HTTP/1.1 200 OK\r\n"
1106 R"(No-Vary-Search: params=("+a"))"
1107 "\r\n\r\n",
1108 true},
1109 // Add test when there is a param with key starting with a percent encoded
1110 // space (+) and gets compared with same key without the leading space.
1111 {GURL(R"(https://a.test/index.html?+a=3)"),
1112 GURL(R"(https://a.test/index.html?a=2)"),
1113 "HTTP/1.1 200 OK\r\n"
1114 R"(No-Vary-Search: params=("+a"))"
1115 "\r\n\r\n",
1116 false},
1117 // Add test for when there are different representations of the character é
1118 // and we are ignoring that key.
1119 {GURL(R"(https://a.test/index.html?%C3%A9=g&a=2&c=4&é=b)"),
1120 GURL(R"(https://a.test/index.html?a=2&é=f&c=4&d=7&é=b)"),
1121 "HTTP/1.1 200 OK\r\n"
1122 R"(No-Vary-Search: params=("d" "%C3%A9"))"
1123 "\r\n\r\n",
1124 true},
1125 // Add test for when there are different representations of the character é
1126 // and we are not ignoring that key.
1127 {GURL(R"(https://a.test/index.html?%C3%A9=f&a=2&c=4&é=b)"),
1128 GURL(R"(https://a.test/index.html?a=2&é=f&c=4&d=7&é=b)"),
1129 "HTTP/1.1 200 OK\r\n"
1130 R"(No-Vary-Search: params, except=("%C3%A9"))"
1131 "\r\n\r\n",
1132 true},
1133 // Add test for when there are different representations of the character é
1134 // and we are not ignoring that key.
1135 {GURL(R"(https://a.test/index.html?%C3%A9=g&a=2&c=4&é=b)"),
1136 GURL(R"(https://a.test/index.html?a=2&é=f&c=4&d=7&é=b)"),
1137 "HTTP/1.1 200 OK\r\n"
1138 R"(No-Vary-Search: params, except=("%C3%A9"))"
1139 "\r\n\r\n",
1140 false},
1141 };
1142
1143 INSTANTIATE_TEST_SUITE_P(HttpNoVarySearchCompare,
1144 HttpNoVarySearchCompare,
1145 testing::ValuesIn(no_vary_search_compare_tests));
1146
1147 } // namespace
1148
1149 } // namespace net
1150