Coverage Report

Created: 2018-09-25 14:53

/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__