/src/mozilla-central/netwerk/cookie/nsCookieService.h
Line | Count | Source (jump to first uncovered line) |
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 "nsIObserver.h" |
12 | | #include "nsWeakReference.h" |
13 | | |
14 | | #include "nsCookie.h" |
15 | | #include "nsCookieKey.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/Atomics.h" |
32 | | #include "mozilla/BasePrincipal.h" |
33 | | #include "mozilla/MemoryReporting.h" |
34 | | #include "mozilla/Maybe.h" |
35 | | #include "mozilla/Monitor.h" |
36 | | #include "mozilla/UniquePtr.h" |
37 | | |
38 | | |
39 | | using mozilla::OriginAttributes; |
40 | | |
41 | | class nsICookiePermission; |
42 | | class nsIEffectiveTLDService; |
43 | | class nsIIDNService; |
44 | | class nsIPrefBranch; |
45 | | class nsIObserverService; |
46 | | class nsIURI; |
47 | | class nsIChannel; |
48 | | class nsIArray; |
49 | | class nsIThread; |
50 | | class mozIStorageService; |
51 | | class mozIThirdPartyUtil; |
52 | | class ReadCookieDBListener; |
53 | | |
54 | | struct nsListIter; |
55 | | |
56 | | namespace mozilla { |
57 | | namespace net { |
58 | | class nsCookieKey; |
59 | | class CookieServiceParent; |
60 | | } // namespace net |
61 | | } // namespace mozilla |
62 | | |
63 | | using mozilla::net::nsCookieKey; |
64 | | // Inherit from nsCookieKey so this can be stored in nsTHashTable |
65 | | // TODO: why aren't we using nsClassHashTable<nsCookieKey, ArrayType>? |
66 | | class nsCookieEntry : public nsCookieKey |
67 | | { |
68 | | public: |
69 | | // Hash methods |
70 | | typedef nsTArray< RefPtr<nsCookie> > ArrayType; |
71 | | typedef ArrayType::index_type IndexType; |
72 | | |
73 | | explicit nsCookieEntry(KeyTypePointer aKey) |
74 | | : nsCookieKey(aKey) |
75 | 0 | {} |
76 | | |
77 | | nsCookieEntry(const nsCookieEntry& toCopy) |
78 | 0 | { |
79 | 0 | // if we end up here, things will break. nsTHashtable shouldn't |
80 | 0 | // allow this, since we set ALLOW_MEMMOVE to true. |
81 | 0 | MOZ_ASSERT_UNREACHABLE("nsCookieEntry copy constructor is forbidden!"); |
82 | 0 | } |
83 | | |
84 | 0 | ~nsCookieEntry() = default; |
85 | | |
86 | 0 | inline ArrayType& GetCookies() { return mCookies; } |
87 | | |
88 | | size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
89 | | |
90 | | private: |
91 | | ArrayType mCookies; |
92 | | }; |
93 | | |
94 | | // struct for a constant cookie for threadsafe |
95 | | struct ConstCookie |
96 | | { |
97 | | ConstCookie(const nsCString& aName, |
98 | | const nsCString& aValue, |
99 | | const nsCString& aHost, |
100 | | const nsCString& aPath, |
101 | | int64_t aExpiry, |
102 | | int64_t aLastAccessed, |
103 | | int64_t aCreationTime, |
104 | | bool aIsSecure, |
105 | | bool aIsHttpOnly, |
106 | | const OriginAttributes &aOriginAttributes, |
107 | | int32_t aSameSite) |
108 | | : name(aName) |
109 | | , value(aValue) |
110 | | , host(aHost) |
111 | | , path(aPath) |
112 | | , expiry(aExpiry) |
113 | | , lastAccessed(aLastAccessed) |
114 | | , creationTime(aCreationTime) |
115 | | , isSecure(aIsSecure) |
116 | | , isHttpOnly(aIsHttpOnly) |
117 | | , originAttributes(aOriginAttributes) |
118 | | , sameSite(aSameSite) |
119 | 0 | { |
120 | 0 | } |
121 | | |
122 | | const nsCString name; |
123 | | const nsCString value; |
124 | | const nsCString host; |
125 | | const nsCString path; |
126 | | const int64_t expiry; |
127 | | const int64_t lastAccessed; |
128 | | const int64_t creationTime; |
129 | | const bool isSecure; |
130 | | const bool isHttpOnly; |
131 | | const OriginAttributes originAttributes; |
132 | | const int32_t sameSite; |
133 | | }; |
134 | | |
135 | | // encapsulates a (key, nsCookie) tuple for temporary storage purposes. |
136 | | struct CookieDomainTuple |
137 | | { |
138 | | nsCookieKey key; |
139 | | mozilla::UniquePtr<ConstCookie> cookie; |
140 | | }; |
141 | | |
142 | | // encapsulates in-memory and on-disk DB states, so we can |
143 | | // conveniently switch state when entering or exiting private browsing. |
144 | | struct DBState final |
145 | | { |
146 | | DBState() |
147 | | : cookieCount(0) |
148 | | , cookieOldestTime(INT64_MAX) |
149 | | , corruptFlag(OK) |
150 | | , readListener(nullptr) |
151 | 0 | { |
152 | 0 | } |
153 | | |
154 | | private: |
155 | | // Private destructor, to discourage deletion outside of Release(): |
156 | 0 | ~DBState() = default; |
157 | | |
158 | | public: |
159 | | NS_INLINE_DECL_REFCOUNTING(DBState) |
160 | | |
161 | | size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
162 | | |
163 | | // State of the database connection. |
164 | | enum CorruptFlag { |
165 | | OK, // normal |
166 | | CLOSING_FOR_REBUILD, // corruption detected, connection closing |
167 | | REBUILDING // close complete, rebuilding database from memory |
168 | | }; |
169 | | |
170 | | nsTHashtable<nsCookieEntry> hostTable; |
171 | | uint32_t cookieCount; |
172 | | int64_t cookieOldestTime; |
173 | | nsCOMPtr<nsIFile> cookieFile; |
174 | | nsCOMPtr<mozIStorageConnection> dbConn; |
175 | | nsCOMPtr<mozIStorageAsyncStatement> stmtInsert; |
176 | | nsCOMPtr<mozIStorageAsyncStatement> stmtDelete; |
177 | | nsCOMPtr<mozIStorageAsyncStatement> stmtUpdate; |
178 | | CorruptFlag corruptFlag; |
179 | | |
180 | | // Various parts representing asynchronous read state. These are useful |
181 | | // while the background read is taking place. |
182 | | nsCOMPtr<mozIStorageConnection> syncConn; |
183 | | nsCOMPtr<mozIStorageStatement> stmtReadDomain; |
184 | | // The asynchronous read listener. This is a weak ref (storage has ownership) |
185 | | // since it may need to outlive the DBState's database connection. |
186 | | ReadCookieDBListener* readListener; |
187 | | |
188 | | // DB completion handlers. |
189 | | nsCOMPtr<mozIStorageStatementCallback> insertListener; |
190 | | nsCOMPtr<mozIStorageStatementCallback> updateListener; |
191 | | nsCOMPtr<mozIStorageStatementCallback> removeListener; |
192 | | nsCOMPtr<mozIStorageCompletionCallback> closeListener; |
193 | | }; |
194 | | |
195 | | // these constants represent a decision about a cookie based on user prefs. |
196 | | enum CookieStatus |
197 | | { |
198 | | STATUS_ACCEPTED, |
199 | | STATUS_ACCEPT_SESSION, |
200 | | STATUS_REJECTED, |
201 | | // STATUS_REJECTED_WITH_ERROR indicates the cookie should be rejected because |
202 | | // of an error (rather than something the user can control). this is used for |
203 | | // notification purposes, since we only want to notify of rejections where |
204 | | // the user can do something about it (e.g. whitelist the site). |
205 | | STATUS_REJECTED_WITH_ERROR |
206 | | }; |
207 | | |
208 | | // Result codes for TryInitDB() and Read(). |
209 | | enum OpenDBResult |
210 | | { |
211 | | RESULT_OK, |
212 | | RESULT_RETRY, |
213 | | RESULT_FAILURE |
214 | | }; |
215 | | |
216 | | /****************************************************************************** |
217 | | * nsCookieService: |
218 | | * class declaration |
219 | | ******************************************************************************/ |
220 | | |
221 | | // struct for temporarily storing cookie attributes during header parsing |
222 | | struct nsCookieAttributes |
223 | | { |
224 | | nsAutoCString name; |
225 | | nsAutoCString value; |
226 | | nsAutoCString host; |
227 | | nsAutoCString path; |
228 | | nsAutoCString expires; |
229 | | nsAutoCString maxage; |
230 | | int64_t expiryTime; |
231 | | bool isSession; |
232 | | bool isSecure; |
233 | | bool isHttpOnly; |
234 | | int8_t sameSite; |
235 | | }; |
236 | | |
237 | | class nsCookieService final : public nsICookieService |
238 | | , public nsICookieManager |
239 | | , public nsIObserver |
240 | | , public nsSupportsWeakReference |
241 | | , public nsIMemoryReporter |
242 | | { |
243 | | private: |
244 | | size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
245 | | |
246 | | static bool sSameSiteEnabled; // cached pref |
247 | | |
248 | | public: |
249 | | NS_DECL_ISUPPORTS |
250 | | NS_DECL_NSIOBSERVER |
251 | | NS_DECL_NSICOOKIESERVICE |
252 | | NS_DECL_NSICOOKIEMANAGER |
253 | | NS_DECL_NSIMEMORYREPORTER |
254 | | |
255 | | nsCookieService(); |
256 | | static already_AddRefed<nsICookieService> GetXPCOMSingleton(); |
257 | | nsresult Init(); |
258 | | |
259 | | /** |
260 | | * Start watching the observer service for messages indicating that an app has |
261 | | * been uninstalled. When an app is uninstalled, we get the cookie service |
262 | | * (thus instantiating it, if necessary) and clear all the cookies for that |
263 | | * app. |
264 | | */ |
265 | | static void AppClearDataObserverInit(); |
266 | | static nsAutoCString GetPathFromURI(nsIURI *aHostURI); |
267 | | static nsresult GetBaseDomain(nsIEffectiveTLDService *aTLDService, nsIURI *aHostURI, nsCString &aBaseDomain, bool &aRequireHostMatch); |
268 | | static nsresult GetBaseDomainFromHost(nsIEffectiveTLDService *aTLDService, const nsACString &aHost, nsCString &aBaseDomain); |
269 | | static bool DomainMatches(nsCookie* aCookie, const nsACString& aHost); |
270 | | static bool IsSameSiteEnabled(); |
271 | | static bool PathMatches(nsCookie* aCookie, const nsACString& aPath); |
272 | | static bool CanSetCookie(nsIURI *aHostURI, const nsCookieKey& aKey, nsCookieAttributes &aCookieAttributes, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel, bool aLeaveSercureAlone, bool &aSetCookie, mozIThirdPartyUtil* aThirdPartyUtil); |
273 | | static CookieStatus CheckPrefs(nsICookiePermission *aPermissionServices, uint8_t aCookieBehavior, bool aThirdPartySession, bool aThirdPartyNonsecureSession, nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource, bool aIsFirstPartyStorageAccessGranted, const char *aCookieHeader, const int aNumOfCookies, const OriginAttributes& aOriginAttrs, uint32_t* aRejectedReason); |
274 | | static int64_t ParseServerTime(const nsCString &aServerTime); |
275 | | void GetCookiesForURI(nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource, bool aFirstPartyStorageAccessGranted, bool aIsSafeTopLevelNav, bool aIsTopLevelForeign, bool aHttpBound, const OriginAttributes& aOriginAttrs, nsTArray<nsCookie*>& aCookieList); |
276 | | |
277 | | protected: |
278 | | virtual ~nsCookieService(); |
279 | | |
280 | | void PrefChanged(nsIPrefBranch *aPrefBranch); |
281 | | void InitDBStates(); |
282 | | OpenDBResult TryInitDB(bool aDeleteExistingDB); |
283 | | void InitDBConn(); |
284 | | nsresult InitDBConnInternal(); |
285 | | nsresult CreateTableWorker(const char* aName); |
286 | | nsresult CreateIndex(); |
287 | | nsresult CreateTable(); |
288 | | nsresult CreateTableForSchemaVersion6(); |
289 | | nsresult CreateTableForSchemaVersion5(); |
290 | | void CloseDBStates(); |
291 | | void CleanupCachedStatements(); |
292 | | void CleanupDefaultDBConnection(); |
293 | | void HandleDBClosed(DBState* aDBState); |
294 | | void HandleCorruptDB(DBState* aDBState); |
295 | | void RebuildCorruptDB(DBState* aDBState); |
296 | | OpenDBResult Read(); |
297 | | mozilla::UniquePtr<ConstCookie> GetCookieFromRow(mozIStorageStatement *aRow, const OriginAttributes &aOriginAttributes); |
298 | | void EnsureReadComplete(bool aInitDBConn); |
299 | | nsresult NormalizeHost(nsCString &aHost); |
300 | | nsresult GetCookieStringCommon(nsIURI *aHostURI, nsIChannel *aChannel, bool aHttpBound, char** aCookie); |
301 | | void GetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource, bool aFirstPartyStorageAccessGranted, bool aIsSafeTopLevelNav, bool aIsTopLevelForeign, bool aHttpBound, const OriginAttributes& aOriginAttrs, nsCString &aCookie); |
302 | | nsresult SetCookieStringCommon(nsIURI *aHostURI, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, bool aFromHttp); |
303 | | void SetCookieStringInternal(nsIURI *aHostURI, bool aIsForeign, bool aIsTrackingResource, bool aFirstPartyStorageAccessGranted, nsDependentCString &aCookieHeader, const nsCString &aServerTime, bool aFromHttp, const OriginAttributes &aOriginAttrs, nsIChannel* aChannel); |
304 | | bool SetCookieInternal(nsIURI *aHostURI, const nsCookieKey& aKey, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel); |
305 | | void AddInternal(const nsCookieKey& aKey, nsCookie *aCookie, int64_t aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, bool aFromHttp); |
306 | | void RemoveCookieFromList(const nsListIter &aIter, mozIStorageBindingParamsArray *aParamsArray = nullptr); |
307 | | void AddCookieToList(const nsCookieKey& aKey, nsCookie *aCookie, DBState *aDBState, mozIStorageBindingParamsArray *aParamsArray, bool aWriteToDB = true); |
308 | | void UpdateCookieInList(nsCookie *aCookie, int64_t aLastAccessed, mozIStorageBindingParamsArray *aParamsArray); |
309 | | static bool GetTokenValue(nsACString::const_char_iterator &aIter, nsACString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, bool &aEqualsFound); |
310 | | static bool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie); |
311 | | bool RequireThirdPartyCheck(); |
312 | | static bool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch); |
313 | | static bool CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI); |
314 | | static bool CheckPrefixes(nsCookieAttributes &aCookie, bool aSecureRequest); |
315 | | static bool GetExpiry(nsCookieAttributes &aCookie, int64_t aServerTime, int64_t aCurrentTime); |
316 | | void RemoveAllFromMemory(); |
317 | | already_AddRefed<nsIArray> PurgeCookies(int64_t aCurrentTimeInUsec); |
318 | | bool FindCookie(const nsCookieKey& aKey, const nsCString& aHost, const nsCString& aName, const nsCString& aPath, nsListIter &aIter); |
319 | | bool FindSecureCookie(const nsCookieKey& aKey, nsCookie* aCookie); |
320 | | void FindStaleCookies(nsCookieEntry *aEntry, int64_t aCurrentTime, const mozilla::Maybe<bool> &aIsSecure, nsTArray<nsListIter>& aOutput, uint32_t aLimit); |
321 | | void TelemetryForEvictingStaleCookie(nsCookie* aEvicted, int64_t oldestCookieTime); |
322 | | void NotifyRejected(nsIURI *aHostURI, nsIChannel* aChannel, uint32_t aRejectedReason); |
323 | | void NotifyThirdParty(nsIURI *aHostURI, bool aAccepted, nsIChannel *aChannel); |
324 | | void NotifyChanged(nsISupports *aSubject, const char16_t *aData, bool aOldCookieIsSession = false, bool aFromHttp = false); |
325 | | void NotifyPurged(nsICookie2* aCookie); |
326 | | already_AddRefed<nsIArray> CreatePurgeList(nsICookie2* aCookie); |
327 | | void CreateOrUpdatePurgeList(nsIArray** aPurgeList, nsICookie2* aCookie); |
328 | | void UpdateCookieOldestTime(DBState* aDBState, nsCookie* aCookie); |
329 | | |
330 | | nsresult GetCookiesWithOriginAttributes(const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain, nsISimpleEnumerator **aEnumerator); |
331 | | nsresult RemoveCookiesWithOriginAttributes(const mozilla::OriginAttributesPattern& aPattern, const nsCString& aBaseDomain); |
332 | | |
333 | | /** |
334 | | * This method is a helper that allows calling nsICookieManager::Remove() |
335 | | * with OriginAttributes parameter. |
336 | | * NOTE: this could be added to a public interface if we happen to need it. |
337 | | */ |
338 | | nsresult Remove(const nsACString& aHost, const OriginAttributes& aAttrs, |
339 | | const nsACString& aName, const nsACString& aPath, |
340 | | bool aBlocked); |
341 | | |
342 | | protected: |
343 | | // cached members. |
344 | | nsCOMPtr<nsICookiePermission> mPermissionService; |
345 | | nsCOMPtr<mozIThirdPartyUtil> mThirdPartyUtil; |
346 | | nsCOMPtr<nsIEffectiveTLDService> mTLDService; |
347 | | nsCOMPtr<nsIIDNService> mIDNService; |
348 | | nsCOMPtr<mozIStorageService> mStorageService; |
349 | | |
350 | | // we have two separate DB states: one for normal browsing and one for |
351 | | // private browsing, switching between them on a per-cookie-request basis. |
352 | | // this state encapsulates both the in-memory table and the on-disk DB. |
353 | | // note that the private states' dbConn should always be null - we never |
354 | | // want to be dealing with the on-disk DB when in private browsing. |
355 | | DBState *mDBState; |
356 | | RefPtr<DBState> mDefaultDBState; |
357 | | RefPtr<DBState> mPrivateDBState; |
358 | | |
359 | | // cached prefs |
360 | | uint8_t mCookieBehavior; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, LIMITFOREIGN} |
361 | | bool mThirdPartySession; |
362 | | bool mThirdPartyNonsecureSession; |
363 | | bool mLeaveSecureAlone; |
364 | | uint16_t mMaxNumberOfCookies; |
365 | | uint16_t mMaxCookiesPerHost; |
366 | | uint16_t mCookieQuotaPerHost; |
367 | | int64_t mCookiePurgeAge; |
368 | | |
369 | | // thread |
370 | | nsCOMPtr<nsIThread> mThread; |
371 | | mozilla::Monitor mMonitor; |
372 | | mozilla::Atomic<bool> mInitializedDBStates; |
373 | | mozilla::Atomic<bool> mInitializedDBConn; |
374 | | mozilla::TimeStamp mEndInitDBConn; |
375 | | nsTArray<CookieDomainTuple> mReadArray; |
376 | | |
377 | | // friends! |
378 | | friend class DBListenerErrorHandler; |
379 | | friend class ReadCookieDBListener; |
380 | | friend class CloseCookieDBListener; |
381 | | |
382 | | static already_AddRefed<nsCookieService> GetSingleton(); |
383 | | friend class mozilla::net::CookieServiceParent; |
384 | | }; |
385 | | |
386 | | #endif // nsCookieService_h__ |