diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-29 10:46:47 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-11-02 12:02:10 +0000 |
commit | 99677208ff3b216fdfec551fbe548da5520cd6fb (patch) | |
tree | 476a4865c10320249360e859d8fdd3e01833b03a /chromium/net/cookies | |
parent | c30a6232df03e1efbd9f3b226777b07e087a1122 (diff) | |
download | qtwebengine-chromium-99677208ff3b216fdfec551fbe548da5520cd6fb.tar.gz |
BASELINE: Update Chromium to 86.0.4240.124
Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/cookies')
25 files changed, 1472 insertions, 443 deletions
diff --git a/chromium/net/cookies/README.md b/chromium/net/cookies/README.md new file mode 100644 index 00000000000..c4baf8e8158 --- /dev/null +++ b/chromium/net/cookies/README.md @@ -0,0 +1,545 @@ +# Cookies + +*** aside +_"In the beginning ~~the Universe was~~ cookies were created. This has +made a lot of people very angry and has been widely regarded as a bad move."_ + +_"Sometimes me think, what is friend? And then me say: a friend is someone to +share last cookie with."_ +*** + +This directory is concerned with the management of cookies, as specified by +[RFC 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis). +Cookies are implemented mostly in this directory, but also elsewhere, as +described [below](#Cookie-implementation-classes). + +*** promo +* Those who wish to work with the implementation of cookies may refer to + [Life of a cookie](#Life-of-a-cookie) and + [Cookie implementation classes](#Cookie-implementation-classes). + +* Those who wish to make use of cookies elsewhere in Chromium may refer to + [Main interfaces for finding, setting, deleting, and observing cookies](#Main-interfaces-for-finding_setting_deleting_and-observing-cookies). +*** + +[TOC] + +## Life of a cookie + +This section describes the lifecycle of a typical/simple cookie on most +platforms, and serves as an overview of some important classes involved in +managing cookies. + +This only covers cookie accesses via +[HTTP requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies). +Other APIs for accessing cookies include JavaScript +([`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) +and [CookieStore API](https://wicg.github.io/cookie-store/)) or Chrome +extensions +([`chrome.cookies`](https://developer.chrome.com/extensions/cookies)). + +### Cookie is received and parsed + +*** note +**Summary:** + +1. An HTTP response containing a `Set-Cookie` header is received. +2. The `Set-Cookie` header is processed by `URLRequestHttpJob`. +3. The header contents are parsed into a `CanonicalCookie` and passed to the + `CookieStore` for storage. +*** + +A cookie starts as a `Set-Cookie` header sent in the server's response to an +HTTP request: + +<pre> +HTTP/1.1 200 OK +Date: ... +Server: ... +... +<b>Set-Cookie: chocolate_chip=tasty; Secure; SameSite=Lax; Max-Age=3600</b> +</pre> + +The response passes through the `HttpNetworkTransaction` and +`HttpCache::Transaction` to the `URLRequestHttpJob`. (See +[Life of a `URLRequest`](/net/docs/life-of-a-url-request.md#send-request-and-read-the-response-headers) +for more details.) The `URLRequestHttpJob` then reads any `Set-Cookie` headers +in the response (there may be multiple) and processes each `Set-Cookie` header +by calling into `//net/cookies` classes for parsing and storing: + +First, the cookie, which has been provided as a string, is parsed into a +`ParsedCookie`. This struct simply records all the token-value pairs present in +the `Set-Cookie` header and keeps track of which cookie attribute each +corresponds to. The first token-value pair is always treated as the cookie's +name and value. + +The `ParsedCookie` is then converted into a `CanonicalCookie`. This is the main +data type representing cookies. Any cookie consumer that does not deal directly +with HTTP headers operates on `CanonicalCookie`s. A `CanonicalCookie` has some +additional guarantees of validity over a `ParsedCookie`, such as sane expiration +times, valid domain and path attributes, etc. Once a `CanonicalCookie` is +created, you will almost never see a `ParsedCookie` used for anything else. + +If a valid `CanonicalCookie` could not be created (due to some illegal syntax, +inconsistent attribute values, or other circumstances preventing parsing), then +we stop here, and `URLRequestHttpJob` moves on to the next `Set-Cookie` header. + +The `NetworkDelegate` also gets a chance to block the setting of the cookie, +based on the user's third-party cookie blocking settings. If it is blocked, +`URLRequestHttpJob` likewise moves on to the next `Set-Cookie` header. + +If this did result in a valid and not-blocked `CanonicalCookie`, it is then +passed to the `CookieStore` to be stored. + +### Cookie is stored + +*** note +**Summary:** + +1. The `CookieStore` receives the `CanonicalCookie` and validates some + additional criteria before updating its in-memory cache of cookies. +2. The `CookieStore` may also update its on-disk backing store via the + `CookieMonster::PersistentCookieStore` interface. +3. The result of the cookie storage attempt is reported back to the + `URLRequestHttpJob`. +*** + +The `CookieStore` lives in the `URLRequestContext` and its main implementation, +used for most platforms, is `CookieMonster`. (The rest of this section assumes +that we are using a `CookieMonster`.) It exposes an asynchronous interface for +storing and retrieving cookies. + +When `CookieMonster` receives a `CanonicalCookie` to be set, it queues a task to +validate and set the cookie. Most of the time this runs immediately, but it may +be delayed if the network service has just started up, and the contents of the +`PersistentCookieStore` are still being loaded from disk. It checks some +criteria against the cookie's source URL and a `CookieOptions` object (which +contains some other parameters describing the "context" in which the cookie is +being set, such as whether it's being accessed in a same-site or cross-site +context). + +If everything checks out, the `CookieMonster` proceeds with setting the cookie. +If an equivalent cookie is present in the store, then it may be deleted. +Equivalent is defined as sharing a name, domain, and path, based on the +invariant specified by the RFC that no two such cookies may exist at a given +time. `CookieMonster` stores its `CanonicalCookie`s in a multimap keyed on the +registrable domain (eTLD+1) of the cookie's domain attribute. + +The cookie may also be persisted to disk by a +`CookieMonster::PersistentCookieStore` depending on factors like whether the +cookie is a persistent cookie (has an expiration date), whether session cookies +should also be persisted (e.g. if the browser is set to restore the previous +browsing session), and whether the profile should have persistent storage (e.g. +yes for normal profiles, but not for Incognito profiles). The +`SQLitePersistentCookieStore` is the main implementation of +`CookieMonster::PersistentCookieStore`. It stores cookies in a SQLite database +on disk, at a filepath specified by the user's profile. + +After the cookie has been stored (or rejected), the `CookieMonster` calls back +to the `URLRequestHttpJob` with the outcome of the storage attempt. The +`URLRequestHttpJob` stashes away the outcomes and stores them in the +`URLRequest` after all `Set-Cookie` headers in the response are processed, so +that interested parties (e.g. DevTools) can subsequently be notified of cookie +activity. + +### Cookie is retrieved and sent + +*** note +**Summary:** + +1. A network request reaches the net stack and generates a `URLRequestHttpJob`, + which queries the `CookieStore` for cookies to include with the request. +2. The `CookieStore` evaluates each of its candidate cookies for whether it can + be included in the request, and reports back to the `URLRequestHttpJob` with + included and excluded cookies. +3. `URLRequestHttpJob` serializes the included cookies into a `Cookie` request + header and attaches it to the outgoing request. +*** + +Some time later, a (credentialed) request to the same eTLD+1 triggers a cookie +access in order to retrieve the relevant cookies to include in the outgoing +`Cookie` request header. The request makes its way to the net stack and causes a +`URLRequestHttpJob` to be created. (See +[Life of a `URLRequest`](/net/docs/life-of-a-url-request.md#check-the-cache_request-an-httpstream) +for more details.) Upon being started, the `URLRequestHttpJob` asks the +`CookieStore` to retrieve the correct cookies for the URL being requested. + +The `CookieMonster` queues a task to retrieve the cookies. Most of the time this +runs immediately, except if the contents of the `PersistentCookieStore` are +still being loaded from disk. The `CookieMonster` examines each of the cookies +it has stored for that URL's registrable domain and decides whether it should be +included or excluded for that request based on the requested URL and the +`CookieOptions`, by computing a `CookieInclusionStatus`. Criteria for inclusion +are described in +[RFC 6265bis](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis#section-5.5) +and include: the URL matching the cookie's `Domain` and `Path` attributes, the +URL being secure if the cookie has the `Secure` attribute, the request context +(i.e. `CookieOptions`) being same-site if the cookie is subject to `SameSite` +enforcement, etc. If any of the requirements are not met, a +`CookieInclusionStatus::ExclusionReason` is recorded. + +After the exclusion reasons have been tallied up for each cookie, the cookies +without any exclusion reasons are deemed suitable for inclusion, and are +returned to the `URLRequestHttpJob`. The excluded cookies are also returned, +along with the `CookieInclusionStatus` describing why each cookie was excluded. + +The included cookies are serialized into a `Cookie` header string (if the +`NetworkDelegate` is ok with it, based on the user's third-party cookie blocking +settings). The `URLRequestHttpJob` attaches this `Cookie` header to the outgoing +request headers: + +<pre> +GET /me/want/cookie/omnomnomnom HTTP/1.1 +Host: ... +User-Agent: ... +<b>Cookie: chocolate_chip=tasty</b> +... +</pre> + +The included cookies, excluded cookies, and their corresponding +`CookieInclusionStatus`es are also stored in the `URLRequest` to notify +consumers of cookie activity notifications. + +## Cookie implementation classes + +This section lists classes involved in cookie management and access. + +The core classes are highlighted. + +### In this directory (//net/cookies) + +*** note +* **[`CanonicalCookie`](/net/cookies/canonical_cookie.h)** + + The main data type representing cookies. Basically everything that's not + directly dealing with HTTP headers or their equivalents operates on these. + + These are generally obtained via `CanonicalCookie::Create()`, which parses a + string (a `Set-Cookie` header) into an intermediate `ParsedCookie`, whose + fields it canonicalizes/validates and then copies into a `CanonicalCookie`. +*** + +*** note +* **[`CookieStore`](/net/cookies/cookie_store.h)** + + The main interface for a given platform's cookie handling. Provides + asynchronous methods for setting and retrieving cookies. + + Its implementations are responsible for keeping track of all the cookies, + finding cookies relevant for given HTTP requests, saving cookies received in + HTTP responses, etc., and need to know quite a bit about cookie semantics. +*** + +*** note +* **[`CookieMonster`](/net/cookies/cookie_monster.h)** + + The implementation of `CookieStore` used on most platforms. + + It stores all cookies in a multimap keyed on the eTLD+1 of the cookie's + domain. Also manages storage limits by evicting cookies when per-eTLD+1 or + global cookie counts are exceeded. + + It can optionally take an implementation of + `CookieMonster::PersistentCookieStore` to load and store cookies + persisently. +*** + +* [`CookieOptions`](/net/cookies/cookie_options.h) + + Contains parameters for a given attempt to access cookies via + `CookieStore`, such as whether the access is for an HTTP request (as opposed + to a JavaScript API), and the same-site or cross-site context of the request + (relevant to enforcement of the `SameSite` cookie attribute). + +* [`SiteForCookies`](/net/cookies/site_for_cookies.h) + + Represents which origins should be considered "same-site" for a given + context (e.g. frame). This is used to compute the same-site or cross-site + context of a cookie access attempt (which is then conveyed to the + `CookieStore` via a `CookieOptions`). + + It is generally the eTLD+1 and scheme of the top-level frame. It may also be + empty, in which case it represents a context that is cross-site to + everything (e.g. a nested iframe whose ancestor frames don't all belong to + the same site). + +* [`CookieInclusionStatus`](/net/cookies/cookie_inclusion_status.h) + + Records the outcome of a given attempt to access a cookie. Various reasons + for cookie exclusion are recorded + (`CookieInclusionStatus::ExclusionReason`), as well as informational + statuses (`CookieInclusionStatus::WarningReason`) typically used to emit + warnings in DevTools. + + May be used as a member of a `CookieAccessResult`, which includes even more + metadata about the outcome of a cookie access attempt. + +* [`CookieAccessDelegate`](/net/cookies/cookie_access_delegate.h) + + Interface for a `CookieStore` to query information from its embedder that + may modify its decisions on cookie inclusion/exclusion. Its main + implementation allows `CookieMonster` to access data from the network + service layer (e.g. `CookieManager`). + +* [`CookieChangeDispatcher`](/net/cookies/cookie_monster_change_dispatcher.h) + + Interface for subscribing to changes in the contents of the `CookieStore`. + The main implementation is `CookieMonsterChangeDispatcher`. + +### Elsewhere in //net + +*** note +* **[`SQLitePersistentCookieStore`](/net/extras/sqlite/sqlite_persistent_cookie_store.h)** + + Implementation of `CookieMonster::PersistentCookieStore` used on most + platforms. Uses a SQLite database to load and store cookies, potentially + using an optional delegate to encrypt and decrypt their at-rest versions. + This class is refcounted. + + `CookieMonster` loads cookies from here on startup. All other operations + attempting to access cookies in the process of being loaded are blocked + until loading of those cookies completes. Thus, it fast-tracks loading of + cookies for an eTLD+1 with pending requests, to decrease latency for + cookie access operations made soon after browser startup (by decreasing the + number of cookies whose loading is blocking requests). +*** + +*** note +* **[`URLRequestHttpJob`](/net/url_request/url_request_http_job.h)** + + A `URLRequestJob` implementation that handles HTTP requests; most + relevantly, the `Cookie` and `Set-Cookie` HTTP headers. It drives the + process for storing cookies and retrieving cookies for HTTP requests. + + Also logs cookie events to the NetLog for each request. +*** + +* [`URLRequest`](/net/url_request/url_request.h) + + Mostly relevant for its two members, `maybe_sent_cookies_` and + `maybe_stored_cookies_`, which are vectors in which `URLRequestHttpJob` + stashes the cookies it considered sending/storing and their + `CookieInclusionStatus`es. These then get mojo'ed over to the browser + process to notify observers of cookie activity. + +### In //services/network + +*** note +* **[`CookieManager`](/services/network/cookie_manager.h)** + + The network service API to cookies. Basically exports a `CookieStore` via + mojo IPC. + + Owned by the `NetworkContext`. +*** + +*** note +* **[`RestrictedCookieManager`](/services/network/restricted_cookie_manager.h)** + + Mojo interface for accessing cookies for a specific origin. This can be + handed out to untrusted (i.e. renderer) processes, as inputs are assumed to + be unsafe. + + It is primarily used for accessing cookies via JavaScript. + It provides a synchronous interface for + [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie), + as well as an asynchronous one for the [CookieStore API](https://wicg.github.io/cookie-store/). +*** + +* [`CookieSettings`](/services/network/cookie_settings.h) + + Keeps track of the content settings (per-profile + [permissions](/components/permissions/README.md) for types of + content that a given origin is allowed to use) for cookies, such as the + user's third-party cookie blocking settings, origins/domains with + third-party cookie blocking exceptions or "legacy" access settings. + + It is not to be confused with `content_settings::CookieSettings`, which + manages the browser's version of the cookie content settings, of which + `network::ContentSettings` is approximately a copy/mirror. The + `ProfileNetworkContextService` populates its contents upon `NetworkContext` + construction from the browser-side content settings, and also updates it + whenever the browser-side content settings change. + +* [`SessionCleanupCookieStore`](/services/network/session_cleanup_cookie_store.h) + + Implements `CookieMonster::PersistentCookieStore`, by wrapping a + `SQLitePersistentCookieStore`. Keeps an in-memory map of cookies per eTLD+1 + to allow deletion of cookies for sites whose cookie content setting is + "session-only" from the persistent store when the session ends. + + +### Elsewhere + +* [`CookieAccessObserver`](/services/network/public/mojom/cookie_access_observer.mojom) + and [`WebContentsObserver`](/content/public/browser/web_contents_observer.h) + + `CookieAccessObserver` is a mojo interface used to observe attempts to + access (read or write) cookies. It is implemented by `NavigationHandle` and + `RenderFrameHost`. + + The cookie accesses are attributable to a committed document that called + `document.cookie` or made a network request (if notified through + `RenderFrameHost`), or a not-yet-committed navigation that resulted in a + network request (if notified through `NavigationHandle`). + + The `CookieAccessObserver`s forward the notifications to `WebContents`, + which then notifies its `WebContentsObserver`s. One such + `WebContentsObserver` that cares about this information is + `PageSpecificContentSettings`, which displays information about allowed and + blocked cookies in UI surfaces (see next item). + +* [`CookiesTreeModel`](/chrome/browser/browsing_data/cookies_tree_model.h) + + Stores cookie information for use in settings UI (the Page Info Bubble and + various `chrome://settings` pages). Populated with info from + `PageSpecificContentSettings`. + +* [`CookieJar`](/third_party/blink/renderer/core/loader/cookie_jar.h) + + Implements the `document.cookie` API in the renderer by requesting a + `RestrictedCookieManager` from the browser. + +* [`CookieStore`](/third_party/blink/renderer/modules/cookie_store/cookie_store.h) + + Implements the JavaScript + [CookieStore API](https://wicg.github.io/cookie-store/) in the renderer by + requesting a `RestrictedCookieManager` from the browser. (Not to be confused + with `net::CookieStore`.) + +* [`CookiesAPI`](/chrome/browser/extensions/api/cookies/cookies_api.h) + + Implements the + [`chrome.cookies`](https://developer.chrome.com/extensions/cookies) API for + Chrome extensions. Gives extensions with the proper permissions essentially + unfettered access to the `CookieStore`. + +### Platform-specific + +* [`CookieStoreIOS` and `CookieStoreIOSPersistent`](/ios/net/cookies) + + iOS-specific `CookieStore` implementations, mainly relying on the iOS native + cookie implementation (`NSHTTPCookie`). + +* [`android_webview::CookieManager`](/android_webview/browser/cookie_manager.h) + + Manages cookies for Android WebView. It typically wraps a + `network::mojom::CookieManager`, but it can also be used before a + `NetworkContext` even exists, thanks to Android WebView's + [cookie API](https://developer.android.com/reference/kotlin/android/webkit/CookieManager), + which means it is sometimes initialized with a bare `net::CookieStore`. + + Also notable for allowing cookies for `file://` scheme URLs (normally they + are only allowed for HTTP and websocket schemes and `chrome-extension://`), + though this is non-default and deprecated. + +## Main interfaces for finding, setting, deleting, and observing cookies + +This section summarizes interfaces for interacting with cookies from various +parts of the codebase. + +### From //net or //services/network + +*** note +Use [`net::CookieStore`](/net/cookies/cookie_store.h) to save and retrieve +[`CanonicalCookie`](/net/cookies/canonical_cookie.h)s. +*** + +* `CanonicalCookie`s are the main data type representing cookies. Get one using + `CanonicalCookie::Create()`. + +* The `CookieStore` can be accessed via its owning `URLRequestContext`, which + can be accessed through `NetworkContext`. + +* To access cookies, you need a `CookieOptions`. The main things in this object + are the `HttpOnly` access permission and the `SameSite` context. The latter + can be obtained from [`cookie_util`](/net/cookies/cookie_util.h) functions. + +* Retrieve cookies using `GetCookieListWithOptionsAsync()`. + +* Save cookies using `SetCanonicalCookieAsync()`. + +*** note +Use `CookieStore` to selectively delete cookies. +*** + +* `DeleteCanonicalCookieAsync()` deletes a single cookie. + +* `DeleteAllCreatedInTimeRangeAsync()` deletes cookies created in a time range. + +* `DeleteAllMatchingInfoAsync()` deletes cookies that match a filter. + +*** note +Use the [`CookieChangeDispatcher`](/net/cookies/cookie_change_dispatcher.h) +interface to subscribe to changes. +*** + +* Use `AddCallbackForCookie()` to observe changes to cookies with a given name + that would be sent with a request to a specific URL. + +* Use `AddCallbackForUrl()` to observe changes to all cookies that would be sent + with a request to a specific URL. + +* Use `AddCallbackForAllChanges()` to observe changes to all cookies in the + `CookieStore`. + +### From the browser process + +*** note +Use [`CookieManager`](/services/network/cookie_manager.h) +(which basically exports a `net::CookieStore` interface via mojo) to save +and retrieve [`CanonicalCookie`](/net/cookies/canonical_cookie.h)s. +*** + +* The profile's `CookieManager` can be accessed from the browser process through + `StoragePartition::GetCookieManagerForBrowserProcess()`. + +* You can also get get a `CookieManager` pipe from the `NetworkContext` using + `GetCookieManager()`. + +* Retrieve cookies using `CookieManager::GetCookieList()`. + +* Save cookies using `CookieManager::SetCanonicalCookie()`. + +*** note +Use `CookieManager` to selectively delete cookies. +*** + +* If you have a copy of the `CanonicalCookie` to delete (e.g. a cookie + previously fetched from the store), use + `CookieManager::DeleteCanonicalCookie()`. + +* To delete cookies with certain characteristics, construct a + [`CookieDeletionFilter`](/services/network/public/mojom/cookie_manager.mojom) + and use `CookieManager::DeleteCookies()`. + +*** note +Use `CookieManager`'s change listener interface to subscribe to changes (this +parallels the `net::CookieChangeDispatcher` interface). +*** + +* Add a `CookieChangeListener` registration for a URL (and optionally a cookie + name) via `AddCookieChangeListener()` + +* Add a `CookieChangeListener` registration for all cookies via + `AddGlobalChangeListener()`. + +### From untrusted (e.g. renderer) processes + +*** note +Use a +[`network::mojom::RestrictedCookieManager`](/services/network/public/mojom/restricted_cookie_manager.mojom) +interface to access cookies for a particular origin. +*** + +* Request a `RestrictedCookieManager` interface from the browser. This creates a + `RestrictedCookieManager` bound to a `RenderFrameHost`, which can only access + cookies on behalf of the corresponding origin. + +* Cookies can be read and written asynchronously (`GetAllForUrl()`, + `SetCanonicalCookie()`) or synchronously (`SetCookieFromString()`, + `GetCookiesString()`). + +* [Compromised renderers](/docs/security/compromised-renderers.md#Cookies) + shouldn't be able to access cookies of another site, or `HttpOnly` cookies + (even from the same site). diff --git a/chromium/net/cookies/canonical_cookie.cc b/chromium/net/cookies/canonical_cookie.cc index 68fa41779bb..1c85b9d7daf 100644 --- a/chromium/net/cookies/canonical_cookie.cc +++ b/chromium/net/cookies/canonical_cookie.cc @@ -589,9 +589,18 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL( // match the cookie-path. if (!IsOnPath(url.path())) status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_NOT_ON_PATH); + + // For LEGACY cookies we should always return the schemeless context, + // otherwise let GetContextForCookieInclusion() decide. + CookieOptions::SameSiteCookieContext::ContextType cookie_inclusion_context = + access_semantics == CookieAccessSemantics::LEGACY + ? options.same_site_cookie_context().context() + : options.same_site_cookie_context().GetContextForCookieInclusion(); + // Don't include same-site cookies for cross-site requests. CookieEffectiveSameSite effective_same_site = GetEffectiveSameSite(access_semantics); + DCHECK(effective_same_site != CookieEffectiveSameSite::UNDEFINED); // Log the effective SameSite mode that is applied to the cookie on this // request, if its SameSite was not specified. if (SameSite() == CookieSameSite::UNSPECIFIED) { @@ -600,20 +609,19 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL( CookieEffectiveSameSite::COUNT); } UMA_HISTOGRAM_ENUMERATION( - "Cookie.RequestSameSiteContext", - options.same_site_cookie_context().GetContextForCookieInclusion(), + "Cookie.RequestSameSiteContext", cookie_inclusion_context, CookieOptions::SameSiteCookieContext::ContextType::COUNT); switch (effective_same_site) { case CookieEffectiveSameSite::STRICT_MODE: - if (options.same_site_cookie_context().GetContextForCookieInclusion() < + if (cookie_inclusion_context < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT) { status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT); } break; case CookieEffectiveSameSite::LAX_MODE: - if (options.same_site_cookie_context().GetContextForCookieInclusion() < + if (cookie_inclusion_context < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { status.AddExclusionReason( (SameSite() == CookieSameSite::UNSPECIFIED) @@ -625,7 +633,7 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL( // TODO(crbug.com/990439): Add a browsertest for this behavior. case CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE: DCHECK(SameSite() == CookieSameSite::UNSPECIFIED); - if (options.same_site_cookie_context().GetContextForCookieInclusion() < + if (cookie_inclusion_context < CookieOptions::SameSiteCookieContext::ContextType:: SAME_SITE_LAX_METHOD_UNSAFE) { // TODO(chlily): Do we need a separate CookieInclusionStatus for this? @@ -668,25 +676,27 @@ CookieAccessResult CanonicalCookie::IncludeForRequestURL( } // TODO(chlily): Log metrics. - return CookieAccessResult(effective_same_site, status); + return CookieAccessResult(effective_same_site, status, access_semantics); } -CookieInclusionStatus CanonicalCookie::IsSetPermittedInContext( +CookieAccessResult CanonicalCookie::IsSetPermittedInContext( const CookieOptions& options, CookieAccessSemantics access_semantics) const { - CookieInclusionStatus status; - IsSetPermittedInContext(options, access_semantics, &status); - return status; + CookieAccessResult access_result; + IsSetPermittedInContext(options, access_semantics, &access_result); + return access_result; } void CanonicalCookie::IsSetPermittedInContext( const CookieOptions& options, CookieAccessSemantics access_semantics, - CookieInclusionStatus* status) const { + CookieAccessResult* access_result) const { + access_result->access_semantics = access_semantics; if (options.exclude_httponly() && IsHttpOnly()) { DVLOG(net::cookie_util::kVlogSetCookies) << "HttpOnly cookie not permitted in script context."; - status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY); + access_result->status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_HTTP_ONLY); } // If both SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure @@ -697,7 +707,7 @@ void CanonicalCookie::IsSetPermittedInContext( SameSite() == CookieSameSite::NO_RESTRICTION && !IsSecure()) { DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() rejecting insecure cookie with SameSite=None."; - status->AddExclusionReason( + access_result->status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE); } // Log whether a SameSite=None cookie is Secure or not. @@ -705,37 +715,45 @@ void CanonicalCookie::IsSetPermittedInContext( UMA_HISTOGRAM_BOOLEAN("Cookie.SameSiteNoneIsSecure", IsSecure()); } - CookieEffectiveSameSite effective_same_site = - GetEffectiveSameSite(access_semantics); - switch (effective_same_site) { + // For LEGACY cookies we should always return the schemeless context, + // otherwise let GetContextForCookieInclusion() decide. + CookieOptions::SameSiteCookieContext::ContextType cookie_inclusion_context = + access_semantics == CookieAccessSemantics::LEGACY + ? options.same_site_cookie_context().context() + : options.same_site_cookie_context().GetContextForCookieInclusion(); + + access_result->effective_same_site = GetEffectiveSameSite(access_semantics); + DCHECK(access_result->effective_same_site != + CookieEffectiveSameSite::UNDEFINED); + switch (access_result->effective_same_site) { case CookieEffectiveSameSite::STRICT_MODE: // This intentionally checks for `< SAME_SITE_LAX`, as we allow // `SameSite=Strict` cookies to be set for top-level navigations that // qualify for receipt of `SameSite=Lax` cookies. - if (options.same_site_cookie_context().GetContextForCookieInclusion() < + if (cookie_inclusion_context < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { DVLOG(net::cookie_util::kVlogSetCookies) << "Trying to set a `SameSite=Strict` cookie from a " "cross-site URL."; - status->AddExclusionReason( + access_result->status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT); } break; case CookieEffectiveSameSite::LAX_MODE: case CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE: - if (options.same_site_cookie_context().GetContextForCookieInclusion() < + if (cookie_inclusion_context < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { if (SameSite() == CookieSameSite::UNSPECIFIED) { DVLOG(net::cookie_util::kVlogSetCookies) << "Cookies with no known SameSite attribute being treated as " "lax; attempt to set from a cross-site URL denied."; - status->AddExclusionReason( + access_result->status.AddExclusionReason( CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); } else { DVLOG(net::cookie_util::kVlogSetCookies) << "Trying to set a `SameSite=Lax` cookie from a cross-site URL."; - status->AddExclusionReason( + access_result->status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_SAMESITE_LAX); } } @@ -744,14 +762,14 @@ void CanonicalCookie::IsSetPermittedInContext( break; } - ApplySameSiteCookieWarningToStatus(SameSite(), effective_same_site, - IsSecure(), - options.same_site_cookie_context(), status, - true /* is_cookie_being_set */); + ApplySameSiteCookieWarningToStatus( + SameSite(), access_result->effective_same_site, IsSecure(), + options.same_site_cookie_context(), &access_result->status, + true /* is_cookie_being_set */); - if (status->IsInclude()) { + if (access_result->status.IsInclude()) { UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedResponseEffectiveSameSite", - effective_same_site, + access_result->effective_same_site, CookieEffectiveSameSite::COUNT); } @@ -941,25 +959,26 @@ bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const { return (base::Time::Now() - creation_date_) <= age_threshold; } -CookieAndLineWithStatus::CookieAndLineWithStatus() = default; +CookieAndLineWithAccessResult::CookieAndLineWithAccessResult() = default; -CookieAndLineWithStatus::CookieAndLineWithStatus( +CookieAndLineWithAccessResult::CookieAndLineWithAccessResult( base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CookieInclusionStatus status) + CookieAccessResult access_result) : cookie(std::move(cookie)), cookie_string(std::move(cookie_string)), - status(status) {} - -CookieAndLineWithStatus::CookieAndLineWithStatus( - const CookieAndLineWithStatus&) = default; + access_result(access_result) {} -CookieAndLineWithStatus& CookieAndLineWithStatus::operator=( - const CookieAndLineWithStatus& cookie_and_line_with_status) = default; +CookieAndLineWithAccessResult::CookieAndLineWithAccessResult( + const CookieAndLineWithAccessResult&) = default; -CookieAndLineWithStatus::CookieAndLineWithStatus(CookieAndLineWithStatus&&) = +CookieAndLineWithAccessResult& CookieAndLineWithAccessResult::operator=( + const CookieAndLineWithAccessResult& cookie_and_line_with_access_result) = default; -CookieAndLineWithStatus::~CookieAndLineWithStatus() = default; +CookieAndLineWithAccessResult::CookieAndLineWithAccessResult( + CookieAndLineWithAccessResult&&) = default; + +CookieAndLineWithAccessResult::~CookieAndLineWithAccessResult() = default; } // namespace net diff --git a/chromium/net/cookies/canonical_cookie.h b/chromium/net/cookies/canonical_cookie.h index aa538085ac8..4cb63368be1 100644 --- a/chromium/net/cookies/canonical_cookie.h +++ b/chromium/net/cookies/canonical_cookie.h @@ -26,13 +26,12 @@ namespace net { class ParsedCookie; class CanonicalCookie; -struct CookieWithStatus; struct CookieWithAccessResult; -struct CookieAndLineWithStatus; +struct CookieAndLineWithAccessResult; using CookieList = std::vector<CanonicalCookie>; -using CookieStatusList = std::vector<CookieWithStatus>; -using CookieAndLineStatusList = std::vector<CookieAndLineWithStatus>; +using CookieAndLineAccessResultList = + std::vector<CookieAndLineWithAccessResult>; using CookieAccessResultList = std::vector<CookieWithAccessResult>; class NET_EXPORT CanonicalCookie { @@ -242,7 +241,7 @@ class NET_EXPORT CanonicalCookie { // WARNING: this does not cover checking whether secure cookies are set in // a secure schema, since whether the schema is secure isn't part of // |options|. - CookieInclusionStatus IsSetPermittedInContext( + CookieAccessResult IsSetPermittedInContext( const CookieOptions& options, CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN) const; @@ -250,7 +249,7 @@ class NET_EXPORT CanonicalCookie { // Overload that updates an existing |status| rather than returning a new one. void IsSetPermittedInContext(const CookieOptions& options, CookieAccessSemantics access_semantics, - CookieInclusionStatus* status) const; + CookieAccessResult* access_result) const; std::string DebugString() const; @@ -362,34 +361,27 @@ class NET_EXPORT CanonicalCookie { CookieSourceScheme source_scheme_; }; -// These enable us to pass along a list of excluded cookie with the reason they -// were excluded -struct CookieWithStatus { - CanonicalCookie cookie; - CookieInclusionStatus status; -}; - // Used to pass excluded cookie information when it's possible that the // canonical cookie object may not be available. -struct NET_EXPORT CookieAndLineWithStatus { - CookieAndLineWithStatus(); - CookieAndLineWithStatus(base::Optional<CanonicalCookie> cookie, - std::string cookie_string, - CookieInclusionStatus status); - CookieAndLineWithStatus( - const CookieAndLineWithStatus& cookie_and_line_with_status); +struct NET_EXPORT CookieAndLineWithAccessResult { + CookieAndLineWithAccessResult(); + CookieAndLineWithAccessResult(base::Optional<CanonicalCookie> cookie, + std::string cookie_string, + CookieAccessResult access_result); + CookieAndLineWithAccessResult( + const CookieAndLineWithAccessResult& cookie_and_line_with_access_result); - CookieAndLineWithStatus& operator=( - const CookieAndLineWithStatus& cookie_and_line_with_status); + CookieAndLineWithAccessResult& operator=( + const CookieAndLineWithAccessResult& cookie_and_line_with_access_result); - CookieAndLineWithStatus( - CookieAndLineWithStatus&& cookie_and_line_with_status); + CookieAndLineWithAccessResult( + CookieAndLineWithAccessResult&& cookie_and_line_with_access_result); - ~CookieAndLineWithStatus(); + ~CookieAndLineWithAccessResult(); base::Optional<CanonicalCookie> cookie; std::string cookie_string; - CookieInclusionStatus status; + CookieAccessResult access_result; }; struct CookieWithAccessResult { diff --git a/chromium/net/cookies/canonical_cookie_unittest.cc b/chromium/net/cookies/canonical_cookie_unittest.cc index 77465c83b92..04c1b6488f5 100644 --- a/chromium/net/cookies/canonical_cookie_unittest.cc +++ b/chromium/net/cookies/canonical_cookie_unittest.cc @@ -758,9 +758,8 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { using SameSiteCookieContext = CookieOptions::SameSiteCookieContext; // Test cases that are the same regardless of feature status or access - // semantics: - // TODO(https://crbug.com/1030938): This test will need to consider - // SchemefulSameSite when it is added to CanonicalCookie. + // semantics. For Schemeful Same-Site this means that the context downgrade is + // a no-op (such as for NO_RESTRICTION cookies) or that there is no downgrade: std::vector<IncludeForRequestURLTestCase> common_test_cases = { // Strict cookies: {"Common=1;SameSite=Strict", CookieSameSite::STRICT_MODE, @@ -781,104 +780,86 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), CookieInclusionStatus()}, - // Strict cookies with downgrade: - {"Common=5;SameSite=Strict", CookieSameSite::STRICT_MODE, - CookieEffectiveSameSite::STRICT_MODE, - SameSiteCookieContext( - SameSiteCookieContext::ContextType::SAME_SITE_STRICT, - SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<CookieInclusionStatus::ExclusionReason>(), - {CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, - {"Common=6;SameSite=Strict", CookieSameSite::STRICT_MODE, - CookieEffectiveSameSite::STRICT_MODE, - SameSiteCookieContext( - SameSiteCookieContext::ContextType::SAME_SITE_STRICT, - SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<CookieInclusionStatus::ExclusionReason>(), - {CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, - {"Common=7;SameSite=Strict", CookieSameSite::STRICT_MODE, - CookieEffectiveSameSite::STRICT_MODE, - SameSiteCookieContext( - SameSiteCookieContext::ContextType::SAME_SITE_STRICT, - SameSiteCookieContext::ContextType::CROSS_SITE), - CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<CookieInclusionStatus::ExclusionReason>(), - {CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, // Lax cookies: - {"Common=8;SameSite=Lax", CookieSameSite::LAX_MODE, + {"Common=5;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, - {"Common=9;SameSite=Lax", CookieSameSite::LAX_MODE, + {"Common=6;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, - {"Common=10;SameSite=Lax", CookieSameSite::LAX_MODE, + {"Common=7;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), CookieInclusionStatus()}, - {"Common=11;SameSite=Lax", CookieSameSite::LAX_MODE, + {"Common=8;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), CookieInclusionStatus()}, // Lax cookies with downgrade: - {"Common=12;SameSite=Lax", CookieSameSite::LAX_MODE, + {"Common=9;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX), CookieInclusionStatus()}, - {"Common=13;SameSite=Lax", CookieSameSite::LAX_MODE, - CookieEffectiveSameSite::LAX_MODE, - SameSiteCookieContext( - SameSiteCookieContext::ContextType::SAME_SITE_STRICT, - SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<CookieInclusionStatus::ExclusionReason>(), - {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, - {"Common=14;SameSite=Lax", CookieSameSite::LAX_MODE, - CookieEffectiveSameSite::LAX_MODE, - SameSiteCookieContext( - SameSiteCookieContext::ContextType::SAME_SITE_STRICT, - SameSiteCookieContext::ContextType::CROSS_SITE), - CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<CookieInclusionStatus::ExclusionReason>(), - {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, - {"Common=15;SameSite=Lax", CookieSameSite::LAX_MODE, - CookieEffectiveSameSite::LAX_MODE, - SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX, - SameSiteCookieContext::ContextType::CROSS_SITE), - CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<CookieInclusionStatus::ExclusionReason>(), - {CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, // None and Secure cookies: - {"Common=16;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + {"Common=10;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), CookieInclusionStatus()}, - {"Common=17;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + {"Common=11;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), CookieInclusionStatus()}, - {"Common=18;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + {"Common=12;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), CookieInclusionStatus()}, - {"Common=19;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + {"Common=13;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CookieInclusionStatus()}}; + CookieInclusionStatus()}, + // Because NO_RESTRICTION cookies are always sent, the schemeful context + // downgrades shouldn't matter. + {"Common=14;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + CookieEffectiveSameSite::NO_RESTRICTION, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX), + CookieInclusionStatus()}, + {"Common=15;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + CookieEffectiveSameSite::NO_RESTRICTION, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), + CookieInclusionStatus()}, + {"Common=16;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + CookieEffectiveSameSite::NO_RESTRICTION, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus()}, + {"Common=17;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + CookieEffectiveSameSite::NO_RESTRICTION, + SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus()}, + {"Common=18;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, + CookieEffectiveSameSite::NO_RESTRICTION, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus()}, + }; // Test cases where the default is None (either access semantics is LEGACY, or - // semantics is UNKNOWN and feature is enabled): + // semantics is UNKNOWN and SameSiteByDefaultCookies feature is disabled): std::vector<IncludeForRequestURLTestCase> default_none_test_cases = { // Unspecified cookies (without SameSite-by-default): {"DefaultNone=1", CookieSameSite::UNSPECIFIED, @@ -907,7 +888,8 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { CookieInclusionStatus()}}; // Test cases where the default is Lax (either access semantics is NONLEGACY, - // or access semantics is UNKNOWN and feature is enabled): + // or access semantics is UNKNOWN and SameSiteByDefaultCookies feature is + // enabled): std::vector<IncludeForRequestURLTestCase> default_lax_test_cases = { // Unspecified recently-created cookies (with SameSite-by-default): {"DefaultLax=1", CookieSameSite::UNSPECIFIED, @@ -961,30 +943,173 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { CookieInclusionStatus(), kLongAge}, }; - VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, - common_test_cases); - VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, - default_lax_test_cases); - VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::LEGACY, - common_test_cases); - VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::LEGACY, - default_none_test_cases); - VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::NONLEGACY, - common_test_cases); - VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::NONLEGACY, - default_lax_test_cases); - VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, - common_test_cases); - VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, - default_none_test_cases); - VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, - common_test_cases); - VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, - default_none_test_cases); - VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, - common_test_cases); - VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, - default_lax_test_cases); + // Test cases that require LEGACY semantics or Schemeful Same-Site to be + // disabled. + std::vector<IncludeForRequestURLTestCase> schemeful_disabled_test_cases = { + {"LEGACY_Schemeful=1;SameSite=Strict", CookieSameSite::STRICT_MODE, + CookieEffectiveSameSite::STRICT_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, + {"LEGACY_Schemeful=2;SameSite=Strict", CookieSameSite::STRICT_MODE, + CookieEffectiveSameSite::STRICT_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, + {"LEGACY_Schemeful=3;SameSite=Strict", CookieSameSite::STRICT_MODE, + CookieEffectiveSameSite::STRICT_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, + {"LEGACY_Schemeful=4;SameSite=Lax", CookieSameSite::LAX_MODE, + CookieEffectiveSameSite::LAX_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + {"LEGACY_Schemeful=5;SameSite=Lax", CookieSameSite::LAX_MODE, + CookieEffectiveSameSite::LAX_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + {"LEGACY_Schemeful=6;SameSite=Lax", CookieSameSite::LAX_MODE, + CookieEffectiveSameSite::LAX_MODE, + SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, + }; + + // Test cases that require NONLEGACY or UNKNOWN semantics with Schemeful + // Same-Site enabled + std::vector<IncludeForRequestURLTestCase> schemeful_enabled_test_cases = { + {"NONLEGACY_Schemeful=1;SameSite=Strict", CookieSameSite::STRICT_MODE, + CookieEffectiveSameSite::STRICT_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX), + CookieInclusionStatus::MakeFromReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT}, + {CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, + {"NONLEGACY_Schemeful=2;SameSite=Strict", CookieSameSite::STRICT_MODE, + CookieEffectiveSameSite::STRICT_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), + CookieInclusionStatus::MakeFromReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT}, + {CookieInclusionStatus:: + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, + {"NONLEGACY_Schemeful=3;SameSite=Strict", CookieSameSite::STRICT_MODE, + CookieEffectiveSameSite::STRICT_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus::MakeFromReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT}, + {CookieInclusionStatus:: + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, + {"NONLEGACY_Schemeful=4;SameSite=Lax", CookieSameSite::LAX_MODE, + CookieEffectiveSameSite::LAX_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), + CookieInclusionStatus::MakeFromReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX}, + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + {"NONLEGACY_Schemeful=5;SameSite=Lax", CookieSameSite::LAX_MODE, + CookieEffectiveSameSite::LAX_MODE, + SameSiteCookieContext( + SameSiteCookieContext::ContextType::SAME_SITE_STRICT, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus::MakeFromReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX}, + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + {"NONLEGACY_Schemeful=6;SameSite=Lax", CookieSameSite::LAX_MODE, + CookieEffectiveSameSite::LAX_MODE, + SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX, + SameSiteCookieContext::ContextType::CROSS_SITE), + CookieInclusionStatus::MakeFromReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX}, + {CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, + }; + + auto SchemefulIndependentCases = [&]() { + // Run the test cases that are independent of Schemeful Same-Site. + VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, + common_test_cases); + VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, + default_lax_test_cases); + VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::LEGACY, + common_test_cases); + VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::LEGACY, + default_none_test_cases); + VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::NONLEGACY, + common_test_cases); + VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::NONLEGACY, + default_lax_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, + common_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, + default_none_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, + common_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, + default_none_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, + common_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, + default_lax_test_cases); + }; + + { + // Schemeful Same-Site disabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kSchemefulSameSite); + + SchemefulIndependentCases(); + + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, + schemeful_disabled_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, + schemeful_disabled_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, + schemeful_disabled_test_cases); + } + { + // Schemeful Same-Site enabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSchemefulSameSite); + + SchemefulIndependentCases(); + + // With LEGACY access the cases should act as if schemeful is disabled, even + // when it's not. + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, + schemeful_disabled_test_cases); + + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, + schemeful_enabled_test_cases); + VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, + schemeful_enabled_test_cases); + } } // Test that non-SameSite, insecure cookies are excluded if both @@ -1095,7 +1220,7 @@ TEST(CanonicalCookieTest, MultipleExclusionReasons) { url, "name=value;HttpOnly;SameSite=Lax", creation_time, server_time); ASSERT_TRUE(cookie3); EXPECT_TRUE(cookie3->IsSetPermittedInContext(options) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_HTTP_ONLY, CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } @@ -1990,15 +2115,15 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { CookieOptions context_network; context_network.set_include_httponly(); - EXPECT_TRUE( - cookie_scriptable.IsSetPermittedInContext(context_network).IsInclude()); - EXPECT_TRUE( - cookie_scriptable.IsSetPermittedInContext(context_script).IsInclude()); + EXPECT_TRUE(cookie_scriptable.IsSetPermittedInContext(context_network) + .status.IsInclude()); + EXPECT_TRUE(cookie_scriptable.IsSetPermittedInContext(context_script) + .status.IsInclude()); - EXPECT_TRUE( - cookie_httponly.IsSetPermittedInContext(context_network).IsInclude()); + EXPECT_TRUE(cookie_httponly.IsSetPermittedInContext(context_network) + .status.IsInclude()); EXPECT_TRUE(cookie_httponly.IsSetPermittedInContext(context_script) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); CookieOptions context_cross_site; @@ -2037,29 +2162,62 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_cross_site) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_lax) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_strict) - .IsInclude()); - - CookieInclusionStatus status_strict_to_lax = - cookie_same_site_unrestricted.IsSetPermittedInContext( - context_same_site_strict_to_lax); - EXPECT_TRUE(status_strict_to_lax.IsInclude()); - EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CookieInclusionStatus status_strict_to_cross = - cookie_same_site_unrestricted.IsSetPermittedInContext( - context_same_site_strict_to_cross); - EXPECT_TRUE(status_strict_to_cross.IsInclude()); - EXPECT_FALSE(status_strict_to_cross.HasDowngradeWarning()); - CookieInclusionStatus status_lax_to_cross = - cookie_same_site_unrestricted.IsSetPermittedInContext( - context_same_site_lax_to_cross); - EXPECT_TRUE(status_lax_to_cross.IsInclude()); - EXPECT_FALSE(status_lax_to_cross.HasDowngradeWarning()); + .status.IsInclude()); + + { + // Schemeful Same-Site disabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kSchemefulSameSite); + + CookieInclusionStatus status_strict_to_lax = + cookie_same_site_unrestricted + .IsSetPermittedInContext(context_same_site_strict_to_lax) + .status; + EXPECT_TRUE(status_strict_to_lax.IsInclude()); + EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); + CookieInclusionStatus status_strict_to_cross = + cookie_same_site_unrestricted + .IsSetPermittedInContext(context_same_site_strict_to_cross) + .status; + EXPECT_TRUE(status_strict_to_cross.IsInclude()); + EXPECT_FALSE(status_strict_to_cross.HasDowngradeWarning()); + CookieInclusionStatus status_lax_to_cross = + cookie_same_site_unrestricted + .IsSetPermittedInContext(context_same_site_lax_to_cross) + .status; + EXPECT_TRUE(status_lax_to_cross.IsInclude()); + EXPECT_FALSE(status_lax_to_cross.HasDowngradeWarning()); + } + { + // Schemeful Same-Site enabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSchemefulSameSite); + + CookieInclusionStatus status_strict_to_lax = + cookie_same_site_unrestricted + .IsSetPermittedInContext(context_same_site_strict_to_lax) + .status; + EXPECT_TRUE(status_strict_to_lax.IsInclude()); + EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); + CookieInclusionStatus status_strict_to_cross = + cookie_same_site_unrestricted + .IsSetPermittedInContext(context_same_site_strict_to_cross) + .status; + EXPECT_TRUE(status_strict_to_cross.IsInclude()); + EXPECT_FALSE(status_strict_to_cross.HasDowngradeWarning()); + CookieInclusionStatus status_lax_to_cross = + cookie_same_site_unrestricted + .IsSetPermittedInContext(context_same_site_lax_to_cross) + .status; + EXPECT_TRUE(status_lax_to_cross.IsInclude()); + EXPECT_FALSE(status_lax_to_cross.HasDowngradeWarning()); + } } { @@ -2069,32 +2227,71 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cookie_same_site_lax.IsSetPermittedInContext(context_cross_site) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); EXPECT_TRUE( cookie_same_site_lax.IsSetPermittedInContext(context_same_site_lax) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE( cookie_same_site_lax.IsSetPermittedInContext(context_same_site_strict) - .IsInclude()); - - CookieInclusionStatus status_strict_to_lax = - cookie_same_site_lax.IsSetPermittedInContext( - context_same_site_strict_to_lax); - EXPECT_TRUE(status_strict_to_lax.IsInclude()); - EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CookieInclusionStatus status_strict_to_cross = - cookie_same_site_lax.IsSetPermittedInContext( - context_same_site_strict_to_cross); - EXPECT_TRUE(status_strict_to_cross.IsInclude()); - EXPECT_TRUE(status_strict_to_cross.HasWarningReason( - CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); - CookieInclusionStatus status_lax_to_cross = - cookie_same_site_lax.IsSetPermittedInContext( - context_same_site_lax_to_cross); - EXPECT_TRUE(status_lax_to_cross.IsInclude()); - EXPECT_TRUE(status_lax_to_cross.HasWarningReason( - CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); + .status.IsInclude()); + + { + // Schemeful Same-Site disabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kSchemefulSameSite); + + CookieInclusionStatus status_strict_to_lax = + cookie_same_site_lax + .IsSetPermittedInContext(context_same_site_strict_to_lax) + .status; + EXPECT_TRUE(status_strict_to_lax.IsInclude()); + EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); + CookieInclusionStatus status_strict_to_cross = + cookie_same_site_lax + .IsSetPermittedInContext(context_same_site_strict_to_cross) + .status; + EXPECT_TRUE(status_strict_to_cross.IsInclude()); + EXPECT_TRUE(status_strict_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); + CookieInclusionStatus status_lax_to_cross = + cookie_same_site_lax + .IsSetPermittedInContext(context_same_site_lax_to_cross) + .status; + EXPECT_TRUE(status_lax_to_cross.IsInclude()); + EXPECT_TRUE(status_lax_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); + } + { + // Schemeful Same-Site enabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSchemefulSameSite); + + CookieInclusionStatus status_strict_to_lax = + cookie_same_site_lax + .IsSetPermittedInContext(context_same_site_strict_to_lax) + .status; + EXPECT_TRUE(status_strict_to_lax.IsInclude()); + EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); + CookieInclusionStatus status_strict_to_cross = + cookie_same_site_lax + .IsSetPermittedInContext(context_same_site_strict_to_cross) + .status; + EXPECT_FALSE(status_strict_to_cross.IsInclude()); + EXPECT_TRUE(status_strict_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); + EXPECT_TRUE(status_strict_to_cross.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)); + CookieInclusionStatus status_lax_to_cross = + cookie_same_site_lax + .IsSetPermittedInContext(context_same_site_lax_to_cross) + .status; + EXPECT_FALSE(status_lax_to_cross.IsInclude()); + EXPECT_TRUE(status_lax_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); + EXPECT_TRUE(status_strict_to_cross.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)); + } } { @@ -2107,32 +2304,96 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { // context really should be accepted. EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_cross_site) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT})); EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_same_site_lax) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_strict .IsSetPermittedInContext(context_same_site_strict) - .IsInclude()); - - CookieInclusionStatus status_strict_to_lax = - cookie_same_site_strict.IsSetPermittedInContext( - context_same_site_strict_to_lax); - EXPECT_TRUE(status_strict_to_lax.IsInclude()); - EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CookieInclusionStatus status_strict_to_cross = - cookie_same_site_strict.IsSetPermittedInContext( - context_same_site_strict_to_cross); - EXPECT_TRUE(status_strict_to_cross.IsInclude()); - EXPECT_TRUE(status_strict_to_cross.HasWarningReason( - CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); - CookieInclusionStatus status_lax_to_cross = - cookie_same_site_strict.IsSetPermittedInContext( - context_same_site_lax_to_cross); - EXPECT_TRUE(status_lax_to_cross.IsInclude()); - EXPECT_TRUE(status_lax_to_cross.HasWarningReason( - CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); + .status.IsInclude()); + + { + // Schemeful Same-Site disabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kSchemefulSameSite); + + CookieInclusionStatus status_strict_to_lax = + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_lax) + .status; + EXPECT_TRUE(status_strict_to_lax.IsInclude()); + EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); + CookieInclusionStatus status_strict_to_cross = + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_cross) + .status; + EXPECT_TRUE(status_strict_to_cross.IsInclude()); + EXPECT_TRUE(status_strict_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); + CookieInclusionStatus status_lax_to_cross = + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_lax_to_cross) + .status; + EXPECT_TRUE(status_lax_to_cross.IsInclude()); + EXPECT_TRUE(status_lax_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); + } + { + // Schemeful Same-Site enabled. + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSchemefulSameSite); + + CookieInclusionStatus status_strict_to_lax = + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_lax) + .status; + EXPECT_TRUE(status_strict_to_lax.IsInclude()); + EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); + CookieInclusionStatus status_strict_to_cross = + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_cross) + .status; + EXPECT_FALSE(status_strict_to_cross.IsInclude()); + EXPECT_TRUE(status_strict_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); + EXPECT_TRUE(status_strict_to_cross.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)); + CookieInclusionStatus status_lax_to_cross = + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_lax_to_cross) + .status; + EXPECT_FALSE(status_lax_to_cross.IsInclude()); + EXPECT_TRUE(status_lax_to_cross.HasWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); + EXPECT_TRUE(status_strict_to_cross.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)); + } + + // Even with Schemeful Same-Site enabled, cookies semantics could change the + // inclusion. + { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kSchemefulSameSite); + + EXPECT_FALSE( + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_cross, + CookieAccessSemantics::UNKNOWN) + .status.IsInclude()); + EXPECT_FALSE( + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_cross, + CookieAccessSemantics::NONLEGACY) + .status.IsInclude()); + // LEGACY semantics should allow cookies which Schemeful Same-Site would + // normally block. + EXPECT_TRUE( + cookie_same_site_strict + .IsSetPermittedInContext(context_same_site_strict_to_cross, + CookieAccessSemantics::LEGACY) + .status.IsInclude()); + } } // Behavior of UNSPECIFIED depends on an experiment and CookieAccessSemantics. @@ -2148,41 +2409,41 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::NONLEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::NONLEGACY) - .IsInclude()); + .status.IsInclude()); } { @@ -2192,44 +2453,124 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::UNKNOWN) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::NONLEGACY) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::NONLEGACY) - .IsInclude()); + .status.IsInclude()); } } +TEST(CanonicalCookieTest, IsSetPermittedEffectiveSameSite) { + GURL url("http://www.example.com/test"); + base::Time current_time = base::Time::Now(); + CookieOptions options; + + // Test IsSetPermitted CookieEffectiveSameSite for + // CanonicalCookie with CookieSameSite::NO_RESTRICTION. + CanonicalCookie cookie_no_restriction( + "A", "2", "www.example.com", "/test", current_time, base::Time(), + base::Time(), true /*secure*/, false /*httponly*/, + CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); + + EXPECT_EQ( + cookie_no_restriction + .IsSetPermittedInContext(options, CookieAccessSemantics::UNKNOWN) + .effective_same_site, + CookieEffectiveSameSite::NO_RESTRICTION); + + // Test IsSetPermitted CookieEffectiveSameSite for + // CanonicalCookie with CookieSameSite::LAX_MODE. + CanonicalCookie cookie_lax("A", "2", "www.example.com", "/test", current_time, + base::Time(), base::Time(), true /*secure*/, + false /*httponly*/, CookieSameSite::LAX_MODE, + COOKIE_PRIORITY_DEFAULT); + + EXPECT_EQ( + cookie_lax + .IsSetPermittedInContext(options, CookieAccessSemantics::UNKNOWN) + .effective_same_site, + CookieEffectiveSameSite::LAX_MODE); + + // Test IsSetPermitted CookieEffectiveSameSite for + // CanonicalCookie with CookieSameSite::STRICT_MODE. + CanonicalCookie cookie_strict( + "A", "2", "www.example.com", "/test", current_time, base::Time(), + base::Time(), true /*secure*/, false /*httponly*/, + CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT); + + EXPECT_EQ( + cookie_strict + .IsSetPermittedInContext(options, CookieAccessSemantics::UNKNOWN) + .effective_same_site, + CookieEffectiveSameSite::STRICT_MODE); + + // Test IsSetPermitted CookieEffectiveSameSite for + // CanonicalCookie with CookieSameSite::UNSPECIFIED. + base::Time creation_time = base::Time::Now() - (kLaxAllowUnsafeMaxAge * 4); + CanonicalCookie cookie_old_unspecified( + "A", "2", "www.example.com", "/test", creation_time, base::Time(), + base::Time(), true /*secure*/, false /*httponly*/, + CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT); + CanonicalCookie cookie_unspecified( + "A", "2", "www.example.com", "/test", current_time, base::Time(), + base::Time(), true /*secure*/, false /*httponly*/, + CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT); + + EXPECT_EQ( + cookie_old_unspecified + .IsSetPermittedInContext(options, CookieAccessSemantics::UNKNOWN) + .effective_same_site, + CookieEffectiveSameSite::LAX_MODE); + + EXPECT_EQ( + cookie_unspecified + .IsSetPermittedInContext(options, CookieAccessSemantics::UNKNOWN) + .effective_same_site, + CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE); + + EXPECT_EQ( + cookie_unspecified + .IsSetPermittedInContext(options, CookieAccessSemantics::NONLEGACY) + .effective_same_site, + CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE); + + EXPECT_EQ(cookie_unspecified + .IsSetPermittedInContext(options, CookieAccessSemantics::LEGACY) + .effective_same_site, + CookieEffectiveSameSite::NO_RESTRICTION); +} + } // namespace net diff --git a/chromium/net/cookies/cookie_access_result.cc b/chromium/net/cookies/cookie_access_result.cc index 182dc53f704..d618254360b 100644 --- a/chromium/net/cookies/cookie_access_result.cc +++ b/chromium/net/cookies/cookie_access_result.cc @@ -10,8 +10,14 @@ CookieAccessResult::CookieAccessResult() = default; CookieAccessResult::CookieAccessResult( CookieEffectiveSameSite effective_same_site, - CookieInclusionStatus status) - : effective_same_site(effective_same_site), status(status) {} + CookieInclusionStatus status, + CookieAccessSemantics access_semantics) + : status(status), + effective_same_site(effective_same_site), + access_semantics(access_semantics) {} + +CookieAccessResult::CookieAccessResult(CookieInclusionStatus status) + : status(status) {} CookieAccessResult::CookieAccessResult(const CookieAccessResult&) = default; diff --git a/chromium/net/cookies/cookie_access_result.h b/chromium/net/cookies/cookie_access_result.h index a21305bfe11..7e5aa208b6f 100644 --- a/chromium/net/cookies/cookie_access_result.h +++ b/chromium/net/cookies/cookie_access_result.h @@ -12,9 +12,15 @@ namespace net { struct NET_EXPORT CookieAccessResult { + // Creating a CookieAccessResult with out any parameters will create a + // CookieInclusionStatus that has no exclusion reasons, therefore + // indicates inclusion. CookieAccessResult(); CookieAccessResult(CookieEffectiveSameSite effective_same_site, - CookieInclusionStatus status); + CookieInclusionStatus status, + CookieAccessSemantics access_semantics); + + explicit CookieAccessResult(CookieInclusionStatus status); CookieAccessResult(const CookieAccessResult& cookie_access_result); @@ -24,9 +30,10 @@ struct NET_EXPORT CookieAccessResult { ~CookieAccessResult(); - CookieEffectiveSameSite effective_same_site = - CookieEffectiveSameSite::LAX_MODE; CookieInclusionStatus status; + CookieEffectiveSameSite effective_same_site = + CookieEffectiveSameSite::UNDEFINED; + CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN; }; } // namespace net diff --git a/chromium/net/cookies/cookie_change_dispatcher.cc b/chromium/net/cookies/cookie_change_dispatcher.cc index 07c6457fc4c..755a4128d19 100644 --- a/chromium/net/cookies/cookie_change_dispatcher.cc +++ b/chromium/net/cookies/cookie_change_dispatcher.cc @@ -37,9 +37,15 @@ const char* CookieChangeCauseToString(CookieChangeCause cause) { CookieChangeInfo::CookieChangeInfo() = default; CookieChangeInfo::CookieChangeInfo(const CanonicalCookie& cookie, - CookieAccessSemantics access_semantics, + CookieAccessResult access_result, CookieChangeCause cause) - : cookie(cookie), access_semantics(access_semantics), cause(cause) {} + : cookie(cookie), access_result(access_result), cause(cause) { + DCHECK(access_result.status.IsInclude()); + if (CookieChangeCauseIsDeletion(cause)) { + DCHECK_EQ(access_result.effective_same_site, + CookieEffectiveSameSite::UNDEFINED); + } +} CookieChangeInfo::~CookieChangeInfo() = default; diff --git a/chromium/net/cookies/cookie_change_dispatcher.h b/chromium/net/cookies/cookie_change_dispatcher.h index c1b7f516249..ffa9a003da7 100644 --- a/chromium/net/cookies/cookie_change_dispatcher.h +++ b/chromium/net/cookies/cookie_change_dispatcher.h @@ -12,6 +12,7 @@ #include "base/compiler_specific.h" #include "net/base/net_export.h" #include "net/cookies/canonical_cookie.h" +#include "net/cookies/cookie_access_result.h" class GURL; @@ -41,15 +42,15 @@ enum class CookieChangeCause { struct NET_EXPORT CookieChangeInfo { CookieChangeInfo(); CookieChangeInfo(const CanonicalCookie& cookie, - CookieAccessSemantics access_semantics, + CookieAccessResult access_result, CookieChangeCause cause); ~CookieChangeInfo(); // The cookie that changed. CanonicalCookie cookie; - // The access semantics of the cookie at the time of the change. - CookieAccessSemantics access_semantics = CookieAccessSemantics::UNKNOWN; + // The access result of the cookie at the time of the change. + CookieAccessResult access_result; // The reason for the change. CookieChangeCause cause = CookieChangeCause::EXPLICIT; diff --git a/chromium/net/cookies/cookie_constants.h b/chromium/net/cookies/cookie_constants.h index 732d7d56c70..8397a471a8b 100644 --- a/chromium/net/cookies/cookie_constants.h +++ b/chromium/net/cookies/cookie_constants.h @@ -47,6 +47,9 @@ enum class CookieEffectiveSameSite { LAX_MODE = 1, STRICT_MODE = 2, LAX_MODE_ALLOW_UNSAFE = 3, + // Undefined is used when no value applies for the object as there is no + // valid cookie object to evaluate on. + UNDEFINED = 4, // Keep last, used for histograms. COUNT diff --git a/chromium/net/cookies/cookie_inclusion_status.cc b/chromium/net/cookies/cookie_inclusion_status.cc index 8e13916ba13..240b17cd1b0 100644 --- a/chromium/net/cookies/cookie_inclusion_status.cc +++ b/chromium/net/cookies/cookie_inclusion_status.cc @@ -51,6 +51,11 @@ bool CookieInclusionStatus::HasExclusionReason(ExclusionReason reason) const { return exclusion_reasons_ & GetExclusionBitmask(reason); } +bool CookieInclusionStatus::HasOnlyExclusionReason( + ExclusionReason reason) const { + return exclusion_reasons_ == GetExclusionBitmask(reason); +} + void CookieInclusionStatus::AddExclusionReason(ExclusionReason reason) { exclusion_reasons_ |= GetExclusionBitmask(reason); // If the cookie would be excluded for reasons other than the new SameSite diff --git a/chromium/net/cookies/cookie_inclusion_status.h b/chromium/net/cookies/cookie_inclusion_status.h index 3f38eddb39b..9e506b55501 100644 --- a/chromium/net/cookies/cookie_inclusion_status.h +++ b/chromium/net/cookies/cookie_inclusion_status.h @@ -184,6 +184,10 @@ class NET_EXPORT CookieInclusionStatus { // Whether the given reason for exclusion is present. bool HasExclusionReason(ExclusionReason status_type) const; + // Whether the given reason for exclusion is present, and is the ONLY reason + // for exclusion. + bool HasOnlyExclusionReason(ExclusionReason status_type) const; + // Add an exclusion reason. void AddExclusionReason(ExclusionReason status_type); diff --git a/chromium/net/cookies/cookie_inclusion_status_unittest.cc b/chromium/net/cookies/cookie_inclusion_status_unittest.cc index bc5c7edaa39..579edb4b8ae 100644 --- a/chromium/net/cookies/cookie_inclusion_status_unittest.cc +++ b/chromium/net/cookies/cookie_inclusion_status_unittest.cc @@ -32,17 +32,31 @@ TEST(CookieInclusionStatusTest, IncludeStatus) { TEST(CookieInclusionStatusTest, ExcludeStatus) { int num_exclusion_reasons = static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + // Test exactly one exclusion reason and multiple (two) exclusion reasons. for (int i = 0; i < num_exclusion_reasons; ++i) { - auto reason = static_cast<CookieInclusionStatus::ExclusionReason>(i); - CookieInclusionStatus status(reason); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.IsInclude()); - EXPECT_TRUE(status.HasExclusionReason(reason)); + auto reason1 = static_cast<CookieInclusionStatus::ExclusionReason>(i); + CookieInclusionStatus status_one_reason(reason1); + EXPECT_TRUE(status_one_reason.IsValid()); + EXPECT_FALSE(status_one_reason.IsInclude()); + EXPECT_TRUE(status_one_reason.HasExclusionReason(reason1)); + EXPECT_TRUE(status_one_reason.HasOnlyExclusionReason(reason1)); + for (int j = 0; j < num_exclusion_reasons; ++j) { if (i == j) continue; - EXPECT_FALSE(status.HasExclusionReason( - static_cast<CookieInclusionStatus::ExclusionReason>(j))); + auto reason2 = static_cast<CookieInclusionStatus::ExclusionReason>(j); + + EXPECT_FALSE(status_one_reason.HasExclusionReason(reason2)); + EXPECT_FALSE(status_one_reason.HasOnlyExclusionReason(reason2)); + + CookieInclusionStatus status_two_reasons = status_one_reason; + status_two_reasons.AddExclusionReason(reason2); + EXPECT_TRUE(status_two_reasons.IsValid()); + EXPECT_FALSE(status_two_reasons.IsInclude()); + EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason1)); + EXPECT_TRUE(status_two_reasons.HasExclusionReason(reason2)); + EXPECT_FALSE(status_two_reasons.HasOnlyExclusionReason(reason1)); + EXPECT_FALSE(status_two_reasons.HasOnlyExclusionReason(reason2)); } } } diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc index 477b47a7721..265deed0e52 100644 --- a/chromium/net/cookies/cookie_monster.cc +++ b/chromium/net/cookies/cookie_monster.cc @@ -765,8 +765,10 @@ void CookieMonster::StoreLoadedCookies( for (auto& cookie : cookies) { CanonicalCookie* cookie_ptr = cookie.get(); - auto inserted = InternalInsertCookie(GetKey(cookie_ptr->Domain()), - std::move(cookie), false); + CookieAccessResult access_result; + access_result.access_semantics = CookieAccessSemantics::UNKNOWN; + auto inserted = InternalInsertCookie( + GetKey(cookie_ptr->Domain()), std::move(cookie), false, access_result); const Time cookie_access_time(cookie_ptr->LastAccessDate()); if (earliest_access_time_.is_null() || cookie_access_time < earliest_access_time_) { @@ -1115,7 +1117,8 @@ base::Time CookieMonster::EffectiveCreationTimeForMaybePreexistingCookie( CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( const std::string& key, std::unique_ptr<CanonicalCookie> cc, - bool sync_to_store) { + bool sync_to_store, + const CookieAccessResult& access_result) { DCHECK(thread_checker_.CalledOnValidThread()); CanonicalCookie* cc_ptr = cc.get(); @@ -1132,19 +1135,16 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( // See InitializeHistograms() for details. int32_t type_sample = - !cc_ptr->IsEffectivelySameSiteNone(GetAccessSemanticsForCookie( - *cc_ptr, false /* legacy_access_granted */)) + !cc_ptr->IsEffectivelySameSiteNone(access_result.access_semantics) ? 1 << COOKIE_TYPE_SAME_SITE : 0; type_sample |= cc_ptr->IsHttpOnly() ? 1 << COOKIE_TYPE_HTTPONLY : 0; type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0; histogram_cookie_type_->Add(type_sample); + DCHECK(access_result.status.IsInclude()); change_dispatcher_.DispatchChange( - CookieChangeInfo(*cc_ptr, - GetAccessSemanticsForCookie( - *cc_ptr, false /* legacy_access_granted */), - CookieChangeCause::INSERTED), + CookieChangeInfo(*cc_ptr, access_result, CookieChangeCause::INSERTED), true); // If this is the first cookie in |cookies_| with this key, increment the @@ -1165,17 +1165,18 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, SetCookiesCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - CookieInclusionStatus status; + CookieAccessResult access_result; bool secure_source = source_url.SchemeIsCryptographic(); cc->SetSourceScheme(secure_source ? CookieSourceScheme::kSecure : CookieSourceScheme::kNonSecure); if ((cc->IsSecure() && !secure_source)) { - status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY); + access_result.status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_SECURE_ONLY); } if (!IsCookieableScheme(source_url.scheme())) { - status.AddExclusionReason( + access_result.status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME); } @@ -1188,7 +1189,7 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, cookie_util::IsRecentCreationTimeGrantsLegacyCookieSemanticsEnabled() ? EffectiveCreationTimeForMaybePreexistingCookie(key, *cc) : base::Time()), - &status); + &access_result); base::Time creation_date = cc->CreationDate(); if (creation_date.is_null()) { @@ -1201,11 +1202,11 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, MaybeDeleteEquivalentCookieAndUpdateStatus( key, *cc, secure_source, options.exclude_httponly(), already_expired, - &creation_date_to_inherit, &status); + &creation_date_to_inherit, &access_result.status); - if (status.HasExclusionReason( + if (access_result.status.HasExclusionReason( CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) || - status.HasExclusionReason( + access_result.status.HasExclusionReason( CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)) { DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() not clobbering httponly cookie or secure cookie for " @@ -1215,13 +1216,13 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, // Now that IsSetPermittedInContext() and // MaybeDeleteEquivalentCookieAndUpdateStatus() have had a chance to set // cookie warnings/exclusions, record the downgrade metric. - if (status.ShouldRecordDowngradeMetrics()) { + if (access_result.status.ShouldRecordDowngradeMetrics()) { UMA_HISTOGRAM_ENUMERATION( "Cookie.SameSiteContextDowngradeResponse", - status.GetBreakingDowngradeMetricsEnumValue(source_url)); + access_result.status.GetBreakingDowngradeMetricsEnumValue(source_url)); } - if (status.IsInclude()) { + if (access_result.status.IsInclude()) { DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() key: " << key << " cc: " << cc->DebugString(); @@ -1255,7 +1256,7 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, MaybeRecordCookieAccessWithOptions(*cc, options, true); - InternalInsertCookie(key, std::move(cc), true); + InternalInsertCookie(key, std::move(cc), true, access_result); } else { DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() not storing already expired cookie."; @@ -1270,7 +1271,7 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, } // TODO(chlily): Log metrics. - MaybeRunCookieCallback(std::move(callback), status); + MaybeRunCookieCallback(std::move(callback), access_result); } void CookieMonster::SetAllCookies(CookieList list, @@ -1295,7 +1296,11 @@ void CookieMonster::SetAllCookies(CookieList list, (cookie.ExpiryDate() - creation_time).InMinutes()); } - InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true); + CookieAccessResult access_result; + access_result.access_semantics = GetAccessSemanticsForCookie( + cookie, false /* legacy_semantics_granted */); + InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true, + access_result); GarbageCollect(creation_time, key); } @@ -1303,7 +1308,7 @@ void CookieMonster::SetAllCookies(CookieList list, // shouldn't have a return value. But it should also be deleted (see // https://codereview.chromium.org/2882063002/#msg64), which would // solve the return value problem. - MaybeRunCookieCallback(std::move(callback), CookieInclusionStatus()); + MaybeRunCookieCallback(std::move(callback), CookieAccessResult()); } void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, @@ -1364,7 +1369,10 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, change_dispatcher_.DispatchChange( CookieChangeInfo( *cc, - GetAccessSemanticsForCookie(*cc, false /* legacy_access_granted */), + CookieAccessResult(CookieEffectiveSameSite::UNDEFINED, + CookieInclusionStatus(), + GetAccessSemanticsForCookie( + *cc, false /* legacy_access_granted */)), mapping.cause), mapping.notify); diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h index 9908e6f8e7e..57ce9d640ac 100644 --- a/chromium/net/cookies/cookie_monster.h +++ b/chromium/net/cookies/cookie_monster.h @@ -448,9 +448,11 @@ class NET_EXPORT CookieMonster : public CookieStore { // Inserts |cc| into cookies_. Returns an iterator that points to the inserted // cookie in cookies_. Guarantee: all iterators to cookies_ remain valid. - CookieMap::iterator InternalInsertCookie(const std::string& key, - std::unique_ptr<CanonicalCookie> cc, - bool sync_to_store); + CookieMap::iterator InternalInsertCookie( + const std::string& key, + std::unique_ptr<CanonicalCookie> cc, + bool sync_to_store, + const CookieAccessResult& access_result); // Sets all cookies from |list| after deleting any equivalent cookie. // For data gathering purposes, this routine is treated as if it is diff --git a/chromium/net/cookies/cookie_monster_change_dispatcher.cc b/chromium/net/cookies/cookie_monster_change_dispatcher.cc index 6bd731f47ca..d79fb3a54d6 100644 --- a/chromium/net/cookies/cookie_monster_change_dispatcher.cc +++ b/chromium/net/cookies/cookie_monster_change_dispatcher.cc @@ -60,7 +60,7 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange( if (!url_.is_empty() && !cookie .IncludeForRequestURL(url_, CookieOptions::MakeAllInclusive(), - change.access_semantics) + change.access_result.access_semantics) .status.IsInclude()) { return; } diff --git a/chromium/net/cookies/cookie_monster_perftest.cc b/chromium/net/cookies/cookie_monster_perftest.cc index 96d16f545a6..10c79a1f191 100644 --- a/chromium/net/cookies/cookie_monster_perftest.cc +++ b/chromium/net/cookies/cookie_monster_perftest.cc @@ -28,8 +28,7 @@ namespace net { namespace { const int kNumCookies = 20000; -const char kCookieLine[] = "A = \"b=;\\\"\" ;secure;;;"; -const char kGoogleURL[] = "http://www.foo.com"; +const char kCookieLine[] = "A = \"b=;\\\"\" ;secure;;; samesite=none"; static constexpr char kMetricPrefixParsedCookie[] = "ParsedCookie."; static constexpr char kMetricPrefixCookieMonster[] = "CookieMonster."; @@ -105,8 +104,9 @@ class SetCookieCallback : public CookieTestCallback { } private: - void Run(CookieInclusionStatus status) { - EXPECT_TRUE(status.IsInclude()); + void Run(CookieAccessResult result) { + EXPECT_TRUE(result.status.IsInclude()) + << "result.status: " << result.status.GetDebugString(); CookieTestCallback::Run(); } CookieOptions options_; @@ -178,7 +178,7 @@ TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) { auto cm = std::make_unique<CookieMonster>(nullptr, nullptr); std::vector<std::string> cookies; for (int i = 0; i < kNumCookies; i++) { - cookies.push_back(base::StringPrintf("a%03d=b", i)); + cookies.push_back(base::StringPrintf("a%03d=b; SameSite=None; Secure", i)); } SetCookieCallback setCookieCallback; @@ -187,9 +187,10 @@ TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) { auto reporter = SetUpCookieMonsterReporter("single_host"); base::ElapsedTimer add_timer; + const GURL kGoogleURL = GURL("https://www.foo.com"); for (std::vector<std::string>::const_iterator it = cookies.begin(); it != cookies.end(); ++it) { - setCookieCallback.SetCookie(cm.get(), GURL(kGoogleURL), *it); + setCookieCallback.SetCookie(cm.get(), kGoogleURL, *it); } reporter.AddResult(kMetricAddTimeMs, add_timer.Elapsed().InMillisecondsF()); @@ -198,7 +199,7 @@ TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) { base::ElapsedTimer query_timer; for (std::vector<std::string>::const_iterator it = cookies.begin(); it != cookies.end(); ++it) { - getCookieListCallback.GetCookieList(cm.get(), GURL(kGoogleURL)); + getCookieListCallback.GetCookieList(cm.get(), kGoogleURL); } reporter.AddResult(kMetricQueryTimeMs, query_timer.Elapsed().InMillisecondsF()); @@ -250,7 +251,8 @@ TEST_F(CookieMonsterTest, TestDomainTree) { auto cm = std::make_unique<CookieMonster>(nullptr, nullptr); GetCookieListCallback getCookieListCallback; SetCookieCallback setCookieCallback; - const char domain_cookie_format_tree[] = "a=b; domain=%s"; + const char domain_cookie_format_tree[] = + "a=b; domain=%s; samesite=none; secure"; const std::string domain_base("top.com"); std::vector<std::string> domain_list; @@ -323,7 +325,8 @@ TEST_F(CookieMonsterTest, TestDomainLine) { domain_list.push_back("b.a.b.a.top.com"); EXPECT_EQ(4u, domain_list.size()); - const char domain_cookie_format_line[] = "a%03d=b; domain=%s"; + const char domain_cookie_format_line[] = + "a%03d=b; domain=%s; samesite=none; secure"; for (int i = 0; i < 8; i++) { for (std::vector<std::string>::const_iterator it = domain_list.begin(); it != domain_list.end(); it++) { @@ -445,8 +448,8 @@ TEST_F(CookieMonsterTest, TestGCTimes) { test_case.num_cookies, test_case.num_old_cookies, 0, 0, CookieMonster::kSafeFromGlobalPurgeDays * 2); - GURL gurl("http://foo.com"); - std::string cookie_line("z=3"); + GURL gurl("https://foo.com"); + std::string cookie_line("z=3; samesite=none; secure"); // Trigger the Garbage collection we're allowed. setCookieCallback.SetCookie(cm.get(), gurl, cookie_line); diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc index fc83d6a6211..a4b72d59e64 100644 --- a/chromium/net/cookies/cookie_monster_unittest.cc +++ b/chromium/net/cookies/cookie_monster_unittest.cc @@ -148,10 +148,10 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { bool SetAllCookies(CookieMonster* cm, const CookieList& list) { DCHECK(cm); - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cm->SetAllCookiesAsync(list, callback.MakeCallback()); callback.WaitUntilDone(); - return callback.result().IsInclude(); + return callback.result().status.IsInclude(); } bool SetCookieWithCreationTime(CookieMonster* cm, @@ -160,13 +160,13 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { base::Time creation_time) { DCHECK(cm); DCHECK(!creation_time.is_null()); - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cm->SetCanonicalCookieAsync( CanonicalCookie::Create(url, cookie_line, creation_time, base::nullopt /* server_time */), url, CookieOptions::MakeAllInclusive(), callback.MakeCallback()); callback.WaitUntilDone(); - return callback.result().IsInclude(); + return callback.result().status.IsInclude(); } uint32_t DeleteAllCreatedInTimeRange(CookieMonster* cm, @@ -981,7 +981,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { // Generate puts to store w/o needing a proper expiration. cookie_monster_->SetPersistSessionCookies(true); - ResultSavingCookieCallback<CookieInclusionStatus> call1; + ResultSavingCookieCallback<CookieAccessResult> call1; cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(), base::nullopt /* server_time */), @@ -992,17 +992,17 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY); call1.WaitUntilDone(); - EXPECT_TRUE(call1.result().IsInclude()); + EXPECT_TRUE(call1.result().status.IsInclude()); EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary()); - ResultSavingCookieCallback<CookieInclusionStatus> call2; + ResultSavingCookieCallback<CookieAccessResult> call2; cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "X=Y", base::Time::Now(), base::nullopt /* server_time */), http_www_foo_.url(), CookieOptions::MakeAllInclusive(), call2.MakeCallback()); ASSERT_TRUE(call2.was_run()); - EXPECT_TRUE(call2.result().IsInclude()); + EXPECT_TRUE(call2.result().status.IsInclude()); EXPECT_EQ("ADD; ", TakeCommandSummary()); } @@ -1020,21 +1020,21 @@ TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) { false, true, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); - ResultSavingCookieCallback<CookieInclusionStatus> call1; + ResultSavingCookieCallback<CookieAccessResult> call1; cookie_monster_->SetAllCookiesAsync(list, call1.MakeCallback()); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(call1.was_run()); ExecuteLoads(CookieStoreCommand::LOAD); call1.WaitUntilDone(); - EXPECT_TRUE(call1.result().IsInclude()); + EXPECT_TRUE(call1.result().status.IsInclude()); EXPECT_EQ("LOAD; ADD; ADD; ", TakeCommandSummary()); // 2nd set doesn't need to read from store. It erases the old cookies, though. - ResultSavingCookieCallback<CookieInclusionStatus> call2; + ResultSavingCookieCallback<CookieAccessResult> call2; cookie_monster_->SetAllCookiesAsync(list, call2.MakeCallback()); ASSERT_TRUE(call2.was_run()); - EXPECT_TRUE(call2.result().IsInclude()); + EXPECT_TRUE(call2.result().status.IsInclude()); EXPECT_EQ("REMOVE; REMOVE; ADD; ADD; ", TakeCommandSummary()); } @@ -1232,7 +1232,7 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { bool get_cookie_list_callback_was_run = false; GetCookieListCallback get_cookie_list_callback_deferred; - ResultSavingCookieCallback<CookieInclusionStatus> set_cookies_callback; + ResultSavingCookieCallback<CookieAccessResult> set_cookies_callback; base::RunLoop run_loop; cookie_monster_->GetCookieListWithOptionsAsync( http_www_foo_.url(), CookieOptions::MakeAllInclusive(), @@ -1273,7 +1273,7 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary()); EXPECT_TRUE(get_cookie_list_callback_was_run); ASSERT_TRUE(set_cookies_callback.was_run()); - EXPECT_TRUE(set_cookies_callback.result().IsInclude()); + EXPECT_TRUE(set_cookies_callback.result().status.IsInclude()); ASSERT_TRUE(get_cookie_list_callback_deferred.was_run()); EXPECT_THAT(get_cookie_list_callback_deferred.cookies(), @@ -1487,38 +1487,38 @@ TEST_F(CookieMonsterTest, SetCookieableSchemes) { base::Optional<base::Time> server_time = base::nullopt; EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "x=1").IsInclude()); - EXPECT_TRUE(SetCanonicalCookieReturnStatus( + EXPECT_TRUE(SetCanonicalCookieReturnAccessResult( cm.get(), CanonicalCookie::Create(http_url, "y=1", now, server_time), http_url, false /*modify_httponly*/) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), foo_url, "x=1") .HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); - EXPECT_TRUE(SetCanonicalCookieReturnStatus( + EXPECT_TRUE(SetCanonicalCookieReturnAccessResult( cm.get(), CanonicalCookie::Create(foo_url, "y=1", now, server_time), foo_url, false /*modify_httponly*/) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm_foo.get(), foo_url, "x=1").IsInclude()); - EXPECT_TRUE(SetCanonicalCookieReturnStatus( + EXPECT_TRUE(SetCanonicalCookieReturnAccessResult( cm_foo.get(), CanonicalCookie::Create(foo_url, "y=1", now, server_time), foo_url, false /*modify_httponly*/) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm_foo.get(), http_url, "x=1") .HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); - EXPECT_TRUE(SetCanonicalCookieReturnStatus( + EXPECT_TRUE(SetCanonicalCookieReturnAccessResult( cm_foo.get(), CanonicalCookie::Create(http_url, "y=1", now, server_time), http_url, false /*modify_httponly*/) - .HasExactlyExclusionReasonsForTesting( + .status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); } @@ -2234,7 +2234,7 @@ TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) { auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; + ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback; cm->SetCanonicalCookieAsync(std::move(cookie), kUrl, CookieOptions::MakeAllInclusive(), set_cookie_callback.MakeCallback()); @@ -2254,7 +2254,7 @@ TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) { // The tasks should run in order, and the get should see the cookies. set_cookie_callback.WaitUntilDone(); - EXPECT_TRUE(set_cookie_callback.result().IsInclude()); + EXPECT_TRUE(set_cookie_callback.result().status.IsInclude()); get_cookies_callback1.WaitUntilDone(); EXPECT_EQ(1u, get_cookies_callback1.cookies().size()); @@ -2322,7 +2322,7 @@ TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) { auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; + ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback; cm->SetCanonicalCookieAsync(std::move(cookie), kUrl, CookieOptions::MakeAllInclusive(), set_cookie_callback.MakeCallback()); @@ -2341,7 +2341,7 @@ TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) { EXPECT_EQ(0u, get_cookies_callback1.cookies().size()); set_cookie_callback.WaitUntilDone(); - EXPECT_TRUE(set_cookie_callback.result().IsInclude()); + EXPECT_TRUE(set_cookie_callback.result().status.IsInclude()); get_cookies_callback2.WaitUntilDone(); EXPECT_EQ(1u, get_cookies_callback2.cookies().size()); @@ -2369,7 +2369,7 @@ TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) { // Get all cookies task that queues a task to set a cookie when executed. auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; + ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback; cm->GetAllCookiesAsync(base::BindOnce( &RunClosureOnAllCookiesReceived, base::BindOnce(&CookieStore::SetCanonicalCookieAsync, @@ -2394,7 +2394,7 @@ TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) { EXPECT_EQ(0u, get_cookies_callback1.cookies().size()); set_cookie_callback.WaitUntilDone(); - EXPECT_TRUE(set_cookie_callback.result().IsInclude()); + EXPECT_TRUE(set_cookie_callback.result().status.IsInclude()); // A subsequent get cookies call should see the new cookie. GetAllCookiesCallback get_cookies_callback2; @@ -2859,10 +2859,10 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { auto preexisting_cookie = CanonicalCookie::Create( https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now(), base::nullopt /* server_time */); - CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult( cm.get(), std::move(preexisting_cookie), https_www_foo_.url(), true /* can_modify_httponly */); - ASSERT_TRUE(status.IsInclude()); + ASSERT_TRUE(access_result.status.IsInclude()); // Set a new cookie with a different name. Should work because cookies with // different names are not considered equivalent nor "equivalent for secure @@ -2879,10 +2879,10 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { base::nullopt /* server_time */); // Allow modifying HttpOnly, so that we don't skip preexisting cookies for // being HttpOnly. - status = SetCanonicalCookieReturnStatus(cm.get(), std::move(bad_cookie), - http_www_foo_.url(), - true /* can_modify_httponly */); - EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + access_result = SetCanonicalCookieReturnAccessResult( + cm.get(), std::move(bad_cookie), http_www_foo_.url(), + true /* can_modify_httponly */); + EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // The preexisting cookie should still be there. EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(), @@ -2910,10 +2910,10 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { base::nullopt /* server_time */); // Allow modifying HttpOnly, so that we don't skip preexisting cookies for // being HttpOnly. - status = SetCanonicalCookieReturnStatus(cm.get(), std::move(bad_cookie), - http_www_foo_.url(), - true /* can_modify_httponly */); - EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + access_result = SetCanonicalCookieReturnAccessResult( + cm.get(), std::move(bad_cookie), http_www_foo_.url(), + true /* can_modify_httponly */); + EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // The preexisting cookie should still be there. EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(), @@ -2938,10 +2938,10 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { bad_cookie = CanonicalCookie::Create(https_www_foo_.url(), "A=E; Secure", base::Time::Now(), base::nullopt /* server_time */); - status = SetCanonicalCookieReturnStatus(cm.get(), std::move(bad_cookie), - https_www_foo_.url(), - false /* can_modify_httponly */); - EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + access_result = SetCanonicalCookieReturnAccessResult( + cm.get(), std::move(bad_cookie), https_www_foo_.url(), + false /* can_modify_httponly */); + EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); entries = net_log_.GetEntries(); @@ -2962,20 +2962,20 @@ TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) { auto preexisting_cookie = CanonicalCookie::Create( https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now(), base::nullopt /* server_time */); - CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult( cm.get(), std::move(preexisting_cookie), https_www_foo_.url(), true /* can_modify_httponly */); - ASSERT_TRUE(status.IsInclude()); + ASSERT_TRUE(access_result.status.IsInclude()); // Attempt to set a new cookie with the same name that is not Secure or // Httponly from an insecure scheme. auto cookie = CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(), base::nullopt /* server_time */); - status = SetCanonicalCookieReturnStatus(cm.get(), std::move(cookie), - http_www_foo_.url(), - false /* can_modify_httponly */); - EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + access_result = SetCanonicalCookieReturnAccessResult( + cm.get(), std::move(cookie), http_www_foo_.url(), + false /* can_modify_httponly */); + EXPECT_TRUE(access_result.status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE, CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); @@ -2997,18 +2997,18 @@ TEST_F(CookieMonsterTest, DontDeleteEquivalentCookieIfSetIsRejected) { auto preexisting_cookie = CanonicalCookie::Create( http_www_foo_.url(), "cookie=foo", base::Time::Now(), base::nullopt /* server_time */); - CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + CookieAccessResult access_result = SetCanonicalCookieReturnAccessResult( cm.get(), std::move(preexisting_cookie), http_www_foo_.url(), false /* can_modify_httponly */); - ASSERT_TRUE(status.IsInclude()); + ASSERT_TRUE(access_result.status.IsInclude()); auto bad_cookie = CanonicalCookie::Create( http_www_foo_.url(), "cookie=bar;secure", base::Time::Now(), base::nullopt /* server_time */); - CookieInclusionStatus status2 = SetCanonicalCookieReturnStatus( + CookieAccessResult access_result2 = SetCanonicalCookieReturnAccessResult( cm.get(), std::move(bad_cookie), http_www_foo_.url(), false /* can_modify_httponly */); - EXPECT_TRUE(status2.HasExactlyExclusionReasonsForTesting( + EXPECT_TRUE(access_result2.status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // Check that the original cookie is still there. @@ -3613,7 +3613,7 @@ TEST_F(CookieMonsterTest, SetCanonicalCookieDoesNotBlockForLoadAll) { CookieMonster cm(persistent_store.get(), nullptr); // Start of a canonical cookie set. - ResultSavingCookieCallback<CookieInclusionStatus> callback_set; + ResultSavingCookieCallback<CookieAccessResult> callback_set; GURL cookie_url("http://a.com/"); cm.SetCanonicalCookieAsync( CanonicalCookie::Create(cookie_url, "A=B", base::Time::Now(), @@ -3699,14 +3699,14 @@ TEST_F(CookieMonsterTest, DeleteCookieWithInheritedTimestamps) { // Write a cookie created at |t1|. auto cookie = CanonicalCookie::Create(url, cookie_line, t1, server_time); - ResultSavingCookieCallback<CookieInclusionStatus> set_callback_1; + ResultSavingCookieCallback<CookieAccessResult> set_callback_1; cm.SetCanonicalCookieAsync(std::move(cookie), url, options, set_callback_1.MakeCallback()); set_callback_1.WaitUntilDone(); // Overwrite the cookie at |t2|. cookie = CanonicalCookie::Create(url, cookie_line, t2, server_time); - ResultSavingCookieCallback<CookieInclusionStatus> set_callback_2; + ResultSavingCookieCallback<CookieAccessResult> set_callback_2; cm.SetCanonicalCookieAsync(std::move(cookie), url, options, set_callback_2.MakeCallback()); set_callback_2.WaitUntilDone(); @@ -3739,11 +3739,11 @@ TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) { ASSERT_TRUE(status.IsInclude()); // ... but the environment is checked on set, so this may be rejected then. - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cm.SetCanonicalCookieAsync(std::move(cookie), url, env_cross_site, callback.MakeCallback()); callback.WaitUntilDone(); - EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( + EXPECT_TRUE(callback.result().status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } @@ -3763,12 +3763,12 @@ TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { ASSERT_TRUE(status.IsInclude()); // Cookie is rejected when attempting to set from a non-secure scheme. - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cm.SetCanonicalCookieAsync(std::move(cookie), http_url, CookieOptions::MakeAllInclusive(), callback.MakeCallback()); callback.WaitUntilDone(); - EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( + EXPECT_TRUE(callback.result().status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); } @@ -3793,11 +3793,11 @@ TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { CookieOptions::SameSiteCookieContext( CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT)); options_no_httponly.set_exclude_httponly(); // Default, but make it explicit. - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cm.SetCanonicalCookieAsync(std::move(cookie), url, options_no_httponly, callback.MakeCallback()); callback.WaitUntilDone(); - EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( + EXPECT_TRUE(callback.result().status.HasExactlyExclusionReasonsForTesting( {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); } @@ -3910,16 +3910,15 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { base::nullopt /* server_time */); // Make a copy so we can delete it after the test. CanonicalCookie cookie_copy = *cookie; - CookieInclusionStatus result = SetCanonicalCookieReturnStatus( + CookieAccessResult result = SetCanonicalCookieReturnAccessResult( cm.get(), std::move(cookie), url, true /* can_modify_httponly (irrelevant) */); - EXPECT_EQ(test.expected_set_cookie_result, result) + EXPECT_EQ(test.expected_set_cookie_result, result.status) << "Test case " << i << " failed."; - if (result.IsInclude()) { + if (result.status.IsInclude()) { auto cookies = GetAllCookiesForURL(cm.get(), url); ASSERT_EQ(1u, cookies.size()); - EXPECT_EQ(test.expected_effective_samesite, - cookies[0].GetEffectiveSameSiteForTesting()) + EXPECT_EQ(test.expected_effective_samesite, result.effective_same_site) << "Test case " << i << " failed."; DeleteCanonicalCookie(cm.get(), cookie_copy); } diff --git a/chromium/net/cookies/cookie_store.h b/chromium/net/cookies/cookie_store.h index 47f2942cd32..5ffbe648343 100644 --- a/chromium/net/cookies/cookie_store.h +++ b/chromium/net/cookies/cookie_store.h @@ -19,8 +19,8 @@ #include "net/base/net_export.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_access_delegate.h" +#include "net/cookies/cookie_access_result.h" #include "net/cookies/cookie_deletion_info.h" -#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" class GURL; @@ -55,7 +55,7 @@ class NET_EXPORT CookieStore { const CookieList& cookies, const std::vector<CookieAccessSemantics>& access_semantics_list)>; using SetCookiesCallback = - base::OnceCallback<void(CookieInclusionStatus status)>; + base::OnceCallback<void(CookieAccessResult access_result)>; using DeleteCallback = base::OnceCallback<void(uint32_t num_deleted)>; using SetCookieableSchemesCallback = base::OnceCallback<void(bool success)>; diff --git a/chromium/net/cookies/cookie_store_change_unittest.h b/chromium/net/cookies/cookie_store_change_unittest.h index ba3767fd677..d2259dcfb3e 100644 --- a/chromium/net/cookies/cookie_store_change_unittest.h +++ b/chromium/net/cookies/cookie_store_change_unittest.h @@ -691,16 +691,20 @@ TYPED_TEST_P(CookieStoreChangeGlobalTest, ChangeIncludesCookieAccessSemantics) { EXPECT_EQ("domain1.test", cookie_changes[0].cookie.Domain()); EXPECT_TRUE(this->IsExpectedAccessSemantics( - CookieAccessSemantics::LEGACY, cookie_changes[0].access_semantics)); + CookieAccessSemantics::LEGACY, + cookie_changes[0].access_result.access_semantics)); EXPECT_EQ("domain2.test", cookie_changes[1].cookie.Domain()); EXPECT_TRUE(this->IsExpectedAccessSemantics( - CookieAccessSemantics::NONLEGACY, cookie_changes[1].access_semantics)); + CookieAccessSemantics::NONLEGACY, + cookie_changes[1].access_result.access_semantics)); EXPECT_EQ("domain3.test", cookie_changes[2].cookie.Domain()); EXPECT_TRUE(this->IsExpectedAccessSemantics( - CookieAccessSemantics::UNKNOWN, cookie_changes[2].access_semantics)); + CookieAccessSemantics::UNKNOWN, + cookie_changes[2].access_result.access_semantics)); EXPECT_EQ("domain4.test", cookie_changes[3].cookie.Domain()); EXPECT_TRUE(this->IsExpectedAccessSemantics( - CookieAccessSemantics::UNKNOWN, cookie_changes[3].access_semantics)); + CookieAccessSemantics::UNKNOWN, + cookie_changes[3].access_result.access_semantics)); } TYPED_TEST_P(CookieStoreChangeUrlTest, NoCookie) { @@ -1715,7 +1719,8 @@ TYPED_TEST_P(CookieStoreChangeUrlTest, ChangeIncludesCookieAccessSemantics) { EXPECT_EQ("domain1.test", cookie_changes[0].cookie.Domain()); EXPECT_TRUE(this->IsExpectedAccessSemantics( - CookieAccessSemantics::LEGACY, cookie_changes[0].access_semantics)); + CookieAccessSemantics::LEGACY, + cookie_changes[0].access_result.access_semantics)); } TYPED_TEST_P(CookieStoreChangeNamedTest, NoCookie) { @@ -2849,7 +2854,8 @@ TYPED_TEST_P(CookieStoreChangeNamedTest, ChangeIncludesCookieAccessSemantics) { EXPECT_EQ("domain1.test", cookie_changes[0].cookie.Domain()); EXPECT_EQ("cookie", cookie_changes[0].cookie.Name()); EXPECT_TRUE(this->IsExpectedAccessSemantics( - CookieAccessSemantics::LEGACY, cookie_changes[0].access_semantics)); + CookieAccessSemantics::LEGACY, + cookie_changes[0].access_result.access_semantics)); } REGISTER_TYPED_TEST_SUITE_P(CookieStoreChangeGlobalTest, diff --git a/chromium/net/cookies/cookie_store_test_helpers.cc b/chromium/net/cookies/cookie_store_test_helpers.cc index aae0c873540..2a541f5cd3d 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.cc +++ b/chromium/net/cookies/cookie_store_test_helpers.cc @@ -68,12 +68,13 @@ DelayedCookieMonster::DelayedCookieMonster() : cookie_monster_( new CookieMonster(nullptr /* store */, nullptr /* netlog */)), did_run_(false), - result_(CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE) {} + result_(CookieAccessResult(CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE))) {} DelayedCookieMonster::~DelayedCookieMonster() = default; void DelayedCookieMonster::SetCookiesInternalCallback( - CookieInclusionStatus result) { + CookieAccessResult result) { result_ = result; did_run_ = true; } diff --git a/chromium/net/cookies/cookie_store_test_helpers.h b/chromium/net/cookies/cookie_store_test_helpers.h index 5f9f03d15d4..269fd673b32 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.h +++ b/chromium/net/cookies/cookie_store_test_helpers.h @@ -86,7 +86,7 @@ class DelayedCookieMonster : public CookieStore { private: // Be called immediately from CookieMonster. - void SetCookiesInternalCallback(CookieInclusionStatus result); + void SetCookiesInternalCallback(CookieAccessResult result); void GetCookiesWithOptionsInternalCallback(const std::string& cookie); void GetCookieListWithOptionsInternalCallback( @@ -106,7 +106,7 @@ class DelayedCookieMonster : public CookieStore { DelayedCookieMonsterChangeDispatcher change_dispatcher_; bool did_run_; - CookieInclusionStatus result_; + CookieAccessResult result_; std::string cookie_; std::string cookie_line_; CookieAccessResultList cookie_access_result_list_; diff --git a/chromium/net/cookies/cookie_store_unittest.h b/chromium/net/cookies/cookie_store_unittest.h index 026ed96ba11..c2f495bedce 100644 --- a/chromium/net/cookies/cookie_store_unittest.h +++ b/chromium/net/cookies/cookie_store_unittest.h @@ -14,9 +14,9 @@ #include "base/bind.h" #include "base/location.h" -#include "base/message_loop/message_loop_current.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_tokenizer.h" +#include "base/task/current_thread.h" #include "base/test/task_environment.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" @@ -127,7 +127,7 @@ class CookieStoreTest : public testing::Test { http_bar_com_("http://bar.com") { // This test may be used outside of the net test suite, and thus may not // have a task environment. - if (!base::MessageLoopCurrent::Get()) { + if (!base::CurrentThread::Get()) { task_environment_ = std::make_unique<base::test::SingleThreadTaskEnvironment>(); } @@ -201,11 +201,11 @@ class CookieStoreTest : public testing::Test { if (!cookie) return false; DCHECK(cs); - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, options, callback.MakeCallback()); callback.WaitUntilDone(); - return callback.result().IsInclude(); + return callback.result().status.IsInclude(); } bool SetCanonicalCookie(CookieStore* cs, @@ -213,7 +213,7 @@ class CookieStoreTest : public testing::Test { const GURL& source_url, bool can_modify_httponly) { DCHECK(cs); - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; CookieOptions options; if (can_modify_httponly) options.set_include_httponly(); @@ -222,7 +222,7 @@ class CookieStoreTest : public testing::Test { cs->SetCanonicalCookieAsync(std::move(cookie), source_url, options, callback.MakeCallback()); callback.WaitUntilDone(); - return callback.result().IsInclude(); + return callback.result().status.IsInclude(); } bool SetCookieWithServerTime(CookieStore* cs, @@ -268,20 +268,20 @@ class CookieStoreTest : public testing::Test { net::CookieOptions::SameSiteCookieContext::MakeInclusive()); DCHECK(cs); - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, options, callback.MakeCallback()); callback.WaitUntilDone(); - return callback.result(); + return callback.result().status; } - CookieInclusionStatus SetCanonicalCookieReturnStatus( + CookieAccessResult SetCanonicalCookieReturnAccessResult( CookieStore* cs, std::unique_ptr<CanonicalCookie> cookie, const GURL& source_url, bool can_modify_httponly) { DCHECK(cs); - ResultSavingCookieCallback<CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieAccessResult> callback; CookieOptions options; if (can_modify_httponly) options.set_include_httponly(); @@ -562,14 +562,15 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { // A secure source is required for setting secure cookies. EXPECT_TRUE( - this->SetCanonicalCookieReturnStatus( + this->SetCanonicalCookieReturnAccessResult( cs, std::make_unique<CanonicalCookie>( "E", "F", http_foo_host, "/", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true) - .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); // A Secure cookie can be created from an insecure URL, but is rejected upon // setting. @@ -579,10 +580,10 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { base::nullopt /* server_time */, &status); EXPECT_TRUE(cookie->IsSecure()); EXPECT_TRUE(status.IsInclude()); - EXPECT_TRUE( - this->SetCanonicalCookieReturnStatus(cs, std::move(cookie), - this->http_www_foo_.url(), true) - .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + EXPECT_TRUE(this->SetCanonicalCookieReturnAccessResult( + cs, std::move(cookie), this->http_www_foo_.url(), true) + .status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); // A secure source is also required for overwriting secure cookies. Writing // a secure cookie then overwriting it from a non-secure source should fail. @@ -595,28 +596,29 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { this->https_www_foo_.url(), true /* modify_http_only */)); EXPECT_TRUE( - this->SetCanonicalCookieReturnStatus( + this->SetCanonicalCookieReturnAccessResult( cs, std::make_unique<CanonicalCookie>( "E", "F", http_foo_host, "/", base::Time(), base::Time(), base::Time(), true /* secure */, false /* httponly */, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true /* modify_http_only */) - .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); if (TypeParam::supports_http_only) { // Permission to modify http only cookies is required to set an // httponly cookie. - EXPECT_TRUE( - this->SetCanonicalCookieReturnStatus( - cs, - std::make_unique<CanonicalCookie>( - "G", "H", http_foo_host, "/unique", base::Time(), - base::Time(), base::Time(), false /* secure */, - true /* httponly */, CookieSameSite::LAX_MODE, - COOKIE_PRIORITY_DEFAULT), - this->http_www_foo_.url(), false /* modify_http_only */) - .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + EXPECT_TRUE(this->SetCanonicalCookieReturnAccessResult( + cs, + std::make_unique<CanonicalCookie>( + "G", "H", http_foo_host, "/unique", base::Time(), + base::Time(), base::Time(), false /* secure */, + true /* httponly */, CookieSameSite::LAX_MODE, + COOKIE_PRIORITY_DEFAULT), + this->http_www_foo_.url(), false /* modify_http_only */) + .status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); // A HttpOnly cookie can be created, but is rejected // upon setting if the options do not specify include_httponly. @@ -626,11 +628,11 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { base::nullopt /* server_time */, &create_status); EXPECT_TRUE(c->IsHttpOnly()); EXPECT_TRUE(create_status.IsInclude()); - EXPECT_TRUE( - this->SetCanonicalCookieReturnStatus(cs, std::move(c), - this->http_www_foo_.url(), - false /* can_modify_httponly */) - .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + EXPECT_TRUE(this->SetCanonicalCookieReturnAccessResult( + cs, std::move(c), this->http_www_foo_.url(), + false /* can_modify_httponly */) + .status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); // Permission to modify httponly cookies is also required to overwrite // an httponly cookie. @@ -642,16 +644,16 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true /* modify_http_only */)); - EXPECT_TRUE( - this->SetCanonicalCookieReturnStatus( - cs, - std::make_unique<CanonicalCookie>( - "G", "H", http_foo_host, "/unique", base::Time(), - base::Time(), base::Time(), false /* secure */, - true /* httponly */, CookieSameSite::LAX_MODE, - COOKIE_PRIORITY_DEFAULT), - this->http_www_foo_.url(), false /* modify_http_only */) - .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + EXPECT_TRUE(this->SetCanonicalCookieReturnAccessResult( + cs, + std::make_unique<CanonicalCookie>( + "G", "H", http_foo_host, "/unique", base::Time(), + base::Time(), base::Time(), false /* secure */, + true /* httponly */, CookieSameSite::LAX_MODE, + COOKIE_PRIORITY_DEFAULT), + this->http_www_foo_.url(), false /* modify_http_only */) + .status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); } else { // Leave store in same state as if the above tests had been run. EXPECT_TRUE(this->SetCanonicalCookie( diff --git a/chromium/net/cookies/cookie_util.cc b/chromium/net/cookies/cookie_util.cc index 99859d89606..86735d1d510 100644 --- a/chromium/net/cookies/cookie_util.cc +++ b/chromium/net/cookies/cookie_util.cc @@ -14,6 +14,7 @@ #include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/stl_util.h" +#include "base/strings/strcat.h" #include "base/strings/string_piece.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" @@ -331,23 +332,40 @@ base::Time ParseCookieExpirationTime(const std::string& time_string) { return base::Time(); } -GURL CookieOriginToURL(const std::string& domain, bool is_https) { - if (domain.empty()) +GURL CookieDomainAndPathToURL(const std::string& domain, + const std::string& path, + const std::string& source_scheme) { + // Note: domain_no_dot could be empty for e.g. file cookies. + std::string domain_no_dot = CookieDomainAsHost(domain); + if (domain_no_dot.empty() || source_scheme.empty()) return GURL(); + return GURL(base::StrCat( + {source_scheme, url::kStandardSchemeSeparator, domain_no_dot, path})); +} - const std::string scheme = is_https ? url::kHttpsScheme : url::kHttpScheme; - return GURL(scheme + url::kStandardSchemeSeparator + - CookieDomainAsHost(domain) + "/"); +GURL CookieDomainAndPathToURL(const std::string& domain, + const std::string& path, + bool is_https) { + return CookieDomainAndPathToURL( + domain, path, + std::string(is_https ? url::kHttpsScheme : url::kHttpScheme)); +} + +GURL CookieDomainAndPathToURL(const std::string& domain, + const std::string& path, + CookieSourceScheme source_scheme) { + return CookieDomainAndPathToURL(domain, path, + source_scheme == CookieSourceScheme::kSecure); +} + +GURL CookieOriginToURL(const std::string& domain, bool is_https) { + return CookieDomainAndPathToURL(domain, "/", is_https); } GURL SimulatedCookieSource(const CanonicalCookie& cookie, const std::string& source_scheme) { - // Note: cookie.DomainWithoutDot() could be empty for e.g. file cookies. - if (cookie.DomainWithoutDot().empty() || source_scheme.empty()) - return GURL(); - - return GURL(source_scheme + url::kStandardSchemeSeparator + - cookie.DomainWithoutDot() + cookie.Path()); + return CookieDomainAndPathToURL(cookie.Domain(), cookie.Path(), + source_scheme); } bool IsDomainMatch(const std::string& domain, const std::string& host) { @@ -657,12 +675,12 @@ bool DoesCreationTimeGrantLegacySemantics(base::Time creation_date) { return (base::Time::Now() - creation_date) < recency_threshold; } -base::OnceCallback<void(CookieInclusionStatus)> -AdaptCookieInclusionStatusToBool(base::OnceCallback<void(bool)> callback) { +base::OnceCallback<void(CookieAccessResult)> AdaptCookieAccessResultToBool( + base::OnceCallback<void(bool)> callback) { return base::BindOnce( [](base::OnceCallback<void(bool)> inner_callback, - const CookieInclusionStatus status) { - bool success = status.IsInclude(); + const CookieAccessResult access_result) { + bool success = access_result.status.IsInclude(); std::move(inner_callback).Run(success); }, std::move(callback)); diff --git a/chromium/net/cookies/cookie_util.h b/chromium/net/cookies/cookie_util.h index be3cd3f458d..b2b7992d03b 100644 --- a/chromium/net/cookies/cookie_util.h +++ b/chromium/net/cookies/cookie_util.h @@ -13,7 +13,7 @@ #include "base/time/time.h" #include "net/base/net_export.h" #include "net/cookies/canonical_cookie.h" -#include "net/cookies/cookie_inclusion_status.h" +#include "net/cookies/cookie_access_result.h" #include "net/cookies/cookie_options.h" #include "net/cookies/site_for_cookies.h" #include "url/origin.h" @@ -81,6 +81,22 @@ NET_EXPORT std::string CookieDomainAsHost(const std::string& cookie_domain); // Time::Max(), respectively. NET_EXPORT base::Time ParseCookieExpirationTime(const std::string& time_string); +// Get a cookie's URL from it's domain, path, and source scheme. +// The first field can be the combined domain-and-host-only-flag (e.g. the +// string returned by CanonicalCookie::Domain()) as opposed to the domain +// attribute per RFC6265bis. The GURL is constructed after stripping off any +// leading dot. +// Note: the GURL returned by this method is not guaranteed to be valid. +NET_EXPORT GURL CookieDomainAndPathToURL(const std::string& domain, + const std::string& path, + const std::string& source_scheme); +NET_EXPORT GURL CookieDomainAndPathToURL(const std::string& domain, + const std::string& path, + bool is_https); +NET_EXPORT GURL CookieDomainAndPathToURL(const std::string& domain, + const std::string& path, + CookieSourceScheme source_scheme); + // Convenience for converting a cookie origin (domain and https pair) to a URL. NET_EXPORT GURL CookieOriginToURL(const std::string& domain, bool is_https); @@ -230,14 +246,14 @@ bool DoesLastHttpSameSiteAccessGrantLegacySemantics( // the feature param, and the creation time of the cookie. bool DoesCreationTimeGrantLegacySemantics(base::Time creation_date); -// Takes a callback accepting a CookieInclusionStatus and returns a callback +// Takes a callback accepting a CookieAccessResult and returns a callback // that accepts a bool, setting the bool to true if the CookieInclusionStatus -// was set to "include", else sending false. +// in CookieAccessResult was set to "include", else sending false. // // Can be used with SetCanonicalCookie when you don't need to know why a cookie // was blocked, only whether it was blocked. -NET_EXPORT base::OnceCallback<void(CookieInclusionStatus)> -AdaptCookieInclusionStatusToBool(base::OnceCallback<void(bool)> callback); +NET_EXPORT base::OnceCallback<void(CookieAccessResult)> +AdaptCookieAccessResultToBool(base::OnceCallback<void(bool)> callback); // Turn a CookieAccessResultList into a CookieList by stripping out access // results (for callers who only care about cookies). diff --git a/chromium/net/cookies/cookie_util_unittest.cc b/chromium/net/cookies/cookie_util_unittest.cc index 14f8edf50f7..8093a6f440e 100644 --- a/chromium/net/cookies/cookie_util_unittest.cc +++ b/chromium/net/cookies/cookie_util_unittest.cc @@ -225,6 +225,36 @@ TEST(CookieUtilTest, TestRequestCookieParsing) { } } +TEST(CookieUtilTest, CookieDomainAndPathToURL) { + struct { + std::string domain; + std::string path; + bool is_https; + std::string expected_url; + } kTests[]{ + {"a.com", "/", true, "https://a.com/"}, + {"a.com", "/", false, "http://a.com/"}, + {".a.com", "/", true, "https://a.com/"}, + {".a.com", "/", false, "http://a.com/"}, + {"b.a.com", "/", true, "https://b.a.com/"}, + {"b.a.com", "/", false, "http://b.a.com/"}, + {"a.com", "/example/path", true, "https://a.com/example/path"}, + {".a.com", "/example/path", false, "http://a.com/example/path"}, + {"b.a.com", "/example/path", true, "https://b.a.com/example/path"}, + {".b.a.com", "/example/path", false, "http://b.a.com/example/path"}, + }; + + for (auto& test : kTests) { + GURL url1 = cookie_util::CookieDomainAndPathToURL(test.domain, test.path, + test.is_https); + GURL url2 = cookie_util::CookieDomainAndPathToURL( + test.domain, test.path, std::string(test.is_https ? "https" : "http")); + // Test both overloads for equality. + EXPECT_EQ(url1, url2); + EXPECT_EQ(url1, GURL(test.expected_url)); + } +} + TEST(CookieUtilTest, SimulatedCookieSource) { GURL secure_url("https://b.a.com"); GURL insecure_url("http://b.a.com"); @@ -1211,16 +1241,17 @@ TEST(CookieUtilTest, TestComputeSameSiteContextForSubresource) { false /* force_ignore_site_for_cookies */)); } -TEST(CookieUtilTest, AdaptCookieInclusionStatusToBool) { +TEST(CookieUtilTest, AdaptCookieAccessResultToBool) { bool result_out = true; base::OnceCallback<void(bool)> callback = base::BindLambdaForTesting( [&result_out](bool result) { result_out = result; }); - base::OnceCallback<void(CookieInclusionStatus)> adapted_callback = - cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); + base::OnceCallback<void(CookieAccessResult)> adapted_callback = + cookie_util::AdaptCookieAccessResultToBool(std::move(callback)); std::move(adapted_callback) - .Run(CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + .Run(CookieAccessResult( + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR))); EXPECT_FALSE(result_out); @@ -1229,9 +1260,9 @@ TEST(CookieUtilTest, AdaptCookieInclusionStatusToBool) { [&result_out](bool result) { result_out = result; }); adapted_callback = - cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); + cookie_util::AdaptCookieAccessResultToBool(std::move(callback)); - std::move(adapted_callback).Run(CookieInclusionStatus()); + std::move(adapted_callback).Run(CookieAccessResult()); EXPECT_TRUE(result_out); } |