123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- // Portions of this code based on Mozilla:
- // (netwerk/cookie/src/nsCookieService.cpp)
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2003
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Daniel Witte (dwitte@stanford.edu)
- * Michiel van Leeuwen (mvl@exedo.nl)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- #include "net/cookies/canonical_cookie.h"
- #include <limits>
- #include <utility>
- #include "base/containers/contains.h"
- #include "base/feature_list.h"
- #include "base/format_macros.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/strings/strcat.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "net/base/features.h"
- #include "net/base/url_util.h"
- #include "net/cookies/cookie_constants.h"
- #include "net/cookies/cookie_inclusion_status.h"
- #include "net/cookies/cookie_options.h"
- #include "net/cookies/cookie_util.h"
- #include "net/cookies/parsed_cookie.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- #include "url/url_canon.h"
- #include "url/url_util.h"
- using base::Time;
- namespace net {
- static constexpr int kMinutesInTwelveHours = 12 * 60;
- static constexpr int kMinutesInTwentyFourHours = 24 * 60;
- namespace {
- // Determine the cookie domain to use for setting the specified cookie.
- bool GetCookieDomain(const GURL& url,
- const ParsedCookie& pc,
- CookieInclusionStatus& status,
- std::string* result) {
- std::string domain_string;
- if (pc.HasDomain())
- domain_string = pc.Domain();
- return cookie_util::GetCookieDomainWithString(url, domain_string, status,
- result);
- }
- // Compares cookies using name, domain and path, so that "equivalent" cookies
- // (per RFC 2965) are equal to each other.
- int PartialCookieOrdering(const CanonicalCookie& a, const CanonicalCookie& b) {
- int diff = a.Name().compare(b.Name());
- if (diff != 0)
- return diff;
- diff = a.Domain().compare(b.Domain());
- if (diff != 0)
- return diff;
- return a.Path().compare(b.Path());
- }
- void AppendCookieLineEntry(const CanonicalCookie& cookie,
- std::string* cookie_line) {
- if (!cookie_line->empty())
- *cookie_line += "; ";
- // In Mozilla, if you set a cookie like "AAA", it will have an empty token
- // and a value of "AAA". When it sends the cookie back, it will send "AAA",
- // so we need to avoid sending "=AAA" for a blank token value.
- if (!cookie.Name().empty())
- *cookie_line += cookie.Name() + "=";
- *cookie_line += cookie.Value();
- }
- // Captures Strict -> Lax context downgrade with Strict cookie
- bool IsBreakingStrictToLaxDowngrade(
- CookieOptions::SameSiteCookieContext::ContextType context,
- CookieOptions::SameSiteCookieContext::ContextType schemeful_context,
- CookieEffectiveSameSite effective_same_site,
- bool is_cookie_being_set) {
- if (context ==
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT &&
- schemeful_context ==
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX &&
- effective_same_site == CookieEffectiveSameSite::STRICT_MODE) {
- // This downgrade only applies when a SameSite=Strict cookie is being sent.
- // A Strict -> Lax downgrade will not affect a Strict cookie which is being
- // set because it will be set in either context.
- return !is_cookie_being_set;
- }
- return false;
- }
- // Captures Strict -> Cross-site context downgrade with {Strict, Lax} cookie
- // Captures Strict -> Lax Unsafe context downgrade with {Strict, Lax} cookie.
- // This is treated as a cross-site downgrade due to the Lax Unsafe context
- // behaving like cross-site.
- bool IsBreakingStrictToCrossDowngrade(
- CookieOptions::SameSiteCookieContext::ContextType context,
- CookieOptions::SameSiteCookieContext::ContextType schemeful_context,
- CookieEffectiveSameSite effective_same_site) {
- bool breaking_schemeful_context =
- schemeful_context ==
- CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE ||
- schemeful_context == CookieOptions::SameSiteCookieContext::ContextType::
- SAME_SITE_LAX_METHOD_UNSAFE;
- bool strict_lax_enforcement =
- effective_same_site == CookieEffectiveSameSite::STRICT_MODE ||
- effective_same_site == CookieEffectiveSameSite::LAX_MODE ||
- // Treat LAX_MODE_ALLOW_UNSAFE the same as LAX_MODE for the purposes of
- // our SameSite enforcement check.
- effective_same_site == CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE;
- if (context ==
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT &&
- breaking_schemeful_context && strict_lax_enforcement) {
- return true;
- }
- return false;
- }
- // Captures Lax -> Cross context downgrade with {Strict, Lax} cookies.
- // Ignores Lax Unsafe context.
- bool IsBreakingLaxToCrossDowngrade(
- CookieOptions::SameSiteCookieContext::ContextType context,
- CookieOptions::SameSiteCookieContext::ContextType schemeful_context,
- CookieEffectiveSameSite effective_same_site,
- bool is_cookie_being_set) {
- bool lax_enforcement =
- effective_same_site == CookieEffectiveSameSite::LAX_MODE ||
- // Treat LAX_MODE_ALLOW_UNSAFE the same as LAX_MODE for the purposes of
- // our SameSite enforcement check.
- effective_same_site == CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE;
- if (context ==
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX &&
- schemeful_context ==
- CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE) {
- // For SameSite=Strict cookies this downgrade only applies when it is being
- // set. A Lax -> Cross downgrade will not affect a Strict cookie which is
- // being sent because it wouldn't be sent in either context.
- return effective_same_site == CookieEffectiveSameSite::STRICT_MODE
- ? is_cookie_being_set
- : lax_enforcement;
- }
- return false;
- }
- void ApplySameSiteCookieWarningToStatus(
- CookieSameSite samesite,
- CookieEffectiveSameSite effective_samesite,
- bool is_secure,
- const CookieOptions::SameSiteCookieContext& same_site_context,
- CookieInclusionStatus* status,
- bool is_cookie_being_set) {
- if (samesite == CookieSameSite::UNSPECIFIED &&
- same_site_context.GetContextForCookieInclusion() <
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) {
- status->AddWarningReason(
- CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
- }
- if (effective_samesite == CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE &&
- same_site_context.GetContextForCookieInclusion() ==
- CookieOptions::SameSiteCookieContext::ContextType::
- SAME_SITE_LAX_METHOD_UNSAFE) {
- // This warning is more specific so remove the previous, more general,
- // warning.
- status->RemoveWarningReason(
- CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
- status->AddWarningReason(
- CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
- }
- if (samesite == CookieSameSite::NO_RESTRICTION && !is_secure) {
- status->AddWarningReason(
- CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
- }
- // Add a warning if the cookie would be accessible in
- // |same_site_context|::context but not in
- // |same_site_context|::schemeful_context.
- if (IsBreakingStrictToLaxDowngrade(same_site_context.context(),
- same_site_context.schemeful_context(),
- effective_samesite, is_cookie_being_set)) {
- status->AddWarningReason(
- CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE);
- } else if (IsBreakingStrictToCrossDowngrade(
- same_site_context.context(),
- same_site_context.schemeful_context(), effective_samesite)) {
- // Which warning to apply depends on the SameSite value.
- if (effective_samesite == CookieEffectiveSameSite::STRICT_MODE) {
- status->AddWarningReason(
- CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE);
- } else {
- // LAX_MODE or LAX_MODE_ALLOW_UNSAFE.
- status->AddWarningReason(
- CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE);
- }
- } else if (IsBreakingLaxToCrossDowngrade(
- same_site_context.context(),
- same_site_context.schemeful_context(), effective_samesite,
- is_cookie_being_set)) {
- // Which warning to apply depends on the SameSite value.
- if (effective_samesite == CookieEffectiveSameSite::STRICT_MODE) {
- status->AddWarningReason(
- CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE);
- } else {
- // LAX_MODE or LAX_MODE_ALLOW_UNSAFE.
- // This warning applies to both set/send.
- status->AddWarningReason(
- CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE);
- }
- }
- // Apply warning for whether inclusion was changed by considering redirects
- // for the SameSite context calculation. This does not look at the actual
- // inclusion or exclusion, but only at whether the inclusion differs between
- // considering redirects and not.
- using ContextDowngradeType = CookieOptions::SameSiteCookieContext::
- ContextMetadata::ContextDowngradeType;
- const auto& metadata = same_site_context.GetMetadataForCurrentSchemefulMode();
- bool apply_cross_site_redirect_downgrade_warning = false;
- switch (effective_samesite) {
- case CookieEffectiveSameSite::STRICT_MODE:
- // Strict contexts are all normalized to lax for cookie writes, so a
- // strict-to-{lax,cross} downgrade cannot occur for response cookies.
- apply_cross_site_redirect_downgrade_warning =
- is_cookie_being_set ? metadata.cross_site_redirect_downgrade ==
- ContextDowngradeType::kLaxToCross
- : (metadata.cross_site_redirect_downgrade ==
- ContextDowngradeType::kStrictToLax ||
- metadata.cross_site_redirect_downgrade ==
- ContextDowngradeType::kStrictToCross);
- break;
- case CookieEffectiveSameSite::LAX_MODE:
- case CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE:
- // Note that a lax-to-cross downgrade can only happen for response
- // cookies, because a laxly same-site context only happens for a safe
- // top-level cross-site request, which cannot be downgraded due to a
- // cross-site redirect to a non-top-level or unsafe cross-site request.
- apply_cross_site_redirect_downgrade_warning =
- metadata.cross_site_redirect_downgrade ==
- (is_cookie_being_set ? ContextDowngradeType::kLaxToCross
- : ContextDowngradeType::kStrictToCross);
- break;
- default:
- break;
- }
- if (apply_cross_site_redirect_downgrade_warning) {
- status->AddWarningReason(
- CookieInclusionStatus::
- WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION);
- }
- // If there are reasons to exclude the cookie other than SameSite, don't warn
- // about the cookie at all.
- status->MaybeClearSameSiteWarning();
- }
- // Converts CookieSameSite to CookieSameSiteForMetrics by adding 1 to it.
- CookieSameSiteForMetrics CookieSameSiteToCookieSameSiteForMetrics(
- CookieSameSite enum_in) {
- return static_cast<CookieSameSiteForMetrics>((static_cast<int>(enum_in) + 1));
- }
- // Checks if `port` is within [0,65535] or url::PORT_UNSPECIFIED. Returns `port`
- // if so and url::PORT_INVALID otherwise.
- int ValidateAndAdjustSourcePort(int port) {
- if ((port >= 0 && port <= 65535) || port == url::PORT_UNSPECIFIED) {
- // 0 would be really weird as it has a special meaning, but it's still
- // technically a valid tcp/ip port so we're going to accept it here.
- return port;
- }
- return url::PORT_INVALID;
- }
- // Tests that a cookie has the attributes for a valid __Host- prefix without
- // testing that the prefix is in the cookie name.
- bool HasValidHostPrefixAttributes(const GURL& url,
- bool secure,
- const std::string& domain,
- const std::string& path) {
- if (!secure || !url.SchemeIsCryptographic() || path != "/")
- return false;
- return domain.empty() || (url.HostIsIPAddress() && url.host() == domain);
- }
- } // namespace
- CookieAccessParams::CookieAccessParams(CookieAccessSemantics access_semantics,
- bool delegate_treats_url_as_trustworthy,
- CookieSamePartyStatus same_party_status)
- : access_semantics(access_semantics),
- delegate_treats_url_as_trustworthy(delegate_treats_url_as_trustworthy),
- same_party_status(same_party_status) {}
- CanonicalCookie::CanonicalCookie() = default;
- CanonicalCookie::CanonicalCookie(const CanonicalCookie& other) = default;
- CanonicalCookie::CanonicalCookie(CanonicalCookie&& other) = default;
- CanonicalCookie& CanonicalCookie::operator=(const CanonicalCookie& other) =
- default;
- CanonicalCookie& CanonicalCookie::operator=(CanonicalCookie&& other) = default;
- CanonicalCookie::CanonicalCookie(
- std::string name,
- std::string value,
- std::string domain,
- std::string path,
- base::Time creation,
- base::Time expiration,
- base::Time last_access,
- base::Time last_update,
- bool secure,
- bool httponly,
- CookieSameSite same_site,
- CookiePriority priority,
- bool same_party,
- absl::optional<CookiePartitionKey> partition_key,
- CookieSourceScheme source_scheme,
- int source_port)
- : name_(std::move(name)),
- value_(std::move(value)),
- domain_(std::move(domain)),
- path_(std::move(path)),
- creation_date_(creation),
- expiry_date_(expiration),
- last_access_date_(last_access),
- last_update_date_(last_update),
- secure_(secure),
- httponly_(httponly),
- same_site_(same_site),
- priority_(priority),
- same_party_(same_party),
- partition_key_(std::move(partition_key)),
- source_scheme_(source_scheme),
- source_port_(source_port) {}
- CanonicalCookie::~CanonicalCookie() = default;
- // static
- std::string CanonicalCookie::CanonPathWithString(
- const GURL& url,
- const std::string& path_string) {
- // The path was supplied in the cookie, we'll take it.
- if (!path_string.empty() && path_string[0] == '/')
- return path_string;
- // The path was not supplied in the cookie or invalid, we will default
- // to the current URL path.
- // """Defaults to the path of the request URL that generated the
- // Set-Cookie response, up to, but not including, the
- // right-most /."""
- // How would this work for a cookie on /? We will include it then.
- const std::string& url_path = url.path();
- size_t idx = url_path.find_last_of('/');
- // The cookie path was invalid or a single '/'.
- if (idx == 0 || idx == std::string::npos)
- return std::string("/");
- // Return up to the rightmost '/'.
- return url_path.substr(0, idx);
- }
- // static
- Time CanonicalCookie::ParseExpiration(const ParsedCookie& pc,
- const Time& current,
- const Time& server_time) {
- // First, try the Max-Age attribute.
- if (pc.HasMaxAge()) {
- int64_t max_age = 0;
- // Use the output if StringToInt64 returns true ("perfect" conversion). This
- // case excludes overflow/underflow, leading/trailing whitespace, non-number
- // strings, and empty string. (ParsedCookie trims whitespace.)
- if (base::StringToInt64(pc.MaxAge(), &max_age)) {
- // RFC 6265bis algorithm for parsing Max-Age:
- // "If delta-seconds is less than or equal to zero (0), let expiry-
- // time be the earliest representable date and time. ... "
- if (max_age <= 0)
- return Time::Min();
- // "... Otherwise, let the expiry-time be the current date and time plus
- // delta-seconds seconds."
- return current + base::Seconds(max_age);
- } else {
- // If the conversion wasn't perfect, but the best-effort conversion
- // resulted in an overflow/underflow, use the min/max representable time.
- // (This is alluded to in the spec, which says the user agent MAY clip an
- // Expires attribute to a saturated time. We'll do the same for Max-Age.)
- if (max_age == std::numeric_limits<int64_t>::min())
- return Time::Min();
- if (max_age == std::numeric_limits<int64_t>::max())
- return Time::Max();
- }
- }
- // Try the Expires attribute.
- if (pc.HasExpires() && !pc.Expires().empty()) {
- // Adjust for clock skew between server and host.
- Time parsed_expiry = cookie_util::ParseCookieExpirationTime(pc.Expires());
- if (!parsed_expiry.is_null()) {
- // Record metrics related to prevalence of clock skew.
- base::TimeDelta clock_skew = (current - server_time);
- // Record the magnitude (absolute value) of the skew in minutes.
- int clock_skew_magnitude = clock_skew.magnitude().InMinutes();
- // Determine the new expiry with clock skew factored in.
- Time adjusted_expiry = parsed_expiry + (current - server_time);
- if (clock_skew.is_positive() || clock_skew.is_zero()) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ClockSkew.AddMinutes",
- clock_skew_magnitude, 1,
- kMinutesInTwelveHours, 100);
- UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ClockSkew.AddMinutes12To24Hours",
- clock_skew_magnitude, kMinutesInTwelveHours,
- kMinutesInTwentyFourHours, 100);
- // Also record the range of minutes added that allowed the cookie to
- // avoid expiring immediately.
- if (parsed_expiry <= Time::Now() && adjusted_expiry > Time::Now()) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Cookie.ClockSkew.WithoutAddMinutesExpires", clock_skew_magnitude,
- 1, kMinutesInTwentyFourHours, 100);
- }
- } else if (clock_skew.is_negative()) {
- // These histograms only support positive numbers, so negative skews
- // will be converted to positive (via magnitude) before recording.
- UMA_HISTOGRAM_CUSTOM_COUNTS("Cookie.ClockSkew.SubtractMinutes",
- clock_skew_magnitude, 1,
- kMinutesInTwelveHours, 100);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Cookie.ClockSkew.SubtractMinutes12To24Hours", clock_skew_magnitude,
- kMinutesInTwelveHours, kMinutesInTwentyFourHours, 100);
- }
- // Record if we were going to expire the cookie before we added the clock
- // skew.
- UMA_HISTOGRAM_BOOLEAN(
- "Cookie.ClockSkew.ExpiredWithoutSkew",
- parsed_expiry <= Time::Now() && adjusted_expiry > Time::Now());
- return adjusted_expiry;
- }
- }
- // Invalid or no expiration, session cookie.
- return Time();
- }
- // static
- base::Time CanonicalCookie::ValidateAndAdjustExpiryDate(
- const base::Time& expiry_date,
- const base::Time& creation_date) {
- if (expiry_date.is_null())
- return expiry_date;
- base::Time fixed_creation_date = creation_date;
- if (fixed_creation_date.is_null()) {
- // TODO(crbug.com/1264458): Push this logic into
- // CanonicalCookie::CreateSanitizedCookie. The four sites that call it
- // with a null `creation_date` (CanonicalCookie::Create cannot be called
- // this way) are:
- // * GaiaCookieManagerService::ForceOnCookieChangeProcessing
- // * CookiesSetFunction::Run
- // * cookie_store.cc::ToCanonicalCookie
- // * network_handler.cc::MakeCookieFromProtocolValues
- fixed_creation_date = base::Time::Now();
- }
- if (base::FeatureList::IsEnabled(features::kClampCookieExpiryTo400Days)) {
- base::Time maximum_expiry_date = fixed_creation_date + base::Days(400);
- if (expiry_date > maximum_expiry_date)
- return maximum_expiry_date;
- }
- return expiry_date;
- }
- // static
- std::unique_ptr<CanonicalCookie> CanonicalCookie::Create(
- const GURL& url,
- const std::string& cookie_line,
- const base::Time& creation_time,
- absl::optional<base::Time> server_time,
- absl::optional<CookiePartitionKey> cookie_partition_key,
- CookieInclusionStatus* status) {
- // Put a pointer on the stack so the rest of the function can assign to it if
- // the default nullptr is passed in.
- CookieInclusionStatus blank_status;
- if (status == nullptr) {
- status = &blank_status;
- }
- *status = CookieInclusionStatus();
- ParsedCookie parsed_cookie(cookie_line, status);
- if (!parsed_cookie.IsValid()) {
- DVLOG(net::cookie_util::kVlogSetCookies)
- << "WARNING: Couldn't parse cookie";
- DCHECK(!status->IsInclude());
- // Don't continue, because an invalid ParsedCookie doesn't have any
- // attributes.
- // TODO(chlily): Log metrics.
- return nullptr;
- }
- // Record warning for non-ASCII octecs in the Domain attribute.
- // This should lead to rejection of the cookie in the future.
- UMA_HISTOGRAM_BOOLEAN("Cookie.DomainHasNonASCII",
- parsed_cookie.HasDomain() &&
- !base::IsStringASCII(parsed_cookie.Domain()));
- std::string cookie_domain;
- if (!GetCookieDomain(url, parsed_cookie, *status, &cookie_domain)) {
- DVLOG(net::cookie_util::kVlogSetCookies)
- << "Create() failed to get a valid cookie domain";
- status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
- }
- std::string cookie_path = CanonPathWithString(
- url, parsed_cookie.HasPath() ? parsed_cookie.Path() : std::string());
- Time cookie_server_time(creation_time);
- if (server_time.has_value() && !server_time->is_null())
- cookie_server_time = server_time.value();
- DCHECK(!creation_time.is_null());
- Time cookie_expires = CanonicalCookie::ParseExpiration(
- parsed_cookie, creation_time, cookie_server_time);
- cookie_expires = ValidateAndAdjustExpiryDate(cookie_expires, creation_time);
- CookiePrefix prefix = GetCookiePrefix(parsed_cookie.Name());
- bool is_cookie_prefix_valid = IsCookiePrefixValid(prefix, url, parsed_cookie);
- RecordCookiePrefixMetrics(prefix, is_cookie_prefix_valid);
- if (parsed_cookie.Name() == "") {
- is_cookie_prefix_valid = !HasHiddenPrefixName(parsed_cookie.Value());
- }
- if (!is_cookie_prefix_valid) {
- DVLOG(net::cookie_util::kVlogSetCookies)
- << "Create() failed because the cookie violated prefix rules.";
- status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
- }
- bool is_same_party_valid = IsCookieSamePartyValid(parsed_cookie);
- if (!is_same_party_valid) {
- status->AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
- }
- // Collect metrics on whether usage of SameParty attribute is correct.
- if (parsed_cookie.IsSameParty())
- UMA_HISTOGRAM_BOOLEAN("Cookie.IsSamePartyValid", is_same_party_valid);
- bool partition_has_nonce = CookiePartitionKey::HasNonce(cookie_partition_key);
- bool is_partitioned_valid =
- IsCookiePartitionedValid(url, parsed_cookie, partition_has_nonce);
- if (!is_partitioned_valid) {
- status->AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED);
- }
- // Collect metrics on whether usage of the Partitioned attribute is correct.
- // Do not include implicit nonce-based partitioned cookies in these metrics.
- if (parsed_cookie.IsPartitioned()) {
- if (!partition_has_nonce)
- UMA_HISTOGRAM_BOOLEAN("Cookie.IsPartitionedValid", is_partitioned_valid);
- } else if (!partition_has_nonce) {
- cookie_partition_key = absl::nullopt;
- }
- if (!status->IsInclude())
- return nullptr;
- CookieSameSiteString samesite_string = CookieSameSiteString::kUnspecified;
- CookieSameSite samesite = parsed_cookie.SameSite(&samesite_string);
- CookieSourceScheme source_scheme = url.SchemeIsCryptographic()
- ? CookieSourceScheme::kSecure
- : CookieSourceScheme::kNonSecure;
- // Get the port, this will get a default value if a port isn't provided.
- int source_port = ValidateAndAdjustSourcePort(url.EffectiveIntPort());
- std::unique_ptr<CanonicalCookie> cc = base::WrapUnique(new CanonicalCookie(
- parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path,
- creation_time, cookie_expires, creation_time,
- /*last_update=*/base::Time::Now(), parsed_cookie.IsSecure(),
- parsed_cookie.IsHttpOnly(), samesite, parsed_cookie.Priority(),
- parsed_cookie.IsSameParty(), cookie_partition_key, source_scheme,
- source_port));
- // TODO(chlily): Log metrics.
- if (!cc->IsCanonical()) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- return nullptr;
- }
- RecordCookieSameSiteAttributeValueHistogram(samesite_string,
- parsed_cookie.IsSameParty());
- UMA_HISTOGRAM_BOOLEAN("Cookie.ControlCharacterTruncation",
- parsed_cookie.HasTruncatedNameOrValue());
- UMA_HISTOGRAM_ENUMERATION(
- "Cookie.TruncatingCharacterInCookieString",
- parsed_cookie.GetTruncatingCharacterInCookieStringType());
- return cc;
- }
- // static
- std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateSanitizedCookie(
- const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- base::Time creation_time,
- base::Time expiration_time,
- base::Time last_access_time,
- bool secure,
- bool http_only,
- CookieSameSite same_site,
- CookiePriority priority,
- bool same_party,
- absl::optional<CookiePartitionKey> partition_key,
- CookieInclusionStatus* status) {
- // Put a pointer on the stack so the rest of the function can assign to it if
- // the default nullptr is passed in.
- CookieInclusionStatus blank_status;
- if (status == nullptr) {
- status = &blank_status;
- }
- *status = CookieInclusionStatus();
- // Validate consistency of passed arguments.
- if (ParsedCookie::ParseTokenString(name) != name) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- } else if (ParsedCookie::ParseValueString(value) != value) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- } else if (ParsedCookie::ParseValueString(path) != path) {
- // NOTE: If `path` contains "terminating characters" ('\r', '\n', and
- // '\0'), ';', or leading / trailing whitespace, path will be rejected,
- // but any other control characters will just get URL-encoded below.
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- }
- if (base::FeatureList::IsEnabled(features::kExtraCookieValidityChecks)) {
- // Validate name and value against character set and size limit constraints.
- // If IsValidCookieNameValuePair identifies that `name` and/or `value` are
- // invalid, it will add an ExclusionReason to `status`.
- ParsedCookie::IsValidCookieNameValuePair(name, value, status);
- } else if (!ParsedCookie::IsValidCookieAttributeValueLegacy(name) ||
- !ParsedCookie::IsValidCookieAttributeValueLegacy(value) ||
- (name.empty() && value.empty())) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- }
- // Validate domain against character set and size limit constraints.
- bool domain_is_valid = true;
- if ((ParsedCookie::ParseValueString(domain) != domain)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
- domain_is_valid = false;
- }
- if (base::FeatureList::IsEnabled(features::kExtraCookieValidityChecks)) {
- if (!ParsedCookie::CookieAttributeValueHasValidCharSet(domain)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
- domain_is_valid = false;
- }
- if (!ParsedCookie::CookieAttributeValueHasValidSize(domain)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE);
- domain_is_valid = false;
- }
- }
- const std::string& domain_attribute =
- domain_is_valid ? domain : std::string();
- std::string cookie_domain;
- // This validation step must happen before GetCookieDomainWithString, so it
- // doesn't fail DCHECKs.
- if (!cookie_util::DomainIsHostOnly(url.host())) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
- } else if (!cookie_util::GetCookieDomainWithString(url, domain_attribute,
- *status, &cookie_domain)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
- }
- CookieSourceScheme source_scheme = CookieSourceScheme::kNonSecure;
- // This validation step must happen before SchemeIsCryptographic, so it
- // doesn't fail DCHECKs.
- if (!url.is_valid()) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
- } else {
- source_scheme = url.SchemeIsCryptographic()
- ? CookieSourceScheme::kSecure
- : CookieSourceScheme::kNonSecure;
- }
- // Get the port, this will get a default value if a port isn't provided.
- int source_port = ValidateAndAdjustSourcePort(url.EffectiveIntPort());
- std::string cookie_path = CanonicalCookie::CanonPathWithString(url, path);
- // Canonicalize path again to make sure it escapes characters as needed.
- url::Component path_component(0, cookie_path.length());
- url::RawCanonOutputT<char> canon_path;
- url::Component canon_path_component;
- url::CanonicalizePath(cookie_path.data(), path_component, &canon_path,
- &canon_path_component);
- std::string encoded_cookie_path = std::string(
- canon_path.data() + canon_path_component.begin, canon_path_component.len);
- if (!path.empty()) {
- if (cookie_path != path) {
- // The path attribute was specified and found to be invalid, so record an
- // error.
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- } else if (base::FeatureList::IsEnabled(
- features::kExtraCookieValidityChecks) &&
- !ParsedCookie::CookieAttributeValueHasValidSize(
- encoded_cookie_path)) {
- // The path attribute was specified and encodes into a value that's longer
- // than the length limit, so record an error.
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE);
- }
- }
- CookiePrefix prefix = GetCookiePrefix(name);
- if (!IsCookiePrefixValid(prefix, url, secure, domain_attribute,
- cookie_path)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
- }
- if (name == "" && HasHiddenPrefixName(value)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
- }
- if (!IsCookieSamePartyValid(same_party, secure, same_site)) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_SAMEPARTY);
- }
- if (!IsCookiePartitionedValid(url, secure,
- /*is_partitioned=*/partition_key.has_value(),
- /*partition_has_nonce=*/
- CookiePartitionKey::HasNonce(partition_key))) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED);
- }
- if (!last_access_time.is_null() && creation_time.is_null()) {
- status->AddExclusionReason(
- net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
- }
- expiration_time = ValidateAndAdjustExpiryDate(expiration_time, creation_time);
- if (!status->IsInclude())
- return nullptr;
- std::unique_ptr<CanonicalCookie> cc = base::WrapUnique(new CanonicalCookie(
- name, value, cookie_domain, encoded_cookie_path, creation_time,
- expiration_time, last_access_time, /*last_update=*/base::Time::Now(),
- secure, http_only, same_site, priority, same_party, partition_key,
- source_scheme, source_port));
- DCHECK(cc->IsCanonical());
- return cc;
- }
- // static
- std::unique_ptr<CanonicalCookie> CanonicalCookie::FromStorage(
- std::string name,
- std::string value,
- std::string domain,
- std::string path,
- base::Time creation,
- base::Time expiration,
- base::Time last_access,
- base::Time last_update,
- bool secure,
- bool httponly,
- CookieSameSite same_site,
- CookiePriority priority,
- bool same_party,
- absl::optional<CookiePartitionKey> partition_key,
- CookieSourceScheme source_scheme,
- int source_port) {
- // We check source_port here because it could have concievably been
- // corrupted and changed to out of range. Eventually this would be caught by
- // IsCanonical*() but since the source_port is only used by metrics so far
- // nothing else checks it. So let's normalize it here and then update this
- // method when origin-bound cookies is implemented.
- // TODO(crbug.com/1170548)
- int validated_port = ValidateAndAdjustSourcePort(source_port);
- std::unique_ptr<CanonicalCookie> cc = base::WrapUnique(new CanonicalCookie(
- std::move(name), std::move(value), std::move(domain), std::move(path),
- creation, expiration, last_access, last_update, secure, httponly,
- same_site, priority, same_party, partition_key, source_scheme,
- validated_port));
- if (cc->IsCanonicalForFromStorage()) {
- // This will help capture the number of times a cookie is canonical but does
- // not have a valid name+value size length
- bool valid_cookie_name_value_pair =
- ParsedCookie::IsValidCookieNameValuePair(cc->Name(), cc->Value());
- UMA_HISTOGRAM_BOOLEAN("Cookie.FromStorageWithValidLength",
- valid_cookie_name_value_pair);
- } else {
- return nullptr;
- }
- return cc;
- }
- // static
- std::unique_ptr<CanonicalCookie> CanonicalCookie::CreateUnsafeCookieForTesting(
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const base::Time& creation,
- const base::Time& expiration,
- const base::Time& last_access,
- const base::Time& last_update,
- bool secure,
- bool httponly,
- CookieSameSite same_site,
- CookiePriority priority,
- bool same_party,
- absl::optional<CookiePartitionKey> partition_key,
- CookieSourceScheme source_scheme,
- int source_port) {
- return base::WrapUnique(new CanonicalCookie(
- name, value, domain, path, creation, expiration, last_access, last_update,
- secure, httponly, same_site, priority, same_party, partition_key,
- source_scheme, source_port));
- }
- std::string CanonicalCookie::DomainWithoutDot() const {
- return cookie_util::CookieDomainAsHost(domain_);
- }
- void CanonicalCookie::SetSourcePort(int port) {
- source_port_ = ValidateAndAdjustSourcePort(port);
- }
- bool CanonicalCookie::IsEquivalentForSecureCookieMatching(
- const CanonicalCookie& secure_cookie) const {
- // Partition keys must both be equivalent.
- bool same_partition_key = PartitionKey() == secure_cookie.PartitionKey();
- // Names must be the same
- bool same_name = name_ == secure_cookie.Name();
- // They should domain-match in one direction or the other. (See RFC 6265bis
- // section 5.1.3.)
- // TODO(chlily): This does not check for the IP address case. This is bad due
- // to https://crbug.com/1069935.
- bool domain_match =
- IsSubdomainOf(DomainWithoutDot(), secure_cookie.DomainWithoutDot()) ||
- IsSubdomainOf(secure_cookie.DomainWithoutDot(), DomainWithoutDot());
- bool path_match = secure_cookie.IsOnPath(Path());
- bool equivalent_for_secure_cookie_matching =
- same_partition_key && same_name && domain_match && path_match;
- // IsEquivalent() is a stricter check than this.
- DCHECK(!IsEquivalent(secure_cookie) || equivalent_for_secure_cookie_matching);
- return equivalent_for_secure_cookie_matching;
- }
- bool CanonicalCookie::IsOnPath(const std::string& url_path) const {
- // A zero length would be unsafe for our trailing '/' checks, and
- // would also make no sense for our prefix match. The code that
- // creates a CanonicalCookie should make sure the path is never zero length,
- // but we double check anyway.
- if (path_.empty())
- return false;
- // The Mozilla code broke this into three cases, based on if the cookie path
- // was longer, the same length, or shorter than the length of the url path.
- // I think the approach below is simpler.
- // Make sure the cookie path is a prefix of the url path. If the url path is
- // shorter than the cookie path, then the cookie path can't be a prefix.
- if (!base::StartsWith(url_path, path_, base::CompareCase::SENSITIVE))
- return false;
- // |url_path| is >= |path_|, and |path_| is a prefix of |url_path|. If they
- // are the are the same length then they are identical, otherwise need an
- // additional check:
- // In order to avoid in correctly matching a cookie path of /blah
- // with a request path of '/blahblah/', we need to make sure that either
- // the cookie path ends in a trailing '/', or that we prefix up to a '/'
- // in the url path. Since we know that the url path length is greater
- // than the cookie path length, it's safe to index one byte past.
- if (path_.length() != url_path.length() && path_.back() != '/' &&
- url_path[path_.length()] != '/') {
- return false;
- }
- return true;
- }
- bool CanonicalCookie::IsDomainMatch(const std::string& host) const {
- return cookie_util::IsDomainMatch(domain_, host);
- }
- CookieAccessResult CanonicalCookie::IncludeForRequestURL(
- const GURL& url,
- const CookieOptions& options,
- const CookieAccessParams& params) const {
- CookieInclusionStatus status;
- // Filter out HttpOnly cookies, per options.
- if (options.exclude_httponly() && IsHttpOnly())
- status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
- // Secure cookies should not be included in requests for URLs with an
- // insecure scheme, unless it is a localhost url, or the CookieAccessDelegate
- // otherwise denotes them as trustworthy
- // (`delegate_treats_url_as_trustworthy`).
- bool is_allowed_to_access_secure_cookies = false;
- CookieAccessScheme cookie_access_scheme =
- cookie_util::ProvisionalAccessScheme(url);
- if (cookie_access_scheme == CookieAccessScheme::kNonCryptographic &&
- params.delegate_treats_url_as_trustworthy) {
- cookie_access_scheme = CookieAccessScheme::kTrustworthy;
- }
- switch (cookie_access_scheme) {
- case CookieAccessScheme::kNonCryptographic:
- if (IsSecure())
- status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
- break;
- case CookieAccessScheme::kTrustworthy:
- is_allowed_to_access_secure_cookies = true;
- if (IsSecure()) {
- status.AddWarningReason(
- CookieInclusionStatus::
- WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC);
- }
- break;
- case CookieAccessScheme::kCryptographic:
- is_allowed_to_access_secure_cookies = true;
- break;
- }
- // Don't include cookies for requests that don't apply to the cookie domain.
- if (!IsDomainMatch(url.host()))
- status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
- // Don't include cookies for requests with a url path that does not path
- // 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 =
- params.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(params.access_semantics);
- DCHECK(effective_same_site != CookieEffectiveSameSite::UNDEFINED);
- UMA_HISTOGRAM_ENUMERATION(
- "Cookie.RequestSameSiteContext", cookie_inclusion_context,
- CookieOptions::SameSiteCookieContext::ContextType::COUNT);
- switch (effective_same_site) {
- case CookieEffectiveSameSite::STRICT_MODE:
- if (cookie_inclusion_context <
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT) {
- status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT);
- }
- break;
- case CookieEffectiveSameSite::LAX_MODE:
- if (cookie_inclusion_context <
- CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) {
- status.AddExclusionReason(
- (SameSite() == CookieSameSite::UNSPECIFIED)
- ? CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX
- : CookieInclusionStatus::EXCLUDE_SAMESITE_LAX);
- }
- break;
- // TODO(crbug.com/990439): Add a browsertest for this behavior.
- case CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE:
- DCHECK(SameSite() == CookieSameSite::UNSPECIFIED);
- if (cookie_inclusion_context <
- CookieOptions::SameSiteCookieContext::ContextType::
- SAME_SITE_LAX_METHOD_UNSAFE) {
- // TODO(chlily): Do we need a separate CookieInclusionStatus for this?
- status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
- }
- break;
- default:
- break;
- }
- // Unless legacy access semantics are in effect, SameSite=None cookies without
- // the Secure attribute should be ignored. This can apply to cookies which
- // were created before "SameSite=None requires Secure" was enabled (as
- // SameSite=None insecure cookies cannot be set while the options are on).
- if (params.access_semantics != CookieAccessSemantics::LEGACY &&
- SameSite() == CookieSameSite::NO_RESTRICTION && !IsSecure()) {
- status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
- }
- switch (params.same_party_status) {
- case CookieSamePartyStatus::kEnforceSamePartyExclude:
- DCHECK(IsSameParty());
- status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
- [[fallthrough]];
- case CookieSamePartyStatus::kEnforceSamePartyInclude: {
- status.AddWarningReason(CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
- // Remove any SameSite exclusion reasons, since SameParty overrides
- // SameSite.
- DCHECK(!status.HasExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
- DCHECK_NE(effective_same_site, CookieEffectiveSameSite::STRICT_MODE);
- bool included_by_samesite =
- !status.HasExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
- !status.HasExclusionReason(
- CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
- if (!included_by_samesite) {
- status.RemoveExclusionReasons({
- CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
- CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
- });
- }
- // Update metrics.
- if (status.HasOnlyExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
- included_by_samesite) {
- status.AddWarningReason(
- CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
- }
- if (status.IsInclude()) {
- UMA_HISTOGRAM_BOOLEAN(
- "Cookie.SamePartyReadIncluded.InclusionUnderSameSite",
- included_by_samesite);
- if (!included_by_samesite) {
- status.AddWarningReason(
- CookieInclusionStatus::
- WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
- }
- }
- break;
- }
- case CookieSamePartyStatus::kNoSamePartyEnforcement:
- // Only apply SameSite-related warnings if SameParty is not in effect.
- ApplySameSiteCookieWarningToStatus(
- SameSite(), effective_same_site, IsSecure(),
- options.same_site_cookie_context(), &status,
- false /* is_cookie_being_set */);
- break;
- }
- if (status.IsInclude()) {
- UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedRequestEffectiveSameSite",
- effective_same_site,
- CookieEffectiveSameSite::COUNT);
- }
- using ContextRedirectTypeBug1221316 = CookieOptions::SameSiteCookieContext::
- ContextMetadata::ContextRedirectTypeBug1221316;
- ContextRedirectTypeBug1221316 redirect_type_for_metrics =
- options.same_site_cookie_context()
- .GetMetadataForCurrentSchemefulMode()
- .redirect_type_bug_1221316;
- if (redirect_type_for_metrics != ContextRedirectTypeBug1221316::kUnset) {
- UMA_HISTOGRAM_ENUMERATION("Cookie.CrossSiteRedirectType.Read",
- redirect_type_for_metrics);
- }
- if (status.HasWarningReason(
- CookieInclusionStatus::
- WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION)) {
- UMA_HISTOGRAM_ENUMERATION(
- "Cookie.CrossSiteRedirectDowngradeChangesInclusion2.Read",
- CookieSameSiteToCookieSameSiteForMetrics(SameSite()));
- }
- return CookieAccessResult(effective_same_site, status,
- params.access_semantics,
- is_allowed_to_access_secure_cookies);
- }
- CookieAccessResult CanonicalCookie::IsSetPermittedInContext(
- const GURL& source_url,
- const CookieOptions& options,
- const CookieAccessParams& params,
- const std::vector<std::string>& cookieable_schemes,
- const absl::optional<CookieAccessResult>& cookie_access_result) const {
- CookieAccessResult access_result;
- if (cookie_access_result) {
- access_result = *cookie_access_result;
- }
- if (!base::Contains(cookieable_schemes, source_url.scheme())) {
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
- }
- CookieAccessScheme access_scheme =
- cookie_util::ProvisionalAccessScheme(source_url);
- if (access_scheme == CookieAccessScheme::kNonCryptographic &&
- params.delegate_treats_url_as_trustworthy) {
- access_scheme = CookieAccessScheme::kTrustworthy;
- }
- switch (access_scheme) {
- case CookieAccessScheme::kNonCryptographic:
- access_result.is_allowed_to_access_secure_cookies = false;
- if (IsSecure()) {
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
- }
- break;
- case CookieAccessScheme::kCryptographic:
- // All cool!
- access_result.is_allowed_to_access_secure_cookies = true;
- break;
- case CookieAccessScheme::kTrustworthy:
- access_result.is_allowed_to_access_secure_cookies = true;
- if (IsSecure()) {
- // OK, but want people aware of this.
- access_result.status.AddWarningReason(
- CookieInclusionStatus::
- WARN_SECURE_ACCESS_GRANTED_NON_CRYPTOGRAPHIC);
- }
- break;
- }
- access_result.access_semantics = params.access_semantics;
- if (options.exclude_httponly() && IsHttpOnly()) {
- DVLOG(net::cookie_util::kVlogSetCookies)
- << "HttpOnly cookie not permitted in script context.";
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
- }
- // Unless legacy access semantics are in effect, SameSite=None cookies without
- // the Secure attribute will be rejected.
- if (params.access_semantics != CookieAccessSemantics::LEGACY &&
- SameSite() == CookieSameSite::NO_RESTRICTION && !IsSecure()) {
- DVLOG(net::cookie_util::kVlogSetCookies)
- << "SetCookie() rejecting insecure cookie with SameSite=None.";
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
- }
- // For LEGACY cookies we should always return the schemeless context,
- // otherwise let GetContextForCookieInclusion() decide.
- CookieOptions::SameSiteCookieContext::ContextType cookie_inclusion_context =
- params.access_semantics == CookieAccessSemantics::LEGACY
- ? options.same_site_cookie_context().context()
- : options.same_site_cookie_context().GetContextForCookieInclusion();
- access_result.effective_same_site =
- GetEffectiveSameSite(params.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 (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.";
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT);
- }
- break;
- case CookieEffectiveSameSite::LAX_MODE:
- case CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE:
- 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.";
- 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.";
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_LAX);
- }
- }
- break;
- default:
- break;
- }
- switch (params.same_party_status) {
- case CookieSamePartyStatus::kEnforceSamePartyExclude:
- DCHECK(IsSameParty());
- access_result.status.AddExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT);
- [[fallthrough]];
- case CookieSamePartyStatus::kEnforceSamePartyInclude: {
- DCHECK(IsSameParty());
- access_result.status.AddWarningReason(
- CookieInclusionStatus::WARN_TREATED_AS_SAMEPARTY);
- // Remove any SameSite exclusion reasons, since SameParty overrides
- // SameSite.
- DCHECK(!access_result.status.HasExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT));
- DCHECK_NE(access_result.effective_same_site,
- CookieEffectiveSameSite::STRICT_MODE);
- bool included_by_samesite =
- !access_result.status.HasExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMESITE_LAX) &&
- !access_result.status.HasExclusionReason(
- CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
- if (!included_by_samesite) {
- access_result.status.RemoveExclusionReasons({
- CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
- CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
- });
- }
- // Update metrics.
- if (access_result.status.HasOnlyExclusionReason(
- CookieInclusionStatus::EXCLUDE_SAMEPARTY_CROSS_PARTY_CONTEXT) &&
- included_by_samesite) {
- access_result.status.AddWarningReason(
- CookieInclusionStatus::WARN_SAMEPARTY_EXCLUSION_OVERRULED_SAMESITE);
- }
- if (access_result.status.IsInclude()) {
- UMA_HISTOGRAM_BOOLEAN(
- "Cookie.SamePartySetIncluded.InclusionUnderSameSite",
- included_by_samesite);
- if (!included_by_samesite) {
- access_result.status.AddWarningReason(
- CookieInclusionStatus::
- WARN_SAMEPARTY_INCLUSION_OVERRULED_SAMESITE);
- }
- }
- break;
- }
- case CookieSamePartyStatus::kNoSamePartyEnforcement:
- // Only apply SameSite-related warnings if SameParty is not in effect.
- ApplySameSiteCookieWarningToStatus(
- SameSite(), access_result.effective_same_site, IsSecure(),
- options.same_site_cookie_context(), &access_result.status,
- true /* is_cookie_being_set */);
- break;
- }
- if (access_result.status.IsInclude()) {
- UMA_HISTOGRAM_ENUMERATION("Cookie.IncludedResponseEffectiveSameSite",
- access_result.effective_same_site,
- CookieEffectiveSameSite::COUNT);
- }
- using ContextRedirectTypeBug1221316 = CookieOptions::SameSiteCookieContext::
- ContextMetadata::ContextRedirectTypeBug1221316;
- ContextRedirectTypeBug1221316 redirect_type_for_metrics =
- options.same_site_cookie_context()
- .GetMetadataForCurrentSchemefulMode()
- .redirect_type_bug_1221316;
- if (redirect_type_for_metrics != ContextRedirectTypeBug1221316::kUnset) {
- UMA_HISTOGRAM_ENUMERATION("Cookie.CrossSiteRedirectType.Write",
- redirect_type_for_metrics);
- }
- if (access_result.status.HasWarningReason(
- CookieInclusionStatus::
- WARN_CROSS_SITE_REDIRECT_DOWNGRADE_CHANGES_INCLUSION)) {
- UMA_HISTOGRAM_ENUMERATION(
- "Cookie.CrossSiteRedirectDowngradeChangesInclusion2.Write",
- CookieSameSiteToCookieSameSiteForMetrics(SameSite()));
- }
- return access_result;
- }
- std::string CanonicalCookie::DebugString() const {
- return base::StringPrintf(
- "name: %s value: %s domain: %s path: %s creation: %" PRId64,
- name_.c_str(), value_.c_str(), domain_.c_str(), path_.c_str(),
- static_cast<int64_t>(creation_date_.ToTimeT()));
- }
- bool CanonicalCookie::PartialCompare(const CanonicalCookie& other) const {
- return PartialCookieOrdering(*this, other) < 0;
- }
- bool CanonicalCookie::IsCanonical() const {
- // TODO(crbug.com/1244172) Eventually we should check the size of name+value,
- // assuming we collect metrics and determine that a low percentage of cookies
- // would fail this check. Note that we still don't want to enforce length
- // checks on domain or path for the reason stated above.
- // TODO(crbug.com/1264458): Eventually we should push this logic into
- // IsCanonicalForFromStorage, but for now we allow cookies already stored with
- // high expiration dates to be retrieved.
- if (ValidateAndAdjustExpiryDate(expiry_date_, creation_date_) != expiry_date_)
- return false;
- return IsCanonicalForFromStorage();
- }
- bool CanonicalCookie::IsCanonicalForFromStorage() const {
- // Not checking domain or path against ParsedCookie as it may have
- // come purely from the URL. Also, don't call IsValidCookieNameValuePair()
- // here because we don't want to enforce the size checks on names or values
- // that may have been reconstituted from the cookie store.
- if (ParsedCookie::ParseTokenString(name_) != name_ ||
- !ParsedCookie::ValueMatchesParsedValue(value_)) {
- return false;
- }
- if (base::FeatureList::IsEnabled(features::kExtraCookieValidityChecks)) {
- if (!ParsedCookie::IsValidCookieName(name_) ||
- !ParsedCookie::IsValidCookieValue(value_)) {
- return false;
- }
- } else {
- if (!ParsedCookie::IsValidCookieAttributeValueLegacy(name_) ||
- !ParsedCookie::IsValidCookieAttributeValueLegacy(value_)) {
- return false;
- }
- }
- if (!last_access_date_.is_null() && creation_date_.is_null())
- return false;
- url::CanonHostInfo canon_host_info;
- std::string canonical_domain(CanonicalizeHost(domain_, &canon_host_info));
- // TODO(rdsmith): This specifically allows for empty domains. The spec
- // suggests this is invalid (if a domain attribute is empty, the cookie's
- // domain is set to the canonicalized request host; see
- // https://tools.ietf.org/html/rfc6265#section-5.3). However, it is
- // needed for Chrome extension cookies.
- // See http://crbug.com/730633 for more information.
- if (canonical_domain != domain_)
- return false;
- if (path_.empty() || path_[0] != '/')
- return false;
- CookiePrefix prefix = GetCookiePrefix(name_);
- switch (prefix) {
- case COOKIE_PREFIX_HOST:
- if (!secure_ || path_ != "/" || domain_.empty() || domain_[0] == '.')
- return false;
- break;
- case COOKIE_PREFIX_SECURE:
- if (!secure_)
- return false;
- break;
- default:
- break;
- }
- if (name_ == "" && HasHiddenPrefixName(value_))
- return false;
- if (!IsCookieSamePartyValid(same_party_, secure_, same_site_))
- return false;
- if (IsPartitioned()) {
- if (CookiePartitionKey::HasNonce(partition_key_))
- return true;
- if (!secure_)
- return false;
- }
- return true;
- }
- bool CanonicalCookie::IsEffectivelySameSiteNone(
- CookieAccessSemantics access_semantics) const {
- return GetEffectiveSameSite(access_semantics) ==
- CookieEffectiveSameSite::NO_RESTRICTION;
- }
- CookieEffectiveSameSite CanonicalCookie::GetEffectiveSameSiteForTesting(
- CookieAccessSemantics access_semantics) const {
- return GetEffectiveSameSite(access_semantics);
- }
- // static
- std::string CanonicalCookie::BuildCookieLine(const CookieList& cookies) {
- std::string cookie_line;
- for (const auto& cookie : cookies) {
- AppendCookieLineEntry(cookie, &cookie_line);
- }
- return cookie_line;
- }
- // static
- std::string CanonicalCookie::BuildCookieLine(
- const CookieAccessResultList& cookie_access_result_list) {
- std::string cookie_line;
- for (const auto& cookie_with_access_result : cookie_access_result_list) {
- const CanonicalCookie& cookie = cookie_with_access_result.cookie;
- AppendCookieLineEntry(cookie, &cookie_line);
- }
- return cookie_line;
- }
- // static
- std::string CanonicalCookie::BuildCookieAttributesLine(
- const CanonicalCookie& cookie) {
- std::string cookie_line;
- // In Mozilla, if you set a cookie like "AAA", it will have an empty token
- // and a value of "AAA". When it sends the cookie back, it will send "AAA",
- // so we need to avoid sending "=AAA" for a blank token value.
- if (!cookie.Name().empty())
- cookie_line += cookie.Name() + "=";
- cookie_line += cookie.Value();
- if (!cookie.Domain().empty())
- cookie_line += "; domain=" + cookie.Domain();
- if (!cookie.Path().empty())
- cookie_line += "; path=" + cookie.Path();
- if (cookie.ExpiryDate() != base::Time())
- cookie_line += "; expires=" + TimeFormatHTTP(cookie.ExpiryDate());
- if (cookie.IsSecure())
- cookie_line += "; secure";
- if (cookie.IsHttpOnly())
- cookie_line += "; httponly";
- switch (cookie.SameSite()) {
- case CookieSameSite::NO_RESTRICTION:
- cookie_line += "; samesite=none";
- break;
- case CookieSameSite::LAX_MODE:
- cookie_line += "; samesite=lax";
- break;
- case CookieSameSite::STRICT_MODE:
- cookie_line += "; samesite=strict";
- break;
- case CookieSameSite::UNSPECIFIED:
- // Don't append any text if the samesite attribute wasn't explicitly set.
- break;
- }
- return cookie_line;
- }
- // static
- CanonicalCookie::CookiePrefix CanonicalCookie::GetCookiePrefix(
- const std::string& name) {
- const char kSecurePrefix[] = "__Secure-";
- const char kHostPrefix[] = "__Host-";
- if (base::StartsWith(name, kSecurePrefix, base::CompareCase::SENSITIVE))
- return CanonicalCookie::COOKIE_PREFIX_SECURE;
- if (base::StartsWith(name, kHostPrefix, base::CompareCase::SENSITIVE))
- return CanonicalCookie::COOKIE_PREFIX_HOST;
- return CanonicalCookie::COOKIE_PREFIX_NONE;
- }
- // static
- void CanonicalCookie::RecordCookiePrefixMetrics(
- CanonicalCookie::CookiePrefix prefix,
- bool is_cookie_valid) {
- const char kCookiePrefixHistogram[] = "Cookie.CookiePrefix";
- UMA_HISTOGRAM_ENUMERATION(kCookiePrefixHistogram, prefix,
- CanonicalCookie::COOKIE_PREFIX_LAST);
- }
- // Returns true if the cookie does not violate any constraints imposed
- // by the cookie name's prefix, as described in
- // https://tools.ietf.org/html/draft-west-cookie-prefixes
- //
- // static
- bool CanonicalCookie::IsCookiePrefixValid(CanonicalCookie::CookiePrefix prefix,
- const GURL& url,
- const ParsedCookie& parsed_cookie) {
- return CanonicalCookie::IsCookiePrefixValid(
- prefix, url, parsed_cookie.IsSecure(),
- parsed_cookie.HasDomain() ? parsed_cookie.Domain() : "",
- parsed_cookie.HasPath() ? parsed_cookie.Path() : "");
- }
- bool CanonicalCookie::IsCookiePrefixValid(CanonicalCookie::CookiePrefix prefix,
- const GURL& url,
- bool secure,
- const std::string& domain,
- const std::string& path) {
- if (prefix == CanonicalCookie::COOKIE_PREFIX_SECURE)
- return secure && url.SchemeIsCryptographic();
- if (prefix == CanonicalCookie::COOKIE_PREFIX_HOST) {
- return HasValidHostPrefixAttributes(url, secure, domain, path);
- }
- return true;
- }
- CookieEffectiveSameSite CanonicalCookie::GetEffectiveSameSite(
- CookieAccessSemantics access_semantics) const {
- base::TimeDelta lax_allow_unsafe_threshold_age =
- base::FeatureList::IsEnabled(
- features::kSameSiteDefaultChecksMethodRigorously)
- ? base::TimeDelta::Min()
- : (base::FeatureList::IsEnabled(
- features::kShortLaxAllowUnsafeThreshold)
- ? kShortLaxAllowUnsafeMaxAge
- : kLaxAllowUnsafeMaxAge);
- switch (SameSite()) {
- // If a cookie does not have a SameSite attribute, the effective SameSite
- // mode depends on the access semantics and whether the cookie is
- // recently-created.
- case CookieSameSite::UNSPECIFIED:
- return (access_semantics == CookieAccessSemantics::LEGACY)
- ? CookieEffectiveSameSite::NO_RESTRICTION
- : (IsRecentlyCreated(lax_allow_unsafe_threshold_age)
- ? CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE
- : CookieEffectiveSameSite::LAX_MODE);
- case CookieSameSite::NO_RESTRICTION:
- return CookieEffectiveSameSite::NO_RESTRICTION;
- case CookieSameSite::LAX_MODE:
- return CookieEffectiveSameSite::LAX_MODE;
- case CookieSameSite::STRICT_MODE:
- return CookieEffectiveSameSite::STRICT_MODE;
- }
- }
- // static
- bool CanonicalCookie::HasHiddenPrefixName(
- const base::StringPiece cookie_value) {
- // Skip BWS as defined by HTTPSEM as SP or HTAB (0x20 or 0x9).
- base::StringPiece value_without_BWS =
- base::TrimString(cookie_value, " \t", base::TRIM_LEADING);
- const base::StringPiece host_prefix = "__Host-";
- // Compare the value to the host_prefix.
- if (base::StartsWith(value_without_BWS, host_prefix)) {
- // The prefix matches, now check if the value string contains a subsequent
- // '='.
- if (value_without_BWS.find_first_of('=', host_prefix.size()) !=
- base::StringPiece::npos) {
- // This value contains a hidden prefix name.
- return true;
- }
- return false;
- }
- // Do a similar check for the secure prefix
- const base::StringPiece secure_prefix = "__Secure-";
- if (base::StartsWith(value_without_BWS, secure_prefix)) {
- if (value_without_BWS.find_first_of('=', secure_prefix.size()) !=
- base::StringPiece::npos) {
- return true;
- }
- }
- return false;
- }
- bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const {
- return (base::Time::Now() - creation_date_) <= age_threshold;
- }
- // static
- bool CanonicalCookie::IsCookieSamePartyValid(
- const ParsedCookie& parsed_cookie) {
- return IsCookieSamePartyValid(parsed_cookie.IsSameParty(),
- parsed_cookie.IsSecure(),
- parsed_cookie.SameSite());
- }
- // static
- bool CanonicalCookie::IsCookieSamePartyValid(bool is_same_party,
- bool is_secure,
- CookieSameSite same_site) {
- if (!is_same_party)
- return true;
- return is_secure && (same_site != CookieSameSite::STRICT_MODE);
- }
- // static
- bool CanonicalCookie::IsCookiePartitionedValid(
- const GURL& url,
- const ParsedCookie& parsed_cookie,
- bool partition_has_nonce) {
- return IsCookiePartitionedValid(
- url, /*secure=*/parsed_cookie.IsSecure(),
- /*is_partitioned=*/parsed_cookie.IsPartitioned(), partition_has_nonce);
- }
- // static
- bool CanonicalCookie::IsCookiePartitionedValid(const GURL& url,
- bool secure,
- bool is_partitioned,
- bool partition_has_nonce) {
- if (!is_partitioned)
- return true;
- if (partition_has_nonce)
- return true;
- bool result = url.SchemeIsCryptographic() && secure;
- DLOG_IF(WARNING, !result)
- << "CanonicalCookie has invalid Partitioned attribute";
- return result;
- }
- CookieAndLineWithAccessResult::CookieAndLineWithAccessResult() = default;
- CookieAndLineWithAccessResult::CookieAndLineWithAccessResult(
- absl::optional<CanonicalCookie> cookie,
- std::string cookie_string,
- CookieAccessResult access_result)
- : cookie(std::move(cookie)),
- cookie_string(std::move(cookie_string)),
- access_result(access_result) {}
- CookieAndLineWithAccessResult::CookieAndLineWithAccessResult(
- const CookieAndLineWithAccessResult&) = default;
- CookieAndLineWithAccessResult& CookieAndLineWithAccessResult::operator=(
- const CookieAndLineWithAccessResult& cookie_and_line_with_access_result) =
- default;
- CookieAndLineWithAccessResult::CookieAndLineWithAccessResult(
- CookieAndLineWithAccessResult&&) = default;
- CookieAndLineWithAccessResult::~CookieAndLineWithAccessResult() = default;
- } // namespace net
|