1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_util.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <cstdio>
8*6777b538SAndroid Build Coastguard Worker #include <cstdlib>
9*6777b538SAndroid Build Coastguard Worker #include <string>
10*6777b538SAndroid Build Coastguard Worker #include <string_view>
11*6777b538SAndroid Build Coastguard Worker #include <utility>
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_tokenizer.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/types/optional_util.h"
24*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
25*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/base/isolation_info.h"
27*6777b538SAndroid Build Coastguard Worker #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
28*6777b538SAndroid Build Coastguard Worker #include "net/base/url_util.h"
29*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_access_delegate.h"
30*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_constants.h"
31*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_inclusion_status.h"
32*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_monster.h"
33*6777b538SAndroid Build Coastguard Worker #include "net/cookies/cookie_options.h"
34*6777b538SAndroid Build Coastguard Worker #include "net/first_party_sets/first_party_set_metadata.h"
35*6777b538SAndroid Build Coastguard Worker #include "net/first_party_sets/first_party_sets_cache_filter.h"
36*6777b538SAndroid Build Coastguard Worker #include "net/http/http_util.h"
37*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
38*6777b538SAndroid Build Coastguard Worker #include "url/url_constants.h"
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker namespace net::cookie_util {
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker namespace {
43*6777b538SAndroid Build Coastguard Worker
44*6777b538SAndroid Build Coastguard Worker using ContextType = CookieOptions::SameSiteCookieContext::ContextType;
45*6777b538SAndroid Build Coastguard Worker using ContextMetadata = CookieOptions::SameSiteCookieContext::ContextMetadata;
46*6777b538SAndroid Build Coastguard Worker
MinNonNullTime()47*6777b538SAndroid Build Coastguard Worker base::Time MinNonNullTime() {
48*6777b538SAndroid Build Coastguard Worker return base::Time::FromInternalValue(1);
49*6777b538SAndroid Build Coastguard Worker }
50*6777b538SAndroid Build Coastguard Worker
51*6777b538SAndroid Build Coastguard Worker // Tries to assemble a base::Time given a base::Time::Exploded representing a
52*6777b538SAndroid Build Coastguard Worker // UTC calendar date.
53*6777b538SAndroid Build Coastguard Worker //
54*6777b538SAndroid Build Coastguard Worker // If the date falls outside of the range supported internally by
55*6777b538SAndroid Build Coastguard Worker // FromUTCExploded() on the current platform, then the result is:
56*6777b538SAndroid Build Coastguard Worker //
57*6777b538SAndroid Build Coastguard Worker // * Time(1) if it's below the range FromUTCExploded() supports.
58*6777b538SAndroid Build Coastguard Worker // * Time::Max() if it's above the range FromUTCExploded() supports.
SaturatedTimeFromUTCExploded(const base::Time::Exploded & exploded,base::Time * out)59*6777b538SAndroid Build Coastguard Worker bool SaturatedTimeFromUTCExploded(const base::Time::Exploded& exploded,
60*6777b538SAndroid Build Coastguard Worker base::Time* out) {
61*6777b538SAndroid Build Coastguard Worker // Try to calculate the base::Time in the normal fashion.
62*6777b538SAndroid Build Coastguard Worker if (base::Time::FromUTCExploded(exploded, out)) {
63*6777b538SAndroid Build Coastguard Worker // Don't return Time(0) on success.
64*6777b538SAndroid Build Coastguard Worker if (out->is_null())
65*6777b538SAndroid Build Coastguard Worker *out = MinNonNullTime();
66*6777b538SAndroid Build Coastguard Worker return true;
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker // base::Time::FromUTCExploded() has platform-specific limits:
70*6777b538SAndroid Build Coastguard Worker //
71*6777b538SAndroid Build Coastguard Worker // * Windows: Years 1601 - 30827
72*6777b538SAndroid Build Coastguard Worker // * 32-bit POSIX: Years 1970 - 2038
73*6777b538SAndroid Build Coastguard Worker //
74*6777b538SAndroid Build Coastguard Worker // Work around this by returning min/max valid times for times outside those
75*6777b538SAndroid Build Coastguard Worker // ranges when imploding the time is doomed to fail.
76*6777b538SAndroid Build Coastguard Worker //
77*6777b538SAndroid Build Coastguard Worker // Note that the following implementation is NOT perfect. It will accept
78*6777b538SAndroid Build Coastguard Worker // some invalid calendar dates in the out-of-range case.
79*6777b538SAndroid Build Coastguard Worker if (!exploded.HasValidValues())
80*6777b538SAndroid Build Coastguard Worker return false;
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker if (exploded.year > base::Time::kExplodedMaxYear) {
83*6777b538SAndroid Build Coastguard Worker *out = base::Time::Max();
84*6777b538SAndroid Build Coastguard Worker return true;
85*6777b538SAndroid Build Coastguard Worker }
86*6777b538SAndroid Build Coastguard Worker if (exploded.year < base::Time::kExplodedMinYear) {
87*6777b538SAndroid Build Coastguard Worker *out = MinNonNullTime();
88*6777b538SAndroid Build Coastguard Worker return true;
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker
91*6777b538SAndroid Build Coastguard Worker return false;
92*6777b538SAndroid Build Coastguard Worker }
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker struct ComputeSameSiteContextResult {
95*6777b538SAndroid Build Coastguard Worker ContextType context_type = ContextType::CROSS_SITE;
96*6777b538SAndroid Build Coastguard Worker ContextMetadata metadata;
97*6777b538SAndroid Build Coastguard Worker };
98*6777b538SAndroid Build Coastguard Worker
MakeSameSiteCookieContext(const ComputeSameSiteContextResult & result,const ComputeSameSiteContextResult & schemeful_result)99*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext MakeSameSiteCookieContext(
100*6777b538SAndroid Build Coastguard Worker const ComputeSameSiteContextResult& result,
101*6777b538SAndroid Build Coastguard Worker const ComputeSameSiteContextResult& schemeful_result) {
102*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext(
103*6777b538SAndroid Build Coastguard Worker result.context_type, schemeful_result.context_type, result.metadata,
104*6777b538SAndroid Build Coastguard Worker schemeful_result.metadata);
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker
107*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextRedirectTypeBug1221316
ComputeContextRedirectTypeBug1221316(bool url_chain_is_length_one,bool same_site_initiator,bool site_for_cookies_is_same_site,bool same_site_redirect_chain)108*6777b538SAndroid Build Coastguard Worker ComputeContextRedirectTypeBug1221316(bool url_chain_is_length_one,
109*6777b538SAndroid Build Coastguard Worker bool same_site_initiator,
110*6777b538SAndroid Build Coastguard Worker bool site_for_cookies_is_same_site,
111*6777b538SAndroid Build Coastguard Worker bool same_site_redirect_chain) {
112*6777b538SAndroid Build Coastguard Worker if (url_chain_is_length_one)
113*6777b538SAndroid Build Coastguard Worker return ContextMetadata::ContextRedirectTypeBug1221316::kNoRedirect;
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker if (!same_site_initiator || !site_for_cookies_is_same_site)
116*6777b538SAndroid Build Coastguard Worker return ContextMetadata::ContextRedirectTypeBug1221316::kCrossSiteRedirect;
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker if (!same_site_redirect_chain) {
119*6777b538SAndroid Build Coastguard Worker return ContextMetadata::ContextRedirectTypeBug1221316::
120*6777b538SAndroid Build Coastguard Worker kPartialSameSiteRedirect;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker return ContextMetadata::ContextRedirectTypeBug1221316::kAllSameSiteRedirect;
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker // This function consolidates the common logic for computing SameSite cookie
127*6777b538SAndroid Build Coastguard Worker // access context in various situations (HTTP vs JS; get vs set).
128*6777b538SAndroid Build Coastguard Worker //
129*6777b538SAndroid Build Coastguard Worker // `is_http` is whether the current cookie access request is associated with a
130*6777b538SAndroid Build Coastguard Worker // network request (as opposed to a non-HTTP API, i.e., JavaScript).
131*6777b538SAndroid Build Coastguard Worker //
132*6777b538SAndroid Build Coastguard Worker // `compute_schemefully` is whether the current computation is for a
133*6777b538SAndroid Build Coastguard Worker // schemeful_context, i.e. whether scheme should be considered when comparing
134*6777b538SAndroid Build Coastguard Worker // two sites.
135*6777b538SAndroid Build Coastguard Worker //
136*6777b538SAndroid Build Coastguard Worker // See documentation of `ComputeSameSiteContextForRequest` for explanations of
137*6777b538SAndroid Build Coastguard Worker // other parameters.
ComputeSameSiteContext(const std::vector<GURL> & url_chain,const SiteForCookies & site_for_cookies,const std::optional<url::Origin> & initiator,bool is_http,bool is_main_frame_navigation,bool compute_schemefully)138*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult ComputeSameSiteContext(
139*6777b538SAndroid Build Coastguard Worker const std::vector<GURL>& url_chain,
140*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
141*6777b538SAndroid Build Coastguard Worker const std::optional<url::Origin>& initiator,
142*6777b538SAndroid Build Coastguard Worker bool is_http,
143*6777b538SAndroid Build Coastguard Worker bool is_main_frame_navigation,
144*6777b538SAndroid Build Coastguard Worker bool compute_schemefully) {
145*6777b538SAndroid Build Coastguard Worker DCHECK(!url_chain.empty());
146*6777b538SAndroid Build Coastguard Worker const GURL& request_url = url_chain.back();
147*6777b538SAndroid Build Coastguard Worker const auto is_same_site_with_site_for_cookies =
148*6777b538SAndroid Build Coastguard Worker [&site_for_cookies, compute_schemefully](const GURL& url) {
149*6777b538SAndroid Build Coastguard Worker return site_for_cookies.IsFirstPartyWithSchemefulMode(
150*6777b538SAndroid Build Coastguard Worker url, compute_schemefully);
151*6777b538SAndroid Build Coastguard Worker };
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker bool site_for_cookies_is_same_site =
154*6777b538SAndroid Build Coastguard Worker is_same_site_with_site_for_cookies(request_url);
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Worker // If the request is a main frame navigation, site_for_cookies must either be
157*6777b538SAndroid Build Coastguard Worker // null (for opaque origins, e.g., data: origins) or same-site with the
158*6777b538SAndroid Build Coastguard Worker // request URL (both schemefully and schemelessly), and the URL cannot be
159*6777b538SAndroid Build Coastguard Worker // ws/wss (these schemes are not navigable).
160*6777b538SAndroid Build Coastguard Worker DCHECK(!is_main_frame_navigation || site_for_cookies_is_same_site ||
161*6777b538SAndroid Build Coastguard Worker site_for_cookies.IsNull());
162*6777b538SAndroid Build Coastguard Worker DCHECK(!is_main_frame_navigation || !request_url.SchemeIsWSOrWSS());
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker // Defaults to a cross-site context type.
165*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult result;
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker // Create a SiteForCookies object from the initiator so that we can reuse
168*6777b538SAndroid Build Coastguard Worker // IsFirstPartyWithSchemefulMode().
169*6777b538SAndroid Build Coastguard Worker bool same_site_initiator =
170*6777b538SAndroid Build Coastguard Worker !initiator ||
171*6777b538SAndroid Build Coastguard Worker SiteForCookies::FromOrigin(initiator.value())
172*6777b538SAndroid Build Coastguard Worker .IsFirstPartyWithSchemefulMode(request_url, compute_schemefully);
173*6777b538SAndroid Build Coastguard Worker
174*6777b538SAndroid Build Coastguard Worker // Check that the URLs in the redirect chain are all same-site with the
175*6777b538SAndroid Build Coastguard Worker // site_for_cookies and hence (by transitivity) same-site with the request
176*6777b538SAndroid Build Coastguard Worker // URL. (If the URL chain only has one member, it's the request_url and we've
177*6777b538SAndroid Build Coastguard Worker // already checked it previously.)
178*6777b538SAndroid Build Coastguard Worker bool same_site_redirect_chain =
179*6777b538SAndroid Build Coastguard Worker url_chain.size() == 1u ||
180*6777b538SAndroid Build Coastguard Worker base::ranges::all_of(url_chain, is_same_site_with_site_for_cookies);
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker // Record what type of redirect was experienced.
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker result.metadata.redirect_type_bug_1221316 =
185*6777b538SAndroid Build Coastguard Worker ComputeContextRedirectTypeBug1221316(
186*6777b538SAndroid Build Coastguard Worker url_chain.size() == 1u, same_site_initiator,
187*6777b538SAndroid Build Coastguard Worker site_for_cookies_is_same_site, same_site_redirect_chain);
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker if (!site_for_cookies_is_same_site)
190*6777b538SAndroid Build Coastguard Worker return result;
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker // Whether the context would be SAME_SITE_STRICT if not considering redirect
193*6777b538SAndroid Build Coastguard Worker // chains, but is different after considering redirect chains.
194*6777b538SAndroid Build Coastguard Worker bool cross_site_redirect_downgraded_from_strict = false;
195*6777b538SAndroid Build Coastguard Worker // Allows the kCookieSameSiteConsidersRedirectChain feature to override the
196*6777b538SAndroid Build Coastguard Worker // result and use SAME_SITE_STRICT.
197*6777b538SAndroid Build Coastguard Worker bool use_strict = false;
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker if (same_site_initiator) {
200*6777b538SAndroid Build Coastguard Worker if (same_site_redirect_chain) {
201*6777b538SAndroid Build Coastguard Worker result.context_type = ContextType::SAME_SITE_STRICT;
202*6777b538SAndroid Build Coastguard Worker return result;
203*6777b538SAndroid Build Coastguard Worker }
204*6777b538SAndroid Build Coastguard Worker cross_site_redirect_downgraded_from_strict = true;
205*6777b538SAndroid Build Coastguard Worker // If we are not supposed to consider redirect chains, record that the
206*6777b538SAndroid Build Coastguard Worker // context result should ultimately be strictly same-site. We cannot
207*6777b538SAndroid Build Coastguard Worker // just return early from here because we don't yet know what the context
208*6777b538SAndroid Build Coastguard Worker // gets downgraded to, so we can't return with the correct metadata until we
209*6777b538SAndroid Build Coastguard Worker // go through the rest of the logic below to determine that.
210*6777b538SAndroid Build Coastguard Worker use_strict = !base::FeatureList::IsEnabled(
211*6777b538SAndroid Build Coastguard Worker features::kCookieSameSiteConsidersRedirectChain);
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker
214*6777b538SAndroid Build Coastguard Worker if (!is_http || is_main_frame_navigation) {
215*6777b538SAndroid Build Coastguard Worker if (cross_site_redirect_downgraded_from_strict) {
216*6777b538SAndroid Build Coastguard Worker result.metadata.cross_site_redirect_downgrade =
217*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextDowngradeType::kStrictToLax;
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker result.context_type =
220*6777b538SAndroid Build Coastguard Worker use_strict ? ContextType::SAME_SITE_STRICT : ContextType::SAME_SITE_LAX;
221*6777b538SAndroid Build Coastguard Worker return result;
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker if (cross_site_redirect_downgraded_from_strict) {
225*6777b538SAndroid Build Coastguard Worker result.metadata.cross_site_redirect_downgrade =
226*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextDowngradeType::kStrictToCross;
227*6777b538SAndroid Build Coastguard Worker }
228*6777b538SAndroid Build Coastguard Worker result.context_type =
229*6777b538SAndroid Build Coastguard Worker use_strict ? ContextType::SAME_SITE_STRICT : ContextType::CROSS_SITE;
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker return result;
232*6777b538SAndroid Build Coastguard Worker }
233*6777b538SAndroid Build Coastguard Worker
234*6777b538SAndroid Build Coastguard Worker // Setting any SameSite={Strict,Lax} cookie only requires a LAX context, so
235*6777b538SAndroid Build Coastguard Worker // normalize any strictly same-site contexts to Lax for cookie writes.
NormalizeStrictToLaxForSet(ComputeSameSiteContextResult & result)236*6777b538SAndroid Build Coastguard Worker void NormalizeStrictToLaxForSet(ComputeSameSiteContextResult& result) {
237*6777b538SAndroid Build Coastguard Worker if (result.context_type == ContextType::SAME_SITE_STRICT)
238*6777b538SAndroid Build Coastguard Worker result.context_type = ContextType::SAME_SITE_LAX;
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker switch (result.metadata.cross_site_redirect_downgrade) {
241*6777b538SAndroid Build Coastguard Worker case ContextMetadata::ContextDowngradeType::kStrictToLax:
242*6777b538SAndroid Build Coastguard Worker result.metadata.cross_site_redirect_downgrade =
243*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextDowngradeType::kNoDowngrade;
244*6777b538SAndroid Build Coastguard Worker break;
245*6777b538SAndroid Build Coastguard Worker case ContextMetadata::ContextDowngradeType::kStrictToCross:
246*6777b538SAndroid Build Coastguard Worker result.metadata.cross_site_redirect_downgrade =
247*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextDowngradeType::kLaxToCross;
248*6777b538SAndroid Build Coastguard Worker break;
249*6777b538SAndroid Build Coastguard Worker default:
250*6777b538SAndroid Build Coastguard Worker break;
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker
ComputeSameSiteContextForSet(const std::vector<GURL> & url_chain,const SiteForCookies & site_for_cookies,const std::optional<url::Origin> & initiator,bool is_http,bool is_main_frame_navigation)254*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext ComputeSameSiteContextForSet(
255*6777b538SAndroid Build Coastguard Worker const std::vector<GURL>& url_chain,
256*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
257*6777b538SAndroid Build Coastguard Worker const std::optional<url::Origin>& initiator,
258*6777b538SAndroid Build Coastguard Worker bool is_http,
259*6777b538SAndroid Build Coastguard Worker bool is_main_frame_navigation) {
260*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext same_site_context;
261*6777b538SAndroid Build Coastguard Worker
262*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult result = ComputeSameSiteContext(
263*6777b538SAndroid Build Coastguard Worker url_chain, site_for_cookies, initiator, is_http, is_main_frame_navigation,
264*6777b538SAndroid Build Coastguard Worker false /* compute_schemefully */);
265*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult schemeful_result = ComputeSameSiteContext(
266*6777b538SAndroid Build Coastguard Worker url_chain, site_for_cookies, initiator, is_http, is_main_frame_navigation,
267*6777b538SAndroid Build Coastguard Worker true /* compute_schemefully */);
268*6777b538SAndroid Build Coastguard Worker
269*6777b538SAndroid Build Coastguard Worker NormalizeStrictToLaxForSet(result);
270*6777b538SAndroid Build Coastguard Worker NormalizeStrictToLaxForSet(schemeful_result);
271*6777b538SAndroid Build Coastguard Worker
272*6777b538SAndroid Build Coastguard Worker return MakeSameSiteCookieContext(result, schemeful_result);
273*6777b538SAndroid Build Coastguard Worker }
274*6777b538SAndroid Build Coastguard Worker
CookieWithAccessResultSorter(const CookieWithAccessResult & a,const CookieWithAccessResult & b)275*6777b538SAndroid Build Coastguard Worker bool CookieWithAccessResultSorter(const CookieWithAccessResult& a,
276*6777b538SAndroid Build Coastguard Worker const CookieWithAccessResult& b) {
277*6777b538SAndroid Build Coastguard Worker return CookieMonster::CookieSorter(&a.cookie, &b.cookie);
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker
280*6777b538SAndroid Build Coastguard Worker } // namespace
281*6777b538SAndroid Build Coastguard Worker
FireStorageAccessHistogram(StorageAccessResult result)282*6777b538SAndroid Build Coastguard Worker void FireStorageAccessHistogram(StorageAccessResult result) {
283*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("API.StorageAccess.AllowedRequests2", result);
284*6777b538SAndroid Build Coastguard Worker }
285*6777b538SAndroid Build Coastguard Worker
DomainIsHostOnly(const std::string & domain_string)286*6777b538SAndroid Build Coastguard Worker bool DomainIsHostOnly(const std::string& domain_string) {
287*6777b538SAndroid Build Coastguard Worker return (domain_string.empty() || domain_string[0] != '.');
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker
CookieDomainAsHost(const std::string & cookie_domain)290*6777b538SAndroid Build Coastguard Worker std::string CookieDomainAsHost(const std::string& cookie_domain) {
291*6777b538SAndroid Build Coastguard Worker if (DomainIsHostOnly(cookie_domain))
292*6777b538SAndroid Build Coastguard Worker return cookie_domain;
293*6777b538SAndroid Build Coastguard Worker return cookie_domain.substr(1);
294*6777b538SAndroid Build Coastguard Worker }
295*6777b538SAndroid Build Coastguard Worker
GetEffectiveDomain(const std::string & scheme,const std::string & host)296*6777b538SAndroid Build Coastguard Worker std::string GetEffectiveDomain(const std::string& scheme,
297*6777b538SAndroid Build Coastguard Worker const std::string& host) {
298*6777b538SAndroid Build Coastguard Worker if (scheme == "http" || scheme == "https" || scheme == "ws" ||
299*6777b538SAndroid Build Coastguard Worker scheme == "wss") {
300*6777b538SAndroid Build Coastguard Worker return registry_controlled_domains::GetDomainAndRegistry(
301*6777b538SAndroid Build Coastguard Worker host,
302*6777b538SAndroid Build Coastguard Worker registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
303*6777b538SAndroid Build Coastguard Worker }
304*6777b538SAndroid Build Coastguard Worker
305*6777b538SAndroid Build Coastguard Worker return CookieDomainAsHost(host);
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker
GetCookieDomainWithString(const GURL & url,const std::string & domain_string,CookieInclusionStatus & status,std::string * result)308*6777b538SAndroid Build Coastguard Worker bool GetCookieDomainWithString(const GURL& url,
309*6777b538SAndroid Build Coastguard Worker const std::string& domain_string,
310*6777b538SAndroid Build Coastguard Worker CookieInclusionStatus& status,
311*6777b538SAndroid Build Coastguard Worker std::string* result) {
312*6777b538SAndroid Build Coastguard Worker // Disallow non-ASCII domain names.
313*6777b538SAndroid Build Coastguard Worker if (!base::IsStringASCII(domain_string)) {
314*6777b538SAndroid Build Coastguard Worker if (base::FeatureList::IsEnabled(features::kCookieDomainRejectNonASCII)) {
315*6777b538SAndroid Build Coastguard Worker status.AddExclusionReason(
316*6777b538SAndroid Build Coastguard Worker CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII);
317*6777b538SAndroid Build Coastguard Worker return false;
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker status.AddWarningReason(CookieInclusionStatus::WARN_DOMAIN_NON_ASCII);
320*6777b538SAndroid Build Coastguard Worker }
321*6777b538SAndroid Build Coastguard Worker
322*6777b538SAndroid Build Coastguard Worker const std::string url_host(url.host());
323*6777b538SAndroid Build Coastguard Worker
324*6777b538SAndroid Build Coastguard Worker // Disallow invalid hostnames containing multiple `.` at the end.
325*6777b538SAndroid Build Coastguard Worker // Httpbis-rfc6265bis draft-11, §5.1.2 says to convert the request host "into
326*6777b538SAndroid Build Coastguard Worker // a sequence of individual domain name labels"; a label can only be empty if
327*6777b538SAndroid Build Coastguard Worker // it is the last label in the name, but a name ending in `..` would have an
328*6777b538SAndroid Build Coastguard Worker // empty label in the penultimate position and is thus invalid.
329*6777b538SAndroid Build Coastguard Worker if (url_host.ends_with("..")) {
330*6777b538SAndroid Build Coastguard Worker return false;
331*6777b538SAndroid Build Coastguard Worker }
332*6777b538SAndroid Build Coastguard Worker // If no domain was specified in the domain string, default to a host cookie.
333*6777b538SAndroid Build Coastguard Worker // We match IE/Firefox in allowing a domain=IPADDR if it matches (case
334*6777b538SAndroid Build Coastguard Worker // in-sensitive) the url ip address hostname and ignoring a leading dot if one
335*6777b538SAndroid Build Coastguard Worker // exists. It should be treated as a host cookie.
336*6777b538SAndroid Build Coastguard Worker if (domain_string.empty() ||
337*6777b538SAndroid Build Coastguard Worker (url.HostIsIPAddress() &&
338*6777b538SAndroid Build Coastguard Worker (base::EqualsCaseInsensitiveASCII(url_host, domain_string) ||
339*6777b538SAndroid Build Coastguard Worker base::EqualsCaseInsensitiveASCII("." + url_host, domain_string)))) {
340*6777b538SAndroid Build Coastguard Worker *result = url_host;
341*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1453416): Once empty label support is implemented we can
342*6777b538SAndroid Build Coastguard Worker // CHECK our assumptions here. For now, we DCHECK as DUMP_WILL_BE_CHECK is
343*6777b538SAndroid Build Coastguard Worker // generating too many crash reports and already know why this is failing.
344*6777b538SAndroid Build Coastguard Worker DCHECK(DomainIsHostOnly(*result));
345*6777b538SAndroid Build Coastguard Worker return true;
346*6777b538SAndroid Build Coastguard Worker }
347*6777b538SAndroid Build Coastguard Worker
348*6777b538SAndroid Build Coastguard Worker // Disallow domain names with %-escaped characters.
349*6777b538SAndroid Build Coastguard Worker for (char c : domain_string) {
350*6777b538SAndroid Build Coastguard Worker if (c == '%')
351*6777b538SAndroid Build Coastguard Worker return false;
352*6777b538SAndroid Build Coastguard Worker }
353*6777b538SAndroid Build Coastguard Worker
354*6777b538SAndroid Build Coastguard Worker url::CanonHostInfo ignored;
355*6777b538SAndroid Build Coastguard Worker std::string cookie_domain(CanonicalizeHost(domain_string, &ignored));
356*6777b538SAndroid Build Coastguard Worker // Get the normalized domain specified in cookie line.
357*6777b538SAndroid Build Coastguard Worker if (cookie_domain.empty())
358*6777b538SAndroid Build Coastguard Worker return false;
359*6777b538SAndroid Build Coastguard Worker if (cookie_domain[0] != '.')
360*6777b538SAndroid Build Coastguard Worker cookie_domain = "." + cookie_domain;
361*6777b538SAndroid Build Coastguard Worker
362*6777b538SAndroid Build Coastguard Worker // Ensure |url| and |cookie_domain| have the same domain+registry.
363*6777b538SAndroid Build Coastguard Worker const std::string url_scheme(url.scheme());
364*6777b538SAndroid Build Coastguard Worker const std::string url_domain_and_registry(
365*6777b538SAndroid Build Coastguard Worker GetEffectiveDomain(url_scheme, url_host));
366*6777b538SAndroid Build Coastguard Worker if (url_domain_and_registry.empty()) {
367*6777b538SAndroid Build Coastguard Worker // We match IE/Firefox by treating an exact match between the normalized
368*6777b538SAndroid Build Coastguard Worker // domain attribute and the request host to be treated as a host cookie.
369*6777b538SAndroid Build Coastguard Worker std::string normalized_domain_string = base::ToLowerASCII(
370*6777b538SAndroid Build Coastguard Worker domain_string[0] == '.' ? domain_string.substr(1) : domain_string);
371*6777b538SAndroid Build Coastguard Worker
372*6777b538SAndroid Build Coastguard Worker if (url_host == normalized_domain_string) {
373*6777b538SAndroid Build Coastguard Worker *result = url_host;
374*6777b538SAndroid Build Coastguard Worker DCHECK(DomainIsHostOnly(*result));
375*6777b538SAndroid Build Coastguard Worker return true;
376*6777b538SAndroid Build Coastguard Worker }
377*6777b538SAndroid Build Coastguard Worker
378*6777b538SAndroid Build Coastguard Worker // Otherwise, IP addresses/intranet hosts/public suffixes can't set
379*6777b538SAndroid Build Coastguard Worker // domain cookies.
380*6777b538SAndroid Build Coastguard Worker return false;
381*6777b538SAndroid Build Coastguard Worker }
382*6777b538SAndroid Build Coastguard Worker const std::string cookie_domain_and_registry(
383*6777b538SAndroid Build Coastguard Worker GetEffectiveDomain(url_scheme, cookie_domain));
384*6777b538SAndroid Build Coastguard Worker if (url_domain_and_registry != cookie_domain_and_registry)
385*6777b538SAndroid Build Coastguard Worker return false; // Can't set a cookie on a different domain + registry.
386*6777b538SAndroid Build Coastguard Worker
387*6777b538SAndroid Build Coastguard Worker // Ensure |url_host| is |cookie_domain| or one of its subdomains. Given that
388*6777b538SAndroid Build Coastguard Worker // we know the domain+registry are the same from the above checks, this is
389*6777b538SAndroid Build Coastguard Worker // basically a simple string suffix check.
390*6777b538SAndroid Build Coastguard Worker const bool is_suffix = (url_host.length() < cookie_domain.length()) ?
391*6777b538SAndroid Build Coastguard Worker (cookie_domain != ("." + url_host)) :
392*6777b538SAndroid Build Coastguard Worker (url_host.compare(url_host.length() - cookie_domain.length(),
393*6777b538SAndroid Build Coastguard Worker cookie_domain.length(), cookie_domain) != 0);
394*6777b538SAndroid Build Coastguard Worker if (is_suffix)
395*6777b538SAndroid Build Coastguard Worker return false;
396*6777b538SAndroid Build Coastguard Worker
397*6777b538SAndroid Build Coastguard Worker *result = cookie_domain;
398*6777b538SAndroid Build Coastguard Worker return true;
399*6777b538SAndroid Build Coastguard Worker }
400*6777b538SAndroid Build Coastguard Worker
401*6777b538SAndroid Build Coastguard Worker // Parse a cookie expiration time. We try to be lenient, but we need to
402*6777b538SAndroid Build Coastguard Worker // assume some order to distinguish the fields. The basic rules:
403*6777b538SAndroid Build Coastguard Worker // - The month name must be present and prefix the first 3 letters of the
404*6777b538SAndroid Build Coastguard Worker // full month name (jan for January, jun for June).
405*6777b538SAndroid Build Coastguard Worker // - If the year is <= 2 digits, it must occur after the day of month.
406*6777b538SAndroid Build Coastguard Worker // - The time must be of the format hh:mm:ss.
407*6777b538SAndroid Build Coastguard Worker // An average cookie expiration will look something like this:
408*6777b538SAndroid Build Coastguard Worker // Sat, 15-Apr-17 21:01:22 GMT
ParseCookieExpirationTime(const std::string & time_string)409*6777b538SAndroid Build Coastguard Worker base::Time ParseCookieExpirationTime(const std::string& time_string) {
410*6777b538SAndroid Build Coastguard Worker static const char* const kMonths[] = {
411*6777b538SAndroid Build Coastguard Worker "jan", "feb", "mar", "apr", "may", "jun",
412*6777b538SAndroid Build Coastguard Worker "jul", "aug", "sep", "oct", "nov", "dec" };
413*6777b538SAndroid Build Coastguard Worker // We want to be pretty liberal, and support most non-ascii and non-digit
414*6777b538SAndroid Build Coastguard Worker // characters as a delimiter. We can't treat : as a delimiter, because it
415*6777b538SAndroid Build Coastguard Worker // is the delimiter for hh:mm:ss, and we want to keep this field together.
416*6777b538SAndroid Build Coastguard Worker // We make sure to include - and +, since they could prefix numbers.
417*6777b538SAndroid Build Coastguard Worker // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes
418*6777b538SAndroid Build Coastguard Worker // will be preserved, and we will get them here. So we make sure to include
419*6777b538SAndroid Build Coastguard Worker // quote characters, and also \ for anything that was internally escaped.
420*6777b538SAndroid Build Coastguard Worker static const char kDelimiters[] = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~";
421*6777b538SAndroid Build Coastguard Worker
422*6777b538SAndroid Build Coastguard Worker base::Time::Exploded exploded = {0};
423*6777b538SAndroid Build Coastguard Worker
424*6777b538SAndroid Build Coastguard Worker base::StringTokenizer tokenizer(time_string, kDelimiters);
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker bool found_day_of_month = false;
427*6777b538SAndroid Build Coastguard Worker bool found_month = false;
428*6777b538SAndroid Build Coastguard Worker bool found_time = false;
429*6777b538SAndroid Build Coastguard Worker bool found_year = false;
430*6777b538SAndroid Build Coastguard Worker
431*6777b538SAndroid Build Coastguard Worker while (tokenizer.GetNext()) {
432*6777b538SAndroid Build Coastguard Worker const std::string token = tokenizer.token();
433*6777b538SAndroid Build Coastguard Worker DCHECK(!token.empty());
434*6777b538SAndroid Build Coastguard Worker bool numerical = base::IsAsciiDigit(token[0]);
435*6777b538SAndroid Build Coastguard Worker
436*6777b538SAndroid Build Coastguard Worker // String field
437*6777b538SAndroid Build Coastguard Worker if (!numerical) {
438*6777b538SAndroid Build Coastguard Worker if (!found_month) {
439*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kMonths); ++i) {
440*6777b538SAndroid Build Coastguard Worker // Match prefix, so we could match January, etc
441*6777b538SAndroid Build Coastguard Worker if (base::StartsWith(token, std::string_view(kMonths[i], 3),
442*6777b538SAndroid Build Coastguard Worker base::CompareCase::INSENSITIVE_ASCII)) {
443*6777b538SAndroid Build Coastguard Worker exploded.month = static_cast<int>(i) + 1;
444*6777b538SAndroid Build Coastguard Worker found_month = true;
445*6777b538SAndroid Build Coastguard Worker break;
446*6777b538SAndroid Build Coastguard Worker }
447*6777b538SAndroid Build Coastguard Worker }
448*6777b538SAndroid Build Coastguard Worker } else {
449*6777b538SAndroid Build Coastguard Worker // If we've gotten here, it means we've already found and parsed our
450*6777b538SAndroid Build Coastguard Worker // month, and we have another string, which we would expect to be the
451*6777b538SAndroid Build Coastguard Worker // the time zone name. According to the RFC and my experiments with
452*6777b538SAndroid Build Coastguard Worker // how sites format their expirations, we don't have much of a reason
453*6777b538SAndroid Build Coastguard Worker // to support timezones. We don't want to ever barf on user input,
454*6777b538SAndroid Build Coastguard Worker // but this DCHECK should pass for well-formed data.
455*6777b538SAndroid Build Coastguard Worker // DCHECK(token == "GMT");
456*6777b538SAndroid Build Coastguard Worker }
457*6777b538SAndroid Build Coastguard Worker // Numeric field w/ a colon
458*6777b538SAndroid Build Coastguard Worker } else if (token.find(':') != std::string::npos) {
459*6777b538SAndroid Build Coastguard Worker if (!found_time &&
460*6777b538SAndroid Build Coastguard Worker #ifdef COMPILER_MSVC
461*6777b538SAndroid Build Coastguard Worker sscanf_s(
462*6777b538SAndroid Build Coastguard Worker #else
463*6777b538SAndroid Build Coastguard Worker sscanf(
464*6777b538SAndroid Build Coastguard Worker #endif
465*6777b538SAndroid Build Coastguard Worker token.c_str(), "%2u:%2u:%2u", &exploded.hour,
466*6777b538SAndroid Build Coastguard Worker &exploded.minute, &exploded.second) == 3) {
467*6777b538SAndroid Build Coastguard Worker found_time = true;
468*6777b538SAndroid Build Coastguard Worker } else {
469*6777b538SAndroid Build Coastguard Worker // We should only ever encounter one time-like thing. If we're here,
470*6777b538SAndroid Build Coastguard Worker // it means we've found a second, which shouldn't happen. We keep
471*6777b538SAndroid Build Coastguard Worker // the first. This check should be ok for well-formed input:
472*6777b538SAndroid Build Coastguard Worker // NOTREACHED();
473*6777b538SAndroid Build Coastguard Worker }
474*6777b538SAndroid Build Coastguard Worker // Numeric field
475*6777b538SAndroid Build Coastguard Worker } else {
476*6777b538SAndroid Build Coastguard Worker // Overflow with atoi() is unspecified, so we enforce a max length.
477*6777b538SAndroid Build Coastguard Worker if (!found_day_of_month && token.length() <= 2) {
478*6777b538SAndroid Build Coastguard Worker exploded.day_of_month = atoi(token.c_str());
479*6777b538SAndroid Build Coastguard Worker found_day_of_month = true;
480*6777b538SAndroid Build Coastguard Worker } else if (!found_year && token.length() <= 5) {
481*6777b538SAndroid Build Coastguard Worker exploded.year = atoi(token.c_str());
482*6777b538SAndroid Build Coastguard Worker found_year = true;
483*6777b538SAndroid Build Coastguard Worker } else {
484*6777b538SAndroid Build Coastguard Worker // If we're here, it means we've either found an extra numeric field,
485*6777b538SAndroid Build Coastguard Worker // or a numeric field which was too long. For well-formed input, the
486*6777b538SAndroid Build Coastguard Worker // following check would be reasonable:
487*6777b538SAndroid Build Coastguard Worker // NOTREACHED();
488*6777b538SAndroid Build Coastguard Worker }
489*6777b538SAndroid Build Coastguard Worker }
490*6777b538SAndroid Build Coastguard Worker }
491*6777b538SAndroid Build Coastguard Worker
492*6777b538SAndroid Build Coastguard Worker if (!found_day_of_month || !found_month || !found_time || !found_year) {
493*6777b538SAndroid Build Coastguard Worker // We didn't find all of the fields we need. For well-formed input, the
494*6777b538SAndroid Build Coastguard Worker // following check would be reasonable:
495*6777b538SAndroid Build Coastguard Worker // NOTREACHED() << "Cookie parse expiration failed: " << time_string;
496*6777b538SAndroid Build Coastguard Worker return base::Time();
497*6777b538SAndroid Build Coastguard Worker }
498*6777b538SAndroid Build Coastguard Worker
499*6777b538SAndroid Build Coastguard Worker // Normalize the year to expand abbreviated years to the full year.
500*6777b538SAndroid Build Coastguard Worker if (exploded.year >= 70 && exploded.year <= 99)
501*6777b538SAndroid Build Coastguard Worker exploded.year += 1900;
502*6777b538SAndroid Build Coastguard Worker if (exploded.year >= 0 && exploded.year <= 69)
503*6777b538SAndroid Build Coastguard Worker exploded.year += 2000;
504*6777b538SAndroid Build Coastguard Worker
505*6777b538SAndroid Build Coastguard Worker // Note that clipping the date if it is outside of a platform-specific range
506*6777b538SAndroid Build Coastguard Worker // is permitted by: https://tools.ietf.org/html/rfc6265#section-5.2.1
507*6777b538SAndroid Build Coastguard Worker base::Time result;
508*6777b538SAndroid Build Coastguard Worker if (SaturatedTimeFromUTCExploded(exploded, &result))
509*6777b538SAndroid Build Coastguard Worker return result;
510*6777b538SAndroid Build Coastguard Worker
511*6777b538SAndroid Build Coastguard Worker // One of our values was out of expected range. For well-formed input,
512*6777b538SAndroid Build Coastguard Worker // the following check would be reasonable:
513*6777b538SAndroid Build Coastguard Worker // NOTREACHED() << "Cookie exploded expiration failed: " << time_string;
514*6777b538SAndroid Build Coastguard Worker
515*6777b538SAndroid Build Coastguard Worker return base::Time();
516*6777b538SAndroid Build Coastguard Worker }
517*6777b538SAndroid Build Coastguard Worker
CookieDomainAndPathToURL(const std::string & domain,const std::string & path,const std::string & source_scheme)518*6777b538SAndroid Build Coastguard Worker GURL CookieDomainAndPathToURL(const std::string& domain,
519*6777b538SAndroid Build Coastguard Worker const std::string& path,
520*6777b538SAndroid Build Coastguard Worker const std::string& source_scheme) {
521*6777b538SAndroid Build Coastguard Worker // Note: domain_no_dot could be empty for e.g. file cookies.
522*6777b538SAndroid Build Coastguard Worker std::string domain_no_dot = CookieDomainAsHost(domain);
523*6777b538SAndroid Build Coastguard Worker if (domain_no_dot.empty() || source_scheme.empty())
524*6777b538SAndroid Build Coastguard Worker return GURL();
525*6777b538SAndroid Build Coastguard Worker return GURL(base::StrCat(
526*6777b538SAndroid Build Coastguard Worker {source_scheme, url::kStandardSchemeSeparator, domain_no_dot, path}));
527*6777b538SAndroid Build Coastguard Worker }
528*6777b538SAndroid Build Coastguard Worker
CookieDomainAndPathToURL(const std::string & domain,const std::string & path,bool is_https)529*6777b538SAndroid Build Coastguard Worker GURL CookieDomainAndPathToURL(const std::string& domain,
530*6777b538SAndroid Build Coastguard Worker const std::string& path,
531*6777b538SAndroid Build Coastguard Worker bool is_https) {
532*6777b538SAndroid Build Coastguard Worker return CookieDomainAndPathToURL(
533*6777b538SAndroid Build Coastguard Worker domain, path,
534*6777b538SAndroid Build Coastguard Worker std::string(is_https ? url::kHttpsScheme : url::kHttpScheme));
535*6777b538SAndroid Build Coastguard Worker }
536*6777b538SAndroid Build Coastguard Worker
CookieDomainAndPathToURL(const std::string & domain,const std::string & path,CookieSourceScheme source_scheme)537*6777b538SAndroid Build Coastguard Worker GURL CookieDomainAndPathToURL(const std::string& domain,
538*6777b538SAndroid Build Coastguard Worker const std::string& path,
539*6777b538SAndroid Build Coastguard Worker CookieSourceScheme source_scheme) {
540*6777b538SAndroid Build Coastguard Worker return CookieDomainAndPathToURL(domain, path,
541*6777b538SAndroid Build Coastguard Worker source_scheme == CookieSourceScheme::kSecure);
542*6777b538SAndroid Build Coastguard Worker }
543*6777b538SAndroid Build Coastguard Worker
CookieOriginToURL(const std::string & domain,bool is_https)544*6777b538SAndroid Build Coastguard Worker GURL CookieOriginToURL(const std::string& domain, bool is_https) {
545*6777b538SAndroid Build Coastguard Worker return CookieDomainAndPathToURL(domain, "/", is_https);
546*6777b538SAndroid Build Coastguard Worker }
547*6777b538SAndroid Build Coastguard Worker
SimulatedCookieSource(const CanonicalCookie & cookie,const std::string & source_scheme)548*6777b538SAndroid Build Coastguard Worker GURL SimulatedCookieSource(const CanonicalCookie& cookie,
549*6777b538SAndroid Build Coastguard Worker const std::string& source_scheme) {
550*6777b538SAndroid Build Coastguard Worker return CookieDomainAndPathToURL(cookie.Domain(), cookie.Path(),
551*6777b538SAndroid Build Coastguard Worker source_scheme);
552*6777b538SAndroid Build Coastguard Worker }
553*6777b538SAndroid Build Coastguard Worker
ProvisionalAccessScheme(const GURL & source_url)554*6777b538SAndroid Build Coastguard Worker CookieAccessScheme ProvisionalAccessScheme(const GURL& source_url) {
555*6777b538SAndroid Build Coastguard Worker return source_url.SchemeIsCryptographic()
556*6777b538SAndroid Build Coastguard Worker ? CookieAccessScheme::kCryptographic
557*6777b538SAndroid Build Coastguard Worker : IsLocalhost(source_url) ? CookieAccessScheme::kTrustworthy
558*6777b538SAndroid Build Coastguard Worker : CookieAccessScheme::kNonCryptographic;
559*6777b538SAndroid Build Coastguard Worker }
560*6777b538SAndroid Build Coastguard Worker
IsDomainMatch(const std::string & domain,const std::string & host)561*6777b538SAndroid Build Coastguard Worker bool IsDomainMatch(const std::string& domain, const std::string& host) {
562*6777b538SAndroid Build Coastguard Worker // Can domain match in two ways; as a domain cookie (where the cookie
563*6777b538SAndroid Build Coastguard Worker // domain begins with ".") or as a host cookie (where it doesn't).
564*6777b538SAndroid Build Coastguard Worker
565*6777b538SAndroid Build Coastguard Worker // Some consumers of the CookieMonster expect to set cookies on
566*6777b538SAndroid Build Coastguard Worker // URLs like http://.strange.url. To retrieve cookies in this instance,
567*6777b538SAndroid Build Coastguard Worker // we allow matching as a host cookie even when the domain_ starts with
568*6777b538SAndroid Build Coastguard Worker // a period.
569*6777b538SAndroid Build Coastguard Worker if (host == domain)
570*6777b538SAndroid Build Coastguard Worker return true;
571*6777b538SAndroid Build Coastguard Worker
572*6777b538SAndroid Build Coastguard Worker // Domain cookie must have an initial ".". To match, it must be
573*6777b538SAndroid Build Coastguard Worker // equal to url's host with initial period removed, or a suffix of
574*6777b538SAndroid Build Coastguard Worker // it.
575*6777b538SAndroid Build Coastguard Worker
576*6777b538SAndroid Build Coastguard Worker // Arguably this should only apply to "http" or "https" cookies, but
577*6777b538SAndroid Build Coastguard Worker // extension cookie tests currently use the funtionality, and if we
578*6777b538SAndroid Build Coastguard Worker // ever decide to implement that it should be done by preventing
579*6777b538SAndroid Build Coastguard Worker // such cookies from being set.
580*6777b538SAndroid Build Coastguard Worker if (domain.empty() || domain[0] != '.')
581*6777b538SAndroid Build Coastguard Worker return false;
582*6777b538SAndroid Build Coastguard Worker
583*6777b538SAndroid Build Coastguard Worker // The host with a "." prefixed.
584*6777b538SAndroid Build Coastguard Worker if (domain.compare(1, std::string::npos, host) == 0)
585*6777b538SAndroid Build Coastguard Worker return true;
586*6777b538SAndroid Build Coastguard Worker
587*6777b538SAndroid Build Coastguard Worker // A pure suffix of the host (ok since we know the domain already
588*6777b538SAndroid Build Coastguard Worker // starts with a ".")
589*6777b538SAndroid Build Coastguard Worker return (host.length() > domain.length() &&
590*6777b538SAndroid Build Coastguard Worker host.compare(host.length() - domain.length(), domain.length(),
591*6777b538SAndroid Build Coastguard Worker domain) == 0);
592*6777b538SAndroid Build Coastguard Worker }
593*6777b538SAndroid Build Coastguard Worker
IsOnPath(const std::string & cookie_path,const std::string & url_path)594*6777b538SAndroid Build Coastguard Worker bool IsOnPath(const std::string& cookie_path, const std::string& url_path) {
595*6777b538SAndroid Build Coastguard Worker // A zero length would be unsafe for our trailing '/' checks, and
596*6777b538SAndroid Build Coastguard Worker // would also make no sense for our prefix match. The code that
597*6777b538SAndroid Build Coastguard Worker // creates a CanonicalCookie should make sure the path is never zero length,
598*6777b538SAndroid Build Coastguard Worker // but we double check anyway.
599*6777b538SAndroid Build Coastguard Worker if (cookie_path.empty()) {
600*6777b538SAndroid Build Coastguard Worker return false;
601*6777b538SAndroid Build Coastguard Worker }
602*6777b538SAndroid Build Coastguard Worker
603*6777b538SAndroid Build Coastguard Worker // The Mozilla code broke this into three cases, based on if the cookie path
604*6777b538SAndroid Build Coastguard Worker // was longer, the same length, or shorter than the length of the url path.
605*6777b538SAndroid Build Coastguard Worker // I think the approach below is simpler.
606*6777b538SAndroid Build Coastguard Worker
607*6777b538SAndroid Build Coastguard Worker // Make sure the cookie path is a prefix of the url path. If the url path is
608*6777b538SAndroid Build Coastguard Worker // shorter than the cookie path, then the cookie path can't be a prefix.
609*6777b538SAndroid Build Coastguard Worker if (!url_path.starts_with(cookie_path)) {
610*6777b538SAndroid Build Coastguard Worker return false;
611*6777b538SAndroid Build Coastguard Worker }
612*6777b538SAndroid Build Coastguard Worker
613*6777b538SAndroid Build Coastguard Worker // |url_path| is >= |cookie_path|, and |cookie_path| is a prefix of
614*6777b538SAndroid Build Coastguard Worker // |url_path|. If they are the are the same length then they are identical,
615*6777b538SAndroid Build Coastguard Worker // otherwise need an additional check:
616*6777b538SAndroid Build Coastguard Worker
617*6777b538SAndroid Build Coastguard Worker // In order to avoid in correctly matching a cookie path of /blah
618*6777b538SAndroid Build Coastguard Worker // with a request path of '/blahblah/', we need to make sure that either
619*6777b538SAndroid Build Coastguard Worker // the cookie path ends in a trailing '/', or that we prefix up to a '/'
620*6777b538SAndroid Build Coastguard Worker // in the url path. Since we know that the url path length is greater
621*6777b538SAndroid Build Coastguard Worker // than the cookie path length, it's safe to index one byte past.
622*6777b538SAndroid Build Coastguard Worker if (cookie_path.length() != url_path.length() && cookie_path.back() != '/' &&
623*6777b538SAndroid Build Coastguard Worker url_path[cookie_path.length()] != '/') {
624*6777b538SAndroid Build Coastguard Worker return false;
625*6777b538SAndroid Build Coastguard Worker }
626*6777b538SAndroid Build Coastguard Worker
627*6777b538SAndroid Build Coastguard Worker return true;
628*6777b538SAndroid Build Coastguard Worker }
629*6777b538SAndroid Build Coastguard Worker
ParseRequestCookieLine(const std::string & header_value,ParsedRequestCookies * parsed_cookies)630*6777b538SAndroid Build Coastguard Worker void ParseRequestCookieLine(const std::string& header_value,
631*6777b538SAndroid Build Coastguard Worker ParsedRequestCookies* parsed_cookies) {
632*6777b538SAndroid Build Coastguard Worker std::string::const_iterator i = header_value.begin();
633*6777b538SAndroid Build Coastguard Worker while (i != header_value.end()) {
634*6777b538SAndroid Build Coastguard Worker // Here we are at the beginning of a cookie.
635*6777b538SAndroid Build Coastguard Worker
636*6777b538SAndroid Build Coastguard Worker // Eat whitespace.
637*6777b538SAndroid Build Coastguard Worker while (i != header_value.end() && *i == ' ') ++i;
638*6777b538SAndroid Build Coastguard Worker if (i == header_value.end()) return;
639*6777b538SAndroid Build Coastguard Worker
640*6777b538SAndroid Build Coastguard Worker // Find cookie name.
641*6777b538SAndroid Build Coastguard Worker std::string::const_iterator cookie_name_beginning = i;
642*6777b538SAndroid Build Coastguard Worker while (i != header_value.end() && *i != '=') ++i;
643*6777b538SAndroid Build Coastguard Worker auto cookie_name = base::MakeStringPiece(cookie_name_beginning, i);
644*6777b538SAndroid Build Coastguard Worker
645*6777b538SAndroid Build Coastguard Worker // Find cookie value.
646*6777b538SAndroid Build Coastguard Worker std::string_view cookie_value;
647*6777b538SAndroid Build Coastguard Worker // Cookies may have no value, in this case '=' may or may not be there.
648*6777b538SAndroid Build Coastguard Worker if (i != header_value.end() && i + 1 != header_value.end()) {
649*6777b538SAndroid Build Coastguard Worker ++i; // Skip '='.
650*6777b538SAndroid Build Coastguard Worker std::string::const_iterator cookie_value_beginning = i;
651*6777b538SAndroid Build Coastguard Worker if (*i == '"') {
652*6777b538SAndroid Build Coastguard Worker ++i; // Skip '"'.
653*6777b538SAndroid Build Coastguard Worker while (i != header_value.end() && *i != '"') ++i;
654*6777b538SAndroid Build Coastguard Worker if (i == header_value.end()) return;
655*6777b538SAndroid Build Coastguard Worker ++i; // Skip '"'.
656*6777b538SAndroid Build Coastguard Worker cookie_value = base::MakeStringPiece(cookie_value_beginning, i);
657*6777b538SAndroid Build Coastguard Worker // i points to character after '"', potentially a ';'.
658*6777b538SAndroid Build Coastguard Worker } else {
659*6777b538SAndroid Build Coastguard Worker while (i != header_value.end() && *i != ';') ++i;
660*6777b538SAndroid Build Coastguard Worker cookie_value = base::MakeStringPiece(cookie_value_beginning, i);
661*6777b538SAndroid Build Coastguard Worker // i points to ';' or end of string.
662*6777b538SAndroid Build Coastguard Worker }
663*6777b538SAndroid Build Coastguard Worker }
664*6777b538SAndroid Build Coastguard Worker parsed_cookies->emplace_back(std::string(cookie_name),
665*6777b538SAndroid Build Coastguard Worker std::string(cookie_value));
666*6777b538SAndroid Build Coastguard Worker // Eat ';'.
667*6777b538SAndroid Build Coastguard Worker if (i != header_value.end()) ++i;
668*6777b538SAndroid Build Coastguard Worker }
669*6777b538SAndroid Build Coastguard Worker }
670*6777b538SAndroid Build Coastguard Worker
SerializeRequestCookieLine(const ParsedRequestCookies & parsed_cookies)671*6777b538SAndroid Build Coastguard Worker std::string SerializeRequestCookieLine(
672*6777b538SAndroid Build Coastguard Worker const ParsedRequestCookies& parsed_cookies) {
673*6777b538SAndroid Build Coastguard Worker std::string buffer;
674*6777b538SAndroid Build Coastguard Worker for (const auto& parsed_cookie : parsed_cookies) {
675*6777b538SAndroid Build Coastguard Worker if (!buffer.empty())
676*6777b538SAndroid Build Coastguard Worker buffer.append("; ");
677*6777b538SAndroid Build Coastguard Worker buffer.append(parsed_cookie.first.begin(), parsed_cookie.first.end());
678*6777b538SAndroid Build Coastguard Worker buffer.push_back('=');
679*6777b538SAndroid Build Coastguard Worker buffer.append(parsed_cookie.second.begin(), parsed_cookie.second.end());
680*6777b538SAndroid Build Coastguard Worker }
681*6777b538SAndroid Build Coastguard Worker return buffer;
682*6777b538SAndroid Build Coastguard Worker }
683*6777b538SAndroid Build Coastguard Worker
ComputeSameSiteContextForRequest(const std::string & http_method,const std::vector<GURL> & url_chain,const SiteForCookies & site_for_cookies,const std::optional<url::Origin> & initiator,bool is_main_frame_navigation,bool force_ignore_site_for_cookies)684*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext ComputeSameSiteContextForRequest(
685*6777b538SAndroid Build Coastguard Worker const std::string& http_method,
686*6777b538SAndroid Build Coastguard Worker const std::vector<GURL>& url_chain,
687*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
688*6777b538SAndroid Build Coastguard Worker const std::optional<url::Origin>& initiator,
689*6777b538SAndroid Build Coastguard Worker bool is_main_frame_navigation,
690*6777b538SAndroid Build Coastguard Worker bool force_ignore_site_for_cookies) {
691*6777b538SAndroid Build Coastguard Worker // Set SameSiteCookieContext according to the rules laid out in
692*6777b538SAndroid Build Coastguard Worker // https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis:
693*6777b538SAndroid Build Coastguard Worker //
694*6777b538SAndroid Build Coastguard Worker // * Include both "strict" and "lax" same-site cookies if the request's
695*6777b538SAndroid Build Coastguard Worker // |url|, |initiator|, and |site_for_cookies| all have the same
696*6777b538SAndroid Build Coastguard Worker // registrable domain. Note: this also covers the case of a request
697*6777b538SAndroid Build Coastguard Worker // without an initiator (only happens for browser-initiated main frame
698*6777b538SAndroid Build Coastguard Worker // navigations). If computing schemefully, the schemes must also match.
699*6777b538SAndroid Build Coastguard Worker //
700*6777b538SAndroid Build Coastguard Worker // * Include only "lax" same-site cookies if the request's |URL| and
701*6777b538SAndroid Build Coastguard Worker // |site_for_cookies| have the same registrable domain, _and_ the
702*6777b538SAndroid Build Coastguard Worker // request's |http_method| is "safe" ("GET" or "HEAD"), and the request
703*6777b538SAndroid Build Coastguard Worker // is a main frame navigation.
704*6777b538SAndroid Build Coastguard Worker //
705*6777b538SAndroid Build Coastguard Worker // This case should occur only for cross-site requests which
706*6777b538SAndroid Build Coastguard Worker // target a top-level browsing context, with a "safe" method.
707*6777b538SAndroid Build Coastguard Worker //
708*6777b538SAndroid Build Coastguard Worker // * Include both "strict" and "lax" same-site cookies if the request is
709*6777b538SAndroid Build Coastguard Worker // tagged with a flag allowing it.
710*6777b538SAndroid Build Coastguard Worker //
711*6777b538SAndroid Build Coastguard Worker // Note that this can be the case for requests initiated by extensions,
712*6777b538SAndroid Build Coastguard Worker // which need to behave as though they are made by the document itself,
713*6777b538SAndroid Build Coastguard Worker // but appear like cross-site ones.
714*6777b538SAndroid Build Coastguard Worker //
715*6777b538SAndroid Build Coastguard Worker // * Otherwise, do not include same-site cookies.
716*6777b538SAndroid Build Coastguard Worker
717*6777b538SAndroid Build Coastguard Worker if (force_ignore_site_for_cookies)
718*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext::MakeInclusive();
719*6777b538SAndroid Build Coastguard Worker
720*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult result = ComputeSameSiteContext(
721*6777b538SAndroid Build Coastguard Worker url_chain, site_for_cookies, initiator, true /* is_http */,
722*6777b538SAndroid Build Coastguard Worker is_main_frame_navigation, false /* compute_schemefully */);
723*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult schemeful_result = ComputeSameSiteContext(
724*6777b538SAndroid Build Coastguard Worker url_chain, site_for_cookies, initiator, true /* is_http */,
725*6777b538SAndroid Build Coastguard Worker is_main_frame_navigation, true /* compute_schemefully */);
726*6777b538SAndroid Build Coastguard Worker
727*6777b538SAndroid Build Coastguard Worker // If the method is safe, the context is Lax. Otherwise, make a note that
728*6777b538SAndroid Build Coastguard Worker // the method is unsafe.
729*6777b538SAndroid Build Coastguard Worker if (!net::HttpUtil::IsMethodSafe(http_method)) {
730*6777b538SAndroid Build Coastguard Worker if (result.context_type == ContextType::SAME_SITE_LAX)
731*6777b538SAndroid Build Coastguard Worker result.context_type = ContextType::SAME_SITE_LAX_METHOD_UNSAFE;
732*6777b538SAndroid Build Coastguard Worker if (schemeful_result.context_type == ContextType::SAME_SITE_LAX)
733*6777b538SAndroid Build Coastguard Worker schemeful_result.context_type = ContextType::SAME_SITE_LAX_METHOD_UNSAFE;
734*6777b538SAndroid Build Coastguard Worker }
735*6777b538SAndroid Build Coastguard Worker
736*6777b538SAndroid Build Coastguard Worker ContextMetadata::HttpMethod http_method_enum =
737*6777b538SAndroid Build Coastguard Worker HttpMethodStringToEnum(http_method);
738*6777b538SAndroid Build Coastguard Worker
739*6777b538SAndroid Build Coastguard Worker if (result.metadata.cross_site_redirect_downgrade !=
740*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextDowngradeType::kNoDowngrade) {
741*6777b538SAndroid Build Coastguard Worker result.metadata.http_method_bug_1221316 = http_method_enum;
742*6777b538SAndroid Build Coastguard Worker }
743*6777b538SAndroid Build Coastguard Worker
744*6777b538SAndroid Build Coastguard Worker if (schemeful_result.metadata.cross_site_redirect_downgrade !=
745*6777b538SAndroid Build Coastguard Worker ContextMetadata::ContextDowngradeType::kNoDowngrade) {
746*6777b538SAndroid Build Coastguard Worker schemeful_result.metadata.http_method_bug_1221316 = http_method_enum;
747*6777b538SAndroid Build Coastguard Worker }
748*6777b538SAndroid Build Coastguard Worker
749*6777b538SAndroid Build Coastguard Worker return MakeSameSiteCookieContext(result, schemeful_result);
750*6777b538SAndroid Build Coastguard Worker }
751*6777b538SAndroid Build Coastguard Worker
752*6777b538SAndroid Build Coastguard Worker NET_EXPORT CookieOptions::SameSiteCookieContext
ComputeSameSiteContextForScriptGet(const GURL & url,const SiteForCookies & site_for_cookies,const std::optional<url::Origin> & initiator,bool force_ignore_site_for_cookies)753*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextForScriptGet(const GURL& url,
754*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
755*6777b538SAndroid Build Coastguard Worker const std::optional<url::Origin>& initiator,
756*6777b538SAndroid Build Coastguard Worker bool force_ignore_site_for_cookies) {
757*6777b538SAndroid Build Coastguard Worker if (force_ignore_site_for_cookies)
758*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext::MakeInclusive();
759*6777b538SAndroid Build Coastguard Worker
760*6777b538SAndroid Build Coastguard Worker // We don't check the redirect chain for script access to cookies (only the
761*6777b538SAndroid Build Coastguard Worker // URL itself).
762*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult result = ComputeSameSiteContext(
763*6777b538SAndroid Build Coastguard Worker {url}, site_for_cookies, initiator, false /* is_http */,
764*6777b538SAndroid Build Coastguard Worker false /* is_main_frame_navigation */, false /* compute_schemefully */);
765*6777b538SAndroid Build Coastguard Worker ComputeSameSiteContextResult schemeful_result = ComputeSameSiteContext(
766*6777b538SAndroid Build Coastguard Worker {url}, site_for_cookies, initiator, false /* is_http */,
767*6777b538SAndroid Build Coastguard Worker false /* is_main_frame_navigation */, true /* compute_schemefully */);
768*6777b538SAndroid Build Coastguard Worker
769*6777b538SAndroid Build Coastguard Worker return MakeSameSiteCookieContext(result, schemeful_result);
770*6777b538SAndroid Build Coastguard Worker }
771*6777b538SAndroid Build Coastguard Worker
ComputeSameSiteContextForResponse(const std::vector<GURL> & url_chain,const SiteForCookies & site_for_cookies,const std::optional<url::Origin> & initiator,bool is_main_frame_navigation,bool force_ignore_site_for_cookies)772*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext ComputeSameSiteContextForResponse(
773*6777b538SAndroid Build Coastguard Worker const std::vector<GURL>& url_chain,
774*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
775*6777b538SAndroid Build Coastguard Worker const std::optional<url::Origin>& initiator,
776*6777b538SAndroid Build Coastguard Worker bool is_main_frame_navigation,
777*6777b538SAndroid Build Coastguard Worker bool force_ignore_site_for_cookies) {
778*6777b538SAndroid Build Coastguard Worker if (force_ignore_site_for_cookies)
779*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext::MakeInclusiveForSet();
780*6777b538SAndroid Build Coastguard Worker
781*6777b538SAndroid Build Coastguard Worker DCHECK(!url_chain.empty());
782*6777b538SAndroid Build Coastguard Worker if (is_main_frame_navigation && !site_for_cookies.IsNull()) {
783*6777b538SAndroid Build Coastguard Worker // If the request is a main frame navigation, site_for_cookies must either
784*6777b538SAndroid Build Coastguard Worker // be null (for opaque origins, e.g., data: origins) or same-site with the
785*6777b538SAndroid Build Coastguard Worker // request URL (both schemefully and schemelessly), and the URL cannot be
786*6777b538SAndroid Build Coastguard Worker // ws/wss (these schemes are not navigable).
787*6777b538SAndroid Build Coastguard Worker DCHECK(
788*6777b538SAndroid Build Coastguard Worker site_for_cookies.IsFirstPartyWithSchemefulMode(url_chain.back(), true));
789*6777b538SAndroid Build Coastguard Worker DCHECK(!url_chain.back().SchemeIsWSOrWSS());
790*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext result =
791*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext::MakeInclusiveForSet();
792*6777b538SAndroid Build Coastguard Worker
793*6777b538SAndroid Build Coastguard Worker const GURL& request_url = url_chain.back();
794*6777b538SAndroid Build Coastguard Worker
795*6777b538SAndroid Build Coastguard Worker for (bool compute_schemefully : {false, true}) {
796*6777b538SAndroid Build Coastguard Worker bool same_site_initiator =
797*6777b538SAndroid Build Coastguard Worker !initiator ||
798*6777b538SAndroid Build Coastguard Worker SiteForCookies::FromOrigin(initiator.value())
799*6777b538SAndroid Build Coastguard Worker .IsFirstPartyWithSchemefulMode(request_url, compute_schemefully);
800*6777b538SAndroid Build Coastguard Worker
801*6777b538SAndroid Build Coastguard Worker const auto is_same_site_with_site_for_cookies =
802*6777b538SAndroid Build Coastguard Worker [&site_for_cookies, compute_schemefully](const GURL& url) {
803*6777b538SAndroid Build Coastguard Worker return site_for_cookies.IsFirstPartyWithSchemefulMode(
804*6777b538SAndroid Build Coastguard Worker url, compute_schemefully);
805*6777b538SAndroid Build Coastguard Worker };
806*6777b538SAndroid Build Coastguard Worker
807*6777b538SAndroid Build Coastguard Worker bool same_site_redirect_chain =
808*6777b538SAndroid Build Coastguard Worker url_chain.size() == 1u ||
809*6777b538SAndroid Build Coastguard Worker base::ranges::all_of(url_chain, is_same_site_with_site_for_cookies);
810*6777b538SAndroid Build Coastguard Worker
811*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext::ContextMetadata& result_metadata =
812*6777b538SAndroid Build Coastguard Worker compute_schemefully ? result.schemeful_metadata() : result.metadata();
813*6777b538SAndroid Build Coastguard Worker
814*6777b538SAndroid Build Coastguard Worker result_metadata.redirect_type_bug_1221316 =
815*6777b538SAndroid Build Coastguard Worker ComputeContextRedirectTypeBug1221316(
816*6777b538SAndroid Build Coastguard Worker url_chain.size() == 1u, same_site_initiator,
817*6777b538SAndroid Build Coastguard Worker true /* site_for_cookies_is_same_site */,
818*6777b538SAndroid Build Coastguard Worker same_site_redirect_chain);
819*6777b538SAndroid Build Coastguard Worker }
820*6777b538SAndroid Build Coastguard Worker return result;
821*6777b538SAndroid Build Coastguard Worker }
822*6777b538SAndroid Build Coastguard Worker
823*6777b538SAndroid Build Coastguard Worker return ComputeSameSiteContextForSet(url_chain, site_for_cookies, initiator,
824*6777b538SAndroid Build Coastguard Worker true /* is_http */,
825*6777b538SAndroid Build Coastguard Worker is_main_frame_navigation);
826*6777b538SAndroid Build Coastguard Worker }
827*6777b538SAndroid Build Coastguard Worker
ComputeSameSiteContextForScriptSet(const GURL & url,const SiteForCookies & site_for_cookies,bool force_ignore_site_for_cookies)828*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext ComputeSameSiteContextForScriptSet(
829*6777b538SAndroid Build Coastguard Worker const GURL& url,
830*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
831*6777b538SAndroid Build Coastguard Worker bool force_ignore_site_for_cookies) {
832*6777b538SAndroid Build Coastguard Worker if (force_ignore_site_for_cookies)
833*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext::MakeInclusiveForSet();
834*6777b538SAndroid Build Coastguard Worker
835*6777b538SAndroid Build Coastguard Worker // It doesn't matter what initiator origin we pass here. Either way, the
836*6777b538SAndroid Build Coastguard Worker // context will be considered same-site iff the site_for_cookies is same-site
837*6777b538SAndroid Build Coastguard Worker // with the url. We don't check the redirect chain for script access to
838*6777b538SAndroid Build Coastguard Worker // cookies (only the URL itself).
839*6777b538SAndroid Build Coastguard Worker return ComputeSameSiteContextForSet(
840*6777b538SAndroid Build Coastguard Worker {url}, site_for_cookies, std::nullopt /* initiator */,
841*6777b538SAndroid Build Coastguard Worker false /* is_http */, false /* is_main_frame_navigation */);
842*6777b538SAndroid Build Coastguard Worker }
843*6777b538SAndroid Build Coastguard Worker
ComputeSameSiteContextForSubresource(const GURL & url,const SiteForCookies & site_for_cookies,bool force_ignore_site_for_cookies)844*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext ComputeSameSiteContextForSubresource(
845*6777b538SAndroid Build Coastguard Worker const GURL& url,
846*6777b538SAndroid Build Coastguard Worker const SiteForCookies& site_for_cookies,
847*6777b538SAndroid Build Coastguard Worker bool force_ignore_site_for_cookies) {
848*6777b538SAndroid Build Coastguard Worker if (force_ignore_site_for_cookies)
849*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext::MakeInclusive();
850*6777b538SAndroid Build Coastguard Worker
851*6777b538SAndroid Build Coastguard Worker // If the URL is same-site as site_for_cookies it's same-site as all frames
852*6777b538SAndroid Build Coastguard Worker // in the tree from the initiator frame up --- including the initiator frame.
853*6777b538SAndroid Build Coastguard Worker
854*6777b538SAndroid Build Coastguard Worker // Schemeless check
855*6777b538SAndroid Build Coastguard Worker if (!site_for_cookies.IsFirstPartyWithSchemefulMode(url, false)) {
856*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext(ContextType::CROSS_SITE,
857*6777b538SAndroid Build Coastguard Worker ContextType::CROSS_SITE);
858*6777b538SAndroid Build Coastguard Worker }
859*6777b538SAndroid Build Coastguard Worker
860*6777b538SAndroid Build Coastguard Worker // Schemeful check
861*6777b538SAndroid Build Coastguard Worker if (!site_for_cookies.IsFirstPartyWithSchemefulMode(url, true)) {
862*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext(ContextType::SAME_SITE_STRICT,
863*6777b538SAndroid Build Coastguard Worker ContextType::CROSS_SITE);
864*6777b538SAndroid Build Coastguard Worker }
865*6777b538SAndroid Build Coastguard Worker
866*6777b538SAndroid Build Coastguard Worker return CookieOptions::SameSiteCookieContext::MakeInclusive();
867*6777b538SAndroid Build Coastguard Worker }
868*6777b538SAndroid Build Coastguard Worker
IsPortBoundCookiesEnabled()869*6777b538SAndroid Build Coastguard Worker bool IsPortBoundCookiesEnabled() {
870*6777b538SAndroid Build Coastguard Worker return base::FeatureList::IsEnabled(features::kEnablePortBoundCookies);
871*6777b538SAndroid Build Coastguard Worker }
872*6777b538SAndroid Build Coastguard Worker
IsSchemeBoundCookiesEnabled()873*6777b538SAndroid Build Coastguard Worker bool IsSchemeBoundCookiesEnabled() {
874*6777b538SAndroid Build Coastguard Worker return base::FeatureList::IsEnabled(features::kEnableSchemeBoundCookies);
875*6777b538SAndroid Build Coastguard Worker }
876*6777b538SAndroid Build Coastguard Worker
IsOriginBoundCookiesPartiallyEnabled()877*6777b538SAndroid Build Coastguard Worker bool IsOriginBoundCookiesPartiallyEnabled() {
878*6777b538SAndroid Build Coastguard Worker return IsPortBoundCookiesEnabled() || IsSchemeBoundCookiesEnabled();
879*6777b538SAndroid Build Coastguard Worker }
880*6777b538SAndroid Build Coastguard Worker
IsTimeLimitedInsecureCookiesEnabled()881*6777b538SAndroid Build Coastguard Worker bool IsTimeLimitedInsecureCookiesEnabled() {
882*6777b538SAndroid Build Coastguard Worker return IsSchemeBoundCookiesEnabled() &&
883*6777b538SAndroid Build Coastguard Worker base::FeatureList::IsEnabled(features::kTimeLimitedInsecureCookies);
884*6777b538SAndroid Build Coastguard Worker }
885*6777b538SAndroid Build Coastguard Worker
IsSchemefulSameSiteEnabled()886*6777b538SAndroid Build Coastguard Worker bool IsSchemefulSameSiteEnabled() {
887*6777b538SAndroid Build Coastguard Worker return base::FeatureList::IsEnabled(features::kSchemefulSameSite);
888*6777b538SAndroid Build Coastguard Worker }
889*6777b538SAndroid Build Coastguard Worker
890*6777b538SAndroid Build Coastguard Worker std::optional<
891*6777b538SAndroid Build Coastguard Worker std::pair<FirstPartySetMetadata, FirstPartySetsCacheFilter::MatchInfo>>
ComputeFirstPartySetMetadataMaybeAsync(const SchemefulSite & request_site,const IsolationInfo & isolation_info,const CookieAccessDelegate * cookie_access_delegate,base::OnceCallback<void (FirstPartySetMetadata,FirstPartySetsCacheFilter::MatchInfo)> callback)892*6777b538SAndroid Build Coastguard Worker ComputeFirstPartySetMetadataMaybeAsync(
893*6777b538SAndroid Build Coastguard Worker const SchemefulSite& request_site,
894*6777b538SAndroid Build Coastguard Worker const IsolationInfo& isolation_info,
895*6777b538SAndroid Build Coastguard Worker const CookieAccessDelegate* cookie_access_delegate,
896*6777b538SAndroid Build Coastguard Worker base::OnceCallback<void(FirstPartySetMetadata,
897*6777b538SAndroid Build Coastguard Worker FirstPartySetsCacheFilter::MatchInfo)> callback) {
898*6777b538SAndroid Build Coastguard Worker if (cookie_access_delegate) {
899*6777b538SAndroid Build Coastguard Worker return cookie_access_delegate->ComputeFirstPartySetMetadataMaybeAsync(
900*6777b538SAndroid Build Coastguard Worker request_site,
901*6777b538SAndroid Build Coastguard Worker base::OptionalToPtr(
902*6777b538SAndroid Build Coastguard Worker isolation_info.network_isolation_key().GetTopFrameSite()),
903*6777b538SAndroid Build Coastguard Worker std::move(callback));
904*6777b538SAndroid Build Coastguard Worker }
905*6777b538SAndroid Build Coastguard Worker
906*6777b538SAndroid Build Coastguard Worker return std::pair(FirstPartySetMetadata(),
907*6777b538SAndroid Build Coastguard Worker FirstPartySetsCacheFilter::MatchInfo());
908*6777b538SAndroid Build Coastguard Worker }
909*6777b538SAndroid Build Coastguard Worker
910*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod
HttpMethodStringToEnum(const std::string & in)911*6777b538SAndroid Build Coastguard Worker HttpMethodStringToEnum(const std::string& in) {
912*6777b538SAndroid Build Coastguard Worker using HttpMethod =
913*6777b538SAndroid Build Coastguard Worker CookieOptions::SameSiteCookieContext::ContextMetadata::HttpMethod;
914*6777b538SAndroid Build Coastguard Worker if (in == "GET")
915*6777b538SAndroid Build Coastguard Worker return HttpMethod::kGet;
916*6777b538SAndroid Build Coastguard Worker if (in == "HEAD")
917*6777b538SAndroid Build Coastguard Worker return HttpMethod::kHead;
918*6777b538SAndroid Build Coastguard Worker if (in == "POST")
919*6777b538SAndroid Build Coastguard Worker return HttpMethod::kPost;
920*6777b538SAndroid Build Coastguard Worker if (in == "PUT")
921*6777b538SAndroid Build Coastguard Worker return HttpMethod::KPut;
922*6777b538SAndroid Build Coastguard Worker if (in == "DELETE")
923*6777b538SAndroid Build Coastguard Worker return HttpMethod::kDelete;
924*6777b538SAndroid Build Coastguard Worker if (in == "CONNECT")
925*6777b538SAndroid Build Coastguard Worker return HttpMethod::kConnect;
926*6777b538SAndroid Build Coastguard Worker if (in == "OPTIONS")
927*6777b538SAndroid Build Coastguard Worker return HttpMethod::kOptions;
928*6777b538SAndroid Build Coastguard Worker if (in == "TRACE")
929*6777b538SAndroid Build Coastguard Worker return HttpMethod::kTrace;
930*6777b538SAndroid Build Coastguard Worker if (in == "PATCH")
931*6777b538SAndroid Build Coastguard Worker return HttpMethod::kPatch;
932*6777b538SAndroid Build Coastguard Worker
933*6777b538SAndroid Build Coastguard Worker return HttpMethod::kUnknown;
934*6777b538SAndroid Build Coastguard Worker }
935*6777b538SAndroid Build Coastguard Worker
IsCookieAccessResultInclude(CookieAccessResult cookie_access_result)936*6777b538SAndroid Build Coastguard Worker bool IsCookieAccessResultInclude(CookieAccessResult cookie_access_result) {
937*6777b538SAndroid Build Coastguard Worker return cookie_access_result.status.IsInclude();
938*6777b538SAndroid Build Coastguard Worker }
939*6777b538SAndroid Build Coastguard Worker
StripAccessResults(const CookieAccessResultList & cookie_access_results_list)940*6777b538SAndroid Build Coastguard Worker CookieList StripAccessResults(
941*6777b538SAndroid Build Coastguard Worker const CookieAccessResultList& cookie_access_results_list) {
942*6777b538SAndroid Build Coastguard Worker CookieList cookies;
943*6777b538SAndroid Build Coastguard Worker for (const CookieWithAccessResult& cookie_with_access_result :
944*6777b538SAndroid Build Coastguard Worker cookie_access_results_list) {
945*6777b538SAndroid Build Coastguard Worker cookies.push_back(cookie_with_access_result.cookie);
946*6777b538SAndroid Build Coastguard Worker }
947*6777b538SAndroid Build Coastguard Worker return cookies;
948*6777b538SAndroid Build Coastguard Worker }
949*6777b538SAndroid Build Coastguard Worker
RecordCookiePortOmniboxHistograms(const GURL & url)950*6777b538SAndroid Build Coastguard Worker NET_EXPORT void RecordCookiePortOmniboxHistograms(const GURL& url) {
951*6777b538SAndroid Build Coastguard Worker int port = url.EffectiveIntPort();
952*6777b538SAndroid Build Coastguard Worker
953*6777b538SAndroid Build Coastguard Worker if (port == url::PORT_UNSPECIFIED)
954*6777b538SAndroid Build Coastguard Worker return;
955*6777b538SAndroid Build Coastguard Worker
956*6777b538SAndroid Build Coastguard Worker if (IsLocalhost(url)) {
957*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("Cookie.Port.OmniboxURLNavigation.Localhost",
958*6777b538SAndroid Build Coastguard Worker ReducePortRangeForCookieHistogram(port));
959*6777b538SAndroid Build Coastguard Worker } else {
960*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("Cookie.Port.OmniboxURLNavigation.RemoteHost",
961*6777b538SAndroid Build Coastguard Worker ReducePortRangeForCookieHistogram(port));
962*6777b538SAndroid Build Coastguard Worker }
963*6777b538SAndroid Build Coastguard Worker }
964*6777b538SAndroid Build Coastguard Worker
DCheckIncludedAndExcludedCookieLists(const CookieAccessResultList & included_cookies,const CookieAccessResultList & excluded_cookies)965*6777b538SAndroid Build Coastguard Worker NET_EXPORT void DCheckIncludedAndExcludedCookieLists(
966*6777b538SAndroid Build Coastguard Worker const CookieAccessResultList& included_cookies,
967*6777b538SAndroid Build Coastguard Worker const CookieAccessResultList& excluded_cookies) {
968*6777b538SAndroid Build Coastguard Worker // Check that all elements of `included_cookies` really should be included,
969*6777b538SAndroid Build Coastguard Worker // and that all elements of `excluded_cookies` really should be excluded.
970*6777b538SAndroid Build Coastguard Worker DCHECK(base::ranges::all_of(included_cookies,
971*6777b538SAndroid Build Coastguard Worker [](const net::CookieWithAccessResult& cookie) {
972*6777b538SAndroid Build Coastguard Worker return cookie.access_result.status.IsInclude();
973*6777b538SAndroid Build Coastguard Worker }));
974*6777b538SAndroid Build Coastguard Worker DCHECK(base::ranges::none_of(excluded_cookies,
975*6777b538SAndroid Build Coastguard Worker [](const net::CookieWithAccessResult& cookie) {
976*6777b538SAndroid Build Coastguard Worker return cookie.access_result.status.IsInclude();
977*6777b538SAndroid Build Coastguard Worker }));
978*6777b538SAndroid Build Coastguard Worker
979*6777b538SAndroid Build Coastguard Worker // Check that the included cookies are still in the correct order.
980*6777b538SAndroid Build Coastguard Worker DCHECK(
981*6777b538SAndroid Build Coastguard Worker base::ranges::is_sorted(included_cookies, CookieWithAccessResultSorter));
982*6777b538SAndroid Build Coastguard Worker }
983*6777b538SAndroid Build Coastguard Worker
IsForceThirdPartyCookieBlockingEnabled()984*6777b538SAndroid Build Coastguard Worker NET_EXPORT bool IsForceThirdPartyCookieBlockingEnabled() {
985*6777b538SAndroid Build Coastguard Worker return base::FeatureList::IsEnabled(
986*6777b538SAndroid Build Coastguard Worker features::kForceThirdPartyCookieBlocking) &&
987*6777b538SAndroid Build Coastguard Worker base::FeatureList::IsEnabled(features::kThirdPartyStoragePartitioning);
988*6777b538SAndroid Build Coastguard Worker }
989*6777b538SAndroid Build Coastguard Worker
990*6777b538SAndroid Build Coastguard Worker } // namespace net::cookie_util
991