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