1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef NET_COOKIES_CANONICAL_COOKIE_H_
6 #define NET_COOKIES_CANONICAL_COOKIE_H_
7
8 #include <memory>
9 #include <string>
10 #include <tuple>
11 #include <vector>
12
13 #include "base/feature_list.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/strings/string_piece.h"
16 #include "base/time/time.h"
17 #include "base/types/pass_key.h"
18 #include "net/base/features.h"
19 #include "net/base/net_export.h"
20 #include "net/cookies/cookie_access_result.h"
21 #include "net/cookies/cookie_constants.h"
22 #include "net/cookies/cookie_inclusion_status.h"
23 #include "net/cookies/cookie_options.h"
24 #include "net/cookies/cookie_partition_key.h"
25 #include "third_party/abseil-cpp/absl/types/optional.h"
26 #include "url/third_party/mozilla/url_parse.h"
27
28 class GURL;
29
30 namespace net {
31
32 class ParsedCookie;
33 class CanonicalCookie;
34
35 struct CookieWithAccessResult;
36 struct CookieAndLineWithAccessResult;
37
38 using CookieList = std::vector<CanonicalCookie>;
39 using CookieAndLineAccessResultList =
40 std::vector<CookieAndLineWithAccessResult>;
41 using CookieAccessResultList = std::vector<CookieWithAccessResult>;
42
43 struct NET_EXPORT CookieAccessParams {
44 CookieAccessParams() = delete;
45 CookieAccessParams(CookieAccessSemantics access_semantics,
46 bool delegate_treats_url_as_trustworthy,
47 CookieSamePartyStatus same_party_status);
48
49 // |access_semantics| is the access mode of the cookie access check.
50 CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN;
51 // |delegate_treats_url_as_trustworthy| should be true iff the
52 // CookieAccessDelegate has authorized access to secure cookies from URLs
53 // which might not otherwise be able to do so.
54 bool delegate_treats_url_as_trustworthy = false;
55 // |same_party_status| indicates whether, and how, SameParty restrictions
56 // should be enforced.
57 CookieSamePartyStatus same_party_status =
58 CookieSamePartyStatus::kNoSamePartyEnforcement;
59 };
60
61 class NET_EXPORT CanonicalCookie {
62 public:
63 using UniqueCookieKey = std::tuple<absl::optional<CookiePartitionKey>,
64 std::string,
65 std::string,
66 std::string>;
67
68 CanonicalCookie();
69 CanonicalCookie(const CanonicalCookie& other);
70 CanonicalCookie(CanonicalCookie&& other);
71 CanonicalCookie& operator=(const CanonicalCookie& other);
72 CanonicalCookie& operator=(CanonicalCookie&& other);
73 ~CanonicalCookie();
74
75 // This constructor does not validate or canonicalize their inputs;
76 // the resulting CanonicalCookies should not be relied on to be canonical
77 // unless the caller has done appropriate validation and canonicalization
78 // themselves.
79 // NOTE: Prefer using CreateSanitizedCookie() over directly using this
80 // constructor.
81 CanonicalCookie(base::PassKey<CanonicalCookie>,
82 std::string name,
83 std::string value,
84 std::string domain,
85 std::string path,
86 base::Time creation,
87 base::Time expiration,
88 base::Time last_access,
89 base::Time last_update,
90 bool secure,
91 bool httponly,
92 CookieSameSite same_site,
93 CookiePriority priority,
94 bool same_party,
95 absl::optional<CookiePartitionKey> partition_key,
96 CookieSourceScheme scheme_secure = CookieSourceScheme::kUnset,
97 int source_port = url::PORT_UNSPECIFIED);
98
99 // Creates a new |CanonicalCookie| from the |cookie_line| and the
100 // |creation_time|. Canonicalizes inputs. May return nullptr if
101 // an attribute value is invalid. |url| must be valid. |creation_time| may
102 // not be null. Sets optional |status| to the relevant CookieInclusionStatus
103 // if provided. |server_time| indicates what the server sending us the Cookie
104 // thought the current time was when the cookie was produced. This is used to
105 // adjust for clock skew between server and host.
106 //
107 // SameSite and HttpOnly related parameters are not checked here,
108 // so creation of CanonicalCookies with e.g. SameSite=Strict from a cross-site
109 // context is allowed. Create() also does not check whether |url| has a secure
110 // scheme if attempting to create a Secure cookie. The Secure, SameSite, and
111 // HttpOnly related parameters should be checked when setting the cookie in
112 // the CookieStore.
113 //
114 // The partition_key argument only needs to be present if the cookie line
115 // contains the Partitioned attribute. If the cookie line will never contain
116 // that attribute, you should use absl::nullopt to indicate you intend to
117 // always create an unpartitioned cookie. If partition_key has a value but the
118 // cookie line does not contain the Partitioned attribute, the resulting
119 // cookie will be unpartitioned. If the partition_key is null, then the cookie
120 // will be unpartitioned even when the cookie line has the Partitioned
121 // attribute.
122 //
123 // If a cookie is returned, |cookie->IsCanonical()| will be true.
124 static std::unique_ptr<CanonicalCookie> Create(
125 const GURL& url,
126 const std::string& cookie_line,
127 const base::Time& creation_time,
128 absl::optional<base::Time> server_time,
129 absl::optional<CookiePartitionKey> cookie_partition_key,
130 CookieInclusionStatus* status = nullptr);
131
132 // Create a canonical cookie based on sanitizing the passed inputs in the
133 // context of the passed URL. Returns a null unique pointer if the inputs
134 // cannot be sanitized. If `status` is provided it will have any relevant
135 // CookieInclusionStatus rejection reasons set. If a cookie is created,
136 // `cookie->IsCanonical()` will be true.
137 static std::unique_ptr<CanonicalCookie> CreateSanitizedCookie(
138 const GURL& url,
139 const std::string& name,
140 const std::string& value,
141 const std::string& domain,
142 const std::string& path,
143 base::Time creation_time,
144 base::Time expiration_time,
145 base::Time last_access_time,
146 bool secure,
147 bool http_only,
148 CookieSameSite same_site,
149 CookiePriority priority,
150 bool same_party,
151 absl::optional<CookiePartitionKey> partition_key,
152 CookieInclusionStatus* status = nullptr);
153
154 // FromStorage is a factory method which is meant for creating a new
155 // CanonicalCookie using properties of a previously existing cookie
156 // that was already ingested into the cookie store.
157 // This should NOT be used to create a new CanonicalCookie that was not
158 // already in the store.
159 // Returns nullptr if the resulting cookie is not canonical,
160 // i.e. cc->IsCanonical() returns false.
161 static std::unique_ptr<CanonicalCookie> FromStorage(
162 std::string name,
163 std::string value,
164 std::string domain,
165 std::string path,
166 base::Time creation,
167 base::Time expiration,
168 base::Time last_access,
169 base::Time last_update,
170 bool secure,
171 bool httponly,
172 CookieSameSite same_site,
173 CookiePriority priority,
174 bool same_party,
175 absl::optional<CookiePartitionKey> partition_key,
176 CookieSourceScheme source_scheme,
177 int source_port);
178
179 // Create a CanonicalCookie that is not guaranteed to actually be Canonical
180 // for tests. This factory should NOT be used in production.
181 static std::unique_ptr<CanonicalCookie> CreateUnsafeCookieForTesting(
182 const std::string& name,
183 const std::string& value,
184 const std::string& domain,
185 const std::string& path,
186 const base::Time& creation,
187 const base::Time& expiration,
188 const base::Time& last_access,
189 const base::Time& last_update,
190 bool secure,
191 bool httponly,
192 CookieSameSite same_site,
193 CookiePriority priority,
194 bool same_party,
195 absl::optional<CookiePartitionKey> partition_key = absl::nullopt,
196 CookieSourceScheme scheme_secure = CookieSourceScheme::kUnset,
197 int source_port = url::PORT_UNSPECIFIED);
198
199 bool operator<(const CanonicalCookie& other) const {
200 // Use the cookie properties that uniquely identify a cookie to determine
201 // ordering.
202 return UniqueKey() < other.UniqueKey();
203 }
204
Name()205 const std::string& Name() const { return name_; }
Value()206 const std::string& Value() const { return value_; }
207 // We represent the cookie's host-only-flag as the absence of a leading dot in
208 // Domain(). See IsDomainCookie() and IsHostCookie() below.
209 // If you want the "cookie's domain" as described in RFC 6265bis, use
210 // DomainWithoutDot().
Domain()211 const std::string& Domain() const { return domain_; }
Path()212 const std::string& Path() const { return path_; }
CreationDate()213 const base::Time& CreationDate() const { return creation_date_; }
ExpiryDate()214 const base::Time& ExpiryDate() const { return expiry_date_; }
LastAccessDate()215 const base::Time& LastAccessDate() const { return last_access_date_; }
LastUpdateDate()216 const base::Time& LastUpdateDate() const { return last_update_date_; }
IsPersistent()217 bool IsPersistent() const { return !expiry_date_.is_null(); }
IsSecure()218 bool IsSecure() const { return secure_; }
IsHttpOnly()219 bool IsHttpOnly() const { return httponly_; }
SameSite()220 CookieSameSite SameSite() const { return same_site_; }
Priority()221 CookiePriority Priority() const { return priority_; }
IsSameParty()222 bool IsSameParty() const { return same_party_; }
IsPartitioned()223 bool IsPartitioned() const { return partition_key_.has_value(); }
PartitionKey()224 const absl::optional<CookiePartitionKey>& PartitionKey() const {
225 return partition_key_;
226 }
227
228 // Returns an enum indicating the scheme of the origin that
229 // set this cookie. This is not part of the cookie spec but is being used to
230 // collect metrics for a potential change to the cookie spec
231 // (https://tools.ietf.org/html/draft-west-cookie-incrementalism-01#section-3.4)
SourceScheme()232 CookieSourceScheme SourceScheme() const { return source_scheme_; }
233 // Returns the port of the origin that originally set this cookie (the
234 // source port). This is not part of the cookie spec but is being used to
235 // collect metrics for a potential change to the cookie spec.
SourcePort()236 int SourcePort() const { return source_port_; }
IsDomainCookie()237 bool IsDomainCookie() const {
238 return !domain_.empty() && domain_[0] == '.'; }
IsHostCookie()239 bool IsHostCookie() const { return !IsDomainCookie(); }
240
241 // Returns the cookie's domain, with the leading dot removed, if present.
242 // This corresponds to the "cookie's domain" as described in RFC 6265bis.
243 std::string DomainWithoutDot() const;
244
IsExpired(const base::Time & current)245 bool IsExpired(const base::Time& current) const {
246 return !expiry_date_.is_null() && current >= expiry_date_;
247 }
248
249 // Are the cookies considered equivalent in the eyes of RFC 2965.
250 // The RFC says that name must match (case-sensitive), domain must
251 // match (case insensitive), and path must match (case sensitive).
252 // For the case insensitive domain compare, we rely on the domain
253 // having been canonicalized (in
254 // GetCookieDomainWithString->CanonicalizeHost).
255 // If partitioned cookies are enabled, then we check the cookies have the same
256 // partition key in addition to the checks in RFC 2965.
IsEquivalent(const CanonicalCookie & ecc)257 bool IsEquivalent(const CanonicalCookie& ecc) const {
258 // It seems like it would make sense to take secure, httponly, and samesite
259 // into account, but the RFC doesn't specify this.
260 // NOTE: Keep this logic in-sync with TrimDuplicateCookiesForKey().
261 return UniqueKey() == ecc.UniqueKey();
262 }
263
264 // Returns a key such that two cookies with the same UniqueKey() are
265 // guaranteed to be equivalent in the sense of IsEquivalent().
266 // The `partition_key_` field will always be nullopt when partitioned cookies
267 // are not enabled.
UniqueKey()268 UniqueCookieKey UniqueKey() const {
269 return std::make_tuple(partition_key_, name_, domain_, path_);
270 }
271
272 // Checks a looser set of equivalency rules than 'IsEquivalent()' in order
273 // to support the stricter 'Secure' behaviors specified in Step 12 of
274 // https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05#section-5.4
275 // which originated from the proposal in
276 // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone#section-3
277 //
278 // Returns 'true' if this cookie's name matches |secure_cookie|, and this
279 // cookie is a domain-match for |secure_cookie| (or vice versa), and
280 // |secure_cookie|'s path is "on" this cookie's path (as per 'IsOnPath()').
281 // If partitioned cookies are enabled, it also checks that the cookie has
282 // the same partition key as |secure_cookie|.
283 //
284 // Note that while the domain-match cuts both ways (e.g. 'example.com'
285 // matches 'www.example.com' in either direction), the path-match is
286 // unidirectional (e.g. '/login/en' matches '/login' and '/', but
287 // '/login' and '/' do not match '/login/en').
288 //
289 // Conceptually:
290 // If new_cookie.IsEquivalentForSecureCookieMatching(secure_cookie) is true,
291 // this means that new_cookie would "shadow" secure_cookie: they would would
292 // be indistinguishable when serialized into a Cookie header. This is
293 // important because, if an attacker is attempting to set new_cookie, it
294 // should not be allowed to mislead the server into using new_cookie's value
295 // instead of secure_cookie's.
296 //
297 // The reason for the asymmetric path comparison ("cookie1=bad; path=/a/b"
298 // from an insecure source is not allowed if "cookie1=good; secure; path=/a"
299 // exists, but "cookie2=bad; path=/a" from an insecure source is allowed if
300 // "cookie2=good; secure; path=/a/b" exists) is because cookies in the Cookie
301 // header are serialized with longer path first. (See CookieSorter in
302 // cookie_monster.cc.) That is, they would be serialized as "Cookie:
303 // cookie1=bad; cookie1=good" in one case, and "Cookie: cookie2=good;
304 // cookie2=bad" in the other case. The first scenario is not allowed because
305 // the attacker injects the bad value, whereas the second scenario is ok
306 // because the good value is still listed first.
307 bool IsEquivalentForSecureCookieMatching(
308 const CanonicalCookie& secure_cookie) const;
309
310 // Returns true if the |other| cookie's data members (instance variables)
311 // match, for comparing cookies in colletions.
HasEquivalentDataMembers(const CanonicalCookie & other)312 bool HasEquivalentDataMembers(const CanonicalCookie& other) const {
313 return creation_date_ == other.creation_date_ &&
314 last_access_date_ == other.last_access_date_ &&
315 expiry_date_ == other.expiry_date_ && secure_ == other.secure_ &&
316 httponly_ == other.httponly_ && same_site_ == other.same_site_ &&
317 priority_ == other.priority_ && same_party_ == other.same_party_ &&
318 partition_key_ == other.partition_key_ && name_ == other.name_ &&
319 value_ == other.value_ && domain_ == other.domain_ &&
320 path_ == other.path_ && last_update_date_ == other.last_update_date_;
321 }
322
SetSourceScheme(CookieSourceScheme source_scheme)323 void SetSourceScheme(CookieSourceScheme source_scheme) {
324 source_scheme_ = source_scheme;
325 }
326
327 // Set the source port value. Performs a range check and sets the port to
328 // url::PORT_INVALID if value isn't in [0,65535] or url::PORT_UNSPECIFIED.
329 void SetSourcePort(int port);
330
SetLastAccessDate(const base::Time & date)331 void SetLastAccessDate(const base::Time& date) {
332 last_access_date_ = date;
333 }
SetCreationDate(const base::Time & date)334 void SetCreationDate(const base::Time& date) { creation_date_ = date; }
335
336 // Returns true if the given |url_path| path-matches this cookie's cookie-path
337 // as described in section 5.1.4 in RFC 6265. This returns true if |path_| and
338 // |url_path| are identical, or if |url_path| is a subdirectory of |path_|.
339 bool IsOnPath(const std::string& url_path) const;
340
341 // This returns true if this cookie's |domain_| indicates that it can be
342 // accessed by |host|.
343 //
344 // In the case where |domain_| has no leading dot, this is a host cookie and
345 // will only domain match if |host| is identical to |domain_|.
346 //
347 // In the case where |domain_| has a leading dot, this is a domain cookie. It
348 // will match |host| if |domain_| is a suffix of |host|, or if |domain_| is
349 // exactly equal to |host| plus a leading dot.
350 //
351 // Note that this isn't quite the same as the "domain-match" algorithm in RFC
352 // 6265bis, since our implementation uses the presence of a leading dot in the
353 // |domain_| string in place of the spec's host-only-flag. That is, if
354 // |domain_| has no leading dot, then we only consider it matching if |host|
355 // is identical (which reflects the intended behavior when the cookie has a
356 // host-only-flag), whereas the RFC also treats them as domain-matching if
357 // |domain_| is a subdomain of |host|.
358 bool IsDomainMatch(const std::string& host) const;
359
360 // Returns if the cookie should be included (and if not, why) for the given
361 // request |url| using the CookieInclusionStatus enum. HTTP only cookies can
362 // be filter by using appropriate cookie |options|.
363 //
364 // PLEASE NOTE that this method does not check whether a cookie is expired or
365 // not!
366 CookieAccessResult IncludeForRequestURL(
367 const GURL& url,
368 const CookieOptions& options,
369 const CookieAccessParams& params) const;
370
371 // Returns if the cookie with given attributes can be set in context described
372 // by |options| and |params|, and if no, describes why.
373 //
374 // |cookie_access_result| is an optional input status, to allow for status
375 // chaining from callers. It helps callers provide the status of a
376 // canonical cookie that may have warnings associated with it.
377 CookieAccessResult IsSetPermittedInContext(
378 const GURL& source_url,
379 const CookieOptions& options,
380 const CookieAccessParams& params,
381 const std::vector<std::string>& cookieable_schemes,
382 const absl::optional<CookieAccessResult>& cookie_access_result =
383 absl::nullopt) const;
384
385 std::string DebugString() const;
386
387 // Returns the canonical path based on the specified url and path attribute
388 // value. Note that this method does not enforce character set or size
389 // checks on `path_string`.
390 static std::string CanonPathWithString(const GURL& url,
391 const std::string& path_string);
392
393 // Returns a "null" time if expiration was unspecified or invalid.
394 static base::Time ParseExpiration(const ParsedCookie& pc,
395 const base::Time& current,
396 const base::Time& server_time);
397
398 // Per rfc6265bis the maximum expiry date is no further than 400 days in the
399 // future. Clamping only occurs when kClampCookieExpiryTo400Days is enabled.
400 static base::Time ValidateAndAdjustExpiryDate(
401 const base::Time& expiry_date,
402 const base::Time& creation_date);
403
404 // Cookie ordering methods.
405
406 // Returns true if the cookie is less than |other|, considering only name,
407 // domain and path. In particular, two equivalent cookies (see IsEquivalent())
408 // are identical for PartialCompare().
409 bool PartialCompare(const CanonicalCookie& other) const;
410
411 // Return whether this object is a valid CanonicalCookie(). Invalid
412 // cookies may be constructed by the detailed constructor.
413 // A cookie is considered canonical if-and-only-if:
414 // * It can be created by CanonicalCookie::Create, or
415 // * It is identical to a cookie created by CanonicalCookie::Create except
416 // that the creation time is null, or
417 // * It can be derived from a cookie created by CanonicalCookie::Create by
418 // entry into and retrieval from a cookie store (specifically, this means
419 // by the setting of an creation time in place of a null creation time, and
420 // the setting of a last access time).
421 // An additional requirement on a CanonicalCookie is that if the last
422 // access time is non-null, the creation time must also be non-null and
423 // greater than the last access time.
424 bool IsCanonical() const;
425
426 // Return whether this object is a valid CanonicalCookie() when retrieving the
427 // cookie from the persistent store. Cookie that exist in the persistent store
428 // may have been created before more recent changes to the definition of
429 // "canonical". To ease the transition to the new definitions, and to prevent
430 // users from having their cookies deleted, this function supports the older
431 // definition of canonical. This function is intended to be temporary because
432 // as the number of older cookies (which are non-compliant with the newer
433 // definition of canonical) decay toward zero it can eventually be replaced
434 // by `IsCanonical()` to enforce the newer definition of canonical.
435 //
436 // A cookie is considered canonical by this function if-and-only-if:
437 // * It is considered canonical by IsCanonical()
438 // * TODO(crbug.com/1244172): Add exceptions once IsCanonical() starts
439 // enforcing them.
440 bool IsCanonicalForFromStorage() const;
441
442 // Returns whether the effective SameSite mode is SameSite=None (i.e. no
443 // SameSite restrictions).
444 bool IsEffectivelySameSiteNone(CookieAccessSemantics access_semantics =
445 CookieAccessSemantics::UNKNOWN) const;
446
447 CookieEffectiveSameSite GetEffectiveSameSiteForTesting(
448 CookieAccessSemantics access_semantics =
449 CookieAccessSemantics::UNKNOWN) const;
450
451 // Returns the cookie line (e.g. "cookie1=value1; cookie2=value2") represented
452 // by |cookies|. The string is built in the same order as the given list.
453 static std::string BuildCookieLine(const CookieList& cookies);
454
455 // Same as above but takes a CookieAccessResultList
456 // (ignores the access result).
457 static std::string BuildCookieLine(const CookieAccessResultList& cookies);
458
459 // Takes a single CanonicalCookie and returns a cookie line containing the
460 // attributes of |cookie| formatted like a http set cookie header.
461 // (e.g. "cookie1=value1; domain=abc.com; path=/; secure").
462 static std::string BuildCookieAttributesLine(const CanonicalCookie& cookie);
463
464 private:
465 FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestPrefixHistograms);
466 FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestHasHiddenPrefixName);
467
468 // The special cookie prefixes as defined in
469 // https://tools.ietf.org/html/draft-west-cookie-prefixes
470 //
471 // This enum is being histogrammed; do not reorder or remove values.
472 enum CookiePrefix {
473 COOKIE_PREFIX_NONE = 0,
474 COOKIE_PREFIX_SECURE,
475 COOKIE_PREFIX_HOST,
476 COOKIE_PREFIX_LAST
477 };
478
479 // Returns the CookiePrefix (or COOKIE_PREFIX_NONE if none) that
480 // applies to the given cookie |name|.
GetCookiePrefix(const std::string & name)481 static CookiePrefix GetCookiePrefix(const std::string& name) {
482 return GetCookiePrefix(name,
483 base::FeatureList::IsEnabled(
484 net::features::kCaseInsensitiveCookiePrefix));
485 }
486
487 // Returns the CookiePrefix (or COOKIE_PREFIX_NONE if none) that
488 // applies to the given cookie |name|. If `check_insensitively` is true then
489 // the string comparison will be performed case insensitively.
490 static CookiePrefix GetCookiePrefix(const std::string& name,
491 bool check_insensitively);
492 // Records histograms to measure how often cookie prefixes appear in
493 // the wild and how often they would be blocked.
494 static void RecordCookiePrefixMetrics(CookiePrefix prefix_case_sensitive,
495 CookiePrefix prefix_case_insensitive,
496 bool is_insensitive_prefix_valid);
497 // Returns true if a prefixed cookie does not violate any of the rules
498 // for that cookie.
499 static bool IsCookiePrefixValid(CookiePrefix prefix,
500 const GURL& url,
501 const ParsedCookie& parsed_cookie);
502 static bool IsCookiePrefixValid(CookiePrefix prefix,
503 const GURL& url,
504 bool secure,
505 const std::string& domain,
506 const std::string& path);
507
508 // Returns the effective SameSite mode to apply to this cookie. Depends on the
509 // value of the given SameSite attribute and the access semantics of the
510 // cookie.
511 // Note: If you are converting to a different representation of a cookie, you
512 // probably want to use SameSite() instead of this method. Otherwise, if you
513 // are considering using this method, consider whether you should use
514 // IncludeForRequestURL() or IsSetPermittedInContext() instead of doing the
515 // SameSite computation yourself.
516 CookieEffectiveSameSite GetEffectiveSameSite(
517 CookieAccessSemantics access_semantics) const;
518
519 // Checks for values that could be misinterpreted as a cookie name prefix.
520 static bool HasHiddenPrefixName(const base::StringPiece cookie_value);
521
522 // Returns whether the cookie was created at most |age_threshold| ago.
523 bool IsRecentlyCreated(base::TimeDelta age_threshold) const;
524
525 // Returns true iff the cookie does not violate any rules associated with
526 // creating a cookie with the SameParty attribute. In particular, if a cookie
527 // has SameParty, then it must be Secure and must not be SameSite=Strict.
528 static bool IsCookieSamePartyValid(const ParsedCookie& parsed_cookie);
529 static bool IsCookieSamePartyValid(bool is_same_party,
530 bool is_secure,
531 CookieSameSite same_site);
532
533 // Returns true iff the cookie is a partitioned cookie with a nonce or that
534 // does not violate the semantics of the Partitioned attribute:
535 // - Must have the Secure attribute OR the cookie partition contains a nonce.
536 static bool IsCookiePartitionedValid(const GURL& url,
537 const ParsedCookie& parsed_cookie,
538 bool partition_has_nonce);
539 static bool IsCookiePartitionedValid(const GURL& url,
540 bool secure,
541 bool is_partitioned,
542 bool partition_has_nonce);
543
544 // Keep defaults here in sync with
545 // services/network/public/interfaces/cookie_manager.mojom.
546 std::string name_;
547 std::string value_;
548 std::string domain_;
549 std::string path_;
550 base::Time creation_date_;
551 base::Time expiry_date_;
552 base::Time last_access_date_;
553 base::Time last_update_date_;
554 bool secure_{false};
555 bool httponly_{false};
556 CookieSameSite same_site_{CookieSameSite::NO_RESTRICTION};
557 CookiePriority priority_{COOKIE_PRIORITY_MEDIUM};
558 bool same_party_{false};
559 // This will be absl::nullopt for all cookies not set with the Partitioned
560 // attribute or without a nonce. If the value is non-null, then the cookie
561 // will only be delivered when the top-frame site matches the partition key
562 // and the nonce (if present). If the partition key is non-null and opaque,
563 // this means the Partitioned cookie was created on an opaque origin or with
564 // a nonce.
565 absl::optional<CookiePartitionKey> partition_key_;
566 CookieSourceScheme source_scheme_{CookieSourceScheme::kUnset};
567 // This can be [0,65535], PORT_UNSPECIFIED, or PORT_INVALID.
568 // PORT_UNSPECIFIED is used for cookies which already existed in the cookie
569 // store prior to this change and therefore their port is unknown.
570 // PORT_INVALID is an error for when an out of range port is provided.
571 int source_port_{url::PORT_UNSPECIFIED};
572 };
573
574 // Used to pass excluded cookie information when it's possible that the
575 // canonical cookie object may not be available.
576 struct NET_EXPORT CookieAndLineWithAccessResult {
577 CookieAndLineWithAccessResult();
578 CookieAndLineWithAccessResult(absl::optional<CanonicalCookie> cookie,
579 std::string cookie_string,
580 CookieAccessResult access_result);
581 CookieAndLineWithAccessResult(
582 const CookieAndLineWithAccessResult& cookie_and_line_with_access_result);
583
584 CookieAndLineWithAccessResult& operator=(
585 const CookieAndLineWithAccessResult& cookie_and_line_with_access_result);
586
587 CookieAndLineWithAccessResult(
588 CookieAndLineWithAccessResult&& cookie_and_line_with_access_result);
589
590 ~CookieAndLineWithAccessResult();
591
592 absl::optional<CanonicalCookie> cookie;
593 std::string cookie_string;
594 CookieAccessResult access_result;
595 };
596
597 struct CookieWithAccessResult {
598 CanonicalCookie cookie;
599 CookieAccessResult access_result;
600 };
601
602 // Provided to allow gtest to create more helpful error messages, instead of
603 // printing hex.
PrintTo(const CanonicalCookie & cc,std::ostream * os)604 inline void PrintTo(const CanonicalCookie& cc, std::ostream* os) {
605 *os << "{ name=" << cc.Name() << ", value=" << cc.Value() << " }";
606 }
PrintTo(const CookieWithAccessResult & cwar,std::ostream * os)607 inline void PrintTo(const CookieWithAccessResult& cwar, std::ostream* os) {
608 *os << "{ ";
609 PrintTo(cwar.cookie, os);
610 *os << ", ";
611 PrintTo(cwar.access_result, os);
612 *os << " }";
613 }
PrintTo(const CookieAndLineWithAccessResult & calwar,std::ostream * os)614 inline void PrintTo(const CookieAndLineWithAccessResult& calwar,
615 std::ostream* os) {
616 *os << "{ ";
617 if (calwar.cookie) {
618 PrintTo(*calwar.cookie, os);
619 } else {
620 *os << "nullopt";
621 }
622 *os << ", " << calwar.cookie_string << ", ";
623 PrintTo(calwar.access_result, os);
624 *os << " }";
625 }
626
627 } // namespace net
628
629 #endif // NET_COOKIES_CANONICAL_COOKIE_H_
630