Bug 1869043 assert that graph set access is main thread only r=padenot
[gecko.git] / netwerk / cookie / CookieJarSettings.cpp
blob09a4789d85986a943e2e713d394b8f350f9ef18b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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 "mozilla/AntiTrackingUtils.h"
8 #include "mozilla/BasePrincipal.h"
9 #include "mozilla/ClearOnShutdown.h"
10 #include "mozilla/ContentBlockingAllowList.h"
11 #include "mozilla/dom/BrowsingContext.h"
12 #include "mozilla/net/CookieJarSettings.h"
13 #include "mozilla/net/NeckoChannelParams.h"
14 #include "mozilla/Permission.h"
15 #include "mozilla/PermissionManager.h"
16 #include "mozilla/SchedulerGroup.h"
17 #include "mozilla/StaticPrefs_network.h"
18 #include "mozilla/Unused.h"
19 #include "nsIPrincipal.h"
20 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
21 # include "nsIProtocolHandler.h"
22 #endif
23 #include "nsIClassInfoImpl.h"
24 #include "nsIChannel.h"
25 #include "nsICookieManager.h"
26 #include "nsICookieService.h"
27 #include "nsIObjectInputStream.h"
28 #include "nsIObjectOutputStream.h"
29 #include "nsNetUtil.h"
31 namespace mozilla {
32 namespace net {
34 NS_IMPL_CLASSINFO(CookieJarSettings, nullptr, nsIClassInfo::THREADSAFE,
35 COOKIEJARSETTINGS_CID)
37 NS_IMPL_ISUPPORTS_CI(CookieJarSettings, nsICookieJarSettings, nsISerializable)
39 static StaticRefPtr<CookieJarSettings> sBlockinAll;
41 namespace {
43 class PermissionComparator {
44 public:
45 static bool Equals(nsIPermission* aA, nsIPermission* aB) {
46 nsCOMPtr<nsIPrincipal> principalA;
47 nsresult rv = aA->GetPrincipal(getter_AddRefs(principalA));
48 if (NS_WARN_IF(NS_FAILED(rv))) {
49 return false;
52 nsCOMPtr<nsIPrincipal> principalB;
53 rv = aB->GetPrincipal(getter_AddRefs(principalB));
54 if (NS_WARN_IF(NS_FAILED(rv))) {
55 return false;
58 bool equals = false;
59 rv = principalA->Equals(principalB, &equals);
60 if (NS_WARN_IF(NS_FAILED(rv))) {
61 return false;
64 return equals;
68 class ReleaseCookiePermissions final : public Runnable {
69 public:
70 explicit ReleaseCookiePermissions(nsTArray<RefPtr<nsIPermission>>&& aArray)
71 : Runnable("ReleaseCookiePermissions"), mArray(std::move(aArray)) {}
73 NS_IMETHOD Run() override {
74 MOZ_ASSERT(NS_IsMainThread());
75 mArray.Clear();
76 return NS_OK;
79 private:
80 nsTArray<RefPtr<nsIPermission>> mArray;
83 } // namespace
85 // static
86 already_AddRefed<nsICookieJarSettings> CookieJarSettings::GetBlockingAll(
87 bool aShouldResistFingerprinting) {
88 MOZ_ASSERT(NS_IsMainThread());
90 if (sBlockinAll) {
91 return do_AddRef(sBlockinAll);
94 sBlockinAll = new CookieJarSettings(nsICookieService::BEHAVIOR_REJECT,
95 OriginAttributes::IsFirstPartyEnabled(),
96 aShouldResistFingerprinting, eFixed);
97 ClearOnShutdown(&sBlockinAll);
99 return do_AddRef(sBlockinAll);
102 // static
103 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
104 CreateMode aMode, bool aShouldResistFingerprinting) {
105 MOZ_ASSERT(NS_IsMainThread());
107 RefPtr<CookieJarSettings> cookieJarSettings;
109 switch (aMode) {
110 case eRegular:
111 case ePrivate:
112 cookieJarSettings = new CookieJarSettings(
113 nsICookieManager::GetCookieBehavior(aMode == ePrivate),
114 OriginAttributes::IsFirstPartyEnabled(), aShouldResistFingerprinting,
115 eProgressive);
116 break;
118 default:
119 MOZ_CRASH("Unexpected create mode.");
122 return cookieJarSettings.forget();
125 // static
126 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
127 nsIPrincipal* aPrincipal) {
128 MOZ_ASSERT(NS_IsMainThread());
130 bool shouldResistFingerprinting =
131 nsContentUtils::ShouldResistFingerprinting_dangerous(
132 aPrincipal, "We are constructing CookieJarSettings here.",
133 RFPTarget::IsAlwaysEnabledForPrecompute);
135 if (aPrincipal && aPrincipal->OriginAttributesRef().mPrivateBrowsingId > 0) {
136 return Create(ePrivate, shouldResistFingerprinting);
139 return Create(eRegular, shouldResistFingerprinting);
142 // static
143 already_AddRefed<nsICookieJarSettings> CookieJarSettings::Create(
144 uint32_t aCookieBehavior, const nsAString& aPartitionKey,
145 bool aIsFirstPartyIsolated, bool aIsOnContentBlockingAllowList,
146 bool aShouldResistFingerprinting) {
147 MOZ_ASSERT(NS_IsMainThread());
149 RefPtr<CookieJarSettings> cookieJarSettings =
150 new CookieJarSettings(aCookieBehavior, aIsFirstPartyIsolated,
151 aShouldResistFingerprinting, eProgressive);
152 cookieJarSettings->mPartitionKey = aPartitionKey;
153 cookieJarSettings->mIsOnContentBlockingAllowList =
154 aIsOnContentBlockingAllowList;
156 return cookieJarSettings.forget();
159 // static
160 already_AddRefed<nsICookieJarSettings> CookieJarSettings::CreateForXPCOM() {
161 MOZ_ASSERT(NS_IsMainThread());
162 return Create(eRegular, /* shouldResistFingerprinting */ false);
165 CookieJarSettings::CookieJarSettings(uint32_t aCookieBehavior,
166 bool aIsFirstPartyIsolated,
167 bool aShouldResistFingerprinting,
168 State aState)
169 : mCookieBehavior(aCookieBehavior),
170 mIsFirstPartyIsolated(aIsFirstPartyIsolated),
171 mIsOnContentBlockingAllowList(false),
172 mIsOnContentBlockingAllowListUpdated(false),
173 mState(aState),
174 mToBeMerged(false),
175 mShouldResistFingerprinting(aShouldResistFingerprinting) {
176 MOZ_ASSERT(NS_IsMainThread());
177 MOZ_ASSERT_IF(
178 mIsFirstPartyIsolated,
179 mCookieBehavior !=
180 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
183 CookieJarSettings::~CookieJarSettings() {
184 if (!NS_IsMainThread() && !mCookiePermissions.IsEmpty()) {
185 RefPtr<Runnable> r =
186 new ReleaseCookiePermissions(std::move(mCookiePermissions));
187 MOZ_ASSERT(mCookiePermissions.IsEmpty());
188 SchedulerGroup::Dispatch(r.forget());
192 NS_IMETHODIMP
193 CookieJarSettings::InitWithURI(nsIURI* aURI, bool aIsPrivate) {
194 NS_ENSURE_ARG(aURI);
196 mCookieBehavior = nsICookieManager::GetCookieBehavior(aIsPrivate);
198 SetPartitionKey(aURI);
199 return NS_OK;
202 NS_IMETHODIMP
203 CookieJarSettings::GetCookieBehavior(uint32_t* aCookieBehavior) {
204 *aCookieBehavior = mCookieBehavior;
205 return NS_OK;
208 NS_IMETHODIMP
209 CookieJarSettings::GetIsFirstPartyIsolated(bool* aIsFirstPartyIsolated) {
210 *aIsFirstPartyIsolated = mIsFirstPartyIsolated;
211 return NS_OK;
214 NS_IMETHODIMP
215 CookieJarSettings::GetShouldResistFingerprinting(
216 bool* aShouldResistFingerprinting) {
217 *aShouldResistFingerprinting = mShouldResistFingerprinting;
218 return NS_OK;
221 NS_IMETHODIMP
222 CookieJarSettings::GetRejectThirdPartyContexts(
223 bool* aRejectThirdPartyContexts) {
224 *aRejectThirdPartyContexts =
225 CookieJarSettings::IsRejectThirdPartyContexts(mCookieBehavior);
226 return NS_OK;
229 NS_IMETHODIMP
230 CookieJarSettings::GetLimitForeignContexts(bool* aLimitForeignContexts) {
231 *aLimitForeignContexts =
232 mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
233 (StaticPrefs::privacy_dynamic_firstparty_limitForeign() &&
234 mCookieBehavior ==
235 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
236 return NS_OK;
239 NS_IMETHODIMP
240 CookieJarSettings::GetBlockingAllThirdPartyContexts(
241 bool* aBlockingAllThirdPartyContexts) {
242 // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
243 // simply rejecting the request to use the storage. In the future, if we
244 // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
245 // for non-cookie storage types, this may change.
246 *aBlockingAllThirdPartyContexts =
247 mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
248 mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN;
249 return NS_OK;
252 NS_IMETHODIMP
253 CookieJarSettings::GetBlockingAllContexts(bool* aBlockingAllContexts) {
254 *aBlockingAllContexts = mCookieBehavior == nsICookieService::BEHAVIOR_REJECT;
255 return NS_OK;
258 NS_IMETHODIMP
259 CookieJarSettings::GetPartitionForeign(bool* aPartitionForeign) {
260 *aPartitionForeign =
261 mCookieBehavior ==
262 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
263 return NS_OK;
266 NS_IMETHODIMP
267 CookieJarSettings::SetPartitionForeign(bool aPartitionForeign) {
268 if (mIsFirstPartyIsolated) {
269 return NS_OK;
272 if (aPartitionForeign) {
273 mCookieBehavior =
274 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
276 return NS_OK;
279 NS_IMETHODIMP
280 CookieJarSettings::GetIsOnContentBlockingAllowList(
281 bool* aIsOnContentBlockingAllowList) {
282 *aIsOnContentBlockingAllowList = mIsOnContentBlockingAllowList;
283 return NS_OK;
286 NS_IMETHODIMP
287 CookieJarSettings::GetPartitionKey(nsAString& aPartitionKey) {
288 aPartitionKey = mPartitionKey;
289 return NS_OK;
292 NS_IMETHODIMP
293 CookieJarSettings::GetFingerprintingRandomizationKey(
294 nsTArray<uint8_t>& aFingerprintingRandomizationKey) {
295 if (!mFingerprintingRandomKey) {
296 return NS_ERROR_NOT_AVAILABLE;
299 aFingerprintingRandomizationKey = mFingerprintingRandomKey->Clone();
300 return NS_OK;
303 NS_IMETHODIMP
304 CookieJarSettings::CookiePermission(nsIPrincipal* aPrincipal,
305 uint32_t* aCookiePermission) {
306 MOZ_RELEASE_ASSERT(NS_IsMainThread());
307 NS_ENSURE_ARG_POINTER(aPrincipal);
308 NS_ENSURE_ARG_POINTER(aCookiePermission);
310 *aCookiePermission = nsIPermissionManager::UNKNOWN_ACTION;
312 nsresult rv;
314 // Let's see if we know this permission.
315 if (!mCookiePermissions.IsEmpty()) {
316 for (const RefPtr<nsIPermission>& permission : mCookiePermissions) {
317 bool match = false;
318 rv = permission->Matches(aPrincipal, false, &match);
319 if (NS_WARN_IF(NS_FAILED(rv)) || !match) {
320 continue;
323 rv = permission->GetCapability(aCookiePermission);
324 if (NS_WARN_IF(NS_FAILED(rv))) {
325 return rv;
328 return NS_OK;
332 // Let's ask the permission manager.
333 PermissionManager* pm = PermissionManager::GetInstance();
334 if (NS_WARN_IF(!pm)) {
335 return NS_ERROR_FAILURE;
338 #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
339 // Check if this protocol doesn't allow cookies.
340 bool hasFlags;
341 nsCOMPtr<nsIURI> uri;
342 BasePrincipal::Cast(aPrincipal)->GetURI(getter_AddRefs(uri));
344 rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS,
345 &hasFlags);
346 if (NS_FAILED(rv) || hasFlags) {
347 *aCookiePermission = PermissionManager::DENY_ACTION;
348 rv = NS_OK; // Reset, so it's not caught as a bad status after the `else`.
349 } else // Note the tricky `else` which controls the call below.
350 #endif
352 rv = pm->TestPermissionFromPrincipal(aPrincipal, "cookie"_ns,
353 aCookiePermission);
354 if (NS_WARN_IF(NS_FAILED(rv))) {
355 return rv;
358 // Let's store the permission, also if the result is UNKNOWN in order to avoid
359 // race conditions.
361 nsCOMPtr<nsIPermission> permission =
362 Permission::Create(aPrincipal, "cookie"_ns, *aCookiePermission, 0, 0, 0);
363 if (permission) {
364 mCookiePermissions.AppendElement(permission);
367 mToBeMerged = true;
368 return NS_OK;
371 void CookieJarSettings::Serialize(CookieJarSettingsArgs& aData) {
372 MOZ_RELEASE_ASSERT(NS_IsMainThread());
374 aData.isFixed() = mState == eFixed;
375 aData.cookieBehavior() = mCookieBehavior;
376 aData.isFirstPartyIsolated() = mIsFirstPartyIsolated;
377 aData.shouldResistFingerprinting() = mShouldResistFingerprinting;
378 aData.isOnContentBlockingAllowList() = mIsOnContentBlockingAllowList;
379 aData.partitionKey() = mPartitionKey;
380 if (mFingerprintingRandomKey) {
381 aData.hasFingerprintingRandomizationKey() = true;
382 aData.fingerprintingRandomizationKey() = mFingerprintingRandomKey->Clone();
383 } else {
384 aData.hasFingerprintingRandomizationKey() = false;
387 for (const RefPtr<nsIPermission>& permission : mCookiePermissions) {
388 nsCOMPtr<nsIPrincipal> principal;
389 nsresult rv = permission->GetPrincipal(getter_AddRefs(principal));
390 if (NS_WARN_IF(NS_FAILED(rv))) {
391 continue;
394 ipc::PrincipalInfo principalInfo;
395 rv = PrincipalToPrincipalInfo(principal, &principalInfo,
396 true /* aSkipBaseDomain */);
397 if (NS_WARN_IF(NS_FAILED(rv))) {
398 continue;
401 uint32_t cookiePermission = 0;
402 rv = permission->GetCapability(&cookiePermission);
403 if (NS_WARN_IF(NS_FAILED(rv))) {
404 continue;
407 aData.cookiePermissions().AppendElement(
408 CookiePermissionData(principalInfo, cookiePermission));
411 mToBeMerged = false;
414 /* static */ void CookieJarSettings::Deserialize(
415 const CookieJarSettingsArgs& aData,
416 nsICookieJarSettings** aCookieJarSettings) {
417 MOZ_RELEASE_ASSERT(NS_IsMainThread());
419 CookiePermissionList list;
420 for (const CookiePermissionData& data : aData.cookiePermissions()) {
421 auto principalOrErr = PrincipalInfoToPrincipal(data.principalInfo());
422 if (NS_WARN_IF(principalOrErr.isErr())) {
423 continue;
426 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
428 nsCOMPtr<nsIPermission> permission = Permission::Create(
429 principal, "cookie"_ns, data.cookiePermission(), 0, 0, 0);
430 if (NS_WARN_IF(!permission)) {
431 continue;
434 list.AppendElement(permission);
437 RefPtr<CookieJarSettings> cookieJarSettings = new CookieJarSettings(
438 aData.cookieBehavior(), aData.isFirstPartyIsolated(),
439 aData.shouldResistFingerprinting(),
440 aData.isFixed() ? eFixed : eProgressive);
442 cookieJarSettings->mIsOnContentBlockingAllowList =
443 aData.isOnContentBlockingAllowList();
444 cookieJarSettings->mCookiePermissions = std::move(list);
445 cookieJarSettings->mPartitionKey = aData.partitionKey();
446 cookieJarSettings->mShouldResistFingerprinting =
447 aData.shouldResistFingerprinting();
449 if (aData.hasFingerprintingRandomizationKey()) {
450 cookieJarSettings->mFingerprintingRandomKey.emplace(
451 aData.fingerprintingRandomizationKey().Clone());
454 cookieJarSettings.forget(aCookieJarSettings);
457 void CookieJarSettings::Merge(const CookieJarSettingsArgs& aData) {
458 MOZ_RELEASE_ASSERT(NS_IsMainThread());
459 MOZ_ASSERT(
460 mCookieBehavior == aData.cookieBehavior() ||
461 (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
462 aData.cookieBehavior() ==
463 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) ||
464 (mCookieBehavior ==
465 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
466 aData.cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER));
468 if (mState == eFixed) {
469 return;
472 // Merge cookie behavior pref values
473 if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER &&
474 aData.cookieBehavior() ==
475 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) {
476 // If the other side has decided to partition third-party cookies, update
477 // our side when first-party isolation is disabled.
478 if (!mIsFirstPartyIsolated) {
479 mCookieBehavior =
480 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
483 if (mCookieBehavior ==
484 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN &&
485 aData.cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
486 // If we've decided to partition third-party cookies, the other side may not
487 // have caught up yet unless it has first-party isolation enabled.
488 if (aData.isFirstPartyIsolated()) {
489 mCookieBehavior = nsICookieService::BEHAVIOR_REJECT_TRACKER;
490 mIsFirstPartyIsolated = true;
493 // Ignore all other cases.
494 MOZ_ASSERT_IF(
495 mIsFirstPartyIsolated,
496 mCookieBehavior !=
497 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN);
499 if (aData.shouldResistFingerprinting()) {
500 mShouldResistFingerprinting = true;
503 PermissionComparator comparator;
505 for (const CookiePermissionData& data : aData.cookiePermissions()) {
506 auto principalOrErr = PrincipalInfoToPrincipal(data.principalInfo());
507 if (NS_WARN_IF(principalOrErr.isErr())) {
508 continue;
511 nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
512 nsCOMPtr<nsIPermission> permission = Permission::Create(
513 principal, "cookie"_ns, data.cookiePermission(), 0, 0, 0);
514 if (NS_WARN_IF(!permission)) {
515 continue;
518 if (!mCookiePermissions.Contains(permission, comparator)) {
519 mCookiePermissions.AppendElement(permission);
524 void CookieJarSettings::SetPartitionKey(nsIURI* aURI) {
525 MOZ_ASSERT(aURI);
527 OriginAttributes attrs;
528 attrs.SetPartitionKey(aURI);
529 mPartitionKey = std::move(attrs.mPartitionKey);
532 void CookieJarSettings::UpdateIsOnContentBlockingAllowList(
533 nsIChannel* aChannel) {
534 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
535 MOZ_ASSERT(aChannel);
537 // Early return if the flag was updated before.
538 if (mIsOnContentBlockingAllowListUpdated) {
539 return;
541 mIsOnContentBlockingAllowListUpdated = true;
543 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
545 nsCOMPtr<nsIURI> uri;
546 nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
547 if (NS_WARN_IF(NS_FAILED(rv))) {
548 return;
551 // We need to recompute the ContentBlockingAllowListPrincipal here for the
552 // top level channel because we might navigate from the the initial
553 // about:blank page or the existing page which may have a different origin
554 // than the URI we are going to load here. Thus, we need to recompute the
555 // prinicpal in order to get the correct ContentBlockingAllowListPrincipal.
556 nsCOMPtr<nsIPrincipal> contentBlockingAllowListPrincipal;
557 OriginAttributes attrs;
558 loadInfo->GetOriginAttributes(&attrs);
559 ContentBlockingAllowList::RecomputePrincipal(
560 uri, attrs, getter_AddRefs(contentBlockingAllowListPrincipal));
562 if (!contentBlockingAllowListPrincipal ||
563 !contentBlockingAllowListPrincipal->GetIsContentPrincipal()) {
564 return;
567 Unused << ContentBlockingAllowList::Check(contentBlockingAllowListPrincipal,
568 NS_UsePrivateBrowsing(aChannel),
569 mIsOnContentBlockingAllowList);
572 // static
573 bool CookieJarSettings::IsRejectThirdPartyContexts(uint32_t aCookieBehavior) {
574 return aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
575 aCookieBehavior ==
576 nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
579 NS_IMETHODIMP
580 CookieJarSettings::Read(nsIObjectInputStream* aStream) {
581 MOZ_RELEASE_ASSERT(NS_IsMainThread());
582 nsresult rv = aStream->Read32(&mCookieBehavior);
583 if (NS_WARN_IF(NS_FAILED(rv))) {
584 return rv;
587 rv = aStream->ReadBoolean(&mIsFirstPartyIsolated);
588 if (NS_WARN_IF(NS_FAILED(rv))) {
589 return rv;
592 rv = aStream->ReadBoolean(&mShouldResistFingerprinting);
593 if (NS_WARN_IF(NS_FAILED(rv))) {
594 return rv;
597 bool isFixed;
598 aStream->ReadBoolean(&isFixed);
599 if (NS_WARN_IF(NS_FAILED(rv))) {
600 return rv;
602 mState = isFixed ? eFixed : eProgressive;
604 rv = aStream->ReadBoolean(&mIsOnContentBlockingAllowList);
605 if (NS_WARN_IF(NS_FAILED(rv))) {
606 return rv;
609 rv = aStream->ReadString(mPartitionKey);
610 if (NS_WARN_IF(NS_FAILED(rv))) {
611 return rv;
614 // Deserializing the cookie permission list.
615 uint32_t cookiePermissionsLength;
616 rv = aStream->Read32(&cookiePermissionsLength);
617 if (NS_WARN_IF(NS_FAILED(rv))) {
618 return rv;
621 if (!cookiePermissionsLength) {
622 // Bailing out early because there is no cookie permission.
623 return NS_OK;
626 CookiePermissionList list;
627 mCookiePermissions.SetCapacity(cookiePermissionsLength);
628 for (uint32_t i = 0; i < cookiePermissionsLength; ++i) {
629 nsAutoCString principalJSON;
630 aStream->ReadCString(principalJSON);
631 if (NS_WARN_IF(NS_FAILED(rv))) {
632 return rv;
635 nsCOMPtr<nsIPrincipal> principal = BasePrincipal::FromJSON(principalJSON);
637 if (NS_WARN_IF(!principal)) {
638 continue;
641 uint32_t cookiePermission;
642 aStream->Read32(&cookiePermission);
643 if (NS_WARN_IF(NS_FAILED(rv))) {
644 return rv;
647 nsCOMPtr<nsIPermission> permission =
648 Permission::Create(principal, "cookie"_ns, cookiePermission, 0, 0, 0);
649 if (NS_WARN_IF(!permission)) {
650 continue;
653 list.AppendElement(permission);
656 mCookiePermissions = std::move(list);
658 return NS_OK;
661 NS_IMETHODIMP
662 CookieJarSettings::Write(nsIObjectOutputStream* aStream) {
663 MOZ_RELEASE_ASSERT(NS_IsMainThread());
664 nsresult rv = aStream->Write32(mCookieBehavior);
665 if (NS_WARN_IF(NS_FAILED(rv))) {
666 return rv;
669 rv = aStream->WriteBoolean(mIsFirstPartyIsolated);
670 if (NS_WARN_IF(NS_FAILED(rv))) {
671 return rv;
674 rv = aStream->WriteBoolean(mShouldResistFingerprinting);
675 if (NS_WARN_IF(NS_FAILED(rv))) {
676 return rv;
679 rv = aStream->WriteBoolean(mState == eFixed);
680 if (NS_WARN_IF(NS_FAILED(rv))) {
681 return rv;
684 rv = aStream->WriteBoolean(mIsOnContentBlockingAllowList);
685 if (NS_WARN_IF(NS_FAILED(rv))) {
686 return rv;
689 rv = aStream->WriteWStringZ(mPartitionKey.get());
690 if (NS_WARN_IF(NS_FAILED(rv))) {
691 return rv;
694 // Serializing the cookie permission list. It will first write the length of
695 // the list, and then, write the cookie permission consecutively.
696 uint32_t cookiePermissionsLength = mCookiePermissions.Length();
697 rv = aStream->Write32(cookiePermissionsLength);
698 if (NS_WARN_IF(NS_FAILED(rv))) {
699 return rv;
702 for (const RefPtr<nsIPermission>& permission : mCookiePermissions) {
703 nsCOMPtr<nsIPrincipal> principal;
704 nsresult rv = permission->GetPrincipal(getter_AddRefs(principal));
705 if (NS_WARN_IF(NS_FAILED(rv))) {
706 continue;
709 nsAutoCString principalJSON;
710 BasePrincipal::Cast(principal)->ToJSON(principalJSON);
712 rv = aStream->WriteStringZ(principalJSON.get());
713 if (NS_WARN_IF(NS_FAILED(rv))) {
714 return rv;
717 uint32_t cookiePermission = 0;
718 rv = permission->GetCapability(&cookiePermission);
719 if (NS_WARN_IF(NS_FAILED(rv))) {
720 continue;
723 rv = aStream->Write32(cookiePermission);
724 if (NS_WARN_IF(NS_FAILED(rv))) {
725 return rv;
729 return NS_OK;
732 } // namespace net
733 } // namespace mozilla