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"
17 #include "nsAutoPtr.h"
18 #include "nsHashKeys.h"
19 #include "nsTHashtable.h"
20 #include "mozIStorageStatement.h"
21 #include "mozIStorageAsyncStatement.h"
22 #include "mozIStoragePendingStatement.h"
23 #include "mozIStorageConnection.h"
24 #include "mozIStorageRow.h"
25 #include "mozIStorageCompletionCallback.h"
26 #include "mozIStorageStatementCallback.h"
28 class nsICookiePermission
;
29 class nsIEffectiveTLDService
;
32 class nsIObserverService
;
36 class mozIStorageService
;
37 class mozIThirdPartyUtil
;
38 class ReadCookieDBListener
;
40 struct nsCookieAttributes
;
42 struct nsEnumerationData
;
46 class CookieServiceParent
;
51 class nsCookieKey
: public PLDHashEntryHdr
54 typedef const nsCookieKey
& KeyType
;
55 typedef const nsCookieKey
* KeyTypePointer
;
60 nsCookieKey(const nsCString
&baseDomain
, uint32_t appId
, bool inBrowser
)
61 : mBaseDomain(baseDomain
)
63 , mInBrowserElement(inBrowser
)
66 nsCookieKey(const KeyTypePointer other
)
67 : mBaseDomain(other
->mBaseDomain
)
68 , mAppId(other
->mAppId
)
69 , mInBrowserElement(other
->mInBrowserElement
)
72 nsCookieKey(const KeyType other
)
73 : mBaseDomain(other
.mBaseDomain
)
74 , mAppId(other
.mAppId
)
75 , mInBrowserElement(other
.mInBrowserElement
)
81 bool KeyEquals(KeyTypePointer other
) const
83 return mBaseDomain
== other
->mBaseDomain
&&
84 mAppId
== other
->mAppId
&&
85 mInBrowserElement
== other
->mInBrowserElement
;
88 static KeyTypePointer
KeyToPointer(KeyType aKey
)
93 static PLDHashNumber
HashKey(KeyTypePointer aKey
)
95 // TODO: more efficient way to generate hash?
96 nsAutoCString
temp(aKey
->mBaseDomain
);
98 temp
.Append(aKey
->mAppId
);
100 temp
.Append(aKey
->mInBrowserElement
? 1 : 0);
101 return mozilla::HashString(temp
);
104 enum { ALLOW_MEMMOVE
= true };
106 nsCString mBaseDomain
;
108 bool mInBrowserElement
;
111 // Inherit from nsCookieKey so this can be stored in nsTHashTable
112 // TODO: why aren't we using nsClassHashTable<nsCookieKey, ArrayType>?
113 class nsCookieEntry
: public nsCookieKey
117 typedef nsTArray
< nsRefPtr
<nsCookie
> > ArrayType
;
118 typedef ArrayType::index_type IndexType
;
120 nsCookieEntry(KeyTypePointer aKey
)
124 nsCookieEntry(const nsCookieEntry
& toCopy
)
126 // if we end up here, things will break. nsTHashtable shouldn't
127 // allow this, since we set ALLOW_MEMMOVE to true.
128 NS_NOTREACHED("nsCookieEntry copy constructor is forbidden!");
134 inline ArrayType
& GetCookies() { return mCookies
; }
140 // encapsulates a (key, nsCookie) tuple for temporary storage purposes.
141 struct CookieDomainTuple
144 nsRefPtr
<nsCookie
> cookie
;
147 // encapsulates in-memory and on-disk DB states, so we can
148 // conveniently switch state when entering or exiting private browsing.
151 DBState() : cookieCount(0), cookieOldestTime(INT64_MAX
), corruptFlag(OK
)
156 NS_INLINE_DECL_REFCOUNTING(DBState
)
158 // State of the database connection.
161 CLOSING_FOR_REBUILD
, // corruption detected, connection closing
162 REBUILDING
// close complete, rebuilding database from memory
165 nsTHashtable
<nsCookieEntry
> hostTable
;
166 uint32_t cookieCount
;
167 int64_t cookieOldestTime
;
168 nsCOMPtr
<nsIFile
> cookieFile
;
169 nsCOMPtr
<mozIStorageConnection
> dbConn
;
170 nsCOMPtr
<mozIStorageAsyncStatement
> stmtInsert
;
171 nsCOMPtr
<mozIStorageAsyncStatement
> stmtDelete
;
172 nsCOMPtr
<mozIStorageAsyncStatement
> stmtUpdate
;
173 CorruptFlag corruptFlag
;
175 // Various parts representing asynchronous read state. These are useful
176 // while the background read is taking place.
177 nsCOMPtr
<mozIStorageConnection
> syncConn
;
178 nsCOMPtr
<mozIStorageStatement
> stmtReadDomain
;
179 nsCOMPtr
<mozIStoragePendingStatement
> pendingRead
;
180 // The asynchronous read listener. This is a weak ref (storage has ownership)
181 // since it may need to outlive the DBState's database connection.
182 ReadCookieDBListener
* readListener
;
183 // An array of (baseDomain, cookie) tuples representing data read in
184 // asynchronously. This is merged into hostTable once read is complete.
185 nsTArray
<CookieDomainTuple
> hostArray
;
186 // A hashset of baseDomains read in synchronously, while the async read is
187 // in flight. This is used to keep track of which data in hostArray is stale
188 // when the time comes to merge.
189 nsTHashtable
<nsCookieKey
> readSet
;
191 // DB completion handlers.
192 nsCOMPtr
<mozIStorageStatementCallback
> insertListener
;
193 nsCOMPtr
<mozIStorageStatementCallback
> updateListener
;
194 nsCOMPtr
<mozIStorageStatementCallback
> removeListener
;
195 nsCOMPtr
<mozIStorageCompletionCallback
> closeListener
;
198 // these constants represent a decision about a cookie based on user prefs.
202 STATUS_ACCEPT_SESSION
,
204 // STATUS_REJECTED_WITH_ERROR indicates the cookie should be rejected because
205 // of an error (rather than something the user can control). this is used for
206 // notification purposes, since we only want to notify of rejections where
207 // the user can do something about it (e.g. whitelist the site).
208 STATUS_REJECTED_WITH_ERROR
211 // Result codes for TryInitDB() and Read().
219 /******************************************************************************
222 ******************************************************************************/
224 class nsCookieService
: public nsICookieService
225 , public nsICookieManager2
227 , public nsSupportsWeakReference
233 NS_DECL_NSICOOKIESERVICE
234 NS_DECL_NSICOOKIEMANAGER
235 NS_DECL_NSICOOKIEMANAGER2
238 virtual ~nsCookieService();
239 static nsICookieService
* GetXPCOMSingleton();
243 * Start watching the observer service for messages indicating that an app has
244 * been uninstalled. When an app is uninstalled, we get the cookie service
245 * (thus instantiating it, if necessary) and clear all the cookies for that
248 static void AppClearDataObserverInit();
251 void PrefChanged(nsIPrefBranch
*aPrefBranch
);
253 OpenDBResult
TryInitDB(bool aDeleteExistingDB
);
254 nsresult
CreateTable();
255 void CloseDBStates();
256 void CloseDefaultDBConnection();
257 void HandleDBClosed(DBState
* aDBState
);
258 void HandleCorruptDB(DBState
* aDBState
);
259 void RebuildCorruptDB(DBState
* aDBState
);
261 template<class T
> nsCookie
* GetCookieFromRow(T
&aRow
);
262 void AsyncReadComplete();
263 void CancelAsyncRead(bool aPurgeReadSet
);
264 void EnsureReadDomain(const nsCookieKey
&aKey
);
265 void EnsureReadComplete();
266 nsresult
NormalizeHost(nsCString
&aHost
);
267 nsresult
GetBaseDomain(nsIURI
*aHostURI
, nsCString
&aBaseDomain
, bool &aRequireHostMatch
);
268 nsresult
GetBaseDomainFromHost(const nsACString
&aHost
, nsCString
&aBaseDomain
);
269 nsresult
GetCookieStringCommon(nsIURI
*aHostURI
, nsIChannel
*aChannel
, bool aHttpBound
, char** aCookie
);
270 void GetCookieStringInternal(nsIURI
*aHostURI
, bool aIsForeign
, bool aHttpBound
, uint32_t aAppId
, bool aInBrowserElement
, bool aIsPrivate
, nsCString
&aCookie
);
271 nsresult
SetCookieStringCommon(nsIURI
*aHostURI
, const char *aCookieHeader
, const char *aServerTime
, nsIChannel
*aChannel
, bool aFromHttp
);
272 void SetCookieStringInternal(nsIURI
*aHostURI
, bool aIsForeign
, nsDependentCString
&aCookieHeader
, const nsCString
&aServerTime
, bool aFromHttp
, uint32_t aAppId
, bool aInBrowserElement
, bool aIsPrivate
, nsIChannel
* aChannel
);
273 bool SetCookieInternal(nsIURI
*aHostURI
, const nsCookieKey
& aKey
, bool aRequireHostMatch
, CookieStatus aStatus
, nsDependentCString
&aCookieHeader
, int64_t aServerTime
, bool aFromHttp
, nsIChannel
* aChannel
);
274 void AddInternal(const nsCookieKey
& aKey
, nsCookie
*aCookie
, int64_t aCurrentTimeInUsec
, nsIURI
*aHostURI
, const char *aCookieHeader
, bool aFromHttp
);
275 void RemoveCookieFromList(const nsListIter
&aIter
, mozIStorageBindingParamsArray
*aParamsArray
= NULL
);
276 void AddCookieToList(const nsCookieKey
& aKey
, nsCookie
*aCookie
, DBState
*aDBState
, mozIStorageBindingParamsArray
*aParamsArray
, bool aWriteToDB
= true);
277 void UpdateCookieInList(nsCookie
*aCookie
, int64_t aLastAccessed
, mozIStorageBindingParamsArray
*aParamsArray
);
278 static bool GetTokenValue(nsASingleFragmentCString::const_char_iterator
&aIter
, nsASingleFragmentCString::const_char_iterator
&aEndIter
, nsDependentCSubstring
&aTokenString
, nsDependentCSubstring
&aTokenValue
, bool &aEqualsFound
);
279 static bool ParseAttributes(nsDependentCString
&aCookieHeader
, nsCookieAttributes
&aCookie
);
280 bool RequireThirdPartyCheck();
281 CookieStatus
CheckPrefs(nsIURI
*aHostURI
, bool aIsForeign
, bool aRequireHostMatch
, const char *aCookieHeader
);
282 bool CheckDomain(nsCookieAttributes
&aCookie
, nsIURI
*aHostURI
, const nsCString
&aBaseDomain
, bool aRequireHostMatch
);
283 static bool CheckPath(nsCookieAttributes
&aCookie
, nsIURI
*aHostURI
);
284 static bool GetExpiry(nsCookieAttributes
&aCookie
, int64_t aServerTime
, int64_t aCurrentTime
);
285 void RemoveAllFromMemory();
286 already_AddRefed
<nsIArray
> PurgeCookies(int64_t aCurrentTimeInUsec
);
287 bool FindCookie(const nsCookieKey
& aKey
, const nsAFlatCString
&aHost
, const nsAFlatCString
&aName
, const nsAFlatCString
&aPath
, nsListIter
&aIter
);
288 static void FindStaleCookie(nsCookieEntry
*aEntry
, int64_t aCurrentTime
, nsListIter
&aIter
);
289 void NotifyRejected(nsIURI
*aHostURI
);
290 void NotifyChanged(nsISupports
*aSubject
, const PRUnichar
*aData
);
291 void NotifyPurged(nsICookie2
* aCookie
);
292 already_AddRefed
<nsIArray
> CreatePurgeList(nsICookie2
* aCookie
);
295 * This method is used to iterate the cookie hash table and select the ones
296 * that are part of a specific app.
298 static PLDHashOperator
GetCookiesForApp(nsCookieEntry
* entry
, void* arg
);
301 * This method is a helper that allows calling nsICookieManager::Remove()
302 * with appId/inBrowserElement parameters.
303 * NOTE: this could be added to a public interface if we happen to need it.
305 nsresult
Remove(const nsACString
& aHost
, uint32_t aAppId
,
306 bool aInBrowserElement
, const nsACString
& aName
,
307 const nsACString
& aPath
, bool aBlocked
);
311 nsCOMPtr
<nsIObserverService
> mObserverService
;
312 nsCOMPtr
<nsICookiePermission
> mPermissionService
;
313 nsCOMPtr
<mozIThirdPartyUtil
> mThirdPartyUtil
;
314 nsCOMPtr
<nsIEffectiveTLDService
> mTLDService
;
315 nsCOMPtr
<nsIIDNService
> mIDNService
;
316 nsCOMPtr
<mozIStorageService
> mStorageService
;
318 // we have two separate DB states: one for normal browsing and one for
319 // private browsing, switching between them on a per-cookie-request basis.
320 // this state encapsulates both the in-memory table and the on-disk DB.
321 // note that the private states' dbConn should always be null - we never
322 // want to be dealing with the on-disk DB when in private browsing.
324 nsRefPtr
<DBState
> mDefaultDBState
;
325 nsRefPtr
<DBState
> mPrivateDBState
;
328 uint8_t mCookieBehavior
; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, LIMITFOREIGN}
329 bool mThirdPartySession
;
330 uint16_t mMaxNumberOfCookies
;
331 uint16_t mMaxCookiesPerHost
;
332 int64_t mCookiePurgeAge
;
335 friend PLDHashOperator
purgeCookiesCallback(nsCookieEntry
*aEntry
, void *aArg
);
336 friend class DBListenerErrorHandler
;
337 friend class ReadCookieDBListener
;
338 friend class CloseCookieDBListener
;
340 static nsCookieService
* GetSingleton();
341 friend class mozilla::net::CookieServiceParent
;
344 #endif // nsCookieService_h__