Line data Source code
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/. */
5 :
6 : #ifndef nsCookieService_h__
7 : #define nsCookieService_h__
8 :
9 : #include "nsICookieService.h"
10 : #include "nsICookieManager.h"
11 : #include "nsICookieManager2.h"
12 : #include "nsIObserver.h"
13 : #include "nsWeakReference.h"
14 :
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"
28 : #include "mozIStorageFunction.h"
29 : #include "nsIVariant.h"
30 : #include "nsIFile.h"
31 : #include "mozilla/BasePrincipal.h"
32 : #include "mozilla/MemoryReporting.h"
33 : #include "mozilla/Maybe.h"
34 :
35 : using mozilla::OriginAttributes;
36 :
37 : class nsICookiePermission;
38 : class nsIEffectiveTLDService;
39 : class nsIIDNService;
40 : class nsIPrefBranch;
41 : class nsIObserverService;
42 : class nsIURI;
43 : class nsIChannel;
44 : class nsIArray;
45 : class mozIStorageService;
46 : class mozIThirdPartyUtil;
47 : class ReadCookieDBListener;
48 :
49 : struct nsCookieAttributes;
50 : struct nsListIter;
51 :
52 : namespace mozilla {
53 : namespace net {
54 : class CookieServiceParent;
55 : } // namespace net
56 : } // namespace mozilla
57 :
58 : // hash key class
59 0 : class nsCookieKey : public PLDHashEntryHdr
60 : {
61 : public:
62 : typedef const nsCookieKey& KeyType;
63 : typedef const nsCookieKey* KeyTypePointer;
64 :
65 0 : nsCookieKey()
66 0 : {}
67 :
68 6 : nsCookieKey(const nsCString &baseDomain, const OriginAttributes &attrs)
69 6 : : mBaseDomain(baseDomain)
70 6 : , mOriginAttributes(attrs)
71 6 : {}
72 :
73 1 : explicit nsCookieKey(KeyTypePointer other)
74 1 : : mBaseDomain(other->mBaseDomain)
75 1 : , mOriginAttributes(other->mOriginAttributes)
76 1 : {}
77 :
78 : nsCookieKey(KeyType other)
79 : : mBaseDomain(other.mBaseDomain)
80 : , mOriginAttributes(other.mOriginAttributes)
81 : {}
82 :
83 7 : ~nsCookieKey()
84 7 : {}
85 :
86 0 : bool KeyEquals(KeyTypePointer other) const
87 : {
88 0 : return mBaseDomain == other->mBaseDomain &&
89 0 : mOriginAttributes == other->mOriginAttributes;
90 : }
91 :
92 8 : static KeyTypePointer KeyToPointer(KeyType aKey)
93 : {
94 8 : return &aKey;
95 : }
96 :
97 1 : static PLDHashNumber HashKey(KeyTypePointer aKey)
98 : {
99 : // TODO: more efficient way to generate hash?
100 2 : nsAutoCString temp(aKey->mBaseDomain);
101 1 : temp.Append('#');
102 2 : nsAutoCString suffix;
103 1 : aKey->mOriginAttributes.CreateSuffix(suffix);
104 1 : temp.Append(suffix);
105 2 : return mozilla::HashString(temp);
106 : }
107 :
108 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
109 :
110 : enum { ALLOW_MEMMOVE = true };
111 :
112 : nsCString mBaseDomain;
113 : OriginAttributes mOriginAttributes;
114 : };
115 :
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< RefPtr<nsCookie> > ArrayType;
123 : typedef ArrayType::index_type IndexType;
124 :
125 0 : explicit nsCookieEntry(KeyTypePointer aKey)
126 0 : : nsCookieKey(aKey)
127 0 : {}
128 :
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 : }
135 :
136 0 : ~nsCookieEntry()
137 0 : {}
138 :
139 0 : inline ArrayType& GetCookies() { return mCookies; }
140 :
141 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
142 :
143 : private:
144 : ArrayType mCookies;
145 : };
146 :
147 : // encapsulates a (key, nsCookie) tuple for temporary storage purposes.
148 0 : struct CookieDomainTuple
149 : {
150 : nsCookieKey key;
151 : RefPtr<nsCookie> cookie;
152 :
153 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
154 : };
155 :
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 final
159 : {
160 2 : DBState() : cookieCount(0), cookieOldestTime(INT64_MAX), corruptFlag(OK)
161 : {
162 2 : }
163 :
164 : private:
165 : // Private destructor, to discourage deletion outside of Release():
166 0 : ~DBState()
167 0 : {
168 0 : }
169 :
170 : public:
171 8 : NS_INLINE_DECL_REFCOUNTING(DBState)
172 :
173 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
174 :
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 : };
181 :
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;
191 :
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;
207 :
208 : // DB completion handlers.
209 : nsCOMPtr<mozIStorageStatementCallback> insertListener;
210 : nsCOMPtr<mozIStorageStatementCallback> updateListener;
211 : nsCOMPtr<mozIStorageStatementCallback> removeListener;
212 : nsCOMPtr<mozIStorageCompletionCallback> closeListener;
213 : };
214 :
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 : };
227 :
228 : // Result codes for TryInitDB() and Read().
229 : enum OpenDBResult
230 : {
231 : RESULT_OK,
232 : RESULT_RETRY,
233 : RESULT_FAILURE
234 : };
235 :
236 : /******************************************************************************
237 : * nsCookieService:
238 : * class declaration
239 : ******************************************************************************/
240 :
241 : class nsCookieService final : 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;
249 :
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
257 :
258 : nsCookieService();
259 : static nsICookieService* GetXPCOMSingleton();
260 : nsresult Init();
261 :
262 : /**
263 : * Start watching the observer service for messages indicating that an app has
264 : * been uninstalled. When an app is uninstalled, we get the cookie service
265 : * (thus instantiating it, if necessary) and clear all the cookies for that
266 : * app.
267 : */
268 : static void AppClearDataObserverInit();
269 :
270 : protected:
271 : virtual ~nsCookieService();
272 :
273 : void PrefChanged(nsIPrefBranch *aPrefBranch);
274 : void InitDBStates();
275 : OpenDBResult TryInitDB(bool aDeleteExistingDB);
276 : nsresult CreateTableWorker(const char* aName);
277 : nsresult CreateIndex();
278 : nsresult CreateTable();
279 : nsresult CreateTableForSchemaVersion6();
280 : nsresult CreateTableForSchemaVersion5();
281 : void CloseDBStates();
282 : void CleanupCachedStatements();
283 : void CleanupDefaultDBConnection();
284 : void HandleDBClosed(DBState* aDBState);
285 : void HandleCorruptDB(DBState* aDBState);
286 : void RebuildCorruptDB(DBState* aDBState);
287 : OpenDBResult Read();
288 : template<class T> nsCookie* GetCookieFromRow(T &aRow, const OriginAttributes& aOriginAttributes);
289 : void AsyncReadComplete();
290 : void CancelAsyncRead(bool aPurgeReadSet);
291 : void EnsureReadDomain(const nsCookieKey &aKey);
292 : void EnsureReadComplete();
293 : nsresult NormalizeHost(nsCString &aHost);
294 : nsresult GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch);
295 : nsresult GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
296 : nsresult GetCookieStringCommon(nsIURI *aHostURI, nsIChannel *aChannel, bool aHttpBound, char** aCookie);
297 : void GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aHttpBound, const OriginAttributes& aOriginAttrs, nsCString &aCookie);
298 : nsresult SetCookieStringCommon(nsIURI *aHostURI, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, bool aFromHttp);
299 : void SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, nsDependentCString &aCookieHeader, const nsCString &aServerTime, bool aFromHttp, const OriginAttributes &aOriginAttrs, nsIChannel* aChannel);
300 : bool SetCookieInternal(nsIURI *aHostURI, const nsCookieKey& aKey, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel);
301 : void AddInternal(const nsCookieKey& aKey, nsCookie *aCookie, int64_t aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, bool aFromHttp);
302 : void RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = nullptr);
303 : void AddCookieToList(const nsCookieKey& aKey, nsCookie *aCookie, DBState *aDBState, mozIStorageBindingParamsArray *aParamsArray, bool aWriteToDB = true);
304 : void UpdateCookieInList(nsCookie *aCookie, int64_t aLastAccessed, mozIStorageBindingParamsArray *aParamsArray);
305 : static bool GetTokenValue(nsACString::const_char_iterator &aIter, nsACString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, bool &aEqualsFound);
306 : static bool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
307 : bool RequireThirdPartyCheck();
308 : CookieStatus CheckPrefs(nsIURI *aHostURI, bool aIsForeign, const char *aCookieHeader);
309 : bool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch);
310 : static bool CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
311 : static bool CheckPrefixes(nsCookieAttributes &aCookie, bool aSecureRequest);
312 : static bool GetExpiry(nsCookieAttributes &aCookie, int64_t aServerTime, int64_t aCurrentTime);
313 : void RemoveAllFromMemory();
314 : already_AddRefed<nsIArray> PurgeCookies(int64_t aCurrentTimeInUsec);
315 : bool FindCookie(const nsCookieKey& aKey, const nsCString& aHost, const nsCString& aName, const nsCString& aPath, nsListIter &aIter);
316 : bool FindSecureCookie(const nsCookieKey& aKey, nsCookie* aCookie);
317 : int64_t FindStaleCookie(nsCookieEntry *aEntry, int64_t aCurrentTime, nsIURI* aSource, const mozilla::Maybe<bool> &aIsSecure, nsListIter &aIter);
318 : void TelemetryForEvictingStaleCookie(nsCookie* aEvicted, int64_t oldestCookieTime);
319 : void NotifyRejected(nsIURI *aHostURI);
320 : void NotifyThirdParty(nsIURI *aHostURI, bool aAccepted, nsIChannel *aChannel);
321 : void NotifyChanged(nsISupports *aSubject, const char16_t *aData, bool aOldCookieIsSession = false);
322 : void NotifyPurged(nsICookie2* aCookie);
323 : already_AddRefed<nsIArray> CreatePurgeList(nsICookie2* aCookie);
324 : void UpdateCookieOldestTime(DBState* aDBState, nsCookie* aCookie);
325 :
326 : nsresult GetCookiesWithOriginAttributes(const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain, nsISimpleEnumerator **aEnumerator);
327 : nsresult RemoveCookiesWithOriginAttributes(const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain);
328 :
329 : /**
330 : * This method is a helper that allows calling nsICookieManager::Remove()
331 : * with OriginAttributes parameter.
332 : * NOTE: this could be added to a public interface if we happen to need it.
333 : */
334 : nsresult Remove(const nsACString& aHost, const OriginAttributes& aAttrs,
335 : const nsACString& aName, const nsACString& aPath,
336 : bool aBlocked);
337 :
338 : protected:
339 : // cached members.
340 : nsCOMPtr<nsICookiePermission> mPermissionService;
341 : nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil;
342 : nsCOMPtr<nsIEffectiveTLDService> mTLDService;
343 : nsCOMPtr<nsIIDNService> mIDNService;
344 : nsCOMPtr<mozIStorageService> mStorageService;
345 :
346 : // we have two separate DB states: one for normal browsing and one for
347 : // private browsing, switching between them on a per-cookie-request basis.
348 : // this state encapsulates both the in-memory table and the on-disk DB.
349 : // note that the private states' dbConn should always be null - we never
350 : // want to be dealing with the on-disk DB when in private browsing.
351 : DBState *mDBState;
352 : RefPtr<DBState> mDefaultDBState;
353 : RefPtr<DBState> mPrivateDBState;
354 :
355 : // cached prefs
356 : uint8_t mCookieBehavior; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, LIMITFOREIGN}
357 : bool mThirdPartySession;
358 : bool mLeaveSecureAlone;
359 : uint16_t mMaxNumberOfCookies;
360 : uint16_t mMaxCookiesPerHost;
361 : int64_t mCookiePurgeAge;
362 :
363 : // friends!
364 : friend class DBListenerErrorHandler;
365 : friend class ReadCookieDBListener;
366 : friend class CloseCookieDBListener;
367 :
368 : static nsCookieService* GetSingleton();
369 : friend class mozilla::net::CookieServiceParent;
370 : };
371 :
372 : #endif // nsCookieService_h__
|