// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef NET_COOKIES_CANONICAL_COOKIE_H_ #define NET_COOKIES_CANONICAL_COOKIE_H_ #include #include #include #include "base/gtest_prod_util.h" #include "base/time/time.h" #include "net/base/net_export.h" #include "net/cookies/cookie_constants.h" #include "net/cookies/cookie_options.h" class GURL; namespace net { class ParsedCookie; class NET_EXPORT CanonicalCookie { public: CanonicalCookie(); CanonicalCookie(const CanonicalCookie& other); // This constructor does not validate or canonicalize their inputs; // the resulting CanonicalCookies should not be relied on to be canonical // unless the caller has done appropriate validation and canonicalization // themselves. CanonicalCookie(const std::string& name, const std::string& value, const std::string& domain, const std::string& path, const base::Time& creation, const base::Time& expiration, const base::Time& last_access, bool secure, bool httponly, CookieSameSite same_site, CookiePriority priority); ~CanonicalCookie(); // Supports the default copy constructor. // Creates a new |CanonicalCookie| from the |cookie_line| and the // |creation_time|. Canonicalizes and validates inputs. May return NULL if // an attribute value is invalid. |creation_time| may not be null. static std::unique_ptr Create( const GURL& url, const std::string& cookie_line, const base::Time& creation_time, const CookieOptions& options); const std::string& Name() const { return name_; } const std::string& Value() const { return value_; } const std::string& Domain() const { return domain_; } const std::string& Path() const { return path_; } const base::Time& CreationDate() const { return creation_date_; } const base::Time& LastAccessDate() const { return last_access_date_; } bool IsPersistent() const { return !expiry_date_.is_null(); } const base::Time& ExpiryDate() const { return expiry_date_; } bool IsSecure() const { return secure_; } bool IsHttpOnly() const { return httponly_; } CookieSameSite SameSite() const { return same_site_; } CookiePriority Priority() const { return priority_; } bool IsDomainCookie() const { return !domain_.empty() && domain_[0] == '.'; } bool IsHostCookie() const { return !IsDomainCookie(); } bool IsExpired(const base::Time& current) const { return !expiry_date_.is_null() && current >= expiry_date_; } // Are the cookies considered equivalent in the eyes of RFC 2965. // The RFC says that name must match (case-sensitive), domain must // match (case insensitive), and path must match (case sensitive). // For the case insensitive domain compare, we rely on the domain // having been canonicalized (in // GetCookieDomainWithString->CanonicalizeHost). bool IsEquivalent(const CanonicalCookie& ecc) const { // It seems like it would make sense to take secure and httponly into // account, but the RFC doesn't specify this. // NOTE: Keep this logic in-sync with TrimDuplicateCookiesForHost(). return (name_ == ecc.Name() && domain_ == ecc.Domain() && path_ == ecc.Path()); } // Checks a looser set of equivalency rules than 'IsEquivalent()' in order // to support the stricter 'Secure' behaviors specified in // https://tools.ietf.org/html/draft-ietf-httpbis-cookie-alone#section-3 // // Returns 'true' if this cookie's name matches |ecc|, and this cookie is // a domain-match for |ecc| (or vice versa), and |ecc|'s path is "on" this // cookie's path (as per 'IsOnPath()'). // // Note that while the domain-match cuts both ways (e.g. 'example.com' // matches 'www.example.com' in either direction), the path-match is // unidirectional (e.g. '/login/en' matches '/login' and '/', but // '/login' and '/' do not match '/login/en'). bool IsEquivalentForSecureCookieMatching(const CanonicalCookie& ecc) const; void SetLastAccessDate(const base::Time& date) { last_access_date_ = date; } void SetCreationDate(const base::Time& date) { creation_date_ = date; } // Returns true if the given |url_path| path-matches the cookie-path as // described in section 5.1.4 in RFC 6265. bool IsOnPath(const std::string& url_path) const; // Returns true if the cookie domain matches the given |host| as described in // section 5.1.3 of RFC 6265. bool IsDomainMatch(const std::string& host) const; // Returns true if the cookie should be included for the given request |url|. // 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! bool IncludeForRequestURL(const GURL& url, const CookieOptions& options) const; std::string DebugString() const; static std::string CanonPathWithString(const GURL& url, const std::string& path_string); // Returns a "null" time if expiration was unspecified or invalid. static base::Time CanonExpiration(const ParsedCookie& pc, const base::Time& current, const base::Time& server_time); // Cookie ordering methods. // Returns true if the cookie is less than |other|, considering only name, // domain and path. In particular, two equivalent cookies (see IsEquivalent()) // are identical for PartialCompare(). bool PartialCompare(const CanonicalCookie& other) const; // Returns true if the cookie is less than |other|, considering all fields. // FullCompare() is consistent with PartialCompare(): cookies sorted using // FullCompare() are also sorted with respect to PartialCompare(). bool FullCompare(const CanonicalCookie& other) const; // Return whether this object is a valid CanonicalCookie(). Invalid // cookies may be constructed by the detailed constructor. // A cookie is considered canonical if-and-only-if: // * It can be created by CanonicalCookie::Create, or // * It is identical to a cookie created by CanonicalCookie::Create except // that the creation time is null, or // * It can be derived from a cookie created by CanonicalCookie::Create by // entry into and retrieval from a cookie store (specifically, this means // by the setting of an creation time in place of a null creation time, and // the setting of a last access time). // An additional requirement on a CanonicalCookie is that if the last // access time is non-null, the creation time must also be non-null and // greater than the last access time. bool IsCanonical() const; private: FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestPrefixHistograms); // The special cookie prefixes as defined in // https://tools.ietf.org/html/draft-west-cookie-prefixes // // This enum is being histogrammed; do not reorder or remove values. enum CookiePrefix { COOKIE_PREFIX_NONE = 0, COOKIE_PREFIX_SECURE, COOKIE_PREFIX_HOST, COOKIE_PREFIX_LAST }; // Returns the CookiePrefix (or COOKIE_PREFIX_NONE if none) that // applies to the given cookie |name|. static CookiePrefix GetCookiePrefix(const std::string& name); // Records histograms to measure how often cookie prefixes appear in // the wild and how often they would be blocked. static void RecordCookiePrefixMetrics(CookiePrefix prefix, bool is_cookie_valid); // Returns true if a prefixed cookie does not violate any of the rules // for that cookie. static bool IsCookiePrefixValid(CookiePrefix prefix, const GURL& url, const ParsedCookie& parsed_cookie); // Returns the cookie's domain, with the leading dot removed, if present. std::string DomainWithoutDot() const; std::string name_; std::string value_; std::string domain_; std::string path_; base::Time creation_date_; base::Time expiry_date_; base::Time last_access_date_; bool secure_; bool httponly_; CookieSameSite same_site_; CookiePriority priority_; }; typedef std::vector CookieList; } // namespace net #endif // NET_COOKIES_CANONICAL_COOKIE_H_