diff options
Diffstat (limited to 'netwerk/cookie/nsCookieService.h')
-rw-r--r-- | netwerk/cookie/nsCookieService.h | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/netwerk/cookie/nsCookieService.h b/netwerk/cookie/nsCookieService.h new file mode 100644 index 000000000..e3b2d3e8a --- /dev/null +++ b/netwerk/cookie/nsCookieService.h @@ -0,0 +1,371 @@ +/* -*- 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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsCookieService_h__ +#define nsCookieService_h__ + +#include "nsICookieService.h" +#include "nsICookieManager.h" +#include "nsICookieManager2.h" +#include "nsIObserver.h" +#include "nsWeakReference.h" + +#include "nsCookie.h" +#include "nsString.h" +#include "nsAutoPtr.h" +#include "nsHashKeys.h" +#include "nsIMemoryReporter.h" +#include "nsTHashtable.h" +#include "mozIStorageStatement.h" +#include "mozIStorageAsyncStatement.h" +#include "mozIStoragePendingStatement.h" +#include "mozIStorageConnection.h" +#include "mozIStorageRow.h" +#include "mozIStorageCompletionCallback.h" +#include "mozIStorageStatementCallback.h" +#include "mozIStorageFunction.h" +#include "nsIVariant.h" +#include "nsIFile.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/Maybe.h" + +using mozilla::NeckoOriginAttributes; +using mozilla::OriginAttributes; + +class nsICookiePermission; +class nsIEffectiveTLDService; +class nsIIDNService; +class nsIPrefBranch; +class nsIObserverService; +class nsIURI; +class nsIChannel; +class nsIArray; +class mozIStorageService; +class mozIThirdPartyUtil; +class ReadCookieDBListener; + +struct nsCookieAttributes; +struct nsListIter; + +namespace mozilla { +namespace net { +class CookieServiceParent; +} // namespace net +} // namespace mozilla + +// hash key class +class nsCookieKey : public PLDHashEntryHdr +{ +public: + typedef const nsCookieKey& KeyType; + typedef const nsCookieKey* KeyTypePointer; + + nsCookieKey() + {} + + nsCookieKey(const nsCString &baseDomain, const NeckoOriginAttributes &attrs) + : mBaseDomain(baseDomain) + , mOriginAttributes(attrs) + {} + + explicit nsCookieKey(KeyTypePointer other) + : mBaseDomain(other->mBaseDomain) + , mOriginAttributes(other->mOriginAttributes) + {} + + nsCookieKey(KeyType other) + : mBaseDomain(other.mBaseDomain) + , mOriginAttributes(other.mOriginAttributes) + {} + + ~nsCookieKey() + {} + + bool KeyEquals(KeyTypePointer other) const + { + return mBaseDomain == other->mBaseDomain && + mOriginAttributes == other->mOriginAttributes; + } + + static KeyTypePointer KeyToPointer(KeyType aKey) + { + return &aKey; + } + + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + // TODO: more efficient way to generate hash? + nsAutoCString temp(aKey->mBaseDomain); + temp.Append('#'); + nsAutoCString suffix; + aKey->mOriginAttributes.CreateSuffix(suffix); + temp.Append(suffix); + return mozilla::HashString(temp); + } + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + enum { ALLOW_MEMMOVE = true }; + + nsCString mBaseDomain; + NeckoOriginAttributes mOriginAttributes; +}; + +// Inherit from nsCookieKey so this can be stored in nsTHashTable +// TODO: why aren't we using nsClassHashTable<nsCookieKey, ArrayType>? +class nsCookieEntry : public nsCookieKey +{ + public: + // Hash methods + typedef nsTArray< RefPtr<nsCookie> > ArrayType; + typedef ArrayType::index_type IndexType; + + explicit nsCookieEntry(KeyTypePointer aKey) + : nsCookieKey(aKey) + {} + + nsCookieEntry(const nsCookieEntry& toCopy) + { + // if we end up here, things will break. nsTHashtable shouldn't + // allow this, since we set ALLOW_MEMMOVE to true. + NS_NOTREACHED("nsCookieEntry copy constructor is forbidden!"); + } + + ~nsCookieEntry() + {} + + inline ArrayType& GetCookies() { return mCookies; } + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + private: + ArrayType mCookies; +}; + +// encapsulates a (key, nsCookie) tuple for temporary storage purposes. +struct CookieDomainTuple +{ + nsCookieKey key; + RefPtr<nsCookie> cookie; + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; +}; + +// encapsulates in-memory and on-disk DB states, so we can +// conveniently switch state when entering or exiting private browsing. +struct DBState final +{ + DBState() : cookieCount(0), cookieOldestTime(INT64_MAX), corruptFlag(OK) + { + } + +private: + // Private destructor, to discourage deletion outside of Release(): + ~DBState() + { + } + +public: + NS_INLINE_DECL_REFCOUNTING(DBState) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + // State of the database connection. + enum CorruptFlag { + OK, // normal + CLOSING_FOR_REBUILD, // corruption detected, connection closing + REBUILDING // close complete, rebuilding database from memory + }; + + nsTHashtable<nsCookieEntry> hostTable; + uint32_t cookieCount; + int64_t cookieOldestTime; + nsCOMPtr<nsIFile> cookieFile; + nsCOMPtr<mozIStorageConnection> dbConn; + nsCOMPtr<mozIStorageAsyncStatement> stmtInsert; + nsCOMPtr<mozIStorageAsyncStatement> stmtDelete; + nsCOMPtr<mozIStorageAsyncStatement> stmtUpdate; + CorruptFlag corruptFlag; + + // Various parts representing asynchronous read state. These are useful + // while the background read is taking place. + nsCOMPtr<mozIStorageConnection> syncConn; + nsCOMPtr<mozIStorageStatement> stmtReadDomain; + nsCOMPtr<mozIStoragePendingStatement> pendingRead; + // The asynchronous read listener. This is a weak ref (storage has ownership) + // since it may need to outlive the DBState's database connection. + ReadCookieDBListener* readListener; + // An array of (baseDomain, cookie) tuples representing data read in + // asynchronously. This is merged into hostTable once read is complete. + nsTArray<CookieDomainTuple> hostArray; + // A hashset of baseDomains read in synchronously, while the async read is + // in flight. This is used to keep track of which data in hostArray is stale + // when the time comes to merge. + nsTHashtable<nsCookieKey> readSet; + + // DB completion handlers. + nsCOMPtr<mozIStorageStatementCallback> insertListener; + nsCOMPtr<mozIStorageStatementCallback> updateListener; + nsCOMPtr<mozIStorageStatementCallback> removeListener; + nsCOMPtr<mozIStorageCompletionCallback> closeListener; +}; + +// these constants represent a decision about a cookie based on user prefs. +enum CookieStatus +{ + STATUS_ACCEPTED, + STATUS_ACCEPT_SESSION, + STATUS_REJECTED, + // STATUS_REJECTED_WITH_ERROR indicates the cookie should be rejected because + // of an error (rather than something the user can control). this is used for + // notification purposes, since we only want to notify of rejections where + // the user can do something about it (e.g. whitelist the site). + STATUS_REJECTED_WITH_ERROR +}; + +// Result codes for TryInitDB() and Read(). +enum OpenDBResult +{ + RESULT_OK, + RESULT_RETRY, + RESULT_FAILURE +}; + +/****************************************************************************** + * nsCookieService: + * class declaration + ******************************************************************************/ + +class nsCookieService final : public nsICookieService + , public nsICookieManager2 + , public nsIObserver + , public nsSupportsWeakReference + , public nsIMemoryReporter +{ + private: + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + NS_DECL_NSICOOKIESERVICE + NS_DECL_NSICOOKIEMANAGER + NS_DECL_NSICOOKIEMANAGER2 + NS_DECL_NSIMEMORYREPORTER + + nsCookieService(); + static nsICookieService* GetXPCOMSingleton(); + nsresult Init(); + + /** + * Start watching the observer service for messages indicating that an app has + * been uninstalled. When an app is uninstalled, we get the cookie service + * (thus instantiating it, if necessary) and clear all the cookies for that + * app. + */ + static void AppClearDataObserverInit(); + + protected: + virtual ~nsCookieService(); + + void PrefChanged(nsIPrefBranch *aPrefBranch); + void InitDBStates(); + OpenDBResult TryInitDB(bool aDeleteExistingDB); + nsresult CreateTable(); + nsresult CreateTableForSchemaVersion6(); + nsresult CreateTableForSchemaVersion5(); + void CloseDBStates(); + void CleanupCachedStatements(); + void CleanupDefaultDBConnection(); + void HandleDBClosed(DBState* aDBState); + void HandleCorruptDB(DBState* aDBState); + void RebuildCorruptDB(DBState* aDBState); + OpenDBResult Read(); + template<class T> nsCookie* GetCookieFromRow(T &aRow, const OriginAttributes& aOriginAttributes); + void AsyncReadComplete(); + void CancelAsyncRead(bool aPurgeReadSet); + void EnsureReadDomain(const nsCookieKey &aKey); + void EnsureReadComplete(); + nsresult NormalizeHost(nsCString &aHost); + nsresult GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch); + nsresult GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain); + nsresult GetCookieStringCommon(nsIURI *aHostURI, nsIChannel *aChannel, bool aHttpBound, char** aCookie); + void GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aHttpBound, const NeckoOriginAttributes aOriginAttrs, bool aIsPrivate, nsCString &aCookie); + nsresult SetCookieStringCommon(nsIURI *aHostURI, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, bool aFromHttp); + void SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, nsDependentCString &aCookieHeader, const nsCString &aServerTime, bool aFromHttp, const NeckoOriginAttributes &aOriginAttrs, bool aIsPrivate, nsIChannel* aChannel); + bool SetCookieInternal(nsIURI *aHostURI, const nsCookieKey& aKey, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel); + void AddInternal(const nsCookieKey& aKey, nsCookie *aCookie, int64_t aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, bool aFromHttp); + void RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = nullptr); + void AddCookieToList(const nsCookieKey& aKey, nsCookie *aCookie, DBState *aDBState, mozIStorageBindingParamsArray *aParamsArray, bool aWriteToDB = true); + void UpdateCookieInList(nsCookie *aCookie, int64_t aLastAccessed, mozIStorageBindingParamsArray *aParamsArray); + static bool GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, bool &aEqualsFound); + static bool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie); + bool RequireThirdPartyCheck(); + CookieStatus CheckPrefs(nsIURI *aHostURI, bool aIsForeign, const char *aCookieHeader); + bool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch); + static bool CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI); + static bool CheckPrefixes(nsCookieAttributes &aCookie, bool aSecureRequest); + static bool GetExpiry(nsCookieAttributes &aCookie, int64_t aServerTime, int64_t aCurrentTime); + void RemoveAllFromMemory(); + already_AddRefed<nsIArray> PurgeCookies(int64_t aCurrentTimeInUsec); + bool FindCookie(const nsCookieKey& aKey, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter); + bool FindSecureCookie(const nsCookieKey& aKey, nsCookie* aCookie); + int64_t FindStaleCookie(nsCookieEntry *aEntry, int64_t aCurrentTime, nsIURI* aSource, mozilla::Maybe<bool> aIsSecure, nsListIter &aIter); + void TelemetryForEvictingStaleCookie(nsCookie* aEvicted, int64_t oldestCookieTime); + void NotifyRejected(nsIURI *aHostURI); + void NotifyThirdParty(nsIURI *aHostURI, bool aAccepted, nsIChannel *aChannel); + void NotifyChanged(nsISupports *aSubject, const char16_t *aData); + void NotifyPurged(nsICookie2* aCookie); + already_AddRefed<nsIArray> CreatePurgeList(nsICookie2* aCookie); + void UpdateCookieOldestTime(DBState* aDBState, nsCookie* aCookie); + + nsresult GetCookiesWithOriginAttributes(const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain, nsISimpleEnumerator **aEnumerator); + nsresult RemoveCookiesWithOriginAttributes(const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain); + + /** + * This method is a helper that allows calling nsICookieManager::Remove() + * with NeckoOriginAttributes parameter. + * NOTE: this could be added to a public interface if we happen to need it. + */ + nsresult Remove(const nsACString& aHost, const NeckoOriginAttributes& aAttrs, + const nsACString& aName, const nsACString& aPath, + bool aBlocked); + + protected: + // cached members. + nsCOMPtr<nsICookiePermission> mPermissionService; + nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil; + nsCOMPtr<nsIEffectiveTLDService> mTLDService; + nsCOMPtr<nsIIDNService> mIDNService; + nsCOMPtr<mozIStorageService> mStorageService; + + // we have two separate DB states: one for normal browsing and one for + // private browsing, switching between them on a per-cookie-request basis. + // this state encapsulates both the in-memory table and the on-disk DB. + // note that the private states' dbConn should always be null - we never + // want to be dealing with the on-disk DB when in private browsing. + DBState *mDBState; + RefPtr<DBState> mDefaultDBState; + RefPtr<DBState> mPrivateDBState; + + // cached prefs + uint8_t mCookieBehavior; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, LIMITFOREIGN} + bool mThirdPartySession; + bool mLeaveSecureAlone; + uint16_t mMaxNumberOfCookies; + uint16_t mMaxCookiesPerHost; + int64_t mCookiePurgeAge; + + // friends! + friend class DBListenerErrorHandler; + friend class ReadCookieDBListener; + friend class CloseCookieDBListener; + + static nsCookieService* GetSingleton(); + friend class mozilla::net::CookieServiceParent; +}; + +#endif // nsCookieService_h__ |