Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsCookieService_h__
7 #define nsCookieService_h__
9 #include "nsICookieService.h"
10 #include "nsICookieManager.h"
11 #include "nsICookieManager2.h"
12 #include "nsIObserver.h"
13 #include "nsWeakReference.h"
15 #include "nsCookie.h"
16 #include "nsString.h"
17 #include "nsAutoPtr.h"
18 #include "nsHashKeys.h"
19 #include "nsIMemoryReporter.h"
20 #include "nsTHashtable.h"
21 #include "mozIStorageStatement.h"
22 #include "mozIStorageAsyncStatement.h"
23 #include "mozIStoragePendingStatement.h"
24 #include "mozIStorageConnection.h"
25 #include "mozIStorageRow.h"
26 #include "mozIStorageCompletionCallback.h"
27 #include "mozIStorageStatementCallback.h"
29 #include "mozilla/MemoryReporting.h"
31 class nsICookiePermission;
32 class nsIEffectiveTLDService;
33 class nsIIDNService;
34 class nsIPrefBranch;
35 class nsIObserverService;
36 class nsIURI;
37 class nsIChannel;
38 class nsIArray;
39 class mozIStorageService;
40 class mozIThirdPartyUtil;
41 class ReadCookieDBListener;
43 struct nsCookieAttributes;
44 struct nsListIter;
45 struct nsEnumerationData;
47 namespace mozilla {
48 namespace net {
49 class CookieServiceParent;
50 }
51 }
53 // hash key class
54 class nsCookieKey : public PLDHashEntryHdr
55 {
56 public:
57 typedef const nsCookieKey& KeyType;
58 typedef const nsCookieKey* KeyTypePointer;
60 nsCookieKey()
61 {}
63 nsCookieKey(const nsCString &baseDomain, uint32_t appId, bool inBrowser)
64 : mBaseDomain(baseDomain)
65 , mAppId(appId)
66 , mInBrowserElement(inBrowser)
67 {}
69 nsCookieKey(KeyTypePointer other)
70 : mBaseDomain(other->mBaseDomain)
71 , mAppId(other->mAppId)
72 , mInBrowserElement(other->mInBrowserElement)
73 {}
75 nsCookieKey(KeyType other)
76 : mBaseDomain(other.mBaseDomain)
77 , mAppId(other.mAppId)
78 , mInBrowserElement(other.mInBrowserElement)
79 {}
81 ~nsCookieKey()
82 {}
84 bool KeyEquals(KeyTypePointer other) const
85 {
86 return mBaseDomain == other->mBaseDomain &&
87 mAppId == other->mAppId &&
88 mInBrowserElement == other->mInBrowserElement;
89 }
91 static KeyTypePointer KeyToPointer(KeyType aKey)
92 {
93 return &aKey;
94 }
96 static PLDHashNumber HashKey(KeyTypePointer aKey)
97 {
98 // TODO: more efficient way to generate hash?
99 nsAutoCString temp(aKey->mBaseDomain);
100 temp.Append("#");
101 temp.Append(aKey->mAppId);
102 temp.Append("#");
103 temp.Append(aKey->mInBrowserElement ? 1 : 0);
104 return mozilla::HashString(temp);
105 }
107 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
109 enum { ALLOW_MEMMOVE = true };
111 nsCString mBaseDomain;
112 uint32_t mAppId;
113 bool mInBrowserElement;
114 };
116 // Inherit from nsCookieKey so this can be stored in nsTHashTable
117 // TODO: why aren't we using nsClassHashTable<nsCookieKey, ArrayType>?
118 class nsCookieEntry : public nsCookieKey
119 {
120 public:
121 // Hash methods
122 typedef nsTArray< nsRefPtr<nsCookie> > ArrayType;
123 typedef ArrayType::index_type IndexType;
125 nsCookieEntry(KeyTypePointer aKey)
126 : nsCookieKey(aKey)
127 {}
129 nsCookieEntry(const nsCookieEntry& toCopy)
130 {
131 // if we end up here, things will break. nsTHashtable shouldn't
132 // allow this, since we set ALLOW_MEMMOVE to true.
133 NS_NOTREACHED("nsCookieEntry copy constructor is forbidden!");
134 }
136 ~nsCookieEntry()
137 {}
139 inline ArrayType& GetCookies() { return mCookies; }
141 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
143 private:
144 ArrayType mCookies;
145 };
147 // encapsulates a (key, nsCookie) tuple for temporary storage purposes.
148 struct CookieDomainTuple
149 {
150 nsCookieKey key;
151 nsRefPtr<nsCookie> cookie;
153 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
154 };
156 // encapsulates in-memory and on-disk DB states, so we can
157 // conveniently switch state when entering or exiting private browsing.
158 struct DBState MOZ_FINAL
159 {
160 DBState() : cookieCount(0), cookieOldestTime(INT64_MAX), corruptFlag(OK)
161 {
162 }
164 private:
165 // Private destructor, to discourage deletion outside of Release():
166 ~DBState()
167 {
168 }
170 public:
171 NS_INLINE_DECL_REFCOUNTING(DBState)
173 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
175 // State of the database connection.
176 enum CorruptFlag {
177 OK, // normal
178 CLOSING_FOR_REBUILD, // corruption detected, connection closing
179 REBUILDING // close complete, rebuilding database from memory
180 };
182 nsTHashtable<nsCookieEntry> hostTable;
183 uint32_t cookieCount;
184 int64_t cookieOldestTime;
185 nsCOMPtr<nsIFile> cookieFile;
186 nsCOMPtr<mozIStorageConnection> dbConn;
187 nsCOMPtr<mozIStorageAsyncStatement> stmtInsert;
188 nsCOMPtr<mozIStorageAsyncStatement> stmtDelete;
189 nsCOMPtr<mozIStorageAsyncStatement> stmtUpdate;
190 CorruptFlag corruptFlag;
192 // Various parts representing asynchronous read state. These are useful
193 // while the background read is taking place.
194 nsCOMPtr<mozIStorageConnection> syncConn;
195 nsCOMPtr<mozIStorageStatement> stmtReadDomain;
196 nsCOMPtr<mozIStoragePendingStatement> pendingRead;
197 // The asynchronous read listener. This is a weak ref (storage has ownership)
198 // since it may need to outlive the DBState's database connection.
199 ReadCookieDBListener* readListener;
200 // An array of (baseDomain, cookie) tuples representing data read in
201 // asynchronously. This is merged into hostTable once read is complete.
202 nsTArray<CookieDomainTuple> hostArray;
203 // A hashset of baseDomains read in synchronously, while the async read is
204 // in flight. This is used to keep track of which data in hostArray is stale
205 // when the time comes to merge.
206 nsTHashtable<nsCookieKey> readSet;
208 // DB completion handlers.
209 nsCOMPtr<mozIStorageStatementCallback> insertListener;
210 nsCOMPtr<mozIStorageStatementCallback> updateListener;
211 nsCOMPtr<mozIStorageStatementCallback> removeListener;
212 nsCOMPtr<mozIStorageCompletionCallback> closeListener;
213 };
215 // these constants represent a decision about a cookie based on user prefs.
216 enum CookieStatus
217 {
218 STATUS_ACCEPTED,
219 STATUS_ACCEPT_SESSION,
220 STATUS_REJECTED,
221 // STATUS_REJECTED_WITH_ERROR indicates the cookie should be rejected because
222 // of an error (rather than something the user can control). this is used for
223 // notification purposes, since we only want to notify of rejections where
224 // the user can do something about it (e.g. whitelist the site).
225 STATUS_REJECTED_WITH_ERROR
226 };
228 // Result codes for TryInitDB() and Read().
229 enum OpenDBResult
230 {
231 RESULT_OK,
232 RESULT_RETRY,
233 RESULT_FAILURE
234 };
236 /******************************************************************************
237 * nsCookieService:
238 * class declaration
239 ******************************************************************************/
241 class nsCookieService : public nsICookieService
242 , public nsICookieManager2
243 , public nsIObserver
244 , public nsSupportsWeakReference
245 , public nsIMemoryReporter
246 {
247 private:
248 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
250 public:
251 NS_DECL_ISUPPORTS
252 NS_DECL_NSIOBSERVER
253 NS_DECL_NSICOOKIESERVICE
254 NS_DECL_NSICOOKIEMANAGER
255 NS_DECL_NSICOOKIEMANAGER2
256 NS_DECL_NSIMEMORYREPORTER
258 nsCookieService();
259 virtual ~nsCookieService();
260 static nsICookieService* GetXPCOMSingleton();
261 nsresult Init();
263 /**
264 * Start watching the observer service for messages indicating that an app has
265 * been uninstalled. When an app is uninstalled, we get the cookie service
266 * (thus instantiating it, if necessary) and clear all the cookies for that
267 * app.
268 */
269 static void AppClearDataObserverInit();
271 protected:
272 void PrefChanged(nsIPrefBranch *aPrefBranch);
273 void InitDBStates();
274 OpenDBResult TryInitDB(bool aDeleteExistingDB);
275 nsresult CreateTable();
276 void CloseDBStates();
277 void CleanupCachedStatements();
278 void CleanupDefaultDBConnection();
279 void HandleDBClosed(DBState* aDBState);
280 void HandleCorruptDB(DBState* aDBState);
281 void RebuildCorruptDB(DBState* aDBState);
282 OpenDBResult Read();
283 template<class T> nsCookie* GetCookieFromRow(T &aRow);
284 void AsyncReadComplete();
285 void CancelAsyncRead(bool aPurgeReadSet);
286 void EnsureReadDomain(const nsCookieKey &aKey);
287 void EnsureReadComplete();
288 nsresult NormalizeHost(nsCString &aHost);
289 nsresult GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch);
290 nsresult GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
291 nsresult GetCookieStringCommon(nsIURI *aHostURI, nsIChannel *aChannel, bool aHttpBound, char** aCookie);
292 void GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aHttpBound, uint32_t aAppId, bool aInBrowserElement, bool aIsPrivate, nsCString &aOrigin, nsCString &aCookie);
293 nsresult SetCookieStringCommon(nsIURI *aHostURI, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, bool aFromHttp);
294 void SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, nsDependentCString &aCookieHeader, const nsCString &aServerTime, bool aFromHttp, uint32_t aAppId, bool aInBrowserElement, bool aIsPrivate, nsIChannel* aChannel);
295 bool SetCookieInternal(nsIURI *aHostURI, const nsCookieKey& aKey, bool aRequireHostMatch, const nsCString &aOrigin, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel);
296 void AddInternal(const nsCookieKey& aKey, nsCookie *aCookie, int64_t aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, bool aFromHttp);
297 void RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = nullptr);
298 void AddCookieToList(const nsCookieKey& aKey, nsCookie *aCookie, DBState *aDBState, mozIStorageBindingParamsArray *aParamsArray, bool aWriteToDB = true);
299 void UpdateCookieInList(nsCookie *aCookie, int64_t aLastAccessed, mozIStorageBindingParamsArray *aParamsArray);
300 static bool GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, bool &aEqualsFound);
301 static bool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
302 bool RequireThirdPartyCheck();
303 CookieStatus CheckPrefs(nsIURI *aHostURI, bool aIsForeign, bool aRequireHostMatch, const char *aCookieHeader);
304 bool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch);
305 static bool CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
306 static bool GetExpiry(nsCookieAttributes &aCookie, int64_t aServerTime, int64_t aCurrentTime);
307 void RemoveAllFromMemory();
308 already_AddRefed<nsIArray> PurgeCookies(int64_t aCurrentTimeInUsec);
309 bool FindCookie(const nsCookieKey& aKey, const nsAFlatCString &aOrigin, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter);
310 static void FindStaleCookie(nsCookieEntry *aEntry, int64_t aCurrentTime, nsListIter &aIter);
311 void NotifyRejected(nsIURI *aHostURI);
312 void NotifyThirdParty(nsIURI *aHostURI, bool aAccepted, nsIChannel *aChannel);
313 void NotifyChanged(nsISupports *aSubject, const char16_t *aData);
314 void NotifyPurged(nsICookie2* aCookie);
315 already_AddRefed<nsIArray> CreatePurgeList(nsICookie2* aCookie);
317 /**
318 * This method is used to iterate the cookie hash table and select the ones
319 * that are part of a specific app.
320 */
321 static PLDHashOperator GetCookiesForApp(nsCookieEntry* entry, void* arg);
323 /**
324 * This method is a helper that allows calling nsICookieManager::Remove()
325 * with appId/inBrowserElement parameters.
326 * NOTE: this could be added to a public interface if we happen to need it.
327 */
328 nsresult Remove(const nsACString& aHost, uint32_t aAppId,
329 bool aInBrowserElement, const nsACString& aName,
330 const nsACString& aPath, bool aBlocked);
332 protected:
333 // cached members.
334 nsCOMPtr<nsIObserverService> mObserverService;
335 nsCOMPtr<nsICookiePermission> mPermissionService;
336 nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
337 nsCOMPtr<nsIEffectiveTLDService> mTLDService;
338 nsCOMPtr<nsIIDNService> mIDNService;
339 nsCOMPtr<mozIStorageService> mStorageService;
341 // we have two separate DB states: one for normal browsing and one for
342 // private browsing, switching between them on a per-cookie-request basis.
343 // this state encapsulates both the in-memory table and the on-disk DB.
344 // note that the private states' dbConn should always be null - we never
345 // want to be dealing with the on-disk DB when in private browsing.
346 DBState *mDBState;
347 nsRefPtr<DBState> mDefaultDBState;
348 nsRefPtr<DBState> mPrivateDBState;
350 // cached prefs
351 uint8_t mCookieBehavior; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, LIMITFOREIGN}
352 bool mThirdPartySession;
353 uint16_t mMaxNumberOfCookies;
354 uint16_t mMaxCookiesPerHost;
355 int64_t mCookiePurgeAge;
357 // friends!
358 friend PLDHashOperator purgeCookiesCallback(nsCookieEntry *aEntry, void *aArg);
359 friend class DBListenerErrorHandler;
360 friend class ReadCookieDBListener;
361 friend class CloseCookieDBListener;
363 static nsCookieService* GetSingleton();
364 friend class mozilla::net::CookieServiceParent;
365 };
367 #endif // nsCookieService_h__