Bug 1909121 - [wpt-sync] Update web-platform-tests to 5af3e9c2a2aba76ade00f0dbc3486e5...
[gecko.git] / netwerk / cookie / CookieService.cpp
blob26f065c1e9cb2f59999c351e49191c556999adbb
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/. */
7 #include "CookieCommons.h"
8 #include "CookieLogging.h"
9 #include "CookieParser.h"
10 #include "mozilla/AppShutdown.h"
11 #include "mozilla/ClearOnShutdown.h"
12 #include "mozilla/Components.h"
13 #include "mozilla/ConsoleReportCollector.h"
14 #include "mozilla/ContentBlockingNotifier.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/dom/Document.h"
17 #include "mozilla/dom/nsMixedContentBlocker.h"
18 #include "mozilla/dom/Promise.h"
19 #include "mozilla/net/CookieJarSettings.h"
20 #include "mozilla/net/CookiePersistentStorage.h"
21 #include "mozilla/net/CookiePrivateStorage.h"
22 #include "mozilla/net/CookieService.h"
23 #include "mozilla/net/CookieServiceChild.h"
24 #include "mozilla/net/HttpBaseChannel.h"
25 #include "mozilla/net/NeckoCommon.h"
26 #include "mozilla/StaticPrefs_network.h"
27 #include "mozilla/StoragePrincipalHelper.h"
28 #include "mozilla/Telemetry.h"
29 #include "mozIThirdPartyUtil.h"
30 #include "nsICookiePermission.h"
31 #include "nsIConsoleReportCollector.h"
32 #include "nsIEffectiveTLDService.h"
33 #include "nsIScriptError.h"
34 #include "nsIScriptSecurityManager.h"
35 #include "nsIURI.h"
36 #include "nsIWebProgressListener.h"
37 #include "nsNetUtil.h"
38 #include "ThirdPartyUtil.h"
40 using namespace mozilla::dom;
42 namespace {
44 uint32_t MakeCookieBehavior(uint32_t aCookieBehavior) {
45 bool isFirstPartyIsolated = OriginAttributes::IsFirstPartyEnabled();
47 if (isFirstPartyIsolated &&
48 aCookieBehavior ==
49 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
50 return nsICookieService::BEHAVIOR_REJECT_TRACKER;
52 return aCookieBehavior;
56 Enables sanitizeOnShutdown cleaning prefs and disables the
57 network.cookie.lifetimePolicy
59 void MigrateCookieLifetimePrefs() {
60 // Former network.cookie.lifetimePolicy values ACCEPT_SESSION/ACCEPT_NORMALLY
61 // are not available anymore 2 = ACCEPT_SESSION
62 if (mozilla::Preferences::GetInt("network.cookie.lifetimePolicy") != 2) {
63 return;
65 if (!mozilla::Preferences::GetBool("privacy.sanitize.sanitizeOnShutdown")) {
66 mozilla::Preferences::SetBool("privacy.sanitize.sanitizeOnShutdown", true);
67 // To avoid clearing categories that the user did not intend to clear
68 mozilla::Preferences::SetBool("privacy.clearOnShutdown.history", false);
69 mozilla::Preferences::SetBool("privacy.clearOnShutdown.formdata", false);
70 mozilla::Preferences::SetBool("privacy.clearOnShutdown.downloads", false);
71 mozilla::Preferences::SetBool("privacy.clearOnShutdown.sessions", false);
72 mozilla::Preferences::SetBool("privacy.clearOnShutdown.siteSettings",
73 false);
75 // We will migrate the new clear on shutdown prefs to align both sets of
76 // prefs incase the user has not migrated yet. We don't have a new sessions
77 // prefs, as it was merged into cookiesAndStorage as part of the effort for
78 // the clear data revamp Bug 1853996
79 mozilla::Preferences::SetBool(
80 "privacy.clearOnShutdown_v2.historyFormDataAndDownloads", false);
81 mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.siteSettings",
82 false);
84 mozilla::Preferences::SetBool("privacy.clearOnShutdown.cookies", true);
85 mozilla::Preferences::SetBool("privacy.clearOnShutdown.cache", true);
86 mozilla::Preferences::SetBool("privacy.clearOnShutdown.offlineApps", true);
88 // Migrate the new clear on shutdown prefs
89 mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.cookiesAndStorage",
90 true);
91 mozilla::Preferences::SetBool("privacy.clearOnShutdown_v2.cache", true);
92 mozilla::Preferences::ClearUser("network.cookie.lifetimePolicy");
95 } // anonymous namespace
97 // static
98 uint32_t nsICookieManager::GetCookieBehavior(bool aIsPrivate) {
99 if (aIsPrivate) {
100 // To sync the cookieBehavior pref between regular and private mode in ETP
101 // custom mode, we will return the regular cookieBehavior pref for private
102 // mode when
103 // 1. The regular cookieBehavior pref has a non-default value.
104 // 2. And the private cookieBehavior pref has a default value.
105 // Also, this can cover the migration case where the user has a non-default
106 // cookieBehavior before the private cookieBehavior was introduced. The
107 // getter here will directly return the regular cookieBehavior, so that the
108 // cookieBehavior for private mode is consistent.
109 if (mozilla::Preferences::HasUserValue(
110 "network.cookie.cookieBehavior.pbmode")) {
111 return MakeCookieBehavior(
112 mozilla::StaticPrefs::network_cookie_cookieBehavior_pbmode());
115 if (mozilla::Preferences::HasUserValue("network.cookie.cookieBehavior")) {
116 return MakeCookieBehavior(
117 mozilla::StaticPrefs::network_cookie_cookieBehavior());
120 return MakeCookieBehavior(
121 mozilla::StaticPrefs::network_cookie_cookieBehavior_pbmode());
123 return MakeCookieBehavior(
124 mozilla::StaticPrefs::network_cookie_cookieBehavior());
127 namespace mozilla {
128 namespace net {
130 /******************************************************************************
131 * CookieService impl:
132 * useful types & constants
133 ******************************************************************************/
135 static StaticRefPtr<CookieService> gCookieService;
137 constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
139 namespace {
141 void ComposeCookieString(nsTArray<RefPtr<Cookie>>& aCookieList,
142 nsACString& aCookieString) {
143 for (Cookie* cookie : aCookieList) {
144 // check if we have anything to write
145 if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
146 // if we've already added a cookie to the return list, append a "; " so
147 // that subsequent cookies are delimited in the final list.
148 if (!aCookieString.IsEmpty()) {
149 aCookieString.AppendLiteral("; ");
152 if (!cookie->Name().IsEmpty()) {
153 // we have a name and value - write both
154 aCookieString += cookie->Name() + "="_ns + cookie->Value();
155 } else {
156 // just write value
157 aCookieString += cookie->Value();
163 // Return false if the cookie should be ignored for the current channel.
164 bool ProcessSameSiteCookieForForeignRequest(nsIChannel* aChannel,
165 Cookie* aCookie,
166 bool aIsSafeTopLevelNav,
167 bool aHadCrossSiteRedirects,
168 bool aLaxByDefault) {
169 // If it's a cross-site request and the cookie is same site only (strict)
170 // don't send it.
171 if (aCookie->SameSite() == nsICookie::SAMESITE_STRICT) {
172 return false;
175 // Explicit SameSite=None cookies are always processed. When laxByDefault
176 // is OFF then so are default cookies.
177 if (aCookie->SameSite() == nsICookie::SAMESITE_NONE ||
178 (!aLaxByDefault && aCookie->IsDefaultSameSite())) {
179 return true;
182 // Lax-by-default cookies are processed even with an intermediate
183 // cross-site redirect (they are treated like aIsSameSiteForeign = false).
184 if (aLaxByDefault && aCookie->IsDefaultSameSite() && aHadCrossSiteRedirects &&
185 StaticPrefs::
186 network_cookie_sameSite_laxByDefault_allowBoomerangRedirect()) {
187 return true;
190 int64_t currentTimeInUsec = PR_Now();
192 // 2 minutes of tolerance for 'SameSite=Lax by default' for cookies set
193 // without a SameSite value when used for unsafe http methods.
194 if (aLaxByDefault && aCookie->IsDefaultSameSite() &&
195 StaticPrefs::network_cookie_sameSite_laxPlusPOST_timeout() > 0 &&
196 currentTimeInUsec - aCookie->CreationTime() <=
197 (StaticPrefs::network_cookie_sameSite_laxPlusPOST_timeout() *
198 PR_USEC_PER_SEC) &&
199 !NS_IsSafeMethodNav(aChannel)) {
200 return true;
203 MOZ_ASSERT((aLaxByDefault && aCookie->IsDefaultSameSite()) ||
204 aCookie->SameSite() == nsICookie::SAMESITE_LAX);
205 // We only have SameSite=Lax or lax-by-default cookies at this point. These
206 // are processed only if it's a top-level navigation
207 return aIsSafeTopLevelNav;
210 } // namespace
212 /******************************************************************************
213 * CookieService impl:
214 * singleton instance ctor/dtor methods
215 ******************************************************************************/
217 already_AddRefed<nsICookieService> CookieService::GetXPCOMSingleton() {
218 if (IsNeckoChild()) {
219 return CookieServiceChild::GetSingleton();
222 return GetSingleton();
225 already_AddRefed<CookieService> CookieService::GetSingleton() {
226 NS_ASSERTION(!IsNeckoChild(), "not a parent process");
228 if (gCookieService) {
229 return do_AddRef(gCookieService);
232 // Create a new singleton CookieService.
233 // We AddRef only once since XPCOM has rules about the ordering of module
234 // teardowns - by the time our module destructor is called, it's too late to
235 // Release our members (e.g. nsIObserverService and nsIPrefBranch), since GC
236 // cycles have already been completed and would result in serious leaks.
237 // See bug 209571.
238 // TODO: Verify what is the earliest point in time during shutdown where
239 // we can deny the creation of the CookieService as a whole.
240 gCookieService = new CookieService();
241 if (gCookieService) {
242 if (NS_SUCCEEDED(gCookieService->Init())) {
243 ClearOnShutdown(&gCookieService);
244 } else {
245 gCookieService = nullptr;
249 return do_AddRef(gCookieService);
252 /******************************************************************************
253 * CookieService impl:
254 * public methods
255 ******************************************************************************/
257 NS_IMPL_ISUPPORTS(CookieService, nsICookieService, nsICookieManager,
258 nsIObserver, nsISupportsWeakReference, nsIMemoryReporter)
260 CookieService::CookieService() = default;
262 nsresult CookieService::Init() {
263 nsresult rv;
264 mTLDService = mozilla::components::EffectiveTLD::Service(&rv);
265 NS_ENSURE_SUCCESS(rv, rv);
267 mThirdPartyUtil = mozilla::components::ThirdPartyUtil::Service();
268 NS_ENSURE_SUCCESS(rv, rv);
270 // Init our default, and possibly private CookieStorages.
271 InitCookieStorages();
273 // Migrate network.cookie.lifetimePolicy pref to sanitizeOnShutdown prefs
274 MigrateCookieLifetimePrefs();
276 RegisterWeakMemoryReporter(this);
278 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
279 NS_ENSURE_STATE(os);
280 os->AddObserver(this, "profile-before-change", true);
281 os->AddObserver(this, "profile-do-change", true);
282 os->AddObserver(this, "last-pb-context-exited", true);
284 return NS_OK;
287 void CookieService::InitCookieStorages() {
288 NS_ASSERTION(!mPersistentStorage, "already have a default CookieStorage");
289 NS_ASSERTION(!mPrivateStorage, "already have a private CookieStorage");
291 // Create two new CookieStorages. If we are in or beyond our observed
292 // shutdown phase, just be non-persistent.
293 if (MOZ_UNLIKELY(StaticPrefs::network_cookie_noPersistentStorage() ||
294 AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown))) {
295 mPersistentStorage = CookiePrivateStorage::Create();
296 } else {
297 mPersistentStorage = CookiePersistentStorage::Create();
300 mPrivateStorage = CookiePrivateStorage::Create();
303 void CookieService::CloseCookieStorages() {
304 // return if we already closed
305 if (!mPersistentStorage) {
306 return;
309 // Let's nullify both storages before calling Close().
310 RefPtr<CookieStorage> privateStorage;
311 privateStorage.swap(mPrivateStorage);
313 RefPtr<CookieStorage> persistentStorage;
314 persistentStorage.swap(mPersistentStorage);
316 privateStorage->Close();
317 persistentStorage->Close();
320 CookieService::~CookieService() {
321 CloseCookieStorages();
323 UnregisterWeakMemoryReporter(this);
325 gCookieService = nullptr;
328 NS_IMETHODIMP
329 CookieService::Observe(nsISupports* /*aSubject*/, const char* aTopic,
330 const char16_t* /*aData*/) {
331 // check the topic
332 if (!strcmp(aTopic, "profile-before-change")) {
333 // The profile is about to change,
334 // or is going away because the application is shutting down.
336 // Close the default DB connection and null out our CookieStorages before
337 // changing.
338 CloseCookieStorages();
340 } else if (!strcmp(aTopic, "profile-do-change")) {
341 NS_ASSERTION(!mPersistentStorage, "shouldn't have a default CookieStorage");
342 NS_ASSERTION(!mPrivateStorage, "shouldn't have a private CookieStorage");
344 // the profile has already changed; init the db from the new location.
345 // if we are in the private browsing state, however, we do not want to read
346 // data into it - we should instead put it into the default state, so it's
347 // ready for us if and when we switch back to it.
348 InitCookieStorages();
350 } else if (!strcmp(aTopic, "last-pb-context-exited")) {
351 // Flush all the cookies stored by private browsing contexts
352 OriginAttributesPattern pattern;
353 pattern.mPrivateBrowsingId.Construct(1);
354 RemoveCookiesWithOriginAttributes(pattern, ""_ns);
355 mPrivateStorage = CookiePrivateStorage::Create();
358 return NS_OK;
361 NS_IMETHODIMP
362 CookieService::GetCookieBehavior(bool aIsPrivate, uint32_t* aCookieBehavior) {
363 NS_ENSURE_ARG_POINTER(aCookieBehavior);
364 *aCookieBehavior = nsICookieManager::GetCookieBehavior(aIsPrivate);
365 return NS_OK;
368 NS_IMETHODIMP
369 CookieService::GetCookieStringFromDocument(Document* aDocument,
370 nsACString& aCookie) {
371 NS_ENSURE_ARG(aDocument);
373 nsresult rv;
375 aCookie.Truncate();
377 if (!IsInitialized()) {
378 return NS_OK;
381 bool thirdParty = true;
382 nsPIDOMWindowInner* innerWindow = aDocument->GetInnerWindow();
383 // in gtests we don't have a window, let's consider those requests as 3rd
384 // party.
385 if (innerWindow) {
386 ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
388 if (thirdPartyUtil) {
389 Unused << thirdPartyUtil->IsThirdPartyWindow(
390 innerWindow->GetOuterWindow(), nullptr, &thirdParty);
394 nsCOMPtr<nsIPrincipal> cookiePrincipal =
395 aDocument->EffectiveCookiePrincipal();
397 nsTArray<nsCOMPtr<nsIPrincipal>> principals;
398 principals.AppendElement(cookiePrincipal);
400 // CHIPS - If CHIPS is enabled the partitioned cookie jar is always available
401 // (and therefore the partitioned principal), the unpartitioned cookie jar is
402 // only available in first-party or third-party with storageAccess contexts.
403 // In both cases, the document will have storage access.
404 bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
405 aDocument->CookieJarSettings()->GetPartitionForeign();
406 bool documentHasStorageAccess = false;
407 rv = aDocument->HasStorageAccessSync(documentHasStorageAccess);
408 NS_ENSURE_SUCCESS(rv, rv);
409 if (isCHIPS && documentHasStorageAccess) {
410 // Assert that the cookie principal is unpartitioned.
411 MOZ_ASSERT(cookiePrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
412 // Only append the partitioned originAttributes if the partitionKey is set.
413 // The partitionKey could be empty for partitionKey in partitioned
414 // originAttributes if the document is for privilege context, such as the
415 // extension's background page.
416 if (!aDocument->PartitionedPrincipal()
417 ->OriginAttributesRef()
418 .mPartitionKey.IsEmpty()) {
419 principals.AppendElement(aDocument->PartitionedPrincipal());
423 nsTArray<RefPtr<Cookie>> cookieList;
425 for (auto& principal : principals) {
426 if (!CookieCommons::IsSchemeSupported(principal)) {
427 return NS_OK;
430 CookieStorage* storage = PickStorage(principal->OriginAttributesRef());
432 nsAutoCString baseDomain;
433 rv = CookieCommons::GetBaseDomain(principal, baseDomain);
434 if (NS_WARN_IF(NS_FAILED(rv))) {
435 return NS_OK;
438 nsAutoCString hostFromURI;
439 rv = nsContentUtils::GetHostOrIPv6WithBrackets(principal, hostFromURI);
440 if (NS_WARN_IF(NS_FAILED(rv))) {
441 return NS_OK;
444 nsAutoCString pathFromURI;
445 rv = principal->GetFilePath(pathFromURI);
446 if (NS_WARN_IF(NS_FAILED(rv))) {
447 return NS_OK;
450 int64_t currentTimeInUsec = PR_Now();
451 int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
453 nsTArray<RefPtr<Cookie>> cookies;
454 storage->GetCookiesFromHost(baseDomain, principal->OriginAttributesRef(),
455 cookies);
456 if (cookies.IsEmpty()) {
457 continue;
460 // check if the nsIPrincipal is using an https secure protocol.
461 // if it isn't, then we can't send a secure cookie over the connection.
462 bool potentiallyTrustworthy =
463 principal->GetIsOriginPotentiallyTrustworthy();
465 bool stale = false;
467 // iterate the cookies!
468 for (Cookie* cookie : cookies) {
469 // check the host, since the base domain lookup is conservative.
470 if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
471 continue;
474 // if the cookie is httpOnly and it's not going directly to the HTTP
475 // connection, don't send it
476 if (cookie->IsHttpOnly()) {
477 continue;
480 if (thirdParty && !CookieCommons::ShouldIncludeCrossSiteCookieForDocument(
481 cookie, aDocument)) {
482 continue;
485 // if the cookie is secure and the host scheme isn't, we can't send it
486 if (cookie->IsSecure() && !potentiallyTrustworthy) {
487 continue;
490 // if the nsIURI path doesn't match the cookie path, don't send it back
491 if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
492 continue;
495 // check if the cookie has expired
496 if (cookie->Expiry() <= currentTime) {
497 continue;
500 // all checks passed - add to list and check if lastAccessed stamp needs
501 // updating
502 cookieList.AppendElement(cookie);
503 if (cookie->IsStale()) {
504 stale = true;
508 if (cookieList.IsEmpty()) {
509 continue;
512 // update lastAccessed timestamps. we only do this if the timestamp is stale
513 // by a certain amount, to avoid thrashing the db during pageload.
514 if (stale) {
515 storage->StaleCookies(cookieList, currentTimeInUsec);
519 if (cookieList.IsEmpty()) {
520 return NS_OK;
523 // return cookies in order of path length; longest to shortest.
524 // this is required per RFC2109. if cookies match in length,
525 // then sort by creation time (see bug 236772).
526 cookieList.Sort(CompareCookiesForSending());
527 ComposeCookieString(cookieList, aCookie);
529 return NS_OK;
532 NS_IMETHODIMP
533 CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
534 nsACString& aCookieString) {
535 NS_ENSURE_ARG(aHostURI);
536 NS_ENSURE_ARG(aChannel);
538 aCookieString.Truncate();
540 if (!CookieCommons::IsSchemeSupported(aHostURI)) {
541 return NS_OK;
544 uint32_t rejectedReason = 0;
545 ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel(
546 aChannel, false, aHostURI, nullptr, &rejectedReason);
548 bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel);
549 bool hadCrossSiteRedirects = false;
550 bool isSameSiteForeign = CookieCommons::IsSameSiteForeign(
551 aChannel, aHostURI, &hadCrossSiteRedirects);
553 OriginAttributes storageOriginAttributes;
554 StoragePrincipalHelper::GetOriginAttributes(
555 aChannel, storageOriginAttributes,
556 StoragePrincipalHelper::eStorageAccessPrincipal);
558 nsTArray<OriginAttributes> originAttributesList;
559 originAttributesList.AppendElement(storageOriginAttributes);
561 // CHIPS - If CHIPS is enabled the partitioned cookie jar is always available
562 // (and therefore the partitioned OriginAttributes), the unpartitioned cookie
563 // jar is only available in first-party or third-party with storageAccess
564 // contexts.
565 nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
566 CookieCommons::GetCookieJarSettings(aChannel);
567 bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
568 cookieJarSettings->GetPartitionForeign();
569 bool isUnpartitioned =
570 !result.contains(ThirdPartyAnalysis::IsForeign) ||
571 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted);
572 if (isCHIPS && isUnpartitioned) {
573 // Assert that the storage originAttributes is empty. In other words,
574 // it's unpartitioned.
575 MOZ_ASSERT(storageOriginAttributes.mPartitionKey.IsEmpty());
576 // Add the partitioned principal to principals
577 OriginAttributes partitionedOriginAttributes;
578 StoragePrincipalHelper::GetOriginAttributes(
579 aChannel, partitionedOriginAttributes,
580 StoragePrincipalHelper::ePartitionedPrincipal);
581 // Only append the partitioned originAttributes if the partitionKey is set.
582 // The partitionKey could be empty for partitionKey in partitioned
583 // originAttributes if the channel is for privilege request, such as
584 // extension's requests.
585 if (!partitionedOriginAttributes.mPartitionKey.IsEmpty()) {
586 originAttributesList.AppendElement(partitionedOriginAttributes);
590 AutoTArray<RefPtr<Cookie>, 8> foundCookieList;
591 GetCookiesForURI(
592 aHostURI, aChannel, result.contains(ThirdPartyAnalysis::IsForeign),
593 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
594 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
595 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
596 rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
597 hadCrossSiteRedirects, true, false, originAttributesList,
598 foundCookieList);
600 ComposeCookieString(foundCookieList, aCookieString);
602 if (!aCookieString.IsEmpty()) {
603 COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, aCookieString, nullptr, false);
605 return NS_OK;
608 NS_IMETHODIMP
609 CookieService::SetCookieStringFromDocument(Document* aDocument,
610 const nsACString& aCookieString) {
611 NS_ENSURE_ARG(aDocument);
613 if (!IsInitialized()) {
614 return NS_OK;
617 nsCOMPtr<nsIURI> documentURI;
618 nsAutoCString baseDomain;
619 OriginAttributes attrs;
621 int64_t currentTimeInUsec = PR_Now();
623 // This function is executed in this context, I don't need to keep objects
624 // alive.
625 auto hasExistingCookiesLambda = [&](const nsACString& aBaseDomain,
626 const OriginAttributes& aAttrs) {
627 CookieStorage* storage = PickStorage(aAttrs);
628 return !!storage->CountCookiesFromHost(aBaseDomain,
629 aAttrs.mPrivateBrowsingId);
632 auto* basePrincipal = BasePrincipal::Cast(aDocument->NodePrincipal());
633 basePrincipal->GetURI(getter_AddRefs(documentURI));
634 if (NS_WARN_IF(!documentURI)) {
635 // Document's principal is not a content or null (may be system), so
636 // can't set cookies
637 return NS_OK;
640 // Console report takes care of the correct reporting at the exit of this
641 // method.
642 RefPtr<ConsoleReportCollector> crc = new ConsoleReportCollector();
643 auto scopeExit = MakeScopeExit([&] { crc->FlushConsoleReports(aDocument); });
645 CookieParser cookieParser(crc, documentURI);
647 RefPtr<Cookie> cookie = CookieCommons::CreateCookieFromDocument(
648 cookieParser, aDocument, aCookieString, currentTimeInUsec, mTLDService,
649 mThirdPartyUtil, hasExistingCookiesLambda, baseDomain, attrs);
650 if (!cookie) {
651 return NS_OK;
654 bool thirdParty = true;
655 nsPIDOMWindowInner* innerWindow = aDocument->GetInnerWindow();
656 // in gtests we don't have a window, let's consider those requests as 3rd
657 // party.
658 if (innerWindow) {
659 ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
661 if (thirdPartyUtil) {
662 Unused << thirdPartyUtil->IsThirdPartyWindow(
663 innerWindow->GetOuterWindow(), nullptr, &thirdParty);
667 if (thirdParty && !CookieCommons::ShouldIncludeCrossSiteCookieForDocument(
668 cookie, aDocument)) {
669 return NS_OK;
672 // add the cookie to the list. AddCookie() takes care of logging.
673 PickStorage(attrs)->AddCookie(
674 &cookieParser, baseDomain, attrs, cookie, currentTimeInUsec, documentURI,
675 aCookieString, false, thirdParty, aDocument->GetBrowsingContext());
676 return NS_OK;
679 NS_IMETHODIMP
680 CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
681 const nsACString& aCookieHeader,
682 nsIChannel* aChannel) {
683 NS_ENSURE_ARG(aHostURI);
684 NS_ENSURE_ARG(aChannel);
686 if (!IsInitialized()) {
687 return NS_OK;
690 if (!CookieCommons::IsSchemeSupported(aHostURI)) {
691 return NS_OK;
694 uint32_t rejectedReason = 0;
695 ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel(
696 aChannel, false, aHostURI, nullptr, &rejectedReason);
698 OriginAttributes storagePrincipalOriginAttributes;
699 StoragePrincipalHelper::GetOriginAttributes(
700 aChannel, storagePrincipalOriginAttributes,
701 StoragePrincipalHelper::eStorageAccessPrincipal);
703 // get the base domain for the host URI.
704 // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
705 // file:// URI's (i.e. with an empty host) are allowed, but any other
706 // scheme must have a non-empty host. A trailing dot in the host
707 // is acceptable.
708 bool requireHostMatch;
709 nsAutoCString baseDomain;
710 nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI, baseDomain,
711 requireHostMatch);
712 if (NS_FAILED(rv)) {
713 COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
714 "couldn't get base domain from URI");
715 return NS_OK;
718 nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
719 CookieCommons::GetCookieJarSettings(aChannel);
721 nsAutoCString hostFromURI;
722 nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
724 nsAutoCString baseDomainFromURI;
725 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, hostFromURI,
726 baseDomainFromURI);
727 NS_ENSURE_SUCCESS(rv, NS_OK);
729 CookieStorage* storage = PickStorage(storagePrincipalOriginAttributes);
731 // check default prefs
732 uint32_t priorCookieCount = storage->CountCookiesFromHost(
733 baseDomainFromURI, storagePrincipalOriginAttributes.mPrivateBrowsingId);
735 nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
737 CookieStatus cookieStatus = CheckPrefs(
738 crc, cookieJarSettings, aHostURI,
739 result.contains(ThirdPartyAnalysis::IsForeign),
740 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
741 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
742 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
743 aCookieHeader, priorCookieCount, storagePrincipalOriginAttributes,
744 &rejectedReason);
746 MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
748 // fire a notification if third party or if cookie was rejected
749 // (but not if there was an error)
750 switch (cookieStatus) {
751 case STATUS_REJECTED:
752 CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
753 OPERATION_WRITE);
754 return NS_OK; // Stop here
755 case STATUS_REJECTED_WITH_ERROR:
756 CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
757 OPERATION_WRITE);
758 return NS_OK;
759 case STATUS_ACCEPTED: // Fallthrough
760 case STATUS_ACCEPT_SESSION:
761 NotifyAccepted(aChannel);
762 break;
763 default:
764 break;
767 bool addonAllowsLoad = false;
768 nsCOMPtr<nsIURI> channelURI;
769 NS_GetFinalChannelURI(aChannel, getter_AddRefs(channelURI));
770 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
771 addonAllowsLoad = BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
772 ->AddonAllowsLoad(channelURI);
774 bool isForeignAndNotAddon = false;
775 if (!addonAllowsLoad) {
776 mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI,
777 &isForeignAndNotAddon);
779 // include sub-document navigations from cross-site to same-site
780 // wrt top-level in our check for thirdparty-ness
781 if (StaticPrefs::network_cookie_sameSite_crossSiteIframeSetCheck() &&
782 !isForeignAndNotAddon &&
783 loadInfo->GetExternalContentPolicyType() ==
784 ExtContentPolicy::TYPE_SUBDOCUMENT) {
785 bool triggeringPrincipalIsThirdParty = false;
786 BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
787 ->IsThirdPartyURI(channelURI, &triggeringPrincipalIsThirdParty);
788 isForeignAndNotAddon |= triggeringPrincipalIsThirdParty;
792 bool mustBePartitioned =
793 isForeignAndNotAddon &&
794 cookieJarSettings->GetCookieBehavior() ==
795 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
796 !result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted);
798 nsCString cookieHeader(aCookieHeader);
800 // CHIPS - The partitioned cookie jar is always available and it is always
801 // possible to store cookies in it using the "Partitioned" attribute.
802 // Prepare the partitioned principals OAs to enable possible partitioned
803 // cookie storing from first-party or with StorageAccess.
804 // Similar behavior to CookieServiceChild::SetCookieStringFromHttp().
805 OriginAttributes partitionedPrincipalOriginAttributes;
806 bool isPartitionedPrincipal =
807 !storagePrincipalOriginAttributes.mPartitionKey.IsEmpty();
808 bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
809 cookieJarSettings->GetPartitionForeign();
810 // Only need to get OAs if we don't already use the partitioned principal.
811 if (isCHIPS && !isPartitionedPrincipal) {
812 StoragePrincipalHelper::GetOriginAttributes(
813 aChannel, partitionedPrincipalOriginAttributes,
814 StoragePrincipalHelper::ePartitionedPrincipal);
817 // process each cookie in the header
818 bool moreCookieToRead = true;
819 while (moreCookieToRead) {
820 CookieParser cookieParser(crc, aHostURI);
822 moreCookieToRead = cookieParser.Parse(
823 baseDomain, requireHostMatch, cookieStatus, cookieHeader, true,
824 isForeignAndNotAddon, mustBePartitioned,
825 storagePrincipalOriginAttributes.IsPrivateBrowsing());
827 if (!cookieParser.ContainsCookie()) {
828 continue;
831 // check permissions from site permission list.
832 if (!CookieCommons::CheckCookiePermission(aChannel,
833 cookieParser.CookieData())) {
834 COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
835 "cookie rejected by permission manager");
836 CookieCommons::NotifyRejected(
837 aHostURI, aChannel,
838 nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION,
839 OPERATION_WRITE);
840 cookieParser.RejectCookie(CookieParser::RejectedByPermissionManager);
841 continue;
844 // CHIPS - If the partitioned attribute is set, store cookie in partitioned
845 // cookie jar independent of context. If the cookies are stored in the
846 // partitioned cookie jar anyway no special treatment of CHIPS cookies
847 // necessary.
848 bool needPartitioned = isCHIPS &&
849 cookieParser.CookieData().isPartitioned() &&
850 !isPartitionedPrincipal;
851 OriginAttributes& cookieOriginAttributes =
852 needPartitioned ? partitionedPrincipalOriginAttributes
853 : storagePrincipalOriginAttributes;
854 // Assert that partitionedPrincipalOriginAttributes are initialized if used.
855 MOZ_ASSERT_IF(
856 needPartitioned,
857 !partitionedPrincipalOriginAttributes.mPartitionKey.IsEmpty());
859 // create a new Cookie
860 RefPtr<Cookie> cookie =
861 Cookie::Create(cookieParser.CookieData(), cookieOriginAttributes);
862 MOZ_ASSERT(cookie);
864 int64_t currentTimeInUsec = PR_Now();
865 cookie->SetLastAccessed(currentTimeInUsec);
866 cookie->SetCreationTime(
867 Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
869 // Use TargetBrowsingContext to also take frame loads into account.
870 RefPtr<BrowsingContext> bc = loadInfo->GetTargetBrowsingContext();
872 // add the cookie to the list. AddCookie() takes care of logging.
873 storage->AddCookie(&cookieParser, baseDomain, cookieOriginAttributes,
874 cookie, currentTimeInUsec, aHostURI, aCookieHeader, true,
875 isForeignAndNotAddon, bc);
878 return NS_OK;
881 void CookieService::NotifyAccepted(nsIChannel* aChannel) {
882 ContentBlockingNotifier::OnDecision(
883 aChannel, ContentBlockingNotifier::BlockingDecision::eAllow, 0);
886 /******************************************************************************
887 * CookieService:
888 * public transaction helper impl
889 ******************************************************************************/
891 NS_IMETHODIMP
892 CookieService::RunInTransaction(nsICookieTransactionCallback* aCallback) {
893 NS_ENSURE_ARG(aCallback);
895 if (!IsInitialized()) {
896 return NS_ERROR_NOT_AVAILABLE;
899 mPersistentStorage->EnsureInitialized();
900 return mPersistentStorage->RunInTransaction(aCallback);
903 /******************************************************************************
904 * nsICookieManager impl:
905 * nsICookieManager
906 ******************************************************************************/
908 NS_IMETHODIMP
909 CookieService::RemoveAll() {
910 if (!IsInitialized()) {
911 return NS_ERROR_NOT_AVAILABLE;
914 mPersistentStorage->EnsureInitialized();
915 mPersistentStorage->RemoveAll();
916 return NS_OK;
919 NS_IMETHODIMP
920 CookieService::GetCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
921 if (!IsInitialized()) {
922 return NS_ERROR_NOT_AVAILABLE;
925 mPersistentStorage->EnsureInitialized();
927 // We expose only non-private cookies.
928 mPersistentStorage->GetCookies(aCookies);
930 return NS_OK;
933 NS_IMETHODIMP
934 CookieService::GetSessionCookies(nsTArray<RefPtr<nsICookie>>& aCookies) {
935 if (!IsInitialized()) {
936 return NS_ERROR_NOT_AVAILABLE;
939 mPersistentStorage->EnsureInitialized();
941 // We expose only non-private cookies.
942 mPersistentStorage->GetSessionCookies(aCookies);
944 return NS_OK;
947 NS_IMETHODIMP
948 CookieService::Add(const nsACString& aHost, const nsACString& aPath,
949 const nsACString& aName, const nsACString& aValue,
950 bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
951 int64_t aExpiry, JS::Handle<JS::Value> aOriginAttributes,
952 int32_t aSameSite, nsICookie::schemeType aSchemeMap,
953 JSContext* aCx) {
954 OriginAttributes attrs;
956 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
957 return NS_ERROR_INVALID_ARG;
960 return AddNative(aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
961 aIsSession, aExpiry, &attrs, aSameSite, aSchemeMap);
964 NS_IMETHODIMP_(nsresult)
965 CookieService::AddNative(const nsACString& aHost, const nsACString& aPath,
966 const nsACString& aName, const nsACString& aValue,
967 bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
968 int64_t aExpiry, OriginAttributes* aOriginAttributes,
969 int32_t aSameSite, nsICookie::schemeType aSchemeMap) {
970 if (NS_WARN_IF(!aOriginAttributes)) {
971 return NS_ERROR_FAILURE;
974 if (!IsInitialized()) {
975 return NS_ERROR_NOT_AVAILABLE;
978 // first, normalize the hostname, and fail if it contains illegal characters.
979 nsAutoCString host(aHost);
980 nsresult rv = NormalizeHost(host);
981 NS_ENSURE_SUCCESS(rv, rv);
983 // get the base domain for the host URI.
984 // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
985 nsAutoCString baseDomain;
986 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
987 NS_ENSURE_SUCCESS(rv, rv);
989 int64_t currentTimeInUsec = PR_Now();
990 CookieKey key = CookieKey(baseDomain, *aOriginAttributes);
992 CookieStruct cookieData(nsCString(aName), nsCString(aValue), nsCString(aHost),
993 nsCString(aPath), aExpiry, currentTimeInUsec,
994 Cookie::GenerateUniqueCreationTime(currentTimeInUsec),
995 aIsHttpOnly, aIsSession, aIsSecure, false, aSameSite,
996 aSameSite, aSchemeMap);
998 RefPtr<Cookie> cookie = Cookie::Create(cookieData, key.mOriginAttributes);
999 MOZ_ASSERT(cookie);
1001 CookieStorage* storage = PickStorage(*aOriginAttributes);
1002 storage->AddCookie(nullptr, baseDomain, *aOriginAttributes, cookie,
1003 currentTimeInUsec, nullptr, VoidCString(), true,
1004 !aOriginAttributes->mPartitionKey.IsEmpty(), nullptr);
1005 return NS_OK;
1008 nsresult CookieService::Remove(const nsACString& aHost,
1009 const OriginAttributes& aAttrs,
1010 const nsACString& aName,
1011 const nsACString& aPath) {
1012 // first, normalize the hostname, and fail if it contains illegal characters.
1013 nsAutoCString host(aHost);
1014 nsresult rv = NormalizeHost(host);
1015 NS_ENSURE_SUCCESS(rv, rv);
1017 nsAutoCString baseDomain;
1018 if (!host.IsEmpty()) {
1019 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
1020 NS_ENSURE_SUCCESS(rv, rv);
1023 if (!IsInitialized()) {
1024 return NS_ERROR_NOT_AVAILABLE;
1027 CookieStorage* storage = PickStorage(aAttrs);
1028 storage->RemoveCookie(baseDomain, aAttrs, host, PromiseFlatCString(aName),
1029 PromiseFlatCString(aPath));
1031 return NS_OK;
1034 NS_IMETHODIMP
1035 CookieService::Remove(const nsACString& aHost, const nsACString& aName,
1036 const nsACString& aPath,
1037 JS::Handle<JS::Value> aOriginAttributes, JSContext* aCx) {
1038 OriginAttributes attrs;
1040 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
1041 return NS_ERROR_INVALID_ARG;
1044 return RemoveNative(aHost, aName, aPath, &attrs);
1047 NS_IMETHODIMP_(nsresult)
1048 CookieService::RemoveNative(const nsACString& aHost, const nsACString& aName,
1049 const nsACString& aPath,
1050 OriginAttributes* aOriginAttributes) {
1051 if (NS_WARN_IF(!aOriginAttributes)) {
1052 return NS_ERROR_FAILURE;
1055 nsresult rv = Remove(aHost, *aOriginAttributes, aName, aPath);
1056 if (NS_WARN_IF(NS_FAILED(rv))) {
1057 return rv;
1060 return NS_OK;
1063 void CookieService::GetCookiesForURI(
1064 nsIURI* aHostURI, nsIChannel* aChannel, bool aIsForeign,
1065 bool aIsThirdPartyTrackingResource,
1066 bool aIsThirdPartySocialTrackingResource,
1067 bool aStorageAccessPermissionGranted, uint32_t aRejectedReason,
1068 bool aIsSafeTopLevelNav, bool aIsSameSiteForeign,
1069 bool aHadCrossSiteRedirects, bool aHttpBound,
1070 bool aAllowSecureCookiesToInsecureOrigin,
1071 const nsTArray<OriginAttributes>& aOriginAttrsList,
1072 nsTArray<RefPtr<Cookie>>& aCookieList) {
1073 NS_ASSERTION(aHostURI, "null host!");
1075 if (!CookieCommons::IsSchemeSupported(aHostURI)) {
1076 return;
1079 if (!IsInitialized()) {
1080 return;
1083 nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
1084 CookieCommons::GetCookieJarSettings(aChannel);
1086 nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
1088 for (const auto& attrs : aOriginAttrsList) {
1089 CookieStorage* storage = PickStorage(attrs);
1091 // get the base domain, host, and path from the URI.
1092 // e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk".
1093 // file:// URI's (i.e. with an empty host) are allowed, but any other
1094 // scheme must have a non-empty host. A trailing dot in the host
1095 // is acceptable.
1096 bool requireHostMatch;
1097 nsAutoCString baseDomain;
1098 nsAutoCString hostFromURI;
1099 nsAutoCString pathFromURI;
1100 nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI,
1101 baseDomain, requireHostMatch);
1102 if (NS_SUCCEEDED(rv)) {
1103 rv = nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
1105 if (NS_SUCCEEDED(rv)) {
1106 rv = aHostURI->GetFilePath(pathFromURI);
1108 if (NS_FAILED(rv)) {
1109 COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, VoidCString(),
1110 "invalid host/path from URI");
1111 return;
1114 nsAutoCString normalizedHostFromURI(hostFromURI);
1115 rv = NormalizeHost(normalizedHostFromURI);
1116 NS_ENSURE_SUCCESS_VOID(rv);
1118 nsAutoCString baseDomainFromURI;
1119 rv = CookieCommons::GetBaseDomainFromHost(
1120 mTLDService, normalizedHostFromURI, baseDomainFromURI);
1121 NS_ENSURE_SUCCESS_VOID(rv);
1123 // check default prefs
1124 uint32_t rejectedReason = aRejectedReason;
1125 uint32_t priorCookieCount = storage->CountCookiesFromHost(
1126 baseDomainFromURI, attrs.mPrivateBrowsingId);
1128 CookieStatus cookieStatus = CheckPrefs(
1129 crc, cookieJarSettings, aHostURI, aIsForeign,
1130 aIsThirdPartyTrackingResource, aIsThirdPartySocialTrackingResource,
1131 aStorageAccessPermissionGranted, VoidCString(), priorCookieCount, attrs,
1132 &rejectedReason);
1134 MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
1136 // for GetCookie(), we only fire acceptance/rejection notifications
1137 // (but not if there was an error)
1138 switch (cookieStatus) {
1139 case STATUS_REJECTED:
1140 // If we don't have any cookies from this host, fail silently.
1141 if (priorCookieCount) {
1142 CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
1143 OPERATION_READ);
1145 return;
1146 default:
1147 break;
1150 // Note: The following permissions logic is mirrored in
1151 // extensions::MatchPattern::MatchesCookie.
1152 // If it changes, please update that function, or file a bug for someone
1153 // else to do so.
1155 // check if aHostURI is using an https secure protocol.
1156 // if it isn't, then we can't send a secure cookie over the connection.
1157 // if SchemeIs fails, assume an insecure connection, to be on the safe side
1158 bool potentiallyTrustworthy =
1159 nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
1161 int64_t currentTimeInUsec = PR_Now();
1162 int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
1163 bool stale = false;
1165 nsTArray<RefPtr<Cookie>> cookies;
1166 storage->GetCookiesFromHost(baseDomain, attrs, cookies);
1167 if (cookies.IsEmpty()) {
1168 continue;
1171 bool laxByDefault =
1172 StaticPrefs::network_cookie_sameSite_laxByDefault() &&
1173 !nsContentUtils::IsURIInPrefList(
1174 aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
1176 // iterate the cookies!
1177 for (Cookie* cookie : cookies) {
1178 // check the host, since the base domain lookup is conservative.
1179 if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
1180 continue;
1183 // if the cookie is secure and the host scheme isn't, we avoid sending
1184 // cookie if possible. But for process synchronization purposes, we may
1185 // want the content process to know about the cookie (without it's value).
1186 // In which case we will wipe the value before sending
1187 if (cookie->IsSecure() && !potentiallyTrustworthy &&
1188 !aAllowSecureCookiesToInsecureOrigin) {
1189 continue;
1192 // if the cookie is httpOnly and it's not going directly to the HTTP
1193 // connection, don't send it
1194 if (cookie->IsHttpOnly() && !aHttpBound) {
1195 continue;
1198 // if the nsIURI path doesn't match the cookie path, don't send it back
1199 if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
1200 continue;
1203 // check if the cookie has expired
1204 if (cookie->Expiry() <= currentTime) {
1205 continue;
1208 // Check if we need to block the cookie because of opt-in partitioning.
1209 // We will only allow partitioned cookies with "partitioned" attribution
1210 // if opt-in partitioning is enabled.
1211 if (aIsForeign && cookieJarSettings->GetPartitionForeign() &&
1212 (StaticPrefs::network_cookie_cookieBehavior_optInPartitioning() ||
1213 (attrs.IsPrivateBrowsing() &&
1214 StaticPrefs::
1215 network_cookie_cookieBehavior_optInPartitioning_pbmode())) &&
1216 !(cookie->IsPartitioned() && cookie->RawIsPartitioned()) &&
1217 !aStorageAccessPermissionGranted) {
1218 continue;
1221 if (aHttpBound && aIsSameSiteForeign) {
1222 bool blockCookie = !ProcessSameSiteCookieForForeignRequest(
1223 aChannel, cookie, aIsSafeTopLevelNav, aHadCrossSiteRedirects,
1224 laxByDefault);
1226 if (blockCookie) {
1227 if (aHadCrossSiteRedirects) {
1228 CookieLogging::LogMessageToConsole(
1229 crc, aHostURI, nsIScriptError::warningFlag,
1230 CONSOLE_REJECTION_CATEGORY, "CookieBlockedCrossSiteRedirect"_ns,
1231 AutoTArray<nsString, 1>{
1232 NS_ConvertUTF8toUTF16(cookie->Name()),
1235 continue;
1239 // all checks passed - add to list and check if lastAccessed stamp needs
1240 // updating
1241 aCookieList.AppendElement(cookie);
1242 if (cookie->IsStale()) {
1243 stale = true;
1247 if (aCookieList.IsEmpty()) {
1248 continue;
1251 // update lastAccessed timestamps. we only do this if the timestamp is stale
1252 // by a certain amount, to avoid thrashing the db during pageload.
1253 if (stale) {
1254 storage->StaleCookies(aCookieList, currentTimeInUsec);
1258 if (aCookieList.IsEmpty()) {
1259 return;
1262 // Send a notification about the acceptance of the cookies now that we found
1263 // some.
1264 NotifyAccepted(aChannel);
1266 // return cookies in order of path length; longest to shortest.
1267 // this is required per RFC2109. if cookies match in length,
1268 // then sort by creation time (see bug 236772).
1269 aCookieList.Sort(CompareCookiesForSending());
1272 /******************************************************************************
1273 * CookieService impl:
1274 * private domain & permission compliance enforcement functions
1275 ******************************************************************************/
1277 nsresult CookieService::NormalizeHost(nsCString& aHost) {
1278 nsAutoCString host;
1279 nsresult rv = NS_DomainToASCIIAllowAnyGlyphfulASCII(aHost, host);
1280 if (NS_FAILED(rv)) {
1281 return rv;
1284 aHost = host;
1285 return NS_OK;
1288 CookieStatus CookieService::CheckPrefs(
1289 nsIConsoleReportCollector* aCRC, nsICookieJarSettings* aCookieJarSettings,
1290 nsIURI* aHostURI, bool aIsForeign, bool aIsThirdPartyTrackingResource,
1291 bool aIsThirdPartySocialTrackingResource,
1292 bool aStorageAccessPermissionGranted, const nsACString& aCookieHeader,
1293 const int aNumOfCookies, const OriginAttributes& aOriginAttrs,
1294 uint32_t* aRejectedReason) {
1295 nsresult rv;
1297 MOZ_ASSERT(aRejectedReason);
1299 *aRejectedReason = 0;
1301 // don't let unsupported scheme sites get/set cookies (could be a security
1302 // issue)
1303 if (!CookieCommons::IsSchemeSupported(aHostURI)) {
1304 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1305 "non http/https sites cannot read cookies");
1306 return STATUS_REJECTED_WITH_ERROR;
1309 nsCOMPtr<nsIPrincipal> principal =
1310 BasePrincipal::CreateContentPrincipal(aHostURI, aOriginAttrs);
1312 if (!principal) {
1313 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1314 "non-content principals cannot get/set cookies");
1315 return STATUS_REJECTED_WITH_ERROR;
1318 // check the permission list first; if we find an entry, it overrides
1319 // default prefs. see bug 184059.
1320 uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
1321 rv = aCookieJarSettings->CookiePermission(principal, &cookiePermission);
1322 if (NS_SUCCEEDED(rv)) {
1323 switch (cookiePermission) {
1324 case nsICookiePermission::ACCESS_DENY:
1325 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1326 "cookies are blocked for this site");
1327 CookieLogging::LogMessageToConsole(
1328 aCRC, aHostURI, nsIScriptError::warningFlag,
1329 CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns,
1330 AutoTArray<nsString, 1>{
1331 NS_ConvertUTF8toUTF16(aCookieHeader),
1334 *aRejectedReason =
1335 nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION;
1336 return STATUS_REJECTED;
1338 case nsICookiePermission::ACCESS_ALLOW:
1339 return STATUS_ACCEPTED;
1340 default:
1341 break;
1345 // No cookies allowed if this request comes from a resource in a 3rd party
1346 // context, when anti-tracking protection is enabled and when we don't have
1347 // access to the first-party cookie jar.
1348 if (aIsForeign && aIsThirdPartyTrackingResource &&
1349 !aStorageAccessPermissionGranted &&
1350 aCookieJarSettings->GetRejectThirdPartyContexts()) {
1351 uint32_t rejectReason =
1352 nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
1353 if (StoragePartitioningEnabled(rejectReason, aCookieJarSettings)) {
1354 MOZ_ASSERT(!aOriginAttrs.mPartitionKey.IsEmpty(),
1355 "We must have a StoragePrincipal here!");
1356 return STATUS_ACCEPTED;
1359 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1360 "cookies are disabled in trackers");
1361 if (aIsThirdPartySocialTrackingResource) {
1362 *aRejectedReason =
1363 nsIWebProgressListener::STATE_COOKIES_BLOCKED_SOCIALTRACKER;
1364 } else {
1365 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER;
1367 return STATUS_REJECTED;
1370 // check default prefs.
1371 // Check aStorageAccessPermissionGranted when checking aCookieBehavior
1372 // so that we take things such as the content blocking allow list into
1373 // account.
1374 if (aCookieJarSettings->GetCookieBehavior() ==
1375 nsICookieService::BEHAVIOR_REJECT &&
1376 !aStorageAccessPermissionGranted) {
1377 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1378 "cookies are disabled");
1379 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL;
1380 return STATUS_REJECTED;
1383 // check if cookie is foreign
1384 if (aIsForeign) {
1385 if (aCookieJarSettings->GetCookieBehavior() ==
1386 nsICookieService::BEHAVIOR_REJECT_FOREIGN &&
1387 !aStorageAccessPermissionGranted) {
1388 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1389 "context is third party");
1390 CookieLogging::LogMessageToConsole(
1391 aCRC, aHostURI, nsIScriptError::warningFlag,
1392 CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns,
1393 AutoTArray<nsString, 1>{
1394 NS_ConvertUTF8toUTF16(aCookieHeader),
1396 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
1397 return STATUS_REJECTED;
1400 if (aCookieJarSettings->GetLimitForeignContexts() &&
1401 !aStorageAccessPermissionGranted && aNumOfCookies == 0) {
1402 COOKIE_LOGFAILURE(!aCookieHeader.IsVoid(), aHostURI, aCookieHeader,
1403 "context is third party");
1404 CookieLogging::LogMessageToConsole(
1405 aCRC, aHostURI, nsIScriptError::warningFlag,
1406 CONSOLE_REJECTION_CATEGORY, "CookieRejectedThirdParty"_ns,
1407 AutoTArray<nsString, 1>{
1408 NS_ConvertUTF8toUTF16(aCookieHeader),
1410 *aRejectedReason = nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
1411 return STATUS_REJECTED;
1415 // if nothing has complained, accept cookie
1416 return STATUS_ACCEPTED;
1419 /******************************************************************************
1420 * CookieService impl:
1421 * private cookielist management functions
1422 ******************************************************************************/
1424 // find whether a given cookie has been previously set. this is provided by the
1425 // nsICookieManager interface.
1426 NS_IMETHODIMP
1427 CookieService::CookieExists(const nsACString& aHost, const nsACString& aPath,
1428 const nsACString& aName,
1429 JS::Handle<JS::Value> aOriginAttributes,
1430 JSContext* aCx, bool* aFoundCookie) {
1431 NS_ENSURE_ARG_POINTER(aCx);
1432 NS_ENSURE_ARG_POINTER(aFoundCookie);
1434 OriginAttributes attrs;
1435 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
1436 return NS_ERROR_INVALID_ARG;
1438 return CookieExistsNative(aHost, aPath, aName, &attrs, aFoundCookie);
1441 NS_IMETHODIMP_(nsresult)
1442 CookieService::CookieExistsNative(const nsACString& aHost,
1443 const nsACString& aPath,
1444 const nsACString& aName,
1445 OriginAttributes* aOriginAttributes,
1446 bool* aFoundCookie) {
1447 nsCOMPtr<nsICookie> cookie;
1448 nsresult rv = GetCookieNative(aHost, aPath, aName, aOriginAttributes,
1449 getter_AddRefs(cookie));
1450 NS_ENSURE_SUCCESS(rv, rv);
1452 *aFoundCookie = cookie != nullptr;
1454 return NS_OK;
1457 NS_IMETHODIMP_(nsresult)
1458 CookieService::GetCookieNative(const nsACString& aHost, const nsACString& aPath,
1459 const nsACString& aName,
1460 OriginAttributes* aOriginAttributes,
1461 nsICookie** aCookie) {
1462 NS_ENSURE_ARG_POINTER(aOriginAttributes);
1463 NS_ENSURE_ARG_POINTER(aCookie);
1465 if (!IsInitialized()) {
1466 return NS_ERROR_NOT_AVAILABLE;
1469 nsAutoCString baseDomain;
1470 nsresult rv =
1471 CookieCommons::GetBaseDomainFromHost(mTLDService, aHost, baseDomain);
1472 NS_ENSURE_SUCCESS(rv, rv);
1474 CookieListIter iter{};
1475 CookieStorage* storage = PickStorage(*aOriginAttributes);
1476 bool foundCookie = storage->FindCookie(baseDomain, *aOriginAttributes, aHost,
1477 aName, aPath, iter);
1479 if (foundCookie) {
1480 RefPtr<Cookie> cookie = iter.Cookie();
1481 NS_ENSURE_TRUE(cookie, NS_ERROR_NULL_POINTER);
1483 cookie.forget(aCookie);
1486 return NS_OK;
1489 // count the number of cookies stored by a particular host. this is provided by
1490 // the nsICookieManager interface.
1491 NS_IMETHODIMP
1492 CookieService::CountCookiesFromHost(const nsACString& aHost,
1493 uint32_t* aCountFromHost) {
1494 // first, normalize the hostname, and fail if it contains illegal characters.
1495 nsAutoCString host(aHost);
1496 nsresult rv = NormalizeHost(host);
1497 NS_ENSURE_SUCCESS(rv, rv);
1499 nsAutoCString baseDomain;
1500 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
1501 NS_ENSURE_SUCCESS(rv, rv);
1503 if (!IsInitialized()) {
1504 return NS_ERROR_NOT_AVAILABLE;
1507 mPersistentStorage->EnsureInitialized();
1509 *aCountFromHost = mPersistentStorage->CountCookiesFromHost(baseDomain, 0);
1511 return NS_OK;
1514 // get an enumerator of cookies stored by a particular host. this is provided by
1515 // the nsICookieManager interface.
1516 NS_IMETHODIMP
1517 CookieService::GetCookiesFromHost(const nsACString& aHost,
1518 JS::Handle<JS::Value> aOriginAttributes,
1519 JSContext* aCx,
1520 nsTArray<RefPtr<nsICookie>>& aResult) {
1521 // first, normalize the hostname, and fail if it contains illegal characters.
1522 nsAutoCString host(aHost);
1523 nsresult rv = NormalizeHost(host);
1524 NS_ENSURE_SUCCESS(rv, rv);
1526 nsAutoCString baseDomain;
1527 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
1528 NS_ENSURE_SUCCESS(rv, rv);
1530 OriginAttributes attrs;
1531 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
1532 return NS_ERROR_INVALID_ARG;
1535 if (!IsInitialized()) {
1536 return NS_ERROR_NOT_AVAILABLE;
1539 CookieStorage* storage = PickStorage(attrs);
1541 nsTArray<RefPtr<Cookie>> cookies;
1542 storage->GetCookiesFromHost(baseDomain, attrs, cookies);
1544 if (cookies.IsEmpty()) {
1545 return NS_OK;
1548 aResult.SetCapacity(cookies.Length());
1549 for (Cookie* cookie : cookies) {
1550 aResult.AppendElement(cookie);
1553 return NS_OK;
1556 NS_IMETHODIMP
1557 CookieService::GetCookiesWithOriginAttributes(
1558 const nsAString& aPattern, const nsACString& aHost,
1559 nsTArray<RefPtr<nsICookie>>& aResult) {
1560 OriginAttributesPattern pattern;
1561 if (!pattern.Init(aPattern)) {
1562 return NS_ERROR_INVALID_ARG;
1565 nsAutoCString host(aHost);
1566 nsresult rv = NormalizeHost(host);
1567 NS_ENSURE_SUCCESS(rv, rv);
1569 nsAutoCString baseDomain;
1570 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
1571 NS_ENSURE_SUCCESS(rv, rv);
1573 return GetCookiesWithOriginAttributes(pattern, baseDomain, aResult);
1576 nsresult CookieService::GetCookiesWithOriginAttributes(
1577 const OriginAttributesPattern& aPattern, const nsCString& aBaseDomain,
1578 nsTArray<RefPtr<nsICookie>>& aResult) {
1579 CookieStorage* storage = PickStorage(aPattern);
1580 storage->GetCookiesWithOriginAttributes(aPattern, aBaseDomain, aResult);
1582 return NS_OK;
1585 NS_IMETHODIMP
1586 CookieService::RemoveCookiesWithOriginAttributes(const nsAString& aPattern,
1587 const nsACString& aHost) {
1588 MOZ_ASSERT(XRE_IsParentProcess());
1590 OriginAttributesPattern pattern;
1591 if (!pattern.Init(aPattern)) {
1592 return NS_ERROR_INVALID_ARG;
1595 nsAutoCString host(aHost);
1596 nsresult rv = NormalizeHost(host);
1597 NS_ENSURE_SUCCESS(rv, rv);
1599 nsAutoCString baseDomain;
1600 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
1601 NS_ENSURE_SUCCESS(rv, rv);
1603 return RemoveCookiesWithOriginAttributes(pattern, baseDomain);
1606 nsresult CookieService::RemoveCookiesWithOriginAttributes(
1607 const OriginAttributesPattern& aPattern, const nsCString& aBaseDomain) {
1608 if (!IsInitialized()) {
1609 return NS_ERROR_NOT_AVAILABLE;
1612 CookieStorage* storage = PickStorage(aPattern);
1613 storage->RemoveCookiesWithOriginAttributes(aPattern, aBaseDomain);
1615 return NS_OK;
1618 NS_IMETHODIMP
1619 CookieService::RemoveCookiesFromExactHost(const nsACString& aHost,
1620 const nsAString& aPattern) {
1621 MOZ_ASSERT(XRE_IsParentProcess());
1623 OriginAttributesPattern pattern;
1624 if (!pattern.Init(aPattern)) {
1625 return NS_ERROR_INVALID_ARG;
1628 return RemoveCookiesFromExactHost(aHost, pattern);
1631 nsresult CookieService::RemoveCookiesFromExactHost(
1632 const nsACString& aHost, const OriginAttributesPattern& aPattern) {
1633 nsAutoCString host(aHost);
1634 nsresult rv = NormalizeHost(host);
1635 NS_ENSURE_SUCCESS(rv, rv);
1637 nsAutoCString baseDomain;
1638 rv = CookieCommons::GetBaseDomainFromHost(mTLDService, host, baseDomain);
1639 NS_ENSURE_SUCCESS(rv, rv);
1641 if (!IsInitialized()) {
1642 return NS_ERROR_NOT_AVAILABLE;
1645 CookieStorage* storage = PickStorage(aPattern);
1646 storage->RemoveCookiesFromExactHost(aHost, baseDomain, aPattern);
1648 return NS_OK;
1651 namespace {
1653 class RemoveAllSinceRunnable : public Runnable {
1654 public:
1655 using CookieArray = nsTArray<RefPtr<nsICookie>>;
1656 RemoveAllSinceRunnable(Promise* aPromise, CookieService* aSelf,
1657 CookieArray&& aCookieArray, int64_t aSinceWhen)
1658 : Runnable("RemoveAllSinceRunnable"),
1659 mPromise(aPromise),
1660 mSelf(aSelf),
1661 mList(std::move(aCookieArray)),
1662 mIndex(0),
1663 mSinceWhen(aSinceWhen) {}
1665 NS_IMETHODIMP Run() override {
1666 RemoveSome();
1668 if (mIndex < mList.Length()) {
1669 return NS_DispatchToCurrentThread(this);
1671 mPromise->MaybeResolveWithUndefined();
1673 return NS_OK;
1676 private:
1677 void RemoveSome() {
1678 for (CookieArray::size_type iter = 0;
1679 iter < kYieldPeriod && mIndex < mList.Length(); ++mIndex, ++iter) {
1680 auto* cookie = static_cast<Cookie*>(mList[mIndex].get());
1681 if (cookie->CreationTime() > mSinceWhen &&
1682 NS_FAILED(mSelf->Remove(cookie->Host(), cookie->OriginAttributesRef(),
1683 cookie->Name(), cookie->Path()))) {
1684 continue;
1689 private:
1690 RefPtr<Promise> mPromise;
1691 RefPtr<CookieService> mSelf;
1692 CookieArray mList;
1693 CookieArray::size_type mIndex;
1694 int64_t mSinceWhen;
1695 static const CookieArray::size_type kYieldPeriod = 10;
1698 } // namespace
1700 NS_IMETHODIMP
1701 CookieService::RemoveAllSince(int64_t aSinceWhen, JSContext* aCx,
1702 Promise** aRetVal) {
1703 nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
1704 if (NS_WARN_IF(!globalObject)) {
1705 return NS_ERROR_UNEXPECTED;
1708 ErrorResult result;
1709 RefPtr<Promise> promise = Promise::Create(globalObject, result);
1710 if (NS_WARN_IF(result.Failed())) {
1711 return result.StealNSResult();
1714 mPersistentStorage->EnsureInitialized();
1716 nsTArray<RefPtr<nsICookie>> cookieList;
1718 // We delete only non-private cookies.
1719 mPersistentStorage->GetAll(cookieList);
1721 RefPtr<RemoveAllSinceRunnable> runMe = new RemoveAllSinceRunnable(
1722 promise, this, std::move(cookieList), aSinceWhen);
1724 promise.forget(aRetVal);
1726 return runMe->Run();
1729 namespace {
1731 class CompareCookiesCreationTime {
1732 public:
1733 static bool Equals(const nsICookie* aCookie1, const nsICookie* aCookie2) {
1734 return static_cast<const Cookie*>(aCookie1)->CreationTime() ==
1735 static_cast<const Cookie*>(aCookie2)->CreationTime();
1738 static bool LessThan(const nsICookie* aCookie1, const nsICookie* aCookie2) {
1739 return static_cast<const Cookie*>(aCookie1)->CreationTime() <
1740 static_cast<const Cookie*>(aCookie2)->CreationTime();
1744 } // namespace
1746 NS_IMETHODIMP
1747 CookieService::GetCookiesSince(int64_t aSinceWhen,
1748 nsTArray<RefPtr<nsICookie>>& aResult) {
1749 if (!IsInitialized()) {
1750 return NS_OK;
1753 mPersistentStorage->EnsureInitialized();
1755 // We expose only non-private cookies.
1756 nsTArray<RefPtr<nsICookie>> cookieList;
1757 mPersistentStorage->GetAll(cookieList);
1759 for (RefPtr<nsICookie>& cookie : cookieList) {
1760 if (static_cast<Cookie*>(cookie.get())->CreationTime() >= aSinceWhen) {
1761 aResult.AppendElement(cookie);
1765 aResult.Sort(CompareCookiesCreationTime());
1766 return NS_OK;
1769 size_t CookieService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
1770 size_t n = aMallocSizeOf(this);
1772 if (mPersistentStorage) {
1773 n += mPersistentStorage->SizeOfIncludingThis(aMallocSizeOf);
1775 if (mPrivateStorage) {
1776 n += mPrivateStorage->SizeOfIncludingThis(aMallocSizeOf);
1779 return n;
1782 MOZ_DEFINE_MALLOC_SIZE_OF(CookieServiceMallocSizeOf)
1784 NS_IMETHODIMP
1785 CookieService::CollectReports(nsIHandleReportCallback* aHandleReport,
1786 nsISupports* aData, bool /*aAnonymize*/) {
1787 MOZ_COLLECT_REPORT("explicit/cookie-service", KIND_HEAP, UNITS_BYTES,
1788 SizeOfIncludingThis(CookieServiceMallocSizeOf),
1789 "Memory used by the cookie service.");
1791 return NS_OK;
1794 bool CookieService::IsInitialized() const {
1795 if (!mPersistentStorage) {
1796 NS_WARNING("No CookieStorage! Profile already close?");
1797 return false;
1800 MOZ_ASSERT(mPrivateStorage);
1801 return true;
1804 CookieStorage* CookieService::PickStorage(const OriginAttributes& aAttrs) {
1805 MOZ_ASSERT(IsInitialized());
1807 if (aAttrs.IsPrivateBrowsing()) {
1808 return mPrivateStorage;
1811 mPersistentStorage->EnsureInitialized();
1812 return mPersistentStorage;
1815 CookieStorage* CookieService::PickStorage(
1816 const OriginAttributesPattern& aAttrs) {
1817 MOZ_ASSERT(IsInitialized());
1819 if (aAttrs.mPrivateBrowsingId.WasPassed() &&
1820 aAttrs.mPrivateBrowsingId.Value() > 0) {
1821 return mPrivateStorage;
1824 mPersistentStorage->EnsureInitialized();
1825 return mPersistentStorage;
1828 bool CookieService::SetCookiesFromIPC(const nsACString& aBaseDomain,
1829 const OriginAttributes& aAttrs,
1830 nsIURI* aHostURI, bool aFromHttp,
1831 bool aIsThirdParty,
1832 const nsTArray<CookieStruct>& aCookies,
1833 BrowsingContext* aBrowsingContext) {
1834 if (!IsInitialized()) {
1835 // If we are probably shutting down, we can ignore this cookie.
1836 return true;
1839 CookieStorage* storage = PickStorage(aAttrs);
1840 int64_t currentTimeInUsec = PR_Now();
1842 for (const CookieStruct& cookieData : aCookies) {
1843 if (!CookieCommons::CheckPathSize(cookieData)) {
1844 return false;
1847 // reject cookie if it's over the size limit, per RFC2109
1848 if (!CookieCommons::CheckNameAndValueSize(cookieData)) {
1849 return false;
1852 CookieCommons::RecordUnicodeTelemetry(cookieData);
1854 if (!CookieCommons::CheckName(cookieData)) {
1855 return false;
1858 if (!CookieCommons::CheckValue(cookieData)) {
1859 return false;
1862 // create a new Cookie and copy attributes
1863 RefPtr<Cookie> cookie = Cookie::Create(cookieData, aAttrs);
1864 if (!cookie) {
1865 continue;
1868 cookie->SetLastAccessed(currentTimeInUsec);
1869 cookie->SetCreationTime(
1870 Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
1872 storage->AddCookie(nullptr, aBaseDomain, aAttrs, cookie, currentTimeInUsec,
1873 aHostURI, ""_ns, aFromHttp, aIsThirdParty,
1874 aBrowsingContext);
1877 return true;
1880 } // namespace net
1881 } // namespace mozilla