1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_COOKIES_COOKIE_BASE_H_
#define NET_COOKIES_COOKIE_BASE_H_
#include <optional>
#include <string>
#include <tuple>
#include "base/types/pass_key.h"
#include "net/base/net_export.h"
#include "net/cookies/cookie_access_result.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_options.h"
#include "net/cookies/cookie_partition_key.h"
class GURL;
namespace net {
class RefUniqueCookieKey;
class UniqueCookieKey;
struct CookieAccessParams;
struct CookieAccessResult;
// A base class for cookies and cookie-like objects. Encapsulates logic for
// determining whether a cookie could be sent/set, based on its attributes and
// the request context.
class NET_EXPORT CookieBase {
public:
// Returns if the cookie should be included (and if not, why) for the given
// request |url| using the CookieInclusionStatus enum. HTTP only cookies can
// be filter by using appropriate cookie |options|.
//
// PLEASE NOTE that this method does not check whether a cookie is expired or
// not!
CookieAccessResult IncludeForRequestURL(
const GURL& url,
const CookieOptions& options,
const CookieAccessParams& params) const;
// Returns if the cookie with given attributes can be set in context described
// by |options| and |params|, and if no, describes why.
//
// |cookie_access_result| is an optional input status, to allow for status
// chaining from callers. It helps callers provide the status of a
// cookie that may have warnings associated with it.
CookieAccessResult IsSetPermittedInContext(
const GURL& source_url,
const CookieOptions& options,
const CookieAccessParams& params,
const std::vector<std::string>& cookieable_schemes,
const std::optional<CookieAccessResult>& cookie_access_result =
std::nullopt) const;
// Returns true if the given |url_path| path-matches this cookie's cookie-path
// as described in section 5.1.4 in RFC 6265. This returns true if |path_| and
// |url_path| are identical, or if |url_path| is a subdirectory of |path_|.
bool IsOnPath(const std::string& url_path) const;
// This returns true if this cookie's |domain_| indicates that it can be
// accessed by |host|.
//
// In the case where |domain_| has no leading dot, this is a host cookie and
// will only domain match if |host| is identical to |domain_|.
//
// In the case where |domain_| has a leading dot, this is a domain cookie. It
// will match |host| if |domain_| is a suffix of |host|, or if |domain_| is
// exactly equal to |host| plus a leading dot.
//
// Note that this isn't quite the same as the "domain-match" algorithm in RFC
// 6265bis, since our implementation uses the presence of a leading dot in the
// |domain_| string in place of the spec's host-only-flag. That is, if
// |domain_| has no leading dot, then we only consider it matching if |host|
// is identical (which reflects the intended behavior when the cookie has a
// host-only-flag), whereas the RFC also treats them as domain-matching if
// |domain_| is a subdomain of |host|.
bool IsDomainMatch(const std::string& host) const;
const std::string& Name() const { return name_; }
// We represent the cookie's host-only-flag as the absence of a leading dot in
// Domain(). See IsDomainCookie() and IsHostCookie() below.
// If you want the "cookie's domain" as described in RFC 6265bis, use
// DomainWithoutDot().
const std::string& Domain() const { return domain_; }
const std::string& Path() const { return path_; }
const base::Time& CreationDate() const { return creation_date_; }
bool SecureAttribute() const { return secure_; }
bool IsHttpOnly() const { return httponly_; }
CookieSameSite SameSite() const { return same_site_; }
// Returns true if this cookie can only be accessed in a secure context.
bool IsSecure() const;
bool IsPartitioned() const { return partition_key_.has_value(); }
const std::optional<CookiePartitionKey>& PartitionKey() const {
return partition_key_;
}
// Returns whether this cookie is Partitioned and its partition key matches a
// a same-site context by checking if the cookies domain site is the same as
// the partition key's site.
// This function should not be used for third-party cookie blocking
// enforcement-related decisions. That logic should rely on `IsPartitioned`.
// These functions are for recording metrics about partitioned cookie usage.
// Returns false if the cookie has no partition key.
bool IsFirstPartyPartitioned() const;
// Returns whether the cookie is partitioned in a third-party context.
// This function should not be used for third-party cookie blocking
// enforcement-related decisions. That logic should rely on `IsPartitioned`.
// These functions are for recording metrics about partitioned cookie usage.
// Returns false if the cookie has no partition key.
bool IsThirdPartyPartitioned() const;
// Returns an enum indicating the scheme of the origin that
// set this cookie. This is not part of the cookie spec but is being used to
// collect metrics for a potential change to the cookie spec
// (https://tools.ietf.org/html/draft-west-cookie-incrementalism-01#section-3.4)
CookieSourceScheme SourceScheme() const { return source_scheme_; }
// Returns the port of the origin that originally set this cookie (the
// source port). This is not part of the cookie spec but is being used to
// collect metrics for a potential change to the cookie spec.
int SourcePort() const { return source_port_; }
bool IsDomainCookie() const { return !domain_.empty() && domain_[0] == '.'; }
bool IsHostCookie() const { return !IsDomainCookie(); }
// Returns the cookie's domain, with the leading dot removed, if present.
// This corresponds to the "cookie's domain" as described in RFC 6265bis.
std::string DomainWithoutDot() const;
// StrictlyUniqueKey always includes the cookie's source scheme and source
// port.
UniqueCookieKey StrictlyUniqueKey() const;
// Returns a key such that two cookies with the same UniqueKey() are
// guaranteed to be equivalent in the sense of IsEquivalent().
// The `partition_key_` field will always be nullopt when partitioned cookies
// are not enabled.
// The source_scheme and source_port fields depend on whether or not their
// associated features are enabled.
UniqueCookieKey UniqueKey() const;
// Returns a non-owning key such that two cookies with the same RefUniqueKey()
// are guaranteed to be equivalent in the sense of IsEquivalent().
// The `partition_key_` field will always be nullopt when partitioned cookies
// are not enabled.
// The source_scheme and source_port fields depend on whether or not their
// associated features are enabled.
// A RefUniqueKey keeps references that point to data in the CookieBase, so it
// must not be stored beyond the lifetime of the CookieBase.
RefUniqueCookieKey RefUniqueKey() const;
// Same as UniqueKey() except it does not contain a source_port or
// source_scheme field. For use for determining aliasing cookies, which do not
// consider the source_port or source_scheme.
UniqueCookieKey LegacyUniqueKey() const;
void SetSourceScheme(CookieSourceScheme source_scheme) {
source_scheme_ = source_scheme;
}
// Set the source port value. Performs a range check and sets the port to
// url::PORT_INVALID if value isn't in [0,65535] or url::PORT_UNSPECIFIED.
void SetSourcePort(int port);
void SetCreationDate(const base::Time& date) { creation_date_ = date; }
protected:
CookieBase();
CookieBase(const CookieBase& other);
CookieBase(CookieBase&& other);
CookieBase& operator=(const CookieBase& other);
CookieBase& operator=(CookieBase&& other);
virtual ~CookieBase();
CookieBase(std::string name,
std::string domain,
std::string path,
base::Time creation,
bool secure,
bool httponly,
CookieSameSite same_site,
std::optional<CookiePartitionKey> partition_key,
CookieSourceScheme source_scheme = CookieSourceScheme::kUnset,
int source_port = url::PORT_UNSPECIFIED);
// Returns the effective SameSite mode to apply to this cookie. Depends on the
// value of the given SameSite attribute and the access semantics of the
// cookie.
// Note: If you are converting to a different representation of a cookie, you
// probably want to use SameSite() instead of this method. Otherwise, if you
// are considering using this method, consider whether you should use
// IncludeForRequestURL() or IsSetPermittedInContext() instead of doing the
// SameSite computation yourself.
CookieEffectiveSameSite GetEffectiveSameSite(
CookieAccessSemantics access_semantics) const;
// Returns the threshold age for lax-allow-unsafe behavior, below which the
// effective SameSite behavior for a cookie that does not specify SameSite is
// lax-allow-unsafe, and above which the effective SameSite is just lax.
// Lax-allow-unsafe behavior (a.k.a. Lax+POST) is a temporary mitigation for
// compatibility reasons that allows a cookie which doesn't specify SameSite
// to still be sent on non-safe requests like POST requests for a short amount
// of time after creation, despite the default enforcement for most (i.e.
// older) SameSite-unspecified cookies being Lax. Implementations should
// override this method if they want to enable Lax-allow-unsafe behavior; by
// default, this method returns base::TimeDelta::Min(), i.e. no cookies will
// ever be lax-allow-unsafe.
virtual base::TimeDelta GetLaxAllowUnsafeThresholdAge() const;
// Returns whether the cookie was created at most |age_threshold| ago.
bool IsRecentlyCreated(base::TimeDelta age_threshold) const;
// Checks if `port` is within [0,65535] or url::PORT_UNSPECIFIED. Returns
// `port` if so and url::PORT_INVALID otherwise.
static int ValidateAndAdjustSourcePort(int port);
private:
// Allows subclasses to add custom logic for e.g. logging metrics. Called
// after inclusion has been determined for the respective access.
virtual void PostIncludeForRequestURL(
const CookieAccessResult& access_result,
const CookieOptions& options_used,
CookieOptions::SameSiteCookieContext::ContextType
cookie_inclusion_context_used) const {}
virtual void PostIsSetPermittedInContext(
const CookieAccessResult& access_result,
const CookieOptions& options_used) const {}
// Keep defaults here in sync with
// services/network/public/interfaces/cookie_manager.mojom.
std::string name_;
std::string domain_;
std::string path_;
base::Time creation_date_;
bool secure_{false};
bool httponly_{false};
CookieSameSite same_site_{CookieSameSite::NO_RESTRICTION};
// This will be std::nullopt for all cookies not set with the Partitioned
// attribute or without a nonce. If the value is non-null, then the cookie
// will only be delivered when the top-frame site matches the partition key
// and the nonce (if present). If the partition key is non-null and opaque,
// this means the Partitioned cookie was created on an opaque origin or with
// a nonce.
std::optional<CookiePartitionKey> partition_key_;
CookieSourceScheme source_scheme_{CookieSourceScheme::kUnset};
// This can be [0,65535], PORT_UNSPECIFIED, or PORT_INVALID.
// PORT_UNSPECIFIED is used for cookies which already existed in the cookie
// store prior to this change and therefore their port is unknown.
// PORT_INVALID is an error for when an out of range port is provided.
int source_port_{url::PORT_UNSPECIFIED};
};
} // namespace net
#endif // NET_COOKIES_COOKIE_BASE_H_
|