blob: da314926b1e28925a86b3ef40890df1f1181da61 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2020 The Chromium Authors
Alexander Timin1cc31f42020-05-12 16:26:012// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakjc492bf82020-09-09 20:02:445#include "content/browser/renderer_host/cookie_utils.h"
Alexander Timin1cc31f42020-05-12 16:26:016
Sandor Major7c3e612f2023-12-01 20:48:087#include <cstddef>
8#include <ostream>
9#include <string>
10
11#include "base/feature_list.h"
12#include "base/logging.h"
Jayson Adams295430202021-07-27 01:07:5713#include "base/ranges/algorithm.h"
sbingler8e26e212023-09-27 23:23:2714#include "base/strings/string_util.h"
Shuran Huang7a6757c22024-04-17 15:17:3915#include "base/unguessable_token.h"
Alexander Timin1cc31f42020-05-12 16:26:0116#include "content/browser/devtools/devtools_instrumentation.h"
Sandor Major7c3e612f2023-12-01 20:48:0817#include "content/browser/navigation_or_document_handle.h"
18#include "content/browser/renderer_host/navigation_request.h"
danakjc492bf82020-09-09 20:02:4419#include "content/browser/renderer_host/render_frame_host_impl.h"
Alexander Timin1cc31f42020-05-12 16:26:0120#include "content/public/browser/browser_context.h"
21#include "content/public/browser/cookie_access_details.h"
Sandor Major7c3e612f2023-12-01 20:48:0822#include "content/public/browser/legacy_tech_cookie_issue_details.h"
Alexander Timin1cc31f42020-05-12 16:26:0123#include "content/public/common/content_client.h"
Sandor Major7c3e612f2023-12-01 20:48:0824#include "content/public/common/content_features.h"
Jihwan Marc Kim3e132f12020-05-20 17:33:1925#include "net/cookies/cookie_inclusion_status.h"
sbingler870b63f2023-04-25 16:47:5826#include "services/metrics/public/cpp/metrics_utils.h"
Alexander Timin1cc31f42020-05-12 16:26:0127#include "services/metrics/public/cpp/ukm_builders.h"
Sandor Major7c3e612f2023-12-01 20:48:0828#include "url/gurl.h"
Alexander Timin1cc31f42020-05-12 16:26:0129
30namespace content {
31
32namespace {
33
sbingler8e26e212023-09-27 23:23:2734void PotentiallyRecordNonAsciiCookieNameValue(
35 RenderFrameHost* rfh,
36 CookieAccessDetails::Type access_type,
37 const std::string& name,
38 const std::string& value) {
39 CHECK(rfh);
40
41 if (access_type != CookieAccessDetails::Type::kChange) {
42 return;
43 }
44
45 // Our data collection policy disallows collecting UKMs while prerendering.
46 // See //content/browser/preloading/prerender/README.md and ask the team to
47 // explore options to record data for prerendering pages if we need to
48 // support the case.
49 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
50 return;
51 }
52
53 bool name_has_non_ascii = !base::IsStringASCII(name);
54 bool value_has_non_ascii = !base::IsStringASCII(value);
55
56 if (name_has_non_ascii || value_has_non_ascii) {
57 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
58
59 auto event = ukm::builders::CookieHasNonAsciiCharacter(source_id);
60
61 // The event itself is what we're interested in, the value of "true" here
62 // can be ignored.
63 if (name_has_non_ascii) {
64 event.SetName(true);
65 }
66
67 if (value_has_non_ascii) {
68 event.SetValue(true);
69 }
70
71 event.Record(ukm::UkmRecorder::Get());
72 }
73}
74
selya7d96d6182024-04-22 11:35:5175// Relies on checks in RecordPartitionedCookiesUKMs to confirm that that the
76// cookie name is not "receive-cookie-deprecation", that cookie is first party
77// partitioned and the RenderFrameHost is not prerendering.
selya778265bc2023-10-23 14:37:5578void RecordFirstPartyPartitionedCookieCrossSiteContextUKM(
79 RenderFrameHostImpl* render_frame_host_impl,
selya7d96d6182024-04-22 11:35:5180 const net::CanonicalCookie& cookie,
81 const ukm::SourceId& source_id) {
selya778265bc2023-10-23 14:37:5582 // Same-site embed with cross-site ancestors (ABA embeds) have a null site
83 // for cookies since it is a cross-site context. If the result of
84 // ComputeSiteForCookies is first-party that means we are not in an ABA
85 // embedded context.
selya01be4aa22024-01-25 18:36:2486 bool has_cross_site_ancestor =
87 !render_frame_host_impl->ComputeSiteForCookies().IsFirstParty(
selya778265bc2023-10-23 14:37:5588 GURL(base::StrCat({url::kHttpsScheme, url::kStandardSchemeSeparator,
selya01be4aa22024-01-25 18:36:2489 cookie.DomainWithoutDot()})));
selya778265bc2023-10-23 14:37:5590
selya7d96d6182024-04-22 11:35:5191 ukm::builders::Cookies_FirstPartyPartitionedInCrossSiteContextV3(source_id)
selya01be4aa22024-01-25 18:36:2492 .SetCookiePresent(has_cross_site_ancestor)
selya778265bc2023-10-23 14:37:5593 .Record(ukm::UkmRecorder::Get());
94}
95
selya7d96d6182024-04-22 11:35:5196// Relies on checks in RecordPartitionedCookiesUKMs to confirm that that the
97// cookie is partitioned, the cookie name is not
98// "receive-cookie-deprecation" and the RenderFrameHost is not prerendering.
99void RecordPartitionedCookieUseV2UKM(RenderFrameHost* rfh,
100 const net::CanonicalCookie& cookie,
101 const ukm::SourceId& source_id) {
102 ukm::builders::PartitionedCookiePresentV2(source_id)
103 .SetPartitionedCookiePresentV2(true)
104 .Record(ukm::UkmRecorder::Get());
105}
106
107void RecordPartitionedCookiesUKMs(RenderFrameHostImpl* render_frame_host_impl,
108 const net::CanonicalCookie& cookie) {
selya27d093e2023-08-02 22:20:00109 // Our data collection policy disallows collecting UKMs while prerendering.
110 // See //content/browser/preloading/prerender/README.md and ask the team to
111 // explore options to record data for prerendering pages if we need to
112 // support the case.
selya7d96d6182024-04-22 11:35:51113 if (render_frame_host_impl->IsInLifecycleState(
114 RenderFrameHost::LifecycleState::kPrerendering)) {
selya27d093e2023-08-02 22:20:00115 return;
116 }
selya27d093e2023-08-02 22:20:00117
selya7d96d6182024-04-22 11:35:51118 // Cookies_FirstPartyPartitionedInCrossSiteContextV3 and
119 // PartitionedCookiePresentV2 both measure cookies
120 // without the name of 'receive-cookie-deprecation'. Return here to ensure
121 // that the metrics do not include those cookies.
122 if (cookie.Name() == "receive-cookie-deprecation") {
123 return;
124 }
125
126 ukm::SourceId source_id = render_frame_host_impl->GetPageUkmSourceId();
127
128 if (cookie.IsFirstPartyPartitioned()) {
129 RecordFirstPartyPartitionedCookieCrossSiteContextUKM(render_frame_host_impl,
130 cookie, source_id);
131 }
132
133 RecordPartitionedCookieUseV2UKM(render_frame_host_impl, cookie, source_id);
selya27d093e2023-08-02 22:20:00134}
135
sbingler870b63f2023-04-25 16:47:58136void RecordRedirectContextDowngradeUKM(RenderFrameHost* rfh,
137 CookieAccessDetails::Type access_type,
138 const net::CanonicalCookie& cookie,
139 const GURL& url) {
140 CHECK(rfh);
Takashi Toyoshimad540b932023-06-30 02:30:27141
142 // Our data collection policy disallows collecting UKMs while prerendering.
143 // See //content/browser/preloading/prerender/README.md and ask the team to
144 // explore options to record data for prerendering pages if we need to
145 // support the case.
146 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
147 return;
148 }
149
sbingler870b63f2023-04-25 16:47:58150 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
151
152 int64_t samesite_value = static_cast<int64_t>(cookie.SameSite());
153 if (access_type == CookieAccessDetails::Type::kRead) {
154 base::TimeDelta cookie_age = base::Time::Now() - cookie.CreationDate();
155
156 ukm::builders::SamesiteRedirectContextDowngrade(source_id)
157 .SetSamesiteValueReadPerCookie(samesite_value)
158 .SetAgePerCookie(
159 ukm::GetExponentialBucketMinForUserTiming(cookie_age.InMinutes()))
160 .Record(ukm::UkmRecorder::Get());
161 } else {
162 CHECK(access_type == CookieAccessDetails::Type::kChange);
163 ukm::builders::SamesiteRedirectContextDowngrade(source_id)
164 .SetSamesiteValueWritePerCookie(samesite_value)
165 .Record(ukm::UkmRecorder::Get());
166 }
167}
168
169void RecordSchemefulContextDowngradeUKM(
170 RenderFrameHost* rfh,
171 CookieAccessDetails::Type access_type,
172 const net::CookieInclusionStatus& status,
173 const GURL& url) {
174 CHECK(rfh);
Takashi Toyoshimad540b932023-06-30 02:30:27175
176 // Our data collection policy disallows collecting UKMs while prerendering.
177 // See //content/browser/preloading/prerender/README.md and ask the team to
178 // explore options to record data for prerendering pages if we need to
179 // support the case.
180 if (rfh->IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering)) {
181 return;
182 }
183
Alexander Timin1cc31f42020-05-12 16:26:01184 ukm::SourceId source_id = rfh->GetPageUkmSourceId();
185
Lei Zhang3ab30192022-08-15 19:52:20186 auto downgrade_metric =
187 static_cast<int64_t>(status.GetBreakingDowngradeMetricsEnumValue(url));
Alexander Timin1cc31f42020-05-12 16:26:01188 if (access_type == CookieAccessDetails::Type::kRead) {
189 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
Lei Zhang3ab30192022-08-15 19:52:20190 .SetRequestPerCookie(downgrade_metric)
Alexander Timin1cc31f42020-05-12 16:26:01191 .Record(ukm::UkmRecorder::Get());
192 } else {
sbingler870b63f2023-04-25 16:47:58193 CHECK(access_type == CookieAccessDetails::Type::kChange);
Alexander Timin1cc31f42020-05-12 16:26:01194 ukm::builders::SchemefulSameSiteContextDowngrade(source_id)
Lei Zhang3ab30192022-08-15 19:52:20195 .SetResponsePerCookie(downgrade_metric)
Alexander Timin1cc31f42020-05-12 16:26:01196 .Record(ukm::UkmRecorder::Get());
197 }
198}
199
Sandor Major7c3e612f2023-12-01 20:48:08200// LINT.IfChange(should_report_dev_tools)
Simon Zünd657178e2021-05-27 06:19:55201bool ShouldReportDevToolsIssueForStatus(
202 const net::CookieInclusionStatus& status) {
203 return status.ShouldWarn() ||
204 status.HasExclusionReason(
Dylan Cutler15fdd1e2022-11-15 22:54:46205 net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII) ||
206 status.HasExclusionReason(
207 net::CookieInclusionStatus::
Shuran Huangdc0b8d82023-09-19 14:49:30208 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) ||
209 status.HasExclusionReason(
210 net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT);
Simon Zünd657178e2021-05-27 06:19:55211}
Sandor Major7c3e612f2023-12-01 20:48:08212// LINT.ThenChange(//content/browser/renderer_host/cookie_utils.cc:should_report_legacy_tech_report)
Simon Zünd657178e2021-05-27 06:19:55213
Sandor Major7c3e612f2023-12-01 20:48:08214// LINT.IfChange(should_report_legacy_tech_report)
215bool ShouldReportLegacyTechIssueForStatus(
216 const net::CookieInclusionStatus& status) {
217 return status.HasExclusionReason(
218 net::CookieInclusionStatus::
219 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) ||
220 status.HasExclusionReason(
221 net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT) ||
222 status.HasWarningReason(
223 net::CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT);
224}
225// LINT.ThenChange(//content/browser/renderer_host/cookie_utils.cc:should_report_dev_tools)
226
227// Logs cookie issues to DevTools Issues Panel and logs events to UseCounters
Shuran Huang8fa11c72023-12-04 16:53:44228// and UKM for a single cookie-accessed event.
Sandor Major0d7fd6292023-10-26 20:15:44229// TODO(crbug.com/977040): Remove when no longer needed.
230void EmitCookieWarningsAndMetricsOnce(
Alexander Timin1cc31f42020-05-12 16:26:01231 RenderFrameHostImpl* rfh,
232 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
233 RenderFrameHostImpl* root_frame_host = rfh->GetMainFrame();
234
Sreeja Kamishettye49854f82021-06-02 00:52:03235 if (!root_frame_host->IsActive())
Alexander Timin1cc31f42020-05-12 16:26:01236 return;
237
238 bool samesite_treated_as_lax_cookies = false;
239 bool samesite_none_insecure_cookies = false;
Alexander Timin1cc31f42020-05-12 16:26:01240 bool breaking_context_downgrade = false;
Lily Chenc4423c02021-03-11 16:02:02241 bool lax_allow_unsafe_cookies = false;
Alexander Timin1cc31f42020-05-12 16:26:01242
Lily Chen2db3a422021-07-20 18:02:25243 bool samesite_cookie_inclusion_changed_by_cross_site_redirect = false;
244
Dylan Cutler8d5f8912022-03-04 17:39:19245 bool partitioned_cookies_exist = false;
246
Ari Chivukula5f21c112022-04-26 19:23:34247 bool cookie_has_not_been_refreshed_in_201_to_300_days = false;
248 bool cookie_has_not_been_refreshed_in_301_to_350_days = false;
249 bool cookie_has_not_been_refreshed_in_351_to_400_days = false;
250
Johann Hofmanne5764d12022-07-13 23:06:28251 bool cookie_has_domain_non_ascii = false;
252
cfredric76b2d222021-01-27 20:12:04253 for (const network::mojom::CookieOrLineWithAccessResultPtr& cookie :
Alexander Timin1cc31f42020-05-12 16:26:01254 cookie_details->cookie_list) {
Johann Hofmann975c0b42022-08-02 21:05:51255 const net::CookieInclusionStatus& status = cookie->access_result.status;
256 if (ShouldReportDevToolsIssueForStatus(status)) {
Shuran Huang7a6757c22024-04-17 15:17:39257 std::optional<std::string> devtools_issue_id;
258 if (status.HasExclusionReason(
259 net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT) ||
260 status.HasWarningReason(
261 net::CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT)) {
262 devtools_issue_id = base::UnguessableToken::Create().ToString();
263 }
Juba Borgohainc93969e2022-02-25 21:56:12264 devtools_instrumentation::ReportCookieIssue(
Simon Zünd657178e2021-05-27 06:19:55265 root_frame_host, cookie, cookie_details->url,
266 cookie_details->site_for_cookies,
267 cookie_details->type == CookieAccessDetails::Type::kRead
Juba Borgohainc93969e2022-02-25 21:56:12268 ? blink::mojom::CookieOperation::kReadCookie
269 : blink::mojom::CookieOperation::kSetCookie,
Shuran Huang7a6757c22024-04-17 15:17:39270 cookie_details->devtools_request_id, devtools_issue_id);
Shuran Huang8fa11c72023-12-04 16:53:44271 }
272
cfredric76b2d222021-01-27 20:12:04273 if (cookie->access_result.status.ShouldWarn()) {
Lily Chen9de4065b2020-06-24 20:18:47274 samesite_treated_as_lax_cookies =
275 samesite_treated_as_lax_cookies ||
cfredrica5fb0982021-01-09 00:18:01276 status.HasWarningReason(
Jihwan Marc Kim3e132f12020-05-20 17:33:19277 net::CookieInclusionStatus::
Lily Chen9de4065b2020-06-24 20:18:47278 WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT) ||
cfredrica5fb0982021-01-09 00:18:01279 status.HasWarningReason(
Jihwan Marc Kim3e132f12020-05-20 17:33:19280 net::CookieInclusionStatus::
Lily Chen9de4065b2020-06-24 20:18:47281 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
Alexander Timin1cc31f42020-05-12 16:26:01282
Lily Chen9de4065b2020-06-24 20:18:47283 samesite_none_insecure_cookies =
284 samesite_none_insecure_cookies ||
cfredrica5fb0982021-01-09 00:18:01285 status.HasWarningReason(
Lily Chen9de4065b2020-06-24 20:18:47286 net::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
287
Lily Chenc4423c02021-03-11 16:02:02288 lax_allow_unsafe_cookies =
289 lax_allow_unsafe_cookies ||
290 status.HasWarningReason(
291 net::CookieInclusionStatus::
292 WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
293
Lily Chen2db3a422021-07-20 18:02:25294 samesite_cookie_inclusion_changed_by_cross_site_redirect =
295 samesite_cookie_inclusion_changed_by_cross_site_redirect ||
296 status.HasWarningReason(
297 net::CookieInclusionStatus::
298 WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION);
Alexander Timin1cc31f42020-05-12 16:26:01299 }
Alexander Timin1cc31f42020-05-12 16:26:01300
Johann Hofmann975c0b42022-08-02 21:05:51301 cookie_has_domain_non_ascii =
302 cookie_has_domain_non_ascii ||
303 status.HasWarningReason(
304 net::CookieInclusionStatus::WARN_DOMAIN_NON_ASCII) ||
305 status.HasExclusionReason(
306 net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII);
307
Dylan Cutler8d5f8912022-03-04 17:39:19308 partitioned_cookies_exist =
309 partitioned_cookies_exist ||
310 (cookie->cookie_or_line->is_cookie() &&
Dylan Cutler051411b42022-07-12 22:20:07311 cookie->cookie_or_line->get_cookie().IsPartitioned() &&
312 // Ignore nonced partition keys since this metric is meant to track
313 // usage of the Partitioned attribute.
314 !cookie->cookie_or_line->get_cookie().PartitionKey()->nonce());
Dylan Cutler8d5f8912022-03-04 17:39:19315
selya27d093e2023-08-02 22:20:00316
selya778265bc2023-10-23 14:37:55317 if (partitioned_cookies_exist) {
selya7d96d6182024-04-22 11:35:51318 RecordPartitionedCookiesUKMs(rfh, cookie->cookie_or_line->get_cookie());
selya778265bc2023-10-23 14:37:55319 }
320
Ayu Ishii2e3998902020-07-14 18:22:30321 breaking_context_downgrade =
322 breaking_context_downgrade ||
sbingler870b63f2023-04-25 16:47:58323 cookie->access_result.status.HasSchemefulDowngradeWarning();
Alexander Timin1cc31f42020-05-12 16:26:01324
sbingler870b63f2023-04-25 16:47:58325 if (cookie->access_result.status.HasSchemefulDowngradeWarning()) {
326 // Unlike with UMA, do not record cookies that have no schemeful downgrade
327 // warning.
328 RecordSchemefulContextDowngradeUKM(rfh, cookie_details->type,
329 cookie->access_result.status,
330 cookie_details->url);
331 }
332
333 if (status.HasWarningReason(
334 net::CookieInclusionStatus::
335 WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION) &&
336 cookie->cookie_or_line->is_cookie()) {
337 RecordRedirectContextDowngradeUKM(rfh, cookie_details->type,
338 cookie->cookie_or_line->get_cookie(),
339 cookie_details->url);
Alexander Timin1cc31f42020-05-12 16:26:01340 }
Ari Chivukula5f21c112022-04-26 19:23:34341
sbingler8e26e212023-09-27 23:23:27342 if (cookie->cookie_or_line->is_cookie()) {
343 PotentiallyRecordNonAsciiCookieNameValue(
344 rfh, cookie_details->type,
345 cookie->cookie_or_line->get_cookie().Name(),
346 cookie->cookie_or_line->get_cookie().Value());
347 }
348
Ari Chivukula5f21c112022-04-26 19:23:34349 // In order to anticipate the potential effects of the expiry limit in
350 // rfc6265bis, we need to check how long it's been since the cookie was
351 // refreshed (if LastUpdateDate is populated). These three buckets were
352 // picked so we could engage sites with some granularity around urgency.
353 // We ignore the space under 200 days as these cookies are not at risk
354 // of expiring and we ignore the space over 400 days as these cookies
355 // have already expired. Metrics will take 200 days from M103 to populate.
356 base::Time last_update_date =
357 cookie->cookie_or_line->is_cookie()
358 ? cookie->cookie_or_line->get_cookie().LastUpdateDate()
359 : base::Time();
360 if (!last_update_date.is_null()) {
361 int days_since_refresh = (base::Time::Now() - last_update_date).InDays();
362 cookie_has_not_been_refreshed_in_201_to_300_days |=
363 days_since_refresh > 200 && days_since_refresh <= 300;
364 cookie_has_not_been_refreshed_in_301_to_350_days |=
365 days_since_refresh > 300 && days_since_refresh <= 350;
366 cookie_has_not_been_refreshed_in_351_to_400_days |=
367 days_since_refresh > 350 && days_since_refresh <= 400;
368 }
Alexander Timin1cc31f42020-05-12 16:26:01369 }
370
Alexander Timin1cc31f42020-05-12 16:26:01371 if (samesite_treated_as_lax_cookies) {
372 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
373 rfh, blink::mojom::WebFeature::kCookieNoSameSite);
374 }
375
376 if (samesite_none_insecure_cookies) {
377 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
378 rfh, blink::mojom::WebFeature::kCookieInsecureAndSameSiteNone);
379 }
380
381 if (breaking_context_downgrade) {
382 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
383 rfh, blink::mojom::WebFeature::kSchemefulSameSiteContextDowngrade);
384 }
cfredrica5fb0982021-01-09 00:18:01385
Lily Chenc4423c02021-03-11 16:02:02386 if (lax_allow_unsafe_cookies) {
387 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
388 rfh, blink::mojom::WebFeature::kLaxAllowingUnsafeCookies);
389 }
390
Lily Chen2db3a422021-07-20 18:02:25391 if (samesite_cookie_inclusion_changed_by_cross_site_redirect) {
392 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
393 rfh, blink::mojom::WebFeature::
394 kSameSiteCookieInclusionChangedByCrossSiteRedirect);
395 }
Dylan Cutler8d5f8912022-03-04 17:39:19396
397 if (partitioned_cookies_exist) {
398 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
399 rfh, blink::mojom::WebFeature::kPartitionedCookies);
400 }
Ari Chivukula5f21c112022-04-26 19:23:34401
402 if (cookie_has_not_been_refreshed_in_201_to_300_days) {
403 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
404 rfh,
405 blink::mojom::WebFeature::kCookieHasNotBeenRefreshedIn201To300Days);
406 }
407
408 if (cookie_has_not_been_refreshed_in_301_to_350_days) {
409 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
410 rfh,
411 blink::mojom::WebFeature::kCookieHasNotBeenRefreshedIn301To350Days);
412 }
413
414 if (cookie_has_not_been_refreshed_in_351_to_400_days) {
415 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
416 rfh,
417 blink::mojom::WebFeature::kCookieHasNotBeenRefreshedIn351To400Days);
418 }
Johann Hofmanne5764d12022-07-13 23:06:28419
420 if (cookie_has_domain_non_ascii) {
421 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
422 rfh, blink::mojom::WebFeature::kCookieDomainNonASCII);
423 }
Alexander Timin1cc31f42020-05-12 16:26:01424}
425
Sandor Major7c3e612f2023-12-01 20:48:08426// Logs cookie issues to Legacy Technology Report.
427void ReportLegacyTechEvent(
428 RenderFrameHostImpl* render_frame_host,
429 NavigationRequest* navigation_request,
430 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
Sandor Major7c3e612f2023-12-01 20:48:08431 CHECK(render_frame_host);
432
433 for (const network::mojom::CookieOrLineWithAccessResultPtr& cookie :
434 cookie_details->cookie_list) {
435 const net::CookieInclusionStatus& status = cookie->access_result.status;
436 if (ShouldReportLegacyTechIssueForStatus(status) &&
437 cookie->cookie_or_line->is_cookie()) {
438 std::string type;
439 if (status.HasExclusionReason(
440 net::CookieInclusionStatus::
441 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET) ||
442 status.HasExclusionReason(
443 net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT)) {
444 type = "ThirdPartyCookieAccessError";
445 } else if (status.HasWarningReason(
446 net::CookieInclusionStatus::WARN_THIRD_PARTY_PHASEOUT)) {
447 type = "ThirdPartyCookieAccessWarning";
448 } else {
449 DLOG(ERROR) << "Unexpected call of ReportLegacyTechEvent.";
450 }
451
452 GURL url = render_frame_host->GetOutermostMainFrameOrEmbedder()
453 ->GetLastCommittedURL();
454 GURL frame_url = render_frame_host->GetLastCommittedURL();
455 if (navigation_request != nullptr) {
456 if (!navigation_request->frame_tree_node()
457 ->GetParentOrOuterDocumentOrEmbedder()) {
458 url = navigation_request->GetURL();
459 frame_url = navigation_request->GetURL();
460 } else {
461 frame_url = navigation_request->GetURL();
462 }
463 }
464
465 LegacyTechCookieIssueDetails cookie_issue_details = {
466 cookie_details->url.spec(),
467 cookie->cookie_or_line->get_cookie().Name(),
468 cookie->cookie_or_line->get_cookie().Domain(),
469 cookie->cookie_or_line->get_cookie().Path(),
470 cookie_details->type == CookieAccessDetails::Type::kChange
471 ? LegacyTechCookieIssueDetails::AccessOperation::kWrite
472 : LegacyTechCookieIssueDetails::AccessOperation::kRead};
473
474 GetContentClient()->browser()->ReportLegacyTechEvent(
475 render_frame_host, type, url, frame_url, /*filename=*/"", /*line=*/0,
476 /*column=*/0, cookie_issue_details);
477 }
478 }
479}
480
Sandor Major0d7fd6292023-10-26 20:15:44481} // namespace
482
483void SplitCookiesIntoAllowedAndBlocked(
484 const network::mojom::CookieAccessDetailsPtr& cookie_details,
485 CookieAccessDetails* allowed,
486 CookieAccessDetails* blocked) {
Victor Tane1f2bc62023-11-15 00:12:20487 // For some cases `site_for_cookies` representative url is empty when
488 // OnCookieAccess is triggered for a third party. For example iframe third
489 // party accesses cookies when TPCD Metadata allows third party cookie access.
490 //
491 // Make `first_party_url` considering both `top_frame_origin` and
492 // `site_for_cookies` which is similar with GetFirstPartyURL() in
493 // components/content_settings/core/common/cookie_settings_base.h.
494 // If the `top_frame_origin` is non-opaque, it is chosen; otherwise, the
495 // `site_for_cookies` representative url is used.
496 const GURL first_party_url =
497 cookie_details->top_frame_origin.opaque()
498 ? cookie_details->site_for_cookies.RepresentativeUrl()
499 : cookie_details->top_frame_origin.GetURL();
500
501 *allowed = CookieAccessDetails({cookie_details->type,
502 cookie_details->url,
503 first_party_url,
504 {},
505 cookie_details->count,
506 /* blocked_by_policy=*/false,
Victor Tanf288abf2023-11-15 05:33:54507 cookie_details->is_ad_tagged,
Dylan Cutler6aea5922024-04-19 18:23:47508 cookie_details->cookie_setting_overrides,
509 cookie_details->site_for_cookies});
Sandor Major0d7fd6292023-10-26 20:15:44510 int allowed_count = base::ranges::count_if(
511 cookie_details->cookie_list,
512 [](const network::mojom::CookieOrLineWithAccessResultPtr&
513 cookie_and_access_result) {
514 // "Included" cookies have no exclusion reasons so we don't also have to
515 // check for !(net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES).
516 return cookie_and_access_result->access_result.status.IsInclude();
517 });
518 allowed->cookie_list.reserve(allowed_count);
519
Victor Tane1f2bc62023-11-15 00:12:20520 *blocked = CookieAccessDetails({cookie_details->type,
521 cookie_details->url,
522 first_party_url,
523 {},
524 cookie_details->count,
525 /* blocked_by_policy=*/true,
Victor Tanf288abf2023-11-15 05:33:54526 cookie_details->is_ad_tagged,
Dylan Cutler6aea5922024-04-19 18:23:47527 cookie_details->cookie_setting_overrides,
528 cookie_details->site_for_cookies});
Sandor Major0d7fd6292023-10-26 20:15:44529 int blocked_count = base::ranges::count_if(
530 cookie_details->cookie_list,
531 [](const network::mojom::CookieOrLineWithAccessResultPtr&
532 cookie_and_access_result) {
533 return cookie_and_access_result->access_result.status
Shuran Huang23593882024-04-11 14:19:32534 .ExcludedByUserPreferencesOrTPCD();
Sandor Major0d7fd6292023-10-26 20:15:44535 });
536 blocked->cookie_list.reserve(blocked_count);
537
538 for (const auto& cookie_and_access_result : cookie_details->cookie_list) {
539 if (cookie_and_access_result->access_result.status
Shuran Huang23593882024-04-11 14:19:32540 .ExcludedByUserPreferencesOrTPCD()) {
Sandor Major0d7fd6292023-10-26 20:15:44541 blocked->cookie_list.emplace_back(
542 std::move(cookie_and_access_result->cookie_or_line->get_cookie()));
543 } else if (cookie_and_access_result->access_result.status.IsInclude()) {
544 allowed->cookie_list.emplace_back(
545 std::move(cookie_and_access_result->cookie_or_line->get_cookie()));
546 }
547 }
548}
549
550void EmitCookieWarningsAndMetrics(
551 RenderFrameHostImpl* rfh,
Sandor Major7c3e612f2023-12-01 20:48:08552 NavigationRequest* navigation_request,
Sandor Major0d7fd6292023-10-26 20:15:44553 const network::mojom::CookieAccessDetailsPtr& cookie_details) {
Sandor Major7c3e612f2023-12-01 20:48:08554 ReportLegacyTechEvent(rfh, navigation_request, cookie_details);
Sandor Major0d7fd6292023-10-26 20:15:44555 for (size_t i = 0; i < cookie_details->count; ++i) {
556 EmitCookieWarningsAndMetricsOnce(rfh, cookie_details);
557 }
558}
559
Alexander Timin1cc31f42020-05-12 16:26:01560} // namespace content