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