tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CookieService.cpp (65399B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et tw=80 : */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "CookieCommons.h"
      8 #include "CookieLogging.h"
      9 #include "CookieParser.h"
     10 #include "CookieService.h"
     11 #include "CookieValidation.h"
     12 #include "mozilla/AppShutdown.h"
     13 #include "mozilla/ClearOnShutdown.h"
     14 #include "mozilla/Components.h"
     15 #include "mozilla/ConsoleReportCollector.h"
     16 #include "mozilla/ContentBlockingNotifier.h"
     17 #include "mozilla/RefPtr.h"
     18 #include "mozilla/dom/Document.h"
     19 #include "mozilla/dom/nsMixedContentBlocker.h"
     20 #include "mozilla/dom/Promise.h"
     21 #include "mozilla/dom/Promise-inl.h"
     22 #include "mozilla/net/CookieJarSettings.h"
     23 #include "mozilla/net/CookiePersistentStorage.h"
     24 #include "mozilla/net/CookiePrivateStorage.h"
     25 #include "mozilla/net/CookieService.h"
     26 #include "mozilla/net/CookieServiceChild.h"
     27 #include "mozilla/net/HttpBaseChannel.h"
     28 #include "mozilla/net/NeckoCommon.h"
     29 #include "mozilla/StaticPrefs_network.h"
     30 #include "mozilla/StoragePrincipalHelper.h"
     31 #include "mozIThirdPartyUtil.h"
     32 #include "nsICookiePermission.h"
     33 #include "nsIConsoleReportCollector.h"
     34 #include "nsIEffectiveTLDService.h"
     35 #include "nsIScriptError.h"
     36 #include "nsIScriptSecurityManager.h"
     37 #include "nsIURI.h"
     38 #include "nsIWebProgressListener.h"
     39 #include "nsNetUtil.h"
     40 #include "ThirdPartyUtil.h"
     41 
     42 using namespace mozilla::dom;
     43 
     44 namespace {
     45 
     46 uint32_t MakeCookieBehavior(uint32_t aCookieBehavior) {
     47  bool isFirstPartyIsolated = OriginAttributes::IsFirstPartyEnabled();
     48 
     49  if (isFirstPartyIsolated &&
     50      aCookieBehavior ==
     51          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
     52    return nsICookieService::BEHAVIOR_REJECT_TRACKER;
     53  }
     54  return aCookieBehavior;
     55 }
     56 
     57 /*
     58 Enables sanitizeOnShutdown cleaning prefs and disables the
     59 network.cookie.lifetimePolicy
     60 */
     61 void MigrateCookieLifetimePrefs() {
     62  // Former network.cookie.lifetimePolicy values ACCEPT_SESSION/ACCEPT_NORMALLY
     63  // are not available anymore 2 = ACCEPT_SESSION
     64  if (mozilla::Preferences::GetInt("network.cookie.lifetimePolicy") != 2) {
     65    return;
     66  }
     67  if (!mozilla::Preferences::GetBool("privacy.sanitize.sanitizeOnShutdown")) {
     68    mozilla::Preferences::SetBool("privacy.sanitize.sanitizeOnShutdown", true);
     69    // To avoid clearing categories that the user did not intend to clear
     70    mozilla::Preferences::SetBool("privacy.clearOnShutdown.history", false);
     71    mozilla::Preferences::SetBool("privacy.clearOnShutdown.formdata", false);
     72    mozilla::Preferences::SetBool("privacy.clearOnShutdown.downloads", false);
     73    mozilla::Preferences::SetBool("privacy.clearOnShutdown.sessions", false);
     74    mozilla::Preferences::SetBool("privacy.clearOnShutdown.siteSettings",
     75                                  false);
     76 
     77    // We will migrate the new clear on shutdown prefs to align both sets of
     78    // prefs incase the user has not migrated yet. We don't have a new sessions
     79    // prefs, as it was merged into cookiesAndStorage as part of the effort for
     80    // the clear data revamp Bug 1853996
     81    mozilla::Preferences::SetBool(
     82        "privacy.clearOnShutdown_v2.browsingHistoryAndDownloads", false);
     83    mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.siteSettings",
     84                                  false);
     85  }
     86  mozilla::Preferences::SetBool("privacy.clearOnShutdown.cookies", true);
     87  mozilla::Preferences::SetBool("privacy.clearOnShutdown.cache", true);
     88  mozilla::Preferences::SetBool("privacy.clearOnShutdown.offlineApps", true);
     89 
     90  // Migrate the new clear on shutdown prefs
     91  mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.cookiesAndStorage",
     92                                true);
     93  mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.cache", true);
     94  mozilla::Preferences::ClearUser("network.cookie.lifetimePolicy");
     95 }
     96 
     97 }  // anonymous namespace
     98 
     99 // static
    100 uint32_t nsICookieManager::GetCookieBehavior(bool aIsPrivate) {
    101  if (aIsPrivate) {
    102    // To sync the cookieBehavior pref between regular and private mode in ETP
    103    // custom mode, we will return the regular cookieBehavior pref for private
    104    // mode when
    105    //   1. The regular cookieBehavior pref has a non-default value.
    106    //   2. And the private cookieBehavior pref has a default value.
    107    // Also, this can cover the migration case where the user has a non-default
    108    // cookieBehavior before the private cookieBehavior was introduced. The
    109    // getter here will directly return the regular cookieBehavior, so that the
    110    // cookieBehavior for private mode is consistent.
    111    if (mozilla::Preferences::HasUserValue(
    112            "network.cookie.cookieBehavior.pbmode")) {
    113      return MakeCookieBehavior(
    114          mozilla::StaticPrefs::network_cookie_cookieBehavior_pbmode());
    115    }
    116 
    117    if (mozilla::Preferences::HasUserValue("network.cookie.cookieBehavior")) {
    118      return MakeCookieBehavior(
    119          mozilla::StaticPrefs::network_cookie_cookieBehavior());
    120    }
    121 
    122    return MakeCookieBehavior(
    123        mozilla::StaticPrefs::network_cookie_cookieBehavior_pbmode());
    124  }
    125  return MakeCookieBehavior(
    126      mozilla::StaticPrefs::network_cookie_cookieBehavior());
    127 }
    128 
    129 namespace mozilla {
    130 namespace net {
    131 
    132 /******************************************************************************
    133 * CookieService impl:
    134 * useful types & constants
    135 ******************************************************************************/
    136 
    137 static StaticRefPtr<CookieService> gCookieService;
    138 
    139 namespace {
    140 
    141 // Return false if the cookie should be ignored for the current channel.
    142 bool ProcessSameSiteCookieForForeignRequest(nsIChannel* aChannel,
    143                                            Cookie* aCookie,
    144                                            bool aIsSafeTopLevelNav,
    145                                            bool aHadCrossSiteRedirects,
    146                                            bool aLaxByDefault) {
    147  // If it's a cross-site request and the cookie is same site only (strict)
    148  // don't send it.
    149  if (aCookie->SameSite() == nsICookie::SAMESITE_STRICT) {
    150    return false;
    151  }
    152 
    153  // Explicit SameSite=None cookies are always processed. When laxByDefault
    154  // is OFF then so are default cookies.
    155  if (aCookie->SameSite() == nsICookie::SAMESITE_NONE ||
    156      (!aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET)) {
    157    return true;
    158  }
    159 
    160  // Lax-by-default cookies are processed even with an intermediate
    161  // cross-site redirect (they are treated like aIsSameSiteForeign = false).
    162  if (aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET &&
    163      aHadCrossSiteRedirects &&
    164      StaticPrefs::
    165          network_cookie_sameSite_laxByDefault_allowBoomerangRedirect()) {
    166    return true;
    167  }
    168 
    169  int64_t currentTimeInUsec = PR_Now();
    170 
    171  // 2 minutes of tolerance for 'SameSite=Lax by default' for cookies set
    172  // without a SameSite value when used for unsafe http methods.
    173  if (aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET &&
    174      StaticPrefs::network_cookie_sameSite_laxPlusPOST_timeout() > 0 &&
    175      currentTimeInUsec - aCookie->UpdateTimeInUSec() <=
    176          (StaticPrefs::network_cookie_sameSite_laxPlusPOST_timeout() *
    177           PR_USEC_PER_SEC) &&
    178      !NS_IsSafeMethodNav(aChannel)) {
    179    return true;
    180  }
    181 
    182  MOZ_ASSERT(
    183      (aLaxByDefault && aCookie->SameSite() == nsICookie::SAMESITE_UNSET) ||
    184      aCookie->SameSite() == nsICookie::SAMESITE_LAX);
    185  // We only have SameSite=Lax or lax-by-default cookies at this point.  These
    186  // are processed only if it's a top-level navigation
    187  return aIsSafeTopLevelNav;
    188 }
    189 
    190 }  // namespace
    191 
    192 /******************************************************************************
    193 * CookieService impl:
    194 * singleton instance ctor/dtor methods
    195 ******************************************************************************/
    196 
    197 already_AddRefed<nsICookieService> CookieService::GetXPCOMSingleton() {
    198  if (IsNeckoChild()) {
    199    return CookieServiceChild::GetSingleton();
    200  }
    201 
    202  return GetSingleton();
    203 }
    204 
    205 already_AddRefed<CookieService> CookieService::GetSingleton() {
    206  NS_ASSERTION(!IsNeckoChild(), "not a parent process");
    207 
    208  if (gCookieService) {
    209    return do_AddRef(gCookieService);
    210  }
    211 
    212  // Create a new singleton CookieService.
    213  // We AddRef only once since XPCOM has rules about the ordering of module
    214  // teardowns - by the time our module destructor is called, it's too late to
    215  // Release our members (e.g. nsIObserverService and nsIPrefBranch), since GC
    216  // cycles have already been completed and would result in serious leaks.
    217  // See bug 209571.
    218  // TODO: Verify what is the earliest point in time during shutdown where
    219  // we can deny the creation of the CookieService as a whole.
    220  gCookieService = new CookieService();
    221  if (gCookieService) {
    222    if (NS_SUCCEEDED(gCookieService->Init())) {
    223      ClearOnShutdown(&gCookieService);
    224    } else {
    225      gCookieService = nullptr;
    226    }
    227  }
    228 
    229  return do_AddRef(gCookieService);
    230 }
    231 
    232 /******************************************************************************
    233 * CookieService impl:
    234 * public methods
    235 ******************************************************************************/
    236 
    237 NS_IMPL_ISUPPORTS(CookieService, nsICookieService, nsICookieManager,
    238                  nsIObserver, nsISupportsWeakReference, nsIMemoryReporter)
    239 
    240 CookieService::CookieService() = default;
    241 
    242 nsresult CookieService::Init() {
    243  nsresult rv;
    244  mTLDService = mozilla::components::EffectiveTLD::Service(&rv);
    245  NS_ENSURE_SUCCESS(rv, rv);
    246 
    247  mThirdPartyUtil = mozilla::components::ThirdPartyUtil::Service();
    248  NS_ENSURE_SUCCESS(rv, rv);
    249 
    250  // Init our default, and possibly private CookieStorages.
    251  InitCookieStorages();
    252 
    253  // Migrate network.cookie.lifetimePolicy pref to sanitizeOnShutdown prefs
    254  MigrateCookieLifetimePrefs();
    255 
    256  RegisterWeakMemoryReporter(this);
    257 
    258  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
    259  NS_ENSURE_STATE(os);
    260  os->AddObserver(this, "profile-before-change", true);
    261  os->AddObserver(this, "profile-do-change", true);
    262  os->AddObserver(this, "last-pb-context-exited", true);
    263  os->AddObserver(this, "browser-delayed-startup-finished", true);
    264 
    265  return NS_OK;
    266 }
    267 
    268 void CookieService::InitCookieStorages() {
    269  NS_ASSERTION(!mPersistentStorage, "already have a default CookieStorage");
    270  NS_ASSERTION(!mPrivateStorage, "already have a private CookieStorage");
    271 
    272  // Create two new CookieStorages. If we are in or beyond our observed
    273  // shutdown phase, just be non-persistent.
    274  if (MOZ_UNLIKELY(StaticPrefs::network_cookie_noPersistentStorage() ||
    275                   AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown))) {
    276    mPersistentStorage = CookiePrivateStorage::Create();
    277  } else {
    278    mPersistentStorage = CookiePersistentStorage::Create();
    279  }
    280 
    281  mPrivateStorage = CookiePrivateStorage::Create();
    282 }
    283 
    284 void CookieService::CloseCookieStorages() {
    285  // return if we already closed
    286  if (!mPersistentStorage) {
    287    return;
    288  }
    289 
    290  // Let's nullify both storages before calling Close().
    291  RefPtr<CookieStorage> privateStorage;
    292  privateStorage.swap(mPrivateStorage);
    293 
    294  RefPtr<CookieStorage> persistentStorage;
    295  persistentStorage.swap(mPersistentStorage);
    296 
    297  privateStorage->Close();
    298  persistentStorage->Close();
    299 }
    300 
    301 CookieService::~CookieService() {
    302  CloseCookieStorages();
    303 
    304  UnregisterWeakMemoryReporter(this);
    305 
    306  gCookieService = nullptr;
    307 }
    308 
    309 NS_IMETHODIMP
    310 CookieService::Observe(nsISupports* /*aSubject*/, const char* aTopic,
    311                       const char16_t* /*aData*/) {
    312  // check the topic
    313  if (!strcmp(aTopic, "profile-before-change")) {
    314    // The profile is about to change,
    315    // or is going away because the application is shutting down.
    316 
    317    // Close the default DB connection and null out our CookieStorages before
    318    // changing.
    319    CloseCookieStorages();
    320 
    321  } else if (!strcmp(aTopic, "profile-do-change")) {
    322    NS_ASSERTION(!mPersistentStorage, "shouldn't have a default CookieStorage");
    323    NS_ASSERTION(!mPrivateStorage, "shouldn't have a private CookieStorage");
    324 
    325    // the profile has already changed; init the db from the new location.
    326    // if we are in the private browsing state, however, we do not want to read
    327    // data into it - we should instead put it into the default state, so it's
    328    // ready for us if and when we switch back to it.
    329    InitCookieStorages();
    330 
    331  } else if (!strcmp(aTopic, "browser-delayed-startup-finished")) {
    332    mThirdPartyCookieBlockingExceptions.Initialize();
    333 
    334    RunOnShutdown([self = RefPtr{this}] {
    335      self->mThirdPartyCookieBlockingExceptions.Shutdown();
    336    });
    337  } else if (!strcmp(aTopic, "last-pb-context-exited")) {
    338    // Flush all the cookies stored by private browsing contexts
    339    OriginAttributesPattern pattern;
    340    pattern.mPrivateBrowsingId.Construct(1);
    341    RemoveCookiesWithOriginAttributes(pattern, ""_ns);
    342    mPrivateStorage = CookiePrivateStorage::Create();
    343  }
    344 
    345  return NS_OK;
    346 }
    347 
    348 NS_IMETHODIMP
    349 CookieService::GetCookieBehavior(bool aIsPrivate, uint32_t* aCookieBehavior) {
    350  NS_ENSURE_ARG_POINTER(aCookieBehavior);
    351  *aCookieBehavior = nsICookieManager::GetCookieBehavior(aIsPrivate);
    352  return NS_OK;
    353 }
    354 
    355 NS_IMETHODIMP
    356 CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
    357                                       nsACString& aCookieString) {
    358  NS_ENSURE_ARG(aHostURI);
    359  NS_ENSURE_ARG(aChannel);
    360 
    361  aCookieString.Truncate();
    362 
    363  if (!CookieCommons::IsSchemeSupported(aHostURI)) {
    364    return NS_OK;
    365  }
    366 
    367  uint32_t rejectedReason = 0;
    368  ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel(
    369      aChannel, false, aHostURI, nullptr, &rejectedReason);
    370 
    371  bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel);
    372  bool hadCrossSiteRedirects = false;
    373  bool isSameSiteForeign = CookieCommons::IsSameSiteForeign(
    374      aChannel, aHostURI, &hadCrossSiteRedirects);
    375 
    376  OriginAttributes storageOriginAttributes;
    377  StoragePrincipalHelper::GetOriginAttributes(
    378      aChannel, storageOriginAttributes,
    379      StoragePrincipalHelper::eStorageAccessPrincipal);
    380 
    381  nsTArray<OriginAttributes> originAttributesList;
    382  originAttributesList.AppendElement(storageOriginAttributes);
    383 
    384  // CHIPS - If CHIPS is enabled the partitioned cookie jar is always available
    385  // (and therefore the partitioned OriginAttributes), the unpartitioned cookie
    386  // jar is only available in first-party or third-party with storageAccess
    387  // contexts.
    388  nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
    389      CookieCommons::GetCookieJarSettings(aChannel);
    390  bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
    391                 !cookieJarSettings->GetBlockingAllContexts();
    392  bool isUnpartitioned =
    393      !result.contains(ThirdPartyAnalysis::IsForeign) ||
    394      result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted);
    395  if (isCHIPS && isUnpartitioned) {
    396    // Assert that the storage originAttributes is empty. In other words,
    397    // it's unpartitioned.
    398    MOZ_ASSERT(storageOriginAttributes.mPartitionKey.IsEmpty());
    399    // Add the partitioned principal to principals
    400    OriginAttributes partitionedOriginAttributes;
    401    StoragePrincipalHelper::GetOriginAttributes(
    402        aChannel, partitionedOriginAttributes,
    403        StoragePrincipalHelper::ePartitionedPrincipal);
    404    // Only append the partitioned originAttributes if the partitionKey is set.
    405    // The partitionKey could be empty for partitionKey in partitioned
    406    // originAttributes if the channel is for privilege request, such as
    407    // extension's requests.
    408    if (!partitionedOriginAttributes.mPartitionKey.IsEmpty()) {
    409      originAttributesList.AppendElement(partitionedOriginAttributes);
    410    }
    411  }
    412 
    413  AutoTArray<RefPtr<Cookie>, 8> foundCookieList;
    414  GetCookiesForURI(
    415      aHostURI, aChannel, result.contains(ThirdPartyAnalysis::IsForeign),
    416      result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
    417      result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
    418      result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
    419      rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
    420      hadCrossSiteRedirects, true, false, originAttributesList,
    421      foundCookieList);
    422 
    423  CookieCommons::ComposeCookieString(foundCookieList, aCookieString);
    424 
    425  if (!aCookieString.IsEmpty()) {
    426    COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, aCookieString, nullptr, false);
    427  }
    428  return NS_OK;
    429 }
    430 
    431 NS_IMETHODIMP
    432 CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
    433                                       const nsACString& aCookieHeader,
    434                                       nsIChannel* aChannel) {
    435  NS_ENSURE_ARG(aHostURI);
    436  NS_ENSURE_ARG(aChannel);
    437 
    438  if (!IsInitialized()) {
    439    return NS_OK;
    440  }
    441 
    442  if (!CookieCommons::IsSchemeSupported(aHostURI)) {
    443    return NS_OK;
    444  }
    445 
    446  uint32_t rejectedReason = 0;
    447  ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel(
    448      aChannel, false, aHostURI, nullptr, &rejectedReason);
    449 
    450  OriginAttributes storagePrincipalOriginAttributes;
    451  StoragePrincipalHelper::GetOriginAttributes(
    452      aChannel, storagePrincipalOriginAttributes,
    453      StoragePrincipalHelper::eStorageAccessPrincipal);
    454 
    455  // get the base domain for the host URI.
    456  // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
    457  // file:// URI's (i.e. with an empty host) are allowed, but any other
    458  // scheme must have a non-empty host. A trailing dot in the host
    459  // is acceptable.
    460  bool requireHostMatch;
    461  nsAutoCString baseDomain;
    462  nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI, baseDomain,
    463                                             requireHostMatch);
    464  if (NS_FAILED(rv)) {
    465    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
    466                      "couldn't get base domain from URI");
    467    return NS_OK;
    468  }
    469 
    470  nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
    471      CookieCommons::GetCookieJarSettings(aChannel);
    472 
    473  nsAutoCString hostFromURI;
    474  nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
    475 
    476  nsAutoCString baseDomainFromURI;
    477  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, hostFromURI,
    478                                            baseDomainFromURI);
    479  NS_ENSURE_SUCCESS(rv, NS_OK);
    480 
    481  CookieStorage* storage = PickStorage(storagePrincipalOriginAttributes);
    482 
    483  // check default prefs
    484  uint32_t priorCookieCount = storage->CountCookiesFromHost(
    485      baseDomainFromURI, storagePrincipalOriginAttributes.mPrivateBrowsingId);
    486 
    487  nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
    488 
    489  CookieStatus cookieStatus = CheckPrefs(
    490      crc, cookieJarSettings, aHostURI,
    491      result.contains(ThirdPartyAnalysis::IsForeign),
    492      result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
    493      result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
    494      result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
    495      aCookieHeader, priorCookieCount, storagePrincipalOriginAttributes,
    496      &rejectedReason);
    497 
    498  MOZ_ASSERT_IF(
    499      rejectedReason &&
    500          rejectedReason !=
    501              nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER,
    502      cookieStatus == STATUS_REJECTED);
    503 
    504  // fire a notification if third party or if cookie was rejected
    505  // (but not if there was an error)
    506  switch (cookieStatus) {
    507    case STATUS_REJECTED:
    508      CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
    509                                    OPERATION_WRITE);
    510      return NS_OK;  // Stop here
    511    case STATUS_REJECTED_WITH_ERROR:
    512      CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
    513                                    OPERATION_WRITE);
    514      return NS_OK;
    515    case STATUS_ACCEPTED:  // Fallthrough
    516    case STATUS_ACCEPT_SESSION:
    517      NotifyAccepted(aChannel);
    518 
    519      // Notify the content blocking event if tracker cookies are partitioned.
    520      if (rejectedReason ==
    521          nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER) {
    522        ContentBlockingNotifier::OnDecision(
    523            aChannel, ContentBlockingNotifier::BlockingDecision::eBlock,
    524            rejectedReason);
    525      }
    526      break;
    527    default:
    528      break;
    529  }
    530 
    531  bool addonAllowsLoad = false;
    532  nsCOMPtr<nsIURI> channelURI;
    533  NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
    534  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    535  addonAllowsLoad = BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
    536                        ->AddonAllowsLoad(channelURI);
    537 
    538  bool isForeignAndNotAddon = false;
    539  if (!addonAllowsLoad) {
    540    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI,
    541                                         &isForeignAndNotAddon);
    542 
    543    // include sub-document navigations from cross-site to same-site
    544    // wrt top-level in our check for thirdparty-ness
    545    if (StaticPrefs::network_cookie_sameSite_crossSiteIframeSetCheck() &&
    546        !isForeignAndNotAddon &&
    547        loadInfo->GetExternalContentPolicyType() ==
    548            ExtContentPolicy::TYPE_SUBDOCUMENT) {
    549      bool triggeringPrincipalIsThirdParty = false;
    550      BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
    551          ->IsThirdPartyURI(channelURI, &triggeringPrincipalIsThirdParty);
    552      isForeignAndNotAddon |= triggeringPrincipalIsThirdParty;
    553    }
    554  }
    555 
    556  bool mustBePartitioned =
    557      isForeignAndNotAddon &&
    558      cookieJarSettings->GetCookieBehavior() ==
    559          nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
    560      !result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted);
    561 
    562  nsCString cookieHeader(aCookieHeader);
    563 
    564  // CHIPS - The partitioned cookie jar is always available and it is always
    565  // possible to store cookies in it using the "Partitioned" attribute.
    566  // Prepare the partitioned principals OAs to enable possible partitioned
    567  // cookie storing from first-party or with StorageAccess.
    568  // Similar behavior to CookieServiceChild::SetCookieStringFromHttp().
    569  OriginAttributes partitionedPrincipalOriginAttributes;
    570  bool isPartitionedPrincipal =
    571      !storagePrincipalOriginAttributes.mPartitionKey.IsEmpty();
    572  bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
    573                 !cookieJarSettings->GetBlockingAllContexts();
    574  // Only need to get OAs if we don't already use the partitioned principal.
    575  if (isCHIPS && !isPartitionedPrincipal) {
    576    StoragePrincipalHelper::GetOriginAttributes(
    577        aChannel, partitionedPrincipalOriginAttributes,
    578        StoragePrincipalHelper::ePartitionedPrincipal);
    579  }
    580 
    581  nsAutoCString dateHeader;
    582  CookieCommons::GetServerDateHeader(aChannel, dateHeader);
    583 
    584  // process each cookie in the header
    585  CookieParser cookieParser(crc, aHostURI);
    586 
    587  cookieParser.Parse(baseDomain, requireHostMatch, cookieStatus, cookieHeader,
    588                     dateHeader, true, isForeignAndNotAddon, mustBePartitioned,
    589                     storagePrincipalOriginAttributes.IsPrivateBrowsing(),
    590                     loadInfo->GetIsOn3PCBExceptionList(),
    591                     CookieCommons::GetCurrentTimeInUSecFromChannel(aChannel));
    592 
    593  if (!cookieParser.ContainsCookie()) {
    594    return NS_OK;
    595  }
    596 
    597  // check permissions from site permission list.
    598  if (!CookieCommons::CheckCookiePermission(aChannel,
    599                                            cookieParser.CookieData())) {
    600    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
    601                      "cookie rejected by permission manager");
    602    CookieCommons::NotifyRejected(
    603        aHostURI, aChannel,
    604        nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION,
    605        OPERATION_WRITE);
    606    cookieParser.RejectCookie(CookieParser::RejectedByPermissionManager);
    607    return NS_OK;
    608  }
    609 
    610  // CHIPS - If the partitioned attribute is set, store cookie in partitioned
    611  // cookie jar independent of context. If the cookies are stored in the
    612  // partitioned cookie jar anyway no special treatment of CHIPS cookies
    613  // necessary.
    614  bool needPartitioned = isCHIPS && cookieParser.CookieData().isPartitioned() &&
    615                         !isPartitionedPrincipal;
    616  OriginAttributes& cookieOriginAttributes =
    617      needPartitioned ? partitionedPrincipalOriginAttributes
    618                      : storagePrincipalOriginAttributes;
    619  // Assert that partitionedPrincipalOriginAttributes are initialized if used.
    620  MOZ_ASSERT_IF(needPartitioned,
    621                !partitionedPrincipalOriginAttributes.mPartitionKey.IsEmpty());
    622 
    623  // create a new Cookie
    624  RefPtr<Cookie> cookie =
    625      Cookie::Create(cookieParser.CookieData(), cookieOriginAttributes);
    626  MOZ_ASSERT(cookie);
    627 
    628  int64_t currentTimeInUsec = PR_Now();
    629  cookie->SetLastAccessedInUSec(currentTimeInUsec);
    630  cookie->SetCreationTimeInUSec(
    631      Cookie::GenerateUniqueCreationTimeInUSec(currentTimeInUsec));
    632  cookie->SetUpdateTimeInUSec(cookie->CreationTimeInUSec());
    633 
    634  // Use TargetBrowsingContext to also take frame loads into account.
    635  RefPtr<BrowsingContext> bc = loadInfo->GetTargetBrowsingContext();
    636 
    637  // add the cookie to the list. AddCookie() takes care of logging.
    638  storage->AddCookie(&cookieParser, baseDomain, cookieOriginAttributes, cookie,
    639                     currentTimeInUsec, aHostURI, aCookieHeader, true,
    640                     isForeignAndNotAddon, bc);
    641 
    642  return NS_OK;
    643 }
    644 
    645 void CookieService::NotifyAccepted(nsIChannel* aChannel) {
    646  ContentBlockingNotifier::OnDecision(
    647      aChannel, ContentBlockingNotifier::BlockingDecision::eAllow, 0);
    648 }
    649 
    650 /******************************************************************************
    651 * CookieService:
    652 * public transaction helper impl
    653 ******************************************************************************/
    654 
    655 NS_IMETHODIMP
    656 CookieService::RunInTransaction(nsICookieTransactionCallback* aCallback) {
    657  NS_ENSURE_ARG(aCallback);
    658 
    659  if (!IsInitialized()) {
    660    return NS_ERROR_NOT_AVAILABLE;
    661  }
    662 
    663  mPersistentStorage->EnsureInitialized();
    664  return mPersistentStorage->RunInTransaction(aCallback);
    665 }
    666 
    667 /******************************************************************************
    668 * nsICookieManager impl:
    669 * nsICookieManager
    670 ******************************************************************************/
    671 
    672 NS_IMETHODIMP
    673 CookieService::RemoveAll() {
    674  if (!IsInitialized()) {
    675    return NS_ERROR_NOT_AVAILABLE;
    676  }
    677 
    678  mPersistentStorage->EnsureInitialized();
    679  mPersistentStorage->RemoveAll();
    680  return NS_OK;
    681 }
    682 
    683 NS_IMETHODIMP
    684 CookieService::GetCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
    685  if (!IsInitialized()) {
    686    return NS_ERROR_NOT_AVAILABLE;
    687  }
    688 
    689  mPersistentStorage->EnsureInitialized();
    690 
    691  // We expose only non-private cookies.
    692  mPersistentStorage->GetCookies(aCookies);
    693 
    694  return NS_OK;
    695 }
    696 
    697 NS_IMETHODIMP
    698 CookieService::GetSessionCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
    699  if (!IsInitialized()) {
    700    return NS_ERROR_NOT_AVAILABLE;
    701  }
    702 
    703  mPersistentStorage->EnsureInitialized();
    704 
    705  // We expose only non-private cookies.
    706  mPersistentStorage->GetSessionCookies(aCookies);
    707 
    708  return NS_OK;
    709 }
    710 
    711 NS_IMETHODIMP
    712 CookieService::Add(const nsACString& aHost, const nsACString& aPath,
    713                   const nsACString& aName, const nsACString& aValue,
    714                   bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
    715                   int64_t aExpiry, JS::Handle<JS::Value> aOriginAttributes,
    716                   int32_t aSameSite, nsICookie::schemeType aSchemeMap,
    717                   bool aIsPartitioned, JSContext* aCx,
    718                   nsICookieValidation** aValidation) {
    719  NS_ENSURE_ARG_POINTER(aCx);
    720  NS_ENSURE_ARG_POINTER(aValidation);
    721 
    722  OriginAttributes attrs;
    723 
    724  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    725    return NS_ERROR_INVALID_ARG;
    726  }
    727 
    728  nsCOMPtr<nsICookieValidation> validation;
    729  nsresult rv = AddInternal(nullptr, aHost, aPath, aName, aValue, aIsSecure,
    730                            aIsHttpOnly, aIsSession, aExpiry, &attrs, aSameSite,
    731                            aSchemeMap, aIsPartitioned, /* from-http: */ true,
    732                            nullptr, getter_AddRefs(validation));
    733  if (rv != NS_ERROR_ILLEGAL_VALUE || !validation ||
    734      CookieValidation::Cast(validation)->Result() ==
    735          nsICookieValidation::eOK) {
    736    validation.forget(aValidation);
    737    return rv;
    738  }
    739 
    740  validation.forget(aValidation);
    741  return NS_OK;
    742 }
    743 
    744 NS_IMETHODIMP_(nsresult)
    745 CookieService::AddNative(nsIURI* aCookieURI, const nsACString& aHost,
    746                         const nsACString& aPath, const nsACString& aName,
    747                         const nsACString& aValue, bool aIsSecure,
    748                         bool aIsHttpOnly, bool aIsSession, int64_t aExpiry,
    749                         OriginAttributes* aOriginAttributes, int32_t aSameSite,
    750                         nsICookie::schemeType aSchemeMap, bool aIsPartitioned,
    751                         bool aFromHttp, const nsID* aOperationID,
    752                         nsICookieValidation** aValidation) {
    753  return AddInternal(aCookieURI, aHost, aPath, aName, aValue, aIsSecure,
    754                     aIsHttpOnly, aIsSession, aExpiry, aOriginAttributes,
    755                     aSameSite, aSchemeMap, aIsPartitioned, aFromHttp,
    756                     aOperationID, aValidation);
    757 }
    758 
    759 nsresult CookieService::AddInternal(
    760    nsIURI* aCookieURI, const nsACString& aHost, const nsACString& aPath,
    761    const nsACString& aName, const nsACString& aValue, bool aIsSecure,
    762    bool aIsHttpOnly, bool aIsSession, int64_t aExpiry,
    763    OriginAttributes* aOriginAttributes, int32_t aSameSite,
    764    nsICookie::schemeType aSchemeMap, bool aIsPartitioned, bool aFromHttp,
    765    const nsID* aOperationID, nsICookieValidation** aValidation) {
    766  NS_ENSURE_ARG_POINTER(aValidation);
    767 
    768  if (NS_WARN_IF(!aOriginAttributes)) {
    769    return NS_ERROR_FAILURE;
    770  }
    771 
    772  if (!IsInitialized()) {
    773    return NS_ERROR_NOT_AVAILABLE;
    774  }
    775 
    776  // first, normalize the hostname, and fail if it contains illegal characters.
    777  nsAutoCString host(aHost);
    778  nsresult rv = NormalizeHost(host);
    779  NS_ENSURE_SUCCESS(rv, rv);
    780 
    781  // get the base domain for the host URI.
    782  // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
    783  nsAutoCString baseDomain;
    784  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
    785  NS_ENSURE_SUCCESS(rv, rv);
    786 
    787  int64_t currentTimeInUsec = PR_Now();
    788  int64_t uniqueCreationTimeInUSec =
    789      Cookie::GenerateUniqueCreationTimeInUSec(currentTimeInUsec);
    790 
    791  CookieStruct cookieData(nsCString(aName), nsCString(aValue), host,
    792                          nsCString(aPath), aExpiry, currentTimeInUsec,
    793                          uniqueCreationTimeInUSec, uniqueCreationTimeInUSec,
    794                          aIsHttpOnly, aIsSession, aIsSecure, aIsPartitioned,
    795                          aSameSite, aSchemeMap);
    796 
    797  RefPtr<CookieValidation> cv = CookieValidation::Validate(cookieData);
    798 
    799  if (cv->Result() != nsICookieValidation::eOK) {
    800    cv.forget(aValidation);
    801    return NS_ERROR_ILLEGAL_VALUE;
    802  }
    803 
    804  RefPtr<Cookie> cookie = Cookie::Create(cookieData, *aOriginAttributes);
    805  MOZ_ASSERT(cookie);
    806 
    807  CookieStorage* storage = PickStorage(*aOriginAttributes);
    808  storage->AddCookie(nullptr, baseDomain, *aOriginAttributes, cookie,
    809                     currentTimeInUsec, aCookieURI, VoidCString(), aFromHttp,
    810                     !aOriginAttributes->mPartitionKey.IsEmpty(), nullptr,
    811                     aOperationID);
    812 
    813  cv.forget(aValidation);
    814  return NS_OK;
    815 }
    816 
    817 nsresult CookieService::Remove(const nsACString& aHost,
    818                               const OriginAttributes& aAttrs,
    819                               const nsACString& aName, const nsACString& aPath,
    820                               bool aFromHttp, const nsID* aOperationID) {
    821  // first, normalize the hostname, and fail if it contains illegal characters.
    822  nsAutoCString host(aHost);
    823  nsresult rv = NormalizeHost(host);
    824  NS_ENSURE_SUCCESS(rv, rv);
    825 
    826  nsAutoCString baseDomain;
    827  if (!host.IsEmpty()) {
    828    rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
    829    NS_ENSURE_SUCCESS(rv, rv);
    830  }
    831 
    832  if (!IsInitialized()) {
    833    return NS_ERROR_NOT_AVAILABLE;
    834  }
    835 
    836  CookieStorage* storage = PickStorage(aAttrs);
    837  storage->RemoveCookie(baseDomain, aAttrs, host, PromiseFlatCString(aName),
    838                        PromiseFlatCString(aPath), aFromHttp, aOperationID);
    839 
    840  return NS_OK;
    841 }
    842 
    843 NS_IMETHODIMP
    844 CookieService::Remove(const nsACString& aHost, const nsACString& aName,
    845                      const nsACString& aPath,
    846                      JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx) {
    847  OriginAttributes attrs;
    848 
    849  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
    850    return NS_ERROR_INVALID_ARG;
    851  }
    852 
    853  return RemoveNative(aHost, aName, aPath, &attrs, /* from http: */ true,
    854                      nullptr);
    855 }
    856 
    857 NS_IMETHODIMP_(nsresult)
    858 CookieService::RemoveNative(const nsACString& aHost, const nsACString& aName,
    859                            const nsACString& aPath,
    860                            OriginAttributes* aOriginAttributes, bool aFromHttp,
    861                            const nsID* aOperationID) {
    862  if (NS_WARN_IF(!aOriginAttributes)) {
    863    return NS_ERROR_FAILURE;
    864  }
    865 
    866  nsresult rv =
    867      Remove(aHost, *aOriginAttributes, aName, aPath, aFromHttp, aOperationID);
    868  if (NS_WARN_IF(NS_FAILED(rv))) {
    869    return rv;
    870  }
    871 
    872  return NS_OK;
    873 }
    874 
    875 void CookieService::GetCookiesForURI(
    876    nsIURI* aHostURI, nsIChannel* aChannel, bool aIsForeign,
    877    bool aIsThirdPartyTrackingResource,
    878    bool aIsThirdPartySocialTrackingResource,
    879    bool aStorageAccessPermissionGranted, uint32_t aRejectedReason,
    880    bool aIsSafeTopLevelNav, bool aIsSameSiteForeign,
    881    bool aHadCrossSiteRedirects, bool aHttpBound,
    882    bool aAllowSecureCookiesToInsecureOrigin,
    883    const nsTArray<OriginAttributes>& aOriginAttrsList,
    884    nsTArray<RefPtr<Cookie>>& aCookieList) {
    885  NS_ASSERTION(aHostURI, "null host!");
    886 
    887  if (!CookieCommons::IsSchemeSupported(aHostURI)) {
    888    return;
    889  }
    890 
    891  if (!IsInitialized()) {
    892    return;
    893  }
    894 
    895  nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
    896      CookieCommons::GetCookieJarSettings(aChannel);
    897 
    898  nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
    899 
    900  nsCOMPtr<nsILoadInfo> loadInfo = aChannel ? aChannel->LoadInfo() : nullptr;
    901  const bool on3pcdException = loadInfo && loadInfo->GetIsOn3PCBExceptionList();
    902 
    903  for (const auto& attrs : aOriginAttrsList) {
    904    CookieStorage* storage = PickStorage(attrs);
    905 
    906    // get the base domain, host, and path from the URI.
    907    // e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk".
    908    // file:// URI's (i.e. with an empty host) are allowed, but any other
    909    // scheme must have a non-empty host. A trailing dot in the host
    910    // is acceptable.
    911    bool requireHostMatch;
    912    nsAutoCString baseDomain;
    913    nsAutoCString hostFromURI;
    914    nsAutoCString pathFromURI;
    915    nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI,
    916                                               baseDomain, requireHostMatch);
    917    if (NS_SUCCEEDED(rv)) {
    918      rv = nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
    919    }
    920    if (NS_SUCCEEDED(rv)) {
    921      rv = aHostURI->GetFilePath(pathFromURI);
    922    }
    923    if (NS_FAILED(rv)) {
    924      COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, VoidCString(),
    925                        "invalid host/path from URI");
    926      return;
    927    }
    928 
    929    nsAutoCString normalizedHostFromURI(hostFromURI);
    930    rv = NormalizeHost(normalizedHostFromURI);
    931    NS_ENSURE_SUCCESS_VOID(rv);
    932 
    933    nsAutoCString baseDomainFromURI;
    934    rv = CookieCommons::GetBaseDomainFromHost(
    935        mTLDService, normalizedHostFromURI, baseDomainFromURI);
    936    NS_ENSURE_SUCCESS_VOID(rv);
    937 
    938    // check default prefs
    939    uint32_t rejectedReason = aRejectedReason;
    940    uint32_t priorCookieCount = storage->CountCookiesFromHost(
    941        baseDomainFromURI, attrs.mPrivateBrowsingId);
    942 
    943    CookieStatus cookieStatus = CheckPrefs(
    944        crc, cookieJarSettings, aHostURI, aIsForeign,
    945        aIsThirdPartyTrackingResource, aIsThirdPartySocialTrackingResource,
    946        aStorageAccessPermissionGranted, VoidCString(), priorCookieCount, attrs,
    947        &rejectedReason);
    948 
    949    MOZ_ASSERT_IF(
    950        rejectedReason &&
    951            rejectedReason !=
    952                nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER,
    953        cookieStatus == STATUS_REJECTED);
    954 
    955    // for GetCookie(), we only fire acceptance/rejection notifications
    956    // (but not if there was an error)
    957    switch (cookieStatus) {
    958      case STATUS_REJECTED:
    959        // If we don't have any cookies from this host, fail silently.
    960        if (priorCookieCount) {
    961          CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
    962                                        OPERATION_READ);
    963        }
    964        return;
    965      default:
    966        break;
    967    }
    968 
    969    // Note: The following permissions logic is mirrored in
    970    // extensions::MatchPattern::MatchesCookie.
    971    // If it changes, please update that function, or file a bug for someone
    972    // else to do so.
    973 
    974    // check if aHostURI is using an https secure protocol.
    975    // if it isn't, then we can't send a secure cookie over the connection.
    976    // if SchemeIs fails, assume an insecure connection, to be on the safe side
    977    bool potentiallyTrustworthy =
    978        nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
    979 
    980    int64_t currentTimeInUsec = PR_Now();
    981    int64_t currentTimeInMSec = currentTimeInUsec / PR_USEC_PER_MSEC;
    982    bool stale = false;
    983 
    984    nsTArray<RefPtr<Cookie>> cookies;
    985    storage->GetCookiesFromHost(baseDomain, attrs, cookies);
    986    if (cookies.IsEmpty()) {
    987      continue;
    988    }
    989 
    990    bool laxByDefault =
    991        StaticPrefs::network_cookie_sameSite_laxByDefault() &&
    992        !nsContentUtils::IsURIInPrefList(
    993            aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
    994 
    995    // iterate the cookies!
    996    for (Cookie* cookie : cookies) {
    997      // check the host, since the base domain lookup is conservative.
    998      if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
    999        continue;
   1000      }
   1001 
   1002      // if the cookie is secure and the host scheme isn't, we avoid sending
   1003      // cookie if possible. But for process synchronization purposes, we may
   1004      // want the content process to know about the cookie (without it's value).
   1005      // In which case we will wipe the value before sending
   1006      if (cookie->IsSecure() && !potentiallyTrustworthy &&
   1007          !aAllowSecureCookiesToInsecureOrigin) {
   1008        continue;
   1009      }
   1010 
   1011      // if the cookie is httpOnly and it's not going directly to the HTTP
   1012      // connection, don't send it
   1013      if (cookie->IsHttpOnly() && !aHttpBound) {
   1014        continue;
   1015      }
   1016 
   1017      // if the nsIURI path doesn't match the cookie path, don't send it back
   1018      if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
   1019        continue;
   1020      }
   1021 
   1022      // check if the cookie has expired
   1023      if (cookie->ExpiryInMSec() <= currentTimeInMSec) {
   1024        continue;
   1025      }
   1026 
   1027      // Check if we need to block the cookie because of opt-in partitioning.
   1028      // We will only allow partitioned cookies with "partitioned" attribution
   1029      // if opt-in partitioning is enabled.
   1030      //
   1031      // Note: If the cookie is on the 3pcd exception list, we will include
   1032      // the cookie.
   1033      if (aIsForeign && cookieJarSettings->GetPartitionForeign() &&
   1034          (StaticPrefs::network_cookie_cookieBehavior_optInPartitioning() ||
   1035           (attrs.IsPrivateBrowsing() &&
   1036            StaticPrefs::
   1037                network_cookie_cookieBehavior_optInPartitioning_pbmode())) &&
   1038          !(cookie->IsPartitioned() && cookie->RawIsPartitioned()) &&
   1039          !aStorageAccessPermissionGranted && !on3pcdException) {
   1040        continue;
   1041      }
   1042 
   1043      if (aHttpBound && aIsSameSiteForeign) {
   1044        bool blockCookie = !ProcessSameSiteCookieForForeignRequest(
   1045            aChannel, cookie, aIsSafeTopLevelNav, aHadCrossSiteRedirects,
   1046            laxByDefault);
   1047 
   1048        if (blockCookie) {
   1049          if (aHadCrossSiteRedirects) {
   1050            CookieLogging::LogMessageToConsole(
   1051                crc, aHostURI, nsIScriptError::warningFlag,
   1052                CONSOLE_REJECTION_CATEGORY, "CookieBlockedCrossSiteRedirect"_ns,
   1053                AutoTArray<nsString, 1>{
   1054                    NS_ConvertUTF8toUTF16(cookie->Name()),
   1055                });
   1056          }
   1057          continue;
   1058        }
   1059      }
   1060 
   1061      // all checks passed - add to list and check if lastAccessedInUSec stamp
   1062      // needs updating
   1063      aCookieList.AppendElement(cookie);
   1064      if (cookie->IsStale()) {
   1065        stale = true;
   1066      }
   1067    }
   1068 
   1069    if (aCookieList.IsEmpty()) {
   1070      continue;
   1071    }
   1072 
   1073    // update lastAccessedInUSec timestamps. we only do this if the timestamp is
   1074    // stale by a certain amount, to avoid thrashing the db during pageload.
   1075    if (stale) {
   1076      storage->StaleCookies(aCookieList, currentTimeInUsec);
   1077    }
   1078  }
   1079 
   1080  if (aCookieList.IsEmpty()) {
   1081    return;
   1082  }
   1083 
   1084  // Send a notification about the acceptance of the cookies now that we found
   1085  // some.
   1086  NotifyAccepted(aChannel);
   1087 
   1088  // return cookies in order of path length; longest to shortest.
   1089  // this is required per RFC2109.  if cookies match in length,
   1090  // then sort by creation time (see bug 236772).
   1091  aCookieList.Sort(CompareCookiesForSending());
   1092 }
   1093 
   1094 /******************************************************************************
   1095 * CookieService impl:
   1096 * private domain & permission compliance enforcement functions
   1097 ******************************************************************************/
   1098 
   1099 nsresult CookieService::NormalizeHost(nsCString& aHost) {
   1100  nsAutoCString host;
   1101  if (!CookieCommons::IsIPv6BaseDomain(aHost)) {
   1102    nsresult rv = NS_DomainToASCII(aHost, host);
   1103    if (NS_FAILED(rv)) {
   1104      return rv;
   1105    }
   1106    aHost = host;
   1107  }
   1108 
   1109  return NS_OK;
   1110 }
   1111 
   1112 CookieStatus CookieService::CheckPrefs(
   1113    nsIConsoleReportCollector* aCRC, nsICookieJarSettings* aCookieJarSettings,
   1114    nsIURI* aHostURI, bool aIsForeign, bool aIsThirdPartyTrackingResource,
   1115    bool aIsThirdPartySocialTrackingResource,
   1116    bool aStorageAccessPermissionGranted, const nsACString& aCookieHeader,
   1117    const int aNumOfCookies, const OriginAttributes& aOriginAttrs,
   1118    uint32_t* aRejectedReason) {
   1119  nsresult rv;
   1120 
   1121  MOZ_ASSERT(aRejectedReason);
   1122 
   1123  *aRejectedReason = 0;
   1124 
   1125  // don't let unsupported scheme sites get/set cookies (could be a security
   1126  // issue)
   1127  if (!CookieCommons::IsSchemeSupported(aHostURI)) {
   1128    COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1129                      "non http/https sites cannot read cookies");
   1130    return STATUS_REJECTED_WITH_ERROR;
   1131  }
   1132 
   1133  nsCOMPtr<nsIPrincipal> principal =
   1134      BasePrincipal::CreateContentPrincipal(aHostURI, aOriginAttrs);
   1135 
   1136  if (!principal) {
   1137    COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1138                      "non-content principals cannot get/set cookies");
   1139    return STATUS_REJECTED_WITH_ERROR;
   1140  }
   1141 
   1142  // check the permission list first; if we find an entry, it overrides
   1143  // default prefs. see bug 184059.
   1144  uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
   1145  rv = aCookieJarSettings->CookiePermission(principal, &cookiePermission);
   1146  if (NS_SUCCEEDED(rv)) {
   1147    switch (cookiePermission) {
   1148      case nsICookiePermission::ACCESS_DENY:
   1149        COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1150                          "cookies are blocked for this site");
   1151        CookieLogging::LogMessageToConsole(
   1152            aCRC, aHostURI, nsIScriptError::warningFlag,
   1153            CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns,
   1154            AutoTArray<nsString, 1>{
   1155                NS_ConvertUTF8toUTF16(aCookieHeader),
   1156            });
   1157 
   1158        *aRejectedReason =
   1159            nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
   1160        return STATUS_REJECTED;
   1161 
   1162      case nsICookiePermission::ACCESS_ALLOW:
   1163        return STATUS_ACCEPTED;
   1164      default:
   1165        break;
   1166    }
   1167  }
   1168 
   1169  // No cookies allowed if this request comes from a resource in a 3rd party
   1170  // context, when anti-tracking protection is enabled and when we don't have
   1171  // access to the first-party cookie jar.
   1172  if (aIsForeign && aIsThirdPartyTrackingResource &&
   1173      !aStorageAccessPermissionGranted &&
   1174      aCookieJarSettings->GetRejectThirdPartyContexts()) {
   1175    // Set the reject reason to partitioned tracker if we are not blocking
   1176    // tracker cookie.
   1177    uint32_t rejectReason =
   1178        aCookieJarSettings->GetPartitionForeign() &&
   1179                !StaticPrefs::
   1180                    network_cookie_cookieBehavior_trackerCookieBlocking()
   1181            ? nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN
   1182            : nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
   1183    if (StoragePartitioningEnabled(rejectReason, aCookieJarSettings)) {
   1184      MOZ_ASSERT(!aOriginAttrs.mPartitionKey.IsEmpty(),
   1185                 "We must have a StoragePrincipal here!");
   1186      // Set the reject reason to partitioned tracker if the resource to reflect
   1187      // that we are partitioning tracker cookies.
   1188      *aRejectedReason =
   1189          nsIWebProgressListener::STATE_COOKIES_PARTITIONED_TRACKER;
   1190      return STATUS_ACCEPTED;
   1191    }
   1192 
   1193    COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1194                      "cookies are disabled in trackers");
   1195    if (aIsThirdPartySocialTrackingResource) {
   1196      *aRejectedReason =
   1197          nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
   1198    } else {
   1199      *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
   1200    }
   1201    return STATUS_REJECTED;
   1202  }
   1203 
   1204  // check default prefs.
   1205  // Check aStorageAccessPermissionGranted when checking aCookieBehavior
   1206  // so that we take things such as the content blocking allow list into
   1207  // account.
   1208  if (aCookieJarSettings->GetCookieBehavior() ==
   1209          nsICookieService::BEHAVIOR_REJECT &&
   1210      !aStorageAccessPermissionGranted) {
   1211    COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1212                      "cookies are disabled");
   1213    *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
   1214    return STATUS_REJECTED;
   1215  }
   1216 
   1217  // check if cookie is foreign
   1218  if (aIsForeign) {
   1219    if (aCookieJarSettings->GetCookieBehavior() ==
   1220            nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
   1221        !aStorageAccessPermissionGranted) {
   1222      COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1223                        "context is third party");
   1224      CookieLogging::LogMessageToConsole(
   1225          aCRC, aHostURI, nsIScriptError::warningFlag,
   1226          CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns,
   1227          AutoTArray<nsString, 1>{
   1228              NS_ConvertUTF8toUTF16(aCookieHeader),
   1229          });
   1230      *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
   1231      return STATUS_REJECTED;
   1232    }
   1233 
   1234    if (aCookieJarSettings->GetLimitForeignContexts() &&
   1235        !aStorageAccessPermissionGranted && aNumOfCookies == 0) {
   1236      COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
   1237                        "context is third party");
   1238      CookieLogging::LogMessageToConsole(
   1239          aCRC, aHostURI, nsIScriptError::warningFlag,
   1240          CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns,
   1241          AutoTArray<nsString, 1>{
   1242              NS_ConvertUTF8toUTF16(aCookieHeader),
   1243          });
   1244      *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
   1245      return STATUS_REJECTED;
   1246    }
   1247  }
   1248 
   1249  // if nothing has complained, accept cookie
   1250  return STATUS_ACCEPTED;
   1251 }
   1252 
   1253 /******************************************************************************
   1254 * CookieService impl:
   1255 * private cookielist management functions
   1256 ******************************************************************************/
   1257 
   1258 // find whether a given cookie has been previously set. this is provided by the
   1259 // nsICookieManager interface.
   1260 NS_IMETHODIMP
   1261 CookieService::CookieExists(const nsACString& aHost, const nsACString& aPath,
   1262                            const nsACString& aName,
   1263                            JS::Handle<JS::Value> aOriginAttributes,
   1264                            JSContext* aCx, bool* aFoundCookie) {
   1265  NS_ENSURE_ARG_POINTER(aCx);
   1266  NS_ENSURE_ARG_POINTER(aFoundCookie);
   1267 
   1268  OriginAttributes attrs;
   1269  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1270    return NS_ERROR_INVALID_ARG;
   1271  }
   1272  return CookieExistsNative(aHost, aPath, aName, &attrs, aFoundCookie);
   1273 }
   1274 
   1275 NS_IMETHODIMP_(nsresult)
   1276 CookieService::CookieExistsNative(const nsACString& aHost,
   1277                                  const nsACString& aPath,
   1278                                  const nsACString& aName,
   1279                                  OriginAttributes* aOriginAttributes,
   1280                                  bool* aFoundCookie) {
   1281  nsCOMPtr<nsICookie> cookie;
   1282  nsresult rv = GetCookieNative(aHost, aPath, aName, aOriginAttributes,
   1283                                getter_AddRefs(cookie));
   1284  NS_ENSURE_SUCCESS(rv, rv);
   1285 
   1286  *aFoundCookie = cookie != nullptr;
   1287 
   1288  return NS_OK;
   1289 }
   1290 
   1291 NS_IMETHODIMP_(nsresult)
   1292 CookieService::GetCookieNative(const nsACString& aHost, const nsACString& aPath,
   1293                               const nsACString& aName,
   1294                               OriginAttributes* aOriginAttributes,
   1295                               nsICookie** aCookie) {
   1296  NS_ENSURE_ARG_POINTER(aOriginAttributes);
   1297  NS_ENSURE_ARG_POINTER(aCookie);
   1298 
   1299  if (!IsInitialized()) {
   1300    return NS_ERROR_NOT_AVAILABLE;
   1301  }
   1302 
   1303  nsAutoCString baseDomain;
   1304  nsresult rv =
   1305      CookieCommons::GetBaseDomainFromHost(mTLDService, aHost, baseDomain);
   1306  NS_ENSURE_SUCCESS(rv, rv);
   1307 
   1308  CookieStorage* storage = PickStorage(*aOriginAttributes);
   1309 
   1310  RefPtr<Cookie> cookie =
   1311      storage->FindCookie(baseDomain, *aOriginAttributes, aHost, aName, aPath);
   1312  cookie.forget(aCookie);
   1313 
   1314  return NS_OK;
   1315 }
   1316 
   1317 // count the number of cookies stored by a particular host. this is provided by
   1318 // the nsICookieManager interface.
   1319 NS_IMETHODIMP
   1320 CookieService::CountCookiesFromHost(const nsACString& aHost,
   1321                                    uint32_t* aCountFromHost) {
   1322  // first, normalize the hostname, and fail if it contains illegal characters.
   1323  nsAutoCString host(aHost);
   1324  nsresult rv = NormalizeHost(host);
   1325  NS_ENSURE_SUCCESS(rv, rv);
   1326 
   1327  nsAutoCString baseDomain;
   1328  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
   1329  NS_ENSURE_SUCCESS(rv, rv);
   1330 
   1331  if (!IsInitialized()) {
   1332    return NS_ERROR_NOT_AVAILABLE;
   1333  }
   1334 
   1335  mPersistentStorage->EnsureInitialized();
   1336 
   1337  *aCountFromHost = mPersistentStorage->CountCookiesFromHost(baseDomain, 0);
   1338 
   1339  return NS_OK;
   1340 }
   1341 
   1342 // get an enumerator of cookies stored by a particular host. this is provided by
   1343 // the nsICookieManager interface.
   1344 NS_IMETHODIMP
   1345 CookieService::GetCookiesFromHost(const nsACString& aHost,
   1346                                  JS::Handle<JS::Value> aOriginAttributes,
   1347                                  bool aSorted, JSContext* aCx,
   1348                                  nsTArray<RefPtr<nsICookie>>& aResult) {
   1349  OriginAttributes attrs;
   1350  if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
   1351    return NS_ERROR_INVALID_ARG;
   1352  }
   1353 
   1354  return GetCookiesFromHostNative(aHost, &attrs, aSorted, aResult);
   1355 }
   1356 
   1357 NS_IMETHODIMP
   1358 CookieService::GetCookiesFromHostNative(const nsACString& aHost,
   1359                                        OriginAttributes* aAttrs, bool aSorted,
   1360                                        nsTArray<RefPtr<nsICookie>>& aResult) {
   1361  // first, normalize the hostname, and fail if it contains illegal characters.
   1362  nsAutoCString host(aHost);
   1363  nsresult rv = NormalizeHost(host);
   1364  NS_ENSURE_SUCCESS(rv, rv);
   1365 
   1366  nsAutoCString baseDomain;
   1367  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
   1368  NS_ENSURE_SUCCESS(rv, rv);
   1369 
   1370  if (!IsInitialized()) {
   1371    return NS_ERROR_NOT_AVAILABLE;
   1372  }
   1373 
   1374  CookieStorage* storage = PickStorage(*aAttrs);
   1375 
   1376  nsTArray<RefPtr<Cookie>> cookies;
   1377  storage->GetCookiesFromHost(baseDomain, *aAttrs, cookies);
   1378 
   1379  if (cookies.IsEmpty()) {
   1380    return NS_OK;
   1381  }
   1382 
   1383  aResult.SetCapacity(cookies.Length());
   1384  for (Cookie* cookie : cookies) {
   1385    aResult.AppendElement(cookie);
   1386  }
   1387 
   1388  if (aSorted) {
   1389    aResult.Sort(CompareCookiesForSending());
   1390  }
   1391 
   1392  return NS_OK;
   1393 }
   1394 
   1395 NS_IMETHODIMP
   1396 CookieService::GetCookiesWithOriginAttributes(
   1397    const nsAString& aPattern, const nsACString& aHost, const bool aSorted,
   1398    nsTArray<RefPtr<nsICookie>>& aResult) {
   1399  OriginAttributesPattern pattern;
   1400  if (!pattern.Init(aPattern)) {
   1401    return NS_ERROR_INVALID_ARG;
   1402  }
   1403 
   1404  nsAutoCString host(aHost);
   1405  nsresult rv = NormalizeHost(host);
   1406  NS_ENSURE_SUCCESS(rv, rv);
   1407 
   1408  nsAutoCString baseDomain;
   1409  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
   1410  NS_ENSURE_SUCCESS(rv, rv);
   1411 
   1412  return GetCookiesWithOriginAttributes(pattern, baseDomain, aSorted, aResult);
   1413 }
   1414 
   1415 nsresult CookieService::GetCookiesWithOriginAttributes(
   1416    const OriginAttributesPattern& aPattern, const nsCString& aBaseDomain,
   1417    bool aSorted, nsTArray<RefPtr<nsICookie>>& aResult) {
   1418  CookieStorage* storage = PickStorage(aPattern);
   1419  storage->GetCookiesWithOriginAttributes(aPattern, aBaseDomain, aSorted,
   1420                                          aResult);
   1421 
   1422  return NS_OK;
   1423 }
   1424 
   1425 NS_IMETHODIMP
   1426 CookieService::RemoveCookiesWithOriginAttributes(const nsAString& aPattern,
   1427                                                 const nsACString& aHost) {
   1428  MOZ_ASSERT(XRE_IsParentProcess());
   1429 
   1430  OriginAttributesPattern pattern;
   1431  if (!pattern.Init(aPattern)) {
   1432    return NS_ERROR_INVALID_ARG;
   1433  }
   1434 
   1435  nsAutoCString host(aHost);
   1436  nsresult rv = NormalizeHost(host);
   1437  NS_ENSURE_SUCCESS(rv, rv);
   1438 
   1439  nsAutoCString baseDomain;
   1440  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
   1441  NS_ENSURE_SUCCESS(rv, rv);
   1442 
   1443  return RemoveCookiesWithOriginAttributes(pattern, baseDomain);
   1444 }
   1445 
   1446 nsresult CookieService::RemoveCookiesWithOriginAttributes(
   1447    const OriginAttributesPattern& aPattern, const nsCString& aBaseDomain) {
   1448  if (!IsInitialized()) {
   1449    return NS_ERROR_NOT_AVAILABLE;
   1450  }
   1451 
   1452  CookieStorage* storage = PickStorage(aPattern);
   1453  storage->RemoveCookiesWithOriginAttributes(aPattern, aBaseDomain);
   1454 
   1455  return NS_OK;
   1456 }
   1457 
   1458 NS_IMETHODIMP
   1459 CookieService::RemoveCookiesFromExactHost(const nsACString& aHost,
   1460                                          const nsAString& aPattern) {
   1461  MOZ_ASSERT(XRE_IsParentProcess());
   1462 
   1463  OriginAttributesPattern pattern;
   1464  if (!pattern.Init(aPattern)) {
   1465    return NS_ERROR_INVALID_ARG;
   1466  }
   1467 
   1468  return RemoveCookiesFromExactHost(aHost, pattern);
   1469 }
   1470 
   1471 nsresult CookieService::RemoveCookiesFromExactHost(
   1472    const nsACString& aHost, const OriginAttributesPattern& aPattern) {
   1473  nsAutoCString host(aHost);
   1474  nsresult rv = NormalizeHost(host);
   1475  NS_ENSURE_SUCCESS(rv, rv);
   1476 
   1477  nsAutoCString baseDomain;
   1478  rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
   1479  NS_ENSURE_SUCCESS(rv, rv);
   1480 
   1481  if (!IsInitialized()) {
   1482    return NS_ERROR_NOT_AVAILABLE;
   1483  }
   1484 
   1485  CookieStorage* storage = PickStorage(aPattern);
   1486  storage->RemoveCookiesFromExactHost(aHost, baseDomain, aPattern);
   1487 
   1488  return NS_OK;
   1489 }
   1490 
   1491 namespace {
   1492 
   1493 class RemoveAllSinceRunnable : public Runnable {
   1494 public:
   1495  using CookieArray = nsTArray<RefPtr<nsICookie>>;
   1496  RemoveAllSinceRunnable(Promise* aPromise, CookieService* aSelf,
   1497                         CookieArray&& aCookieArray, int64_t aSinceWhen)
   1498      : Runnable("RemoveAllSinceRunnable"),
   1499        mPromise(aPromise),
   1500        mSelf(aSelf),
   1501        mList(std::move(aCookieArray)),
   1502        mIndex(0),
   1503        mSinceWhen(aSinceWhen) {}
   1504 
   1505  NS_IMETHODIMP Run() override {
   1506    RemoveSome();
   1507 
   1508    if (mIndex < mList.Length()) {
   1509      return NS_DispatchToCurrentThread(this);
   1510    }
   1511    mPromise->MaybeResolveWithUndefined();
   1512 
   1513    return NS_OK;
   1514  }
   1515 
   1516 private:
   1517  void RemoveSome() {
   1518    for (CookieArray::size_type iter = 0;
   1519         iter < kYieldPeriod && mIndex < mList.Length(); ++mIndex, ++iter) {
   1520      auto* cookie = static_cast<Cookie*>(mList[mIndex].get());
   1521      if (cookie->CreationTimeInUSec() > mSinceWhen &&
   1522          NS_FAILED(mSelf->Remove(cookie->Host(), cookie->OriginAttributesRef(),
   1523                                  cookie->Name(), cookie->Path(),
   1524                                  /* from http: */ true, nullptr))) {
   1525        continue;
   1526      }
   1527    }
   1528  }
   1529 
   1530 private:
   1531  RefPtr<Promise> mPromise;
   1532  RefPtr<CookieService> mSelf;
   1533  CookieArray mList;
   1534  CookieArray::size_type mIndex;
   1535  int64_t mSinceWhen;
   1536  static const CookieArray::size_type kYieldPeriod = 10;
   1537 };
   1538 
   1539 }  // namespace
   1540 
   1541 NS_IMETHODIMP
   1542 CookieService::RemoveAllSince(int64_t aSinceWhen, JSContext* aCx,
   1543                              Promise** aRetVal) {
   1544  nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
   1545  if (NS_WARN_IF(!globalObject)) {
   1546    return NS_ERROR_UNEXPECTED;
   1547  }
   1548 
   1549  ErrorResult result;
   1550  RefPtr<Promise> promise = Promise::Create(globalObject, result);
   1551  if (NS_WARN_IF(result.Failed())) {
   1552    return result.StealNSResult();
   1553  }
   1554 
   1555  mPersistentStorage->EnsureInitialized();
   1556 
   1557  nsTArray<RefPtr<nsICookie>> cookieList;
   1558 
   1559  // We delete only non-private cookies.
   1560  mPersistentStorage->GetAll(cookieList);
   1561 
   1562  RefPtr<RemoveAllSinceRunnable> runMe = new RemoveAllSinceRunnable(
   1563      promise, this, std::move(cookieList), aSinceWhen);
   1564 
   1565  promise.forget(aRetVal);
   1566 
   1567  return runMe->Run();
   1568 }
   1569 
   1570 namespace {
   1571 
   1572 class CompareCookiesCreationTime {
   1573 public:
   1574  static bool Equals(const nsICookie* aCookie1, const nsICookie* aCookie2) {
   1575    return static_cast<const Cookie*>(aCookie1)->CreationTimeInUSec() ==
   1576           static_cast<const Cookie*>(aCookie2)->CreationTimeInUSec();
   1577  }
   1578 
   1579  static bool LessThan(const nsICookie* aCookie1, const nsICookie* aCookie2) {
   1580    return static_cast<const Cookie*>(aCookie1)->CreationTimeInUSec() <
   1581           static_cast<const Cookie*>(aCookie2)->CreationTimeInUSec();
   1582  }
   1583 };
   1584 
   1585 }  // namespace
   1586 
   1587 NS_IMETHODIMP
   1588 CookieService::GetCookiesSince(int64_t aSinceWhen,
   1589                               nsTArray<RefPtr<nsICookie>>& aResult) {
   1590  if (!IsInitialized()) {
   1591    return NS_OK;
   1592  }
   1593 
   1594  mPersistentStorage->EnsureInitialized();
   1595 
   1596  // We expose only non-private cookies.
   1597  nsTArray<RefPtr<nsICookie>> cookieList;
   1598  mPersistentStorage->GetAll(cookieList);
   1599 
   1600  for (RefPtr<nsICookie>& cookie : cookieList) {
   1601    if (static_cast<Cookie*>(cookie.get())->CreationTimeInUSec() >=
   1602        aSinceWhen) {
   1603      aResult.AppendElement(cookie);
   1604    }
   1605  }
   1606 
   1607  aResult.Sort(CompareCookiesCreationTime());
   1608  return NS_OK;
   1609 }
   1610 
   1611 size_t CookieService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
   1612  size_t n = aMallocSizeOf(this);
   1613 
   1614  if (mPersistentStorage) {
   1615    n += mPersistentStorage->SizeOfIncludingThis(aMallocSizeOf);
   1616  }
   1617  if (mPrivateStorage) {
   1618    n += mPrivateStorage->SizeOfIncludingThis(aMallocSizeOf);
   1619  }
   1620 
   1621  return n;
   1622 }
   1623 
   1624 MOZ_DEFINE_MALLOC_SIZE_OF(CookieServiceMallocSizeOf)
   1625 
   1626 NS_IMETHODIMP
   1627 CookieService::CollectReports(nsIHandleReportCallback* aHandleReport,
   1628                              nsISupports* aData, bool /*aAnonymize*/) {
   1629  MOZ_COLLECT_REPORT("explicit/cookie-service", KIND_HEAP, UNITS_BYTES,
   1630                     SizeOfIncludingThis(CookieServiceMallocSizeOf),
   1631                     "Memory used by the cookie service.");
   1632 
   1633  return NS_OK;
   1634 }
   1635 
   1636 bool CookieService::IsInitialized() const {
   1637  if (!mPersistentStorage) {
   1638    NS_WARNING("No CookieStorage! Profile already close?");
   1639    return false;
   1640  }
   1641 
   1642  MOZ_ASSERT(mPrivateStorage);
   1643  return true;
   1644 }
   1645 
   1646 CookieStorage* CookieService::PickStorage(const OriginAttributes& aAttrs) {
   1647  MOZ_ASSERT(IsInitialized());
   1648 
   1649  if (aAttrs.IsPrivateBrowsing()) {
   1650    return mPrivateStorage;
   1651  }
   1652 
   1653  mPersistentStorage->EnsureInitialized();
   1654  return mPersistentStorage;
   1655 }
   1656 
   1657 CookieStorage* CookieService::PickStorage(
   1658    const OriginAttributesPattern& aAttrs) {
   1659  MOZ_ASSERT(IsInitialized());
   1660 
   1661  if (aAttrs.mPrivateBrowsingId.WasPassed() &&
   1662      aAttrs.mPrivateBrowsingId.Value() > 0) {
   1663    return mPrivateStorage;
   1664  }
   1665 
   1666  mPersistentStorage->EnsureInitialized();
   1667  return mPersistentStorage;
   1668 }
   1669 
   1670 nsICookieValidation::ValidationError CookieService::SetCookiesFromIPC(
   1671    const nsACString& aBaseDomain, const OriginAttributes& aAttrs,
   1672    nsIURI* aHostURI, bool aFromHttp, bool aIsThirdParty,
   1673    const nsTArray<CookieStruct>& aCookies, BrowsingContext* aBrowsingContext) {
   1674  if (!IsInitialized()) {
   1675    // If we are probably shutting down, we can ignore this cookie.
   1676    return nsICookieValidation::eOK;
   1677  }
   1678 
   1679  CookieStorage* storage = PickStorage(aAttrs);
   1680  int64_t currentTimeInUsec = PR_Now();
   1681 
   1682  for (const CookieStruct& cookieData : aCookies) {
   1683    RefPtr<CookieValidation> validation = CookieValidation::ValidateForHost(
   1684        cookieData, aHostURI, aBaseDomain, false, aFromHttp);
   1685    MOZ_ASSERT(validation);
   1686 
   1687    if (validation->Result() != nsICookieValidation::eOK) {
   1688      return validation->Result();
   1689    }
   1690 
   1691    // create a new Cookie and copy attributes
   1692    RefPtr<Cookie> cookie = Cookie::Create(cookieData, aAttrs);
   1693    if (!cookie) {
   1694      continue;
   1695    }
   1696 
   1697    cookie->SetLastAccessedInUSec(currentTimeInUsec);
   1698    cookie->SetCreationTimeInUSec(
   1699        Cookie::GenerateUniqueCreationTimeInUSec(currentTimeInUsec));
   1700    cookie->SetUpdateTimeInUSec(cookie->CreationTimeInUSec());
   1701 
   1702    storage->AddCookie(nullptr, aBaseDomain, aAttrs, cookie, currentTimeInUsec,
   1703                       aHostURI, ""_ns, aFromHttp, aIsThirdParty,
   1704                       aBrowsingContext);
   1705  }
   1706 
   1707  return nsICookieValidation::eOK;
   1708 }
   1709 
   1710 void CookieService::GetCookiesFromHost(
   1711    const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes,
   1712    nsTArray<RefPtr<Cookie>>& aCookies) {
   1713  if (!IsInitialized()) {
   1714    return;
   1715  }
   1716 
   1717  CookieStorage* storage = PickStorage(aOriginAttributes);
   1718  storage->GetCookiesFromHost(aBaseDomain, aOriginAttributes, aCookies);
   1719 }
   1720 
   1721 void CookieService::StaleCookies(const nsTArray<RefPtr<Cookie>>& aCookies,
   1722                                 int64_t aCurrentTimeInUsec) {
   1723  if (!IsInitialized()) {
   1724    return;
   1725  }
   1726 
   1727  if (aCookies.IsEmpty()) {
   1728    return;
   1729  }
   1730 
   1731  OriginAttributes originAttributes = aCookies[0]->OriginAttributesRef();
   1732 #ifdef MOZ_DEBUG
   1733  for (Cookie* cookie : aCookies) {
   1734    MOZ_ASSERT(originAttributes == cookie->OriginAttributesRef());
   1735  }
   1736 #endif
   1737 
   1738  CookieStorage* storage = PickStorage(originAttributes);
   1739  storage->StaleCookies(aCookies, aCurrentTimeInUsec);
   1740 }
   1741 
   1742 bool CookieService::HasExistingCookies(
   1743    const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes) {
   1744  if (!IsInitialized()) {
   1745    return false;
   1746  }
   1747 
   1748  CookieStorage* storage = PickStorage(aOriginAttributes);
   1749  return !!storage->CountCookiesFromHost(aBaseDomain,
   1750                                         aOriginAttributes.mPrivateBrowsingId);
   1751 }
   1752 
   1753 void CookieService::AddCookieFromDocument(
   1754    CookieParser& aCookieParser, const nsACString& aBaseDomain,
   1755    const OriginAttributes& aOriginAttributes, Cookie& aCookie,
   1756    int64_t aCurrentTimeInUsec, nsIURI* aDocumentURI, bool aThirdParty,
   1757    Document* aDocument) {
   1758  MOZ_ASSERT(aDocumentURI);
   1759  MOZ_ASSERT(aDocument);
   1760 
   1761  if (!IsInitialized()) {
   1762    return;
   1763  }
   1764 
   1765  nsAutoCString cookieString;
   1766  aCookieParser.GetCookieString(cookieString);
   1767 
   1768  PickStorage(aOriginAttributes)
   1769      ->AddCookie(&aCookieParser, aBaseDomain, aOriginAttributes, &aCookie,
   1770                  aCurrentTimeInUsec, aDocumentURI, cookieString, false,
   1771                  aThirdParty, aDocument->GetBrowsingContext());
   1772 }
   1773 
   1774 /* static */
   1775 void CookieService::Update3PCBExceptionInfo(nsIChannel* aChannel) {
   1776  MOZ_ASSERT(aChannel);
   1777  MOZ_ASSERT(XRE_IsParentProcess());
   1778 
   1779  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   1780  RefPtr<CookieService> csSingleton = CookieService::GetSingleton();
   1781 
   1782  // Bail out if the channel is a top-level loading. The exception is only
   1783  // applicable to third-party loading.
   1784  if (loadInfo->GetExternalContentPolicyType() ==
   1785      ExtContentPolicy::TYPE_DOCUMENT) {
   1786    return;
   1787  }
   1788 
   1789  // Bail out earlier if the 3PCB exception service is not initialized.
   1790  if (!csSingleton->mThirdPartyCookieBlockingExceptions.IsInitialized()) {
   1791    return;
   1792  }
   1793 
   1794  // If the channel is triggered by a system principal, we don't need to do
   1795  // anything because the channel is for loading system resources.
   1796  if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
   1797    return;
   1798  }
   1799 
   1800  bool isInExceptionList =
   1801      csSingleton->mThirdPartyCookieBlockingExceptions.CheckExceptionForChannel(
   1802          aChannel);
   1803 
   1804  (void)loadInfo->SetIsOn3PCBExceptionList(isInExceptionList);
   1805 }
   1806 
   1807 NS_IMETHODIMP
   1808 CookieService::AddThirdPartyCookieBlockingExceptions(
   1809    const nsTArray<RefPtr<nsIThirdPartyCookieExceptionEntry>>& aExceptions) {
   1810  for (const auto& ex : aExceptions) {
   1811    nsAutoCString exception;
   1812    MOZ_ALWAYS_SUCCEEDS(ex->Serialize(exception));
   1813    mThirdPartyCookieBlockingExceptions.Insert(exception);
   1814  }
   1815 
   1816  return NS_OK;
   1817 }
   1818 
   1819 NS_IMETHODIMP
   1820 CookieService::RemoveThirdPartyCookieBlockingExceptions(
   1821    const nsTArray<RefPtr<nsIThirdPartyCookieExceptionEntry>>& aExceptions) {
   1822  for (const auto& ex : aExceptions) {
   1823    nsAutoCString exception;
   1824    MOZ_ALWAYS_SUCCEEDS(ex->Serialize(exception));
   1825    mThirdPartyCookieBlockingExceptions.Remove(exception);
   1826  }
   1827 
   1828  return NS_OK;
   1829 }
   1830 
   1831 NS_IMETHODIMP
   1832 CookieService::TestGet3PCBExceptions(nsTArray<nsCString>& aExceptions) {
   1833  aExceptions.Clear();
   1834 
   1835  mThirdPartyCookieBlockingExceptions.GetExceptions(aExceptions);
   1836 
   1837  return NS_OK;
   1838 }
   1839 
   1840 NS_IMETHODIMP
   1841 CookieService::MaybeCapExpiry(int64_t aExpiryInMSec, int64_t* aResult) {
   1842  NS_ENSURE_ARG_POINTER(aResult);
   1843  *aResult =
   1844      CookieCommons::MaybeCapExpiry(PR_Now() / PR_USEC_PER_MSEC, aExpiryInMSec);
   1845  return NS_OK;
   1846 }
   1847 
   1848 }  // namespace net
   1849 }  // namespace mozilla