1 // Copyright 2020 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/cookies/cookie_inclusion_status.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8
9 namespace net {
10
TEST(CookieInclusionStatusTest,IncludeStatus)11 TEST(CookieInclusionStatusTest, IncludeStatus) {
12 int num_exclusion_reasons =
13 static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
14 int num_warning_reasons =
15 static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS);
16 // Zero-argument constructor
17 CookieInclusionStatus status;
18 EXPECT_TRUE(status.IsInclude());
19 for (int i = 0; i < num_exclusion_reasons; ++i) {
20 EXPECT_FALSE(status.HasExclusionReason(
21 static_cast<CookieInclusionStatus::ExclusionReason>(i)));
22 }
23 for (int i = 0; i < num_warning_reasons; ++i) {
24 EXPECT_FALSE(status.HasWarningReason(
25 static_cast<CookieInclusionStatus::WarningReason>(i)));
26 }
27 EXPECT_FALSE(
28 status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
29 }
30
TEST(CookieInclusionStatusTest,ExcludeStatus)31 TEST(CookieInclusionStatusTest, ExcludeStatus) {
32 int num_exclusion_reasons =
33 static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
34 // Test exactly one exclusion reason and multiple (two) exclusion reasons.
35 for (int i = 0; i < num_exclusion_reasons; ++i) {
36 auto reason1 = static_cast<CookieInclusionStatus::ExclusionReason>(i);
37 if (reason1 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT &&
38 reason1 != CookieInclusionStatus::
39 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) {
40 continue;
41 }
42 CookieInclusionStatus status_one_reason =
43 CookieInclusionStatus::MakeFromReasonsForTesting(
44 /*exclusions=*/{reason1});
45 EXPECT_FALSE(status_one_reason.IsInclude());
46 EXPECT_TRUE(status_one_reason.HasExclusionReason(reason1));
47 EXPECT_TRUE(status_one_reason.HasOnlyExclusionReason(reason1));
48
49 for (int j = 0; j < num_exclusion_reasons; ++j) {
50 if (i == j)
51 continue;
52 auto reason2 = static_cast<CookieInclusionStatus::ExclusionReason>(j);
53 if (reason2 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT &&
54 reason2 != CookieInclusionStatus::
55 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) {
56 continue;
57 }
58 EXPECT_FALSE(status_one_reason.HasExclusionReason(reason2));
59 EXPECT_FALSE(status_one_reason.HasOnlyExclusionReason(reason2));
60
61 CookieInclusionStatus status_two_reasons = status_one_reason;
62 status_two_reasons.AddExclusionReason(reason2);
63 EXPECT_FALSE(status_two_reasons.IsInclude());
64
65 if (reason1 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT &&
66 reason2 != CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT) {
67 EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1));
68 EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2));
69 }
70 }
71 }
72 }
73
TEST(CookieInclusionStatusTest,ExcludeStatus_MaybeClearThirdPartyPhaseoutReason)74 TEST(CookieInclusionStatusTest,
75 ExcludeStatus_MaybeClearThirdPartyPhaseoutReason) {
76 int num_exclusion_reasons =
77 static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
78 CookieInclusionStatus::ExclusionReason reason1 =
79 CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT;
80 const CookieInclusionStatus status_one_reason =
81 CookieInclusionStatus::MakeFromReasonsForTesting(
82 /*exclusions=*/{reason1});
83 ASSERT_FALSE(status_one_reason.IsInclude());
84 ASSERT_TRUE(status_one_reason.HasOnlyExclusionReason(reason1));
85
86 for (int j = 0; j < num_exclusion_reasons; ++j) {
87 auto reason2 = static_cast<CookieInclusionStatus::ExclusionReason>(j);
88 if (reason1 == reason2) {
89 continue;
90 }
91 EXPECT_FALSE(status_one_reason.HasExclusionReason(reason2)) << reason2;
92
93 CookieInclusionStatus status_two_reasons = status_one_reason;
94 status_two_reasons.AddExclusionReason(reason2);
95 EXPECT_FALSE(status_two_reasons.IsInclude());
96
97 if (reason2 == CookieInclusionStatus::
98 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) {
99 EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1));
100 EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2));
101 } else {
102 EXPECT_TRUE(status_two_reasons.HasOnlyExclusionReason(reason2));
103 }
104 }
105 }
106
TEST(CookieInclusionStatusTest,AddExclusionReason_MaybeClearThirdPartyPhaseoutReason)107 TEST(CookieInclusionStatusTest,
108 AddExclusionReason_MaybeClearThirdPartyPhaseoutReason) {
109 CookieInclusionStatus status;
110 status.AddWarningReason(CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT);
111 ASSERT_TRUE(status.ShouldWarn());
112 ASSERT_TRUE(status.HasExactlyWarningReasonsForTesting(
113 {CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT}));
114 // Adding an exclusion reason should clear 3PCD warning reason.
115 status.AddExclusionReason(
116 CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT);
117 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
118 {CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT}));
119 EXPECT_FALSE(status.ShouldWarn());
120
121 status.AddExclusionReason(
122 CookieInclusionStatus::
123 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET);
124 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
125 {CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT,
126 CookieInclusionStatus::
127 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET}));
128 // Adding an exclusion reason unrelated with 3PCD should clear 3PCD related
129 // exclusion reasons.
130 status.AddExclusionReason(
131 CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
132 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
133 {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE}));
134 EXPECT_FALSE(status.IsInclude());
135 }
136
TEST(CookieInclusionStatusTest,AddExclusionReason)137 TEST(CookieInclusionStatusTest, AddExclusionReason) {
138 CookieInclusionStatus status;
139 status.AddWarningReason(
140 CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
141 status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
142 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
143 {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR}));
144 // Adding an exclusion reason other than
145 // EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX or
146 // EXCLUDE_SAMESITE_NONE_INSECURE should clear any SameSite warning.
147 EXPECT_FALSE(status.ShouldWarn());
148
149 status = CookieInclusionStatus();
150 status.AddWarningReason(
151 CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
152 status.AddExclusionReason(
153 CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
154 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
155 {CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
156 EXPECT_TRUE(status.HasExactlyWarningReasonsForTesting(
157 {CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT}));
158 }
159
TEST(CookieInclusionStatusTest,ExemptionReason)160 TEST(CookieInclusionStatusTest, ExemptionReason) {
161 CookieInclusionStatus status;
162 status.MaybeSetExemptionReason(
163 CookieInclusionStatus::ExemptionReason::k3PCDMetadata);
164 ASSERT_EQ(status.exemption_reason(),
165 CookieInclusionStatus::ExemptionReason::k3PCDMetadata);
166 ASSERT_TRUE(status.IsInclude());
167 ASSERT_EQ(status.GetDebugString(),
168 "INCLUDE, DO_NOT_WARN, Exemption3PCDMetadata");
169
170 // Updating exemption reason would be no-op.
171 status.MaybeSetExemptionReason(
172 CookieInclusionStatus::ExemptionReason::kEnterprisePolicy);
173 EXPECT_EQ(status.exemption_reason(),
174 CookieInclusionStatus::ExemptionReason::k3PCDMetadata);
175
176 // Adding an exclusion reason resets the exemption reason.
177 status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
178 EXPECT_EQ(status.exemption_reason(),
179 CookieInclusionStatus::ExemptionReason::kNone);
180
181 // Setting exemption reason when the cookie is already excluded would be
182 // no-op.
183 status.MaybeSetExemptionReason(
184 CookieInclusionStatus::ExemptionReason::kEnterprisePolicy);
185 EXPECT_EQ(status.exemption_reason(),
186 CookieInclusionStatus::ExemptionReason::kNone);
187 }
188
TEST(CookieInclusionStatusTest,CheckEachWarningReason)189 TEST(CookieInclusionStatusTest, CheckEachWarningReason) {
190 CookieInclusionStatus status;
191
192 int num_warning_reasons =
193 static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS);
194 EXPECT_FALSE(status.ShouldWarn());
195 for (int i = 0; i < num_warning_reasons; ++i) {
196 auto reason = static_cast<CookieInclusionStatus::WarningReason>(i);
197 status.AddWarningReason(reason);
198 EXPECT_TRUE(status.IsInclude());
199 EXPECT_TRUE(status.ShouldWarn());
200 EXPECT_TRUE(status.HasWarningReason(reason));
201 for (int j = 0; j < num_warning_reasons; ++j) {
202 if (i == j)
203 continue;
204 EXPECT_FALSE(status.HasWarningReason(
205 static_cast<CookieInclusionStatus::WarningReason>(j)));
206 }
207 status.RemoveWarningReason(reason);
208 EXPECT_FALSE(status.ShouldWarn());
209 }
210 }
211
TEST(CookieInclusionStatusTest,RemoveExclusionReason)212 TEST(CookieInclusionStatusTest, RemoveExclusionReason) {
213 CookieInclusionStatus status =
214 CookieInclusionStatus::MakeFromReasonsForTesting(
215 /*exclusions=*/{CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR});
216 ASSERT_TRUE(
217 status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
218
219 status.RemoveExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
220 EXPECT_FALSE(
221 status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
222
223 // Removing a nonexistent exclusion reason doesn't do anything.
224 ASSERT_FALSE(
225 status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
226 status.RemoveExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS);
227 EXPECT_FALSE(
228 status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
229 }
230
TEST(CookieInclusionStatusTest,RemoveWarningReason)231 TEST(CookieInclusionStatusTest, RemoveWarningReason) {
232 CookieInclusionStatus status =
233 CookieInclusionStatus::MakeFromReasonsForTesting(
234 {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR},
235 {CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE});
236 EXPECT_TRUE(status.ShouldWarn());
237 ASSERT_TRUE(status.HasWarningReason(
238 CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE));
239
240 status.RemoveWarningReason(
241 CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
242 EXPECT_FALSE(status.ShouldWarn());
243 EXPECT_FALSE(status.HasWarningReason(
244 CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE));
245
246 // Removing a nonexistent warning reason doesn't do anything.
247 ASSERT_FALSE(status.HasWarningReason(
248 CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT));
249 status.RemoveWarningReason(
250 CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
251 EXPECT_FALSE(status.ShouldWarn());
252 EXPECT_FALSE(status.HasWarningReason(
253 CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT));
254 }
255
TEST(CookieInclusionStatusTest,HasSchemefulDowngradeWarning)256 TEST(CookieInclusionStatusTest, HasSchemefulDowngradeWarning) {
257 std::vector<CookieInclusionStatus::WarningReason> downgrade_warnings = {
258 CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE,
259 CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE,
260 CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE,
261 CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE,
262 CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE,
263 };
264
265 CookieInclusionStatus empty_status;
266 EXPECT_FALSE(empty_status.HasSchemefulDowngradeWarning());
267
268 CookieInclusionStatus not_downgrade;
269 not_downgrade.AddWarningReason(
270 CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
271 EXPECT_FALSE(not_downgrade.HasSchemefulDowngradeWarning());
272
273 for (auto warning : downgrade_warnings) {
274 CookieInclusionStatus status;
275 status.AddWarningReason(warning);
276 CookieInclusionStatus::WarningReason reason;
277
278 EXPECT_TRUE(status.HasSchemefulDowngradeWarning(&reason));
279 EXPECT_EQ(warning, reason);
280 }
281 }
282
TEST(CookieInclusionStatusTest,ShouldRecordDowngradeMetrics)283 TEST(CookieInclusionStatusTest, ShouldRecordDowngradeMetrics) {
284 EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting({})
285 .ShouldRecordDowngradeMetrics());
286
287 EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
288 {
289 CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
290 })
291 .ShouldRecordDowngradeMetrics());
292
293 EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
294 {
295 CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
296 })
297 .ShouldRecordDowngradeMetrics());
298
299 EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
300 {
301 CookieInclusionStatus::
302 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
303 })
304 .ShouldRecordDowngradeMetrics());
305
306 // Note: the following cases cannot occur under normal circumstances.
307 EXPECT_TRUE(CookieInclusionStatus::MakeFromReasonsForTesting(
308 {
309 CookieInclusionStatus::
310 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
311 CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
312 })
313 .ShouldRecordDowngradeMetrics());
314 EXPECT_FALSE(CookieInclusionStatus::MakeFromReasonsForTesting(
315 {
316 CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
317 CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
318 })
319 .ShouldRecordDowngradeMetrics());
320 }
321
TEST(CookieInclusionStatusTest,RemoveExclusionReasons)322 TEST(CookieInclusionStatusTest, RemoveExclusionReasons) {
323 CookieInclusionStatus status =
324 CookieInclusionStatus::MakeFromReasonsForTesting({
325 CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
326 CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
327 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
328 });
329 ASSERT_TRUE(status.HasExactlyExclusionReasonsForTesting({
330 CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
331 CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
332 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
333 }));
334
335 status.RemoveExclusionReasons(
336 {CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
337 CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR,
338 CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT});
339 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting({
340 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
341 }));
342
343 // Removing a nonexistent exclusion reason doesn't do anything.
344 ASSERT_FALSE(
345 status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS));
346 status.RemoveExclusionReasons({CookieInclusionStatus::NUM_EXCLUSION_REASONS});
347 EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting({
348 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
349 }));
350 }
351
TEST(CookieInclusionStatusTest,ValidateExclusionAndWarningFromWire)352 TEST(CookieInclusionStatusTest, ValidateExclusionAndWarningFromWire) {
353 uint32_t exclusion_reasons = 0ul;
354 uint32_t warning_reasons = 0ul;
355
356 EXPECT_TRUE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
357 exclusion_reasons, warning_reasons));
358
359 exclusion_reasons = static_cast<uint32_t>(~0ul);
360 warning_reasons = static_cast<uint32_t>(~0ul);
361 EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
362 exclusion_reasons, warning_reasons));
363 EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
364 exclusion_reasons, 0u));
365 EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
366 0u, warning_reasons));
367
368 exclusion_reasons = (1u << CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
369 warning_reasons = (1u << CookieInclusionStatus::WARN_PORT_MISMATCH);
370 EXPECT_TRUE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
371 exclusion_reasons, warning_reasons));
372
373 exclusion_reasons = (1u << CookieInclusionStatus::NUM_EXCLUSION_REASONS);
374 warning_reasons = (1u << CookieInclusionStatus::NUM_WARNING_REASONS);
375 EXPECT_FALSE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
376 exclusion_reasons, warning_reasons));
377
378 exclusion_reasons =
379 (1u << (CookieInclusionStatus::NUM_EXCLUSION_REASONS - 1));
380 warning_reasons = (1u << (CookieInclusionStatus::NUM_WARNING_REASONS - 1));
381 EXPECT_TRUE(CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
382 exclusion_reasons, warning_reasons));
383 }
384
TEST(CookieInclusionStatusTest,ExcludedByUserPreferencesOrTPCD)385 TEST(CookieInclusionStatusTest, ExcludedByUserPreferencesOrTPCD) {
386 CookieInclusionStatus status =
387 CookieInclusionStatus::MakeFromReasonsForTesting(
388 {CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES});
389 EXPECT_TRUE(status.ExcludedByUserPreferencesOrTPCD());
390
391 status = CookieInclusionStatus::MakeFromReasonsForTesting({
392 CookieInclusionStatus::ExclusionReason::EXCLUDE_THIRD_PARTY_PHASEOUT,
393 });
394 EXPECT_TRUE(status.ExcludedByUserPreferencesOrTPCD());
395
396 status = CookieInclusionStatus::MakeFromReasonsForTesting({
397 CookieInclusionStatus::ExclusionReason::EXCLUDE_THIRD_PARTY_PHASEOUT,
398 CookieInclusionStatus::ExclusionReason::
399 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
400 });
401 EXPECT_TRUE(status.ExcludedByUserPreferencesOrTPCD());
402
403 status = CookieInclusionStatus::MakeFromReasonsForTesting({
404 CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES,
405 CookieInclusionStatus::ExclusionReason::EXCLUDE_FAILURE_TO_STORE,
406 });
407 EXPECT_FALSE(status.ExcludedByUserPreferencesOrTPCD());
408
409 status = CookieInclusionStatus::MakeFromReasonsForTesting({
410 CookieInclusionStatus::ExclusionReason::
411 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
412 });
413 EXPECT_FALSE(status.ExcludedByUserPreferencesOrTPCD());
414
415 status = CookieInclusionStatus::MakeFromReasonsForTesting({
416 CookieInclusionStatus::ExclusionReason::EXCLUDE_FAILURE_TO_STORE,
417 });
418 EXPECT_FALSE(status.ExcludedByUserPreferencesOrTPCD());
419 }
420
421 } // namespace net
422