Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#ifndef mozilla_net_CookieStorage_h
#define mozilla_net_CookieStorage_h
#include "CookieKey.h"
#include "nsICookieNotification.h"
#include "nsIObserver.h"
#include "nsTHashtable.h"
#include "nsWeakReference.h"
#include <functional>
#include "CookieCommons.h"
class nsIArray;
class nsICookie;
class nsICookieTransactionCallback;
class nsIPrefBranch;
namespace mozilla {
namespace net {
class Cookie;
class CookieParser;
// Inherit from CookieKey so this can be stored in nsTHashTable
// TODO: why aren't we using nsClassHashTable<CookieKey, ArrayType>?
class CookieEntry : public CookieKey {
public:
// Hash methods
using ArrayType = nsTArray<RefPtr<Cookie>>;
using IndexType = ArrayType::index_type;
explicit CookieEntry(KeyTypePointer aKey) : CookieKey(aKey) {}
CookieEntry(const CookieEntry& toCopy) {
// if we end up here, things will break. nsTHashtable shouldn't
// allow this, since we set ALLOW_MEMMOVE to true.
MOZ_ASSERT_UNREACHABLE("CookieEntry copy constructor is forbidden!");
}
~CookieEntry() = default;
inline ArrayType& GetCookies() { return mCookies; }
inline const ArrayType& GetCookies() const { return mCookies; }
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
bool IsPartitioned() const;
private:
ArrayType mCookies;
};
// stores the CookieEntry entryclass and an index into the cookie array within
// that entryclass, for purposes of storing an iteration state that points to a
// certain cookie.
struct CookieListIter {
// default (non-initializing) constructor.
CookieListIter() = default;
// explicit constructor to a given iterator state with entryclass 'aEntry'
// and index 'aIndex'.
explicit CookieListIter(CookieEntry* aEntry, CookieEntry::IndexType aIndex)
: entry(aEntry), index(aIndex) {}
// get the Cookie * the iterator currently points to.
mozilla::net::Cookie* Cookie() const { return entry->GetCookies()[index]; }
CookieEntry* entry;
CookieEntry::IndexType index;
};
class CookieStorage : public nsIObserver, public nsSupportsWeakReference {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
void GetCookies(nsTArray<RefPtr<nsICookie>>& aCookies) const;
void GetSessionCookies(nsTArray<RefPtr<nsICookie>>& aCookies) const;
bool FindCookie(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
const nsACString& aHost, const nsACString& aName,
const nsACString& aPath, CookieListIter& aIter);
uint32_t CountCookiesFromHost(const nsACString& aBaseDomain,
uint32_t aPrivateBrowsingId);
uint32_t CountCookieBytesNotMatchingCookie(const Cookie& cookie,
const nsACString& baseDomain);
void GetAll(nsTArray<RefPtr<nsICookie>>& aResult) const;
void GetCookiesFromHost(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
nsTArray<RefPtr<Cookie>>& aCookies);
void GetCookiesWithOriginAttributes(const OriginAttributesPattern& aPattern,
const nsACString& aBaseDomain,
bool aSorted,
nsTArray<RefPtr<nsICookie>>& aResult);
void RemoveCookie(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
const nsACString& aHost, const nsACString& aName,
const nsACString& aPath, const nsID* aOperationID);
virtual void RemoveCookiesWithOriginAttributes(
const OriginAttributesPattern& aPattern, const nsACString& aBaseDomain);
virtual void RemoveCookiesFromExactHost(
const nsACString& aHost, const nsACString& aBaseDomain,
const OriginAttributesPattern& aPattern);
void RemoveAll();
void NotifyChanged(nsISupports* aSubject,
nsICookieNotification::Action aAction,
const nsACString& aBaseDomain, bool aIsThirdParty = false,
dom::BrowsingContext* aBrowsingContext = nullptr,
bool aOldCookieIsSession = false,
const nsID* aOperationID = nullptr);
void AddCookie(CookieParser* aCookieParser, const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes, Cookie* aCookie,
int64_t aCurrentTimeInUsec, nsIURI* aHostURI,
const nsACString& aCookieHeader, bool aFromHttp,
bool aIsThirdParty, dom::BrowsingContext* aBrowsingContext,
const nsID* aOperationID = nullptr);
// return true if we finish within the byte limit
bool RemoveCookiesFromBackUntilUnderLimit(
nsTArray<CookieListIter>& aCookieListIter, Cookie* aCookie,
const nsACString& aBaseDomain, nsCOMPtr<nsIArray>& aPurgedList);
void RemoveOlderCookiesUntilUnderLimit(CookieEntry* aEntry, Cookie* aCookie,
const nsACString& aBaseDomain,
nsCOMPtr<nsIArray>& aPurgedList);
// prevent excessive purging by using a soft and hard limit
// the soft limit (aka quota) is derived directly from partitionLimitCapacity
// pref while the hard limit is 1.2 times the partitionLimitCapacity pref we
// use the hard limit to trigger purging and telemetry and when we do purge,
// we purge down to the soft limit (quota)
int32_t PartitionLimitExceededBytes(Cookie* aCookie,
const nsACString& aBaseDomain,
bool aHardMax);
static void CreateOrUpdatePurgeList(nsCOMPtr<nsIArray>& aPurgedList,
nsICookie* aCookie);
virtual void StaleCookies(const nsTArray<RefPtr<Cookie>>& aCookieList,
int64_t aCurrentTimeInUsec) = 0;
virtual void Close() = 0;
virtual void EnsureInitialized() = 0;
virtual nsresult RunInTransaction(
nsICookieTransactionCallback* aCallback) = 0;
protected:
CookieStorage() = default;
virtual ~CookieStorage() = default;
void Init();
void AddCookieToList(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
Cookie* aCookie);
virtual void StoreCookie(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
Cookie* aCookie) = 0;
virtual const char* NotificationTopic() const = 0;
virtual void NotifyChangedInternal(nsICookieNotification* aSubject,
bool aOldCookieIsSession) = 0;
virtual void RemoveAllInternal() = 0;
// This method calls RemoveCookieFromDB + RemoveCookieFromListInternal.
void RemoveCookieFromList(const CookieListIter& aIter);
void RemoveCookieFromListInternal(const CookieListIter& aIter);
virtual void RemoveCookieFromDB(const Cookie& aCookie) = 0;
already_AddRefed<nsIArray> PurgeCookiesWithCallbacks(
int64_t aCurrentTimeInUsec, uint16_t aMaxNumberOfCookies,
int64_t aCookiePurgeAge,
std::function<void(const CookieListIter&)>&& aRemoveCookieCallback,
std::function<void()>&& aFinalizeCallback);
nsTHashtable<CookieEntry> mHostTable;
uint32_t mCookieCount{0};
private:
void PrefChanged(nsIPrefBranch* aPrefBranch);
bool FindSecureCookie(const nsACString& aBaseDomain,
const OriginAttributes& aOriginAttributes,
Cookie* aCookie);
static void FindStaleCookies(CookieEntry* aEntry, int64_t aCurrentTime,
bool aIsSecure,
nsTArray<CookieListIter>& aOutput,
uint32_t aLimit);
void UpdateCookieOldestTime(Cookie* aCookie);
void MergeCookieSchemeMap(Cookie* aOldCookie, Cookie* aNewCookie);
static already_AddRefed<nsIArray> CreatePurgeList(nsICookie* aCookie);
virtual already_AddRefed<nsIArray> PurgeCookies(int64_t aCurrentTimeInUsec,
uint16_t aMaxNumberOfCookies,
int64_t aCookiePurgeAge) = 0;
// Serialize aBaseDomain e.g. apply "zero abbreveation" (::), use single
// zeros and remove brackets to match principal base domain representation.
static bool SerializeIPv6BaseDomain(nsACString& aBaseDomain);
virtual void CollectCookieJarSizeData() = 0;
int64_t mCookieOldestTime{INT64_MAX};
uint16_t mMaxNumberOfCookies{kMaxNumberOfCookies};
uint16_t mMaxCookiesPerHost{kMaxCookiesPerHost};
uint16_t mCookieQuotaPerHost{kCookieQuotaPerHost};
int64_t mCookiePurgeAge{kCookiePurgeAge};
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_CookieStorage_h