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 <initializer_list>
8 #include <string_view>
9 #include <tuple>
10 #include <utility>
11
12 #include "base/notreached.h"
13 #include "base/ranges/algorithm.h"
14 #include "base/strings/strcat.h"
15 #include "url/gurl.h"
16
17 namespace net {
18
19 CookieInclusionStatus::CookieInclusionStatus() = default;
20
CookieInclusionStatus(ExclusionReason reason)21 CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason) {
22 exclusion_reasons_[reason] = true;
23 }
24
CookieInclusionStatus(ExclusionReason reason,WarningReason warning)25 CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason,
26 WarningReason warning) {
27 exclusion_reasons_[reason] = true;
28 warning_reasons_[warning] = true;
29 }
30
CookieInclusionStatus(WarningReason warning)31 CookieInclusionStatus::CookieInclusionStatus(WarningReason warning) {
32 warning_reasons_[warning] = true;
33 }
34
CookieInclusionStatus(std::vector<ExclusionReason> exclusions,std::vector<WarningReason> warnings,ExemptionReason exemption)35 CookieInclusionStatus::CookieInclusionStatus(
36 std::vector<ExclusionReason> exclusions,
37 std::vector<WarningReason> warnings,
38 ExemptionReason exemption) {
39 for (ExclusionReason reason : exclusions) {
40 exclusion_reasons_[reason] = true;
41 }
42 for (WarningReason warning : warnings) {
43 warning_reasons_[warning] = true;
44 }
45 exemption_reason_ = exemption;
46 }
47
48 CookieInclusionStatus::CookieInclusionStatus(
49 const CookieInclusionStatus& other) = default;
50
51 CookieInclusionStatus& CookieInclusionStatus::operator=(
52 const CookieInclusionStatus& other) = default;
53
operator ==(const CookieInclusionStatus & other) const54 bool CookieInclusionStatus::operator==(
55 const CookieInclusionStatus& other) const {
56 return exclusion_reasons_ == other.exclusion_reasons_ &&
57 warning_reasons_ == other.warning_reasons_ &&
58 exemption_reason_ == other.exemption_reason_;
59 }
60
operator !=(const CookieInclusionStatus & other) const61 bool CookieInclusionStatus::operator!=(
62 const CookieInclusionStatus& other) const {
63 return !operator==(other);
64 }
65
operator <(const CookieInclusionStatus & other) const66 bool CookieInclusionStatus::operator<(
67 const CookieInclusionStatus& other) const {
68 static_assert(NUM_EXCLUSION_REASONS <= sizeof(unsigned long) * CHAR_BIT,
69 "use .ullong() instead");
70 static_assert(NUM_WARNING_REASONS <= sizeof(unsigned long) * CHAR_BIT,
71 "use .ullong() instead");
72 return std::make_tuple(exclusion_reasons_.to_ulong(),
73 warning_reasons_.to_ulong(), exemption_reason_) <
74 std::make_tuple(other.exclusion_reasons_.to_ulong(),
75 other.warning_reasons_.to_ulong(),
76 other.exemption_reason_);
77 }
78
IsInclude() const79 bool CookieInclusionStatus::IsInclude() const {
80 return exclusion_reasons_.none();
81 }
82
HasExclusionReason(ExclusionReason reason) const83 bool CookieInclusionStatus::HasExclusionReason(ExclusionReason reason) const {
84 return exclusion_reasons_[reason];
85 }
86
HasOnlyExclusionReason(ExclusionReason reason) const87 bool CookieInclusionStatus::HasOnlyExclusionReason(
88 ExclusionReason reason) const {
89 return exclusion_reasons_[reason] && exclusion_reasons_.count() == 1;
90 }
91
AddExclusionReason(ExclusionReason reason)92 void CookieInclusionStatus::AddExclusionReason(ExclusionReason reason) {
93 exclusion_reasons_[reason] = true;
94 // If the cookie would be excluded for reasons other than the new SameSite
95 // rules, don't bother warning about it.
96 MaybeClearSameSiteWarning();
97 // If the cookie would be excluded for reasons unrelated to 3pcd, don't bother
98 // warning about 3pcd.
99 MaybeClearThirdPartyPhaseoutReason();
100 // If the cookie would have been excluded, clear the exemption reason.
101 exemption_reason_ = ExemptionReason::kNone;
102 }
103
RemoveExclusionReason(ExclusionReason reason)104 void CookieInclusionStatus::RemoveExclusionReason(ExclusionReason reason) {
105 exclusion_reasons_[reason] = false;
106 }
107
RemoveExclusionReasons(const std::vector<ExclusionReason> & reasons)108 void CookieInclusionStatus::RemoveExclusionReasons(
109 const std::vector<ExclusionReason>& reasons) {
110 exclusion_reasons_ = ExclusionReasonsWithout(reasons);
111 }
112
MaybeSetExemptionReason(ExemptionReason reason)113 void CookieInclusionStatus::MaybeSetExemptionReason(ExemptionReason reason) {
114 if (IsInclude() && exemption_reason_ == ExemptionReason::kNone) {
115 exemption_reason_ = reason;
116 }
117 }
118
119 CookieInclusionStatus::ExclusionReasonBitset
ExclusionReasonsWithout(const std::vector<ExclusionReason> & reasons) const120 CookieInclusionStatus::ExclusionReasonsWithout(
121 const std::vector<ExclusionReason>& reasons) const {
122 CookieInclusionStatus::ExclusionReasonBitset result(exclusion_reasons_);
123 for (const ExclusionReason reason : reasons) {
124 result[reason] = false;
125 }
126 return result;
127 }
128
MaybeClearSameSiteWarning()129 void CookieInclusionStatus::MaybeClearSameSiteWarning() {
130 if (ExclusionReasonsWithout({
131 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
132 EXCLUDE_SAMESITE_NONE_INSECURE,
133 }) != 0u) {
134 RemoveWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
135 RemoveWarningReason(WARN_SAMESITE_NONE_INSECURE);
136 RemoveWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
137 }
138
139 if (!ShouldRecordDowngradeMetrics()) {
140 RemoveWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE);
141 RemoveWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE);
142 RemoveWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE);
143 RemoveWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE);
144 RemoveWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE);
145
146 RemoveWarningReason(WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION);
147 }
148 }
149
MaybeClearThirdPartyPhaseoutReason()150 void CookieInclusionStatus::MaybeClearThirdPartyPhaseoutReason() {
151 if (!IsInclude()) {
152 RemoveWarningReason(WARN_THIRD_PARTY_PHASEOUT);
153 }
154 if (ExclusionReasonsWithout(
155 {EXCLUDE_THIRD_PARTY_PHASEOUT,
156 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET}) != 0u) {
157 RemoveExclusionReason(EXCLUDE_THIRD_PARTY_PHASEOUT);
158 RemoveExclusionReason(EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET);
159 }
160 }
161
ShouldRecordDowngradeMetrics() const162 bool CookieInclusionStatus::ShouldRecordDowngradeMetrics() const {
163 return ExclusionReasonsWithout({
164 EXCLUDE_SAMESITE_STRICT,
165 EXCLUDE_SAMESITE_LAX,
166 EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
167 }) == 0u;
168 }
169
ShouldWarn() const170 bool CookieInclusionStatus::ShouldWarn() const {
171 return warning_reasons_.any();
172 }
173
HasWarningReason(WarningReason reason) const174 bool CookieInclusionStatus::HasWarningReason(WarningReason reason) const {
175 return warning_reasons_[reason];
176 }
177
HasSchemefulDowngradeWarning(CookieInclusionStatus::WarningReason * reason) const178 bool CookieInclusionStatus::HasSchemefulDowngradeWarning(
179 CookieInclusionStatus::WarningReason* reason) const {
180 if (!ShouldWarn())
181 return false;
182
183 const CookieInclusionStatus::WarningReason kDowngradeWarnings[] = {
184 WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE,
185 WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE,
186 WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE,
187 WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE,
188 WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE,
189 };
190
191 for (auto warning : kDowngradeWarnings) {
192 if (!HasWarningReason(warning))
193 continue;
194
195 if (reason)
196 *reason = warning;
197
198 return true;
199 }
200
201 return false;
202 }
203
AddWarningReason(WarningReason reason)204 void CookieInclusionStatus::AddWarningReason(WarningReason reason) {
205 warning_reasons_[reason] = true;
206 }
207
RemoveWarningReason(WarningReason reason)208 void CookieInclusionStatus::RemoveWarningReason(WarningReason reason) {
209 warning_reasons_[reason] = false;
210 }
211
212 CookieInclusionStatus::ContextDowngradeMetricValues
GetBreakingDowngradeMetricsEnumValue(const GURL & url) const213 CookieInclusionStatus::GetBreakingDowngradeMetricsEnumValue(
214 const GURL& url) const {
215 bool url_is_secure = url.SchemeIsCryptographic();
216
217 // Start the |reason| as something other than the downgrade warnings.
218 WarningReason reason = WarningReason::NUM_WARNING_REASONS;
219
220 // Don't bother checking the return value because the default switch case
221 // will handle if no reason was found.
222 HasSchemefulDowngradeWarning(&reason);
223
224 switch (reason) {
225 case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE:
226 return url_is_secure
227 ? ContextDowngradeMetricValues::kStrictLaxStrictSecure
228 : ContextDowngradeMetricValues::kStrictLaxStrictInsecure;
229 case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE:
230 return url_is_secure
231 ? ContextDowngradeMetricValues::kStrictCrossStrictSecure
232 : ContextDowngradeMetricValues::kStrictCrossStrictInsecure;
233 case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE:
234 return url_is_secure
235 ? ContextDowngradeMetricValues::kStrictCrossLaxSecure
236 : ContextDowngradeMetricValues::kStrictCrossLaxInsecure;
237 case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE:
238 return url_is_secure
239 ? ContextDowngradeMetricValues::kLaxCrossStrictSecure
240 : ContextDowngradeMetricValues::kLaxCrossStrictInsecure;
241 case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE:
242 return url_is_secure ? ContextDowngradeMetricValues::kLaxCrossLaxSecure
243 : ContextDowngradeMetricValues::kLaxCrossLaxInsecure;
244 default:
245 return url_is_secure ? ContextDowngradeMetricValues::kNoDowngradeSecure
246 : ContextDowngradeMetricValues::kNoDowngradeInsecure;
247 }
248 }
249
GetDebugString() const250 std::string CookieInclusionStatus::GetDebugString() const {
251 std::string out;
252
253 if (IsInclude())
254 base::StrAppend(&out, {"INCLUDE, "});
255
256 constexpr std::pair<ExclusionReason, const char*> exclusion_reasons[] = {
257 {EXCLUDE_UNKNOWN_ERROR, "EXCLUDE_UNKNOWN_ERROR"},
258 {EXCLUDE_HTTP_ONLY, "EXCLUDE_HTTP_ONLY"},
259 {EXCLUDE_SECURE_ONLY, "EXCLUDE_SECURE_ONLY"},
260 {EXCLUDE_DOMAIN_MISMATCH, "EXCLUDE_DOMAIN_MISMATCH"},
261 {EXCLUDE_NOT_ON_PATH, "EXCLUDE_NOT_ON_PATH"},
262 {EXCLUDE_SAMESITE_STRICT, "EXCLUDE_SAMESITE_STRICT"},
263 {EXCLUDE_SAMESITE_LAX, "EXCLUDE_SAMESITE_LAX"},
264 {EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
265 "EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX"},
266 {EXCLUDE_SAMESITE_NONE_INSECURE, "EXCLUDE_SAMESITE_NONE_INSECURE"},
267 {EXCLUDE_USER_PREFERENCES, "EXCLUDE_USER_PREFERENCES"},
268 {EXCLUDE_FAILURE_TO_STORE, "EXCLUDE_FAILURE_TO_STORE"},
269 {EXCLUDE_NONCOOKIEABLE_SCHEME, "EXCLUDE_NONCOOKIEABLE_SCHEME"},
270 {EXCLUDE_OVERWRITE_SECURE, "EXCLUDE_OVERWRITE_SECURE"},
271 {EXCLUDE_OVERWRITE_HTTP_ONLY, "EXCLUDE_OVERWRITE_HTTP_ONLY"},
272 {EXCLUDE_INVALID_DOMAIN, "EXCLUDE_INVALID_DOMAIN"},
273 {EXCLUDE_INVALID_PREFIX, "EXCLUDE_INVALID_PREFIX"},
274 {EXCLUDE_INVALID_PARTITIONED, "EXCLUDE_INVALID_PARTITIONED"},
275 {EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE,
276 "EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE"},
277 {EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE,
278 "EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE"},
279 {EXCLUDE_DOMAIN_NON_ASCII, "EXCLUDE_DOMAIN_NON_ASCII"},
280 {EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
281 "EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET"},
282 {EXCLUDE_PORT_MISMATCH, "EXCLUDE_PORT_MISMATCH"},
283 {EXCLUDE_SCHEME_MISMATCH, "EXCLUDE_SCHEME_MISMATCH"},
284 {EXCLUDE_SHADOWING_DOMAIN, "EXCLUDE_SHADOWING_DOMAIN"},
285 {EXCLUDE_DISALLOWED_CHARACTER, "EXCLUDE_DISALLOWED_CHARACTER"},
286 {EXCLUDE_THIRD_PARTY_PHASEOUT, "EXCLUDE_THIRD_PARTY_PHASEOUT"},
287 {EXCLUDE_NO_COOKIE_CONTENT, "EXCLUDE_NO_COOKIE_CONTENT"},
288 };
289 static_assert(
290 std::size(exclusion_reasons) == ExclusionReason::NUM_EXCLUSION_REASONS,
291 "Please ensure all ExclusionReason variants are enumerated in "
292 "GetDebugString");
293 static_assert(base::ranges::is_sorted(exclusion_reasons),
294 "Please keep the ExclusionReason variants sorted in numerical "
295 "order in GetDebugString");
296
297 for (const auto& reason : exclusion_reasons) {
298 if (HasExclusionReason(reason.first))
299 base::StrAppend(&out, {reason.second, ", "});
300 }
301
302 // Add warning
303 if (!ShouldWarn()) {
304 base::StrAppend(&out, {"DO_NOT_WARN, "});
305 }
306
307 constexpr std::pair<WarningReason, const char*> warning_reasons[] = {
308 {WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
309 "WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT"},
310 {WARN_SAMESITE_NONE_INSECURE, "WARN_SAMESITE_NONE_INSECURE"},
311 {WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE,
312 "WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE"},
313 {WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE,
314 "WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE"},
315 {WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE,
316 "WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE"},
317 {WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE,
318 "WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE"},
319 {WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE,
320 "WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE"},
321 {WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE,
322 "WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE"},
323 {WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC,
324 "WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC"},
325 {WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION,
326 "WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION"},
327 {WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE,
328 "WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE"},
329 {WARN_DOMAIN_NON_ASCII, "WARN_DOMAIN_NON_ASCII"},
330 {WARN_PORT_MISMATCH, "WARN_PORT_MISMATCH"},
331 {WARN_SCHEME_MISMATCH, "WARN_SCHEME_MISMATCH"},
332 {WARN_TENTATIVELY_ALLOWING_SECURE_SOURCE_SCHEME,
333 "WARN_TENTATIVELY_ALLOWING_SECURE_SOURCE_SCHEME"},
334 {WARN_SHADOWING_DOMAIN, "WARN_SHADOWING_DOMAIN"},
335 {WARN_THIRD_PARTY_PHASEOUT, "WARN_THIRD_PARTY_PHASEOUT"},
336 };
337 static_assert(
338 std::size(warning_reasons) == WarningReason::NUM_WARNING_REASONS,
339 "Please ensure all WarningReason variants are enumerated in "
340 "GetDebugString");
341 static_assert(base::ranges::is_sorted(warning_reasons),
342 "Please keep the WarningReason variants sorted in numerical "
343 "order in GetDebugString");
344
345 for (const auto& reason : warning_reasons) {
346 if (HasWarningReason(reason.first))
347 base::StrAppend(&out, {reason.second, ", "});
348 }
349
350 // Add exemption reason
351 if (exemption_reason() == CookieInclusionStatus::ExemptionReason::kNone) {
352 base::StrAppend(&out, {"NO_EXEMPTION"});
353 return out;
354 }
355
356 std::string_view reason;
357 switch (exemption_reason()) {
358 case ExemptionReason::kUserSetting:
359 reason = "ExemptionUserSetting";
360 break;
361 case ExemptionReason::k3PCDMetadata:
362 reason = "Exemption3PCDMetadata";
363 break;
364 case ExemptionReason::k3PCDDeprecationTrial:
365 reason = "Exemption3PCDDeprecationTrial";
366 break;
367 case ExemptionReason::k3PCDHeuristics:
368 reason = "Exemption3PCDHeuristics";
369 break;
370 case ExemptionReason::kEnterprisePolicy:
371 reason = "ExemptionEnterprisePolicy";
372 break;
373 case ExemptionReason::kStorageAccess:
374 reason = "ExemptionStorageAccess";
375 break;
376 case ExemptionReason::kTopLevelStorageAccess:
377 reason = "ExemptionTopLevelStorageAccess";
378 break;
379 case ExemptionReason::kCorsOptIn:
380 reason = "ExemptionCorsOptIn";
381 break;
382 case ExemptionReason::kNone:
383 NOTREACHED_NORETURN();
384 };
385 base::StrAppend(&out, {reason});
386
387 return out;
388 }
389
HasExactlyExclusionReasonsForTesting(std::vector<CookieInclusionStatus::ExclusionReason> reasons) const390 bool CookieInclusionStatus::HasExactlyExclusionReasonsForTesting(
391 std::vector<CookieInclusionStatus::ExclusionReason> reasons) const {
392 CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons);
393 return expected.exclusion_reasons_ == exclusion_reasons_;
394 }
395
HasExactlyWarningReasonsForTesting(std::vector<WarningReason> reasons) const396 bool CookieInclusionStatus::HasExactlyWarningReasonsForTesting(
397 std::vector<WarningReason> reasons) const {
398 CookieInclusionStatus expected = MakeFromReasonsForTesting({}, reasons);
399 return expected.warning_reasons_ == warning_reasons_;
400 }
401
402 // static
ValidateExclusionAndWarningFromWire(uint32_t exclusion_reasons,uint32_t warning_reasons)403 bool CookieInclusionStatus::ValidateExclusionAndWarningFromWire(
404 uint32_t exclusion_reasons,
405 uint32_t warning_reasons) {
406 uint32_t exclusion_mask =
407 static_cast<uint32_t>(~0ul << ExclusionReason::NUM_EXCLUSION_REASONS);
408 uint32_t warning_mask =
409 static_cast<uint32_t>(~0ul << WarningReason::NUM_WARNING_REASONS);
410 return (exclusion_reasons & exclusion_mask) == 0 &&
411 (warning_reasons & warning_mask) == 0;
412 }
413
MakeFromReasonsForTesting(std::vector<ExclusionReason> exclusions,std::vector<WarningReason> warnings,ExemptionReason exemption,bool use_literal)414 CookieInclusionStatus CookieInclusionStatus::MakeFromReasonsForTesting(
415 std::vector<ExclusionReason> exclusions,
416 std::vector<WarningReason> warnings,
417 ExemptionReason exemption,
418 bool use_literal) {
419 CookieInclusionStatus literal_status(exclusions, warnings, exemption);
420 if (use_literal) {
421 return literal_status;
422 }
423 CookieInclusionStatus status;
424 for (ExclusionReason reason : exclusions) {
425 status.AddExclusionReason(reason);
426 }
427 for (WarningReason warning : warnings) {
428 status.AddWarningReason(warning);
429 }
430 status.MaybeSetExemptionReason(exemption);
431
432 CHECK_EQ(status, literal_status);
433 return status;
434 }
435
ExcludedByUserPreferencesOrTPCD() const436 bool CookieInclusionStatus::ExcludedByUserPreferencesOrTPCD() const {
437 if (HasOnlyExclusionReason(ExclusionReason::EXCLUDE_USER_PREFERENCES) ||
438 HasOnlyExclusionReason(ExclusionReason::EXCLUDE_THIRD_PARTY_PHASEOUT)) {
439 return true;
440 }
441 return exclusion_reasons_.count() == 2 &&
442 exclusion_reasons_[ExclusionReason::EXCLUDE_THIRD_PARTY_PHASEOUT] &&
443 exclusion_reasons_
444 [ExclusionReason::
445 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET];
446 }
447
448 } // namespace net
449