1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
23 * Neil Deakin <enndeakin@sympatico.ca>
24 * Johnny Stenback <jst@mozilla.com>
25 * Ehsan Akhgari <ehsan.akhgari@gmail.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef nsDOMStorage_h___
42 #define nsDOMStorage_h___
45 #include "nsAutoPtr.h"
46 #include "nsIDOMStorageObsolete.h"
47 #include "nsIDOMStorage.h"
48 #include "nsIDOMStorageList.h"
49 #include "nsIDOMStorageItem.h"
50 #include "nsIPermissionManager.h"
51 #include "nsInterfaceHashtable.h"
52 #include "nsVoidArray.h"
54 #include "nsPIDOMStorage.h"
55 #include "nsIDOMToString.h"
56 #include "nsDOMEvent.h"
57 #include "nsIDOMStorageEvent.h"
58 #include "nsIDOMStorageEventObsolete.h"
59 #include "nsIDOMStorageManager.h"
60 #include "nsCycleCollectionParticipant.h"
61 #include "nsIObserver.h"
63 #include "nsWeakReference.h"
65 #define NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER "domstorage-flush-timer"
68 #include "nsDOMStorageDBWrapper.h"
71 #define IS_PERMISSION_ALLOWED(perm) \
72 ((perm) != nsIPermissionManager::UNKNOWN_ACTION && \
73 (perm) != nsIPermissionManager::DENY_ACTION)
77 class nsDOMStorageItem
;
78 class nsDOMStoragePersistentDB
;
85 using mozilla::dom::StorageParent
;
89 class nsDOMStorageEntry
: public nsVoidPtrHashKey
92 nsDOMStorageEntry(KeyTypePointer aStr
);
93 nsDOMStorageEntry(const nsDOMStorageEntry
& aToCopy
);
96 // weak reference so that it can be deleted when no longer used
97 DOMStorageImpl
* mStorage
;
100 class nsSessionStorageEntry
: public nsStringHashKey
103 nsSessionStorageEntry(KeyTypePointer aStr
);
104 nsSessionStorageEntry(const nsSessionStorageEntry
& aToCopy
);
105 ~nsSessionStorageEntry();
107 nsRefPtr
<nsDOMStorageItem
> mItem
;
110 class nsDOMStorageManager
: public nsIDOMStorageManager
117 // nsIDOMStorageManager
118 NS_DECL_NSIDOMSTORAGEMANAGER
123 nsDOMStorageManager();
125 void AddToStoragesHash(DOMStorageImpl
* aStorage
);
126 void RemoveFromStoragesHash(DOMStorageImpl
* aStorage
);
128 nsresult
ClearAllStorages();
130 PRBool
InPrivateBrowsingMode() { return mInPrivateBrowsing
; }
132 static nsresult
Initialize();
133 static nsDOMStorageManager
* GetInstance();
134 static void Shutdown();
137 * Checks whether there is any data waiting to be flushed from a temp table.
139 PRBool
UnflushedDataExists();
141 static nsDOMStorageManager
* gStorageManager
;
145 nsTHashtable
<nsDOMStorageEntry
> mStorages
;
146 PRBool mInPrivateBrowsing
;
149 class DOMStorageBase
: public nsISupports
153 DOMStorageBase(DOMStorageBase
&);
155 virtual void InitAsSessionStorage(nsIURI
* aDomainURI
);
156 virtual void InitAsLocalStorage(nsIURI
* aDomainURI
, bool aCanUseChromePersist
);
157 virtual void InitAsGlobalStorage(const nsACString
& aDomainDemanded
);
159 virtual nsTArray
<nsString
>* GetKeys(bool aCallerSecure
) = 0;
160 virtual nsresult
GetLength(bool aCallerSecure
, PRUint32
* aLength
) = 0;
161 virtual nsresult
GetKey(bool aCallerSecure
, PRUint32 aIndex
, nsAString
& aKey
) = 0;
162 virtual nsIDOMStorageItem
* GetValue(bool aCallerSecure
, const nsAString
& aKey
,
164 virtual nsresult
SetValue(bool aCallerSecure
, const nsAString
& aKey
,
165 const nsAString
& aData
, nsAString
& aOldValue
) = 0;
166 virtual nsresult
RemoveValue(bool aCallerSecure
, const nsAString
& aKey
,
167 nsAString
& aOldValue
) = 0;
168 virtual nsresult
Clear(bool aCallerSecure
, PRInt32
* aOldCount
) = 0;
170 // If true, the contents of the storage should be stored in the
171 // database, otherwise this storage should act like a session
173 // This call relies on mSessionOnly, and should only be used
174 // after a CacheStoragePermissions() call. See the comments
175 // for mSessionOnly below.
180 // retrieve the value and secure state corresponding to a key out of storage.
182 GetDBValue(const nsAString
& aKey
,
184 PRBool
* aSecure
) = 0;
186 // set the value corresponding to a key in the storage. If
187 // aSecure is false, then attempts to modify a secure value
188 // throw NS_ERROR_DOM_INVALID_ACCESS_ERR
190 SetDBValue(const nsAString
& aKey
,
191 const nsAString
& aValue
,
194 // set the value corresponding to a key as secure.
196 SetSecure(const nsAString
& aKey
, PRBool aSecure
) = 0;
199 CloneFrom(bool aCallerSecure
, DOMStorageBase
* aThat
) = 0;
201 // e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending
202 // on association with a domain (globalStorage) or
203 // an origin (localStorage).
204 nsCString
& GetScopeDBKey() {return mScopeDBKey
;}
206 // e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain or
207 // reversed offline application allowed domain.
208 nsCString
& GetQuotaDomainDBKey(PRBool aOfflineAllowed
)
210 return aOfflineAllowed
? mQuotaDomainDBKey
: mQuotaETLDplus1DomainDBKey
;
213 virtual bool CacheStoragePermissions() = 0;
216 friend class nsDOMStorageManager
;
217 friend class nsDOMStorage
;
219 nsPIDOMStorage::nsDOMStorageType mStorageType
;
221 // true if the storage database should be used for values
224 // true if the preferences indicates that this storage should be
225 // session only. This member is updated by
226 // CacheStoragePermissions(), using the current principal.
227 // CacheStoragePermissions() must be called at each entry point to
228 // make sure this stays up to date.
229 PRPackedBool mSessionOnly
;
231 // domain this store is associated with
234 // keys are used for database queries.
235 // see comments of the getters bellow.
236 nsCString mScopeDBKey
;
237 nsCString mQuotaETLDplus1DomainDBKey
;
238 nsCString mQuotaDomainDBKey
;
240 bool mCanUseChromePersist
;
243 class DOMStorageImpl
: public DOMStorageBase
247 NS_DECL_CYCLE_COLLECTION_CLASS(DOMStorageImpl
)
248 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
250 DOMStorageImpl(nsDOMStorage
*);
251 DOMStorageImpl(nsDOMStorage
*, DOMStorageImpl
&);
254 virtual void InitAsSessionStorage(nsIURI
* aDomainURI
);
255 virtual void InitAsLocalStorage(nsIURI
* aDomainURI
, bool aCanUseChromePersist
);
256 virtual void InitAsGlobalStorage(const nsACString
& aDomainDemanded
);
258 PRBool
SessionOnly() {
262 virtual nsTArray
<nsString
>* GetKeys(bool aCallerSecure
);
263 virtual nsresult
GetLength(bool aCallerSecure
, PRUint32
* aLength
);
264 virtual nsresult
GetKey(bool aCallerSecure
, PRUint32 aIndex
, nsAString
& aKey
);
265 virtual nsIDOMStorageItem
* GetValue(bool aCallerSecure
, const nsAString
& aKey
,
267 virtual nsresult
SetValue(bool aCallerSecure
, const nsAString
& aKey
,
268 const nsAString
& aData
, nsAString
& aOldValue
);
269 virtual nsresult
RemoveValue(bool aCallerSecure
, const nsAString
& aKey
,
270 nsAString
& aOldValue
);
271 virtual nsresult
Clear(bool aCallerSecure
, PRInt32
* aOldCount
);
273 // cache the keys from the database for faster lookup
274 nsresult
CacheKeysFromDB();
276 // Some privileged internal pages can use a persistent storage even in
277 // session-only or private-browsing modes.
278 bool CanUseChromePersist();
280 // retrieve the value and secure state corresponding to a key out of storage
281 // that has been cached in mItems hash table.
283 GetCachedValue(const nsAString
& aKey
,
287 // retrieve the value and secure state corresponding to a key out of storage.
289 GetDBValue(const nsAString
& aKey
,
293 // set the value corresponding to a key in the storage. If
294 // aSecure is false, then attempts to modify a secure value
295 // throw NS_ERROR_DOM_INVALID_ACCESS_ERR
297 SetDBValue(const nsAString
& aKey
,
298 const nsAString
& aValue
,
301 // set the value corresponding to a key as secure.
303 SetSecure(const nsAString
& aKey
, PRBool aSecure
);
305 // clear all values from the store
309 CloneFrom(bool aCallerSecure
, DOMStorageBase
* aThat
);
311 virtual bool CacheStoragePermissions();
315 static nsDOMStorageDBWrapper
* gStorageDB
;
317 friend class nsDOMStorageManager
;
318 friend class nsDOMStoragePersistentDB
;
319 friend class StorageParent
;
321 void Init(nsDOMStorage
*);
323 // Cross-process storage implementations never have InitAs(Session|Local|Global)Storage
324 // called, so the appropriate initialization needs to happen from the child.
325 void InitFromChild(bool aUseDB
, bool aCanUseChromePersist
, bool aSessionOnly
,
326 const nsACString
& aDomain
,
327 const nsACString
& aScopeDBKey
,
328 const nsACString
& aQuotaDomainDBKey
,
329 const nsACString
& aQuotaETLDplus1DomainDBKey
,
330 PRUint32 aStorageType
);
331 void SetSessionOnly(bool aSessionOnly
);
333 static nsresult
InitDB();
335 // true if items from the database are cached
336 PRPackedBool mItemsCached
;
338 // the key->value item pairs
339 nsTHashtable
<nsSessionStorageEntry
> mItems
;
341 // Weak reference to the owning storage instance
342 nsDOMStorage
* mOwner
;
345 class nsDOMStorage
: public nsIDOMStorageObsolete
,
346 public nsPIDOMStorage
350 nsDOMStorage(nsDOMStorage
& aThat
);
351 virtual ~nsDOMStorage();
353 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
354 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage
, nsIDOMStorageObsolete
)
356 NS_DECL_NSIDOMSTORAGEOBSOLETE
358 // Helpers for implementing nsIDOMStorage
359 nsresult
GetItem(const nsAString
& key
, nsAString
& aData
);
363 virtual nsresult
InitAsSessionStorage(nsIPrincipal
*aPrincipal
, const nsSubstring
&aDocumentURI
);
364 virtual nsresult
InitAsLocalStorage(nsIPrincipal
*aPrincipal
, const nsSubstring
&aDocumentURI
);
365 virtual nsresult
InitAsGlobalStorage(const nsACString
&aDomainDemanded
);
366 virtual already_AddRefed
<nsIDOMStorage
> Clone();
367 virtual already_AddRefed
<nsIDOMStorage
> Fork(const nsSubstring
&aDocumentURI
);
368 virtual PRBool
IsForkOf(nsIDOMStorage
* aThat
);
369 virtual nsTArray
<nsString
> *GetKeys();
370 virtual nsIPrincipal
* Principal();
371 virtual PRBool
CanAccess(nsIPrincipal
*aPrincipal
);
372 virtual nsDOMStorageType
StorageType();
373 virtual void BroadcastChangeNotification(const nsSubstring
&aKey
,
374 const nsSubstring
&aOldValue
,
375 const nsSubstring
&aNewValue
);
377 // Check whether storage may be used by the caller, and whether it
378 // is session only. Returns true if storage may be used.
380 CanUseStorage(PRPackedBool
* aSessionOnly
);
382 // Check whether this URI can use chrome persist storage. This kind of
383 // storage can bypass cookies limits, private browsing and uses the offline
386 URICanUseChromePersist(nsIURI
* aURI
);
388 // Check whether storage may be used. Updates mSessionOnly based on
389 // the result of CanUseStorage.
391 CacheStoragePermissions();
393 nsIDOMStorageItem
* GetNamedItem(const nsAString
& aKey
, nsresult
* aResult
);
395 static nsDOMStorage
* FromSupports(nsISupports
* aSupports
)
397 return static_cast<nsDOMStorage
*>(static_cast<nsIDOMStorageObsolete
*>(aSupports
));
400 nsresult
SetSecure(const nsAString
& aKey
, PRBool aSecure
)
402 return mStorageImpl
->SetSecure(aKey
, aSecure
);
405 nsresult
CloneFrom(nsDOMStorage
* aThat
);
408 friend class nsDOMStorage2
;
409 friend class nsDOMStoragePersistentDB
;
411 nsRefPtr
<DOMStorageBase
> mStorageImpl
;
413 PRBool
CanAccessSystem(nsIPrincipal
*aPrincipal
);
415 // document URI of the document this storage is bound to
416 nsString mDocumentURI
;
418 // true if this storage was initialized as a localStorage object. localStorage
419 // objects are scoped to scheme/host/port in the database, while globalStorage
420 // objects are scoped just to host. this flag also tells the manager to map
421 // this storage also in mLocalStorages hash table.
422 nsDOMStorageType mStorageType
;
424 friend class nsIDOMStorage2
;
425 nsPIDOMStorage
* mSecurityChecker
;
426 nsPIDOMStorage
* mEventBroadcaster
;
429 class nsDOMStorage2
: public nsIDOMStorage
,
430 public nsPIDOMStorage
434 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
435 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage2
, nsIDOMStorage
)
437 nsDOMStorage2(nsDOMStorage2
& aThat
);
440 NS_DECL_NSIDOMSTORAGE
443 virtual nsresult
InitAsSessionStorage(nsIPrincipal
*aPrincipal
, const nsSubstring
&aDocumentURI
);
444 virtual nsresult
InitAsLocalStorage(nsIPrincipal
*aPrincipal
, const nsSubstring
&aDocumentURI
);
445 virtual nsresult
InitAsGlobalStorage(const nsACString
&aDomainDemanded
);
446 virtual already_AddRefed
<nsIDOMStorage
> Clone();
447 virtual already_AddRefed
<nsIDOMStorage
> Fork(const nsSubstring
&aDocumentURI
);
448 virtual PRBool
IsForkOf(nsIDOMStorage
* aThat
);
449 virtual nsTArray
<nsString
> *GetKeys();
450 virtual nsIPrincipal
* Principal();
451 virtual PRBool
CanAccess(nsIPrincipal
*aPrincipal
);
452 virtual nsDOMStorageType
StorageType();
453 virtual void BroadcastChangeNotification(const nsSubstring
&aKey
,
454 const nsSubstring
&aOldValue
,
455 const nsSubstring
&aNewValue
);
457 nsresult
InitAsSessionStorageFork(nsIPrincipal
*aPrincipal
,
458 const nsSubstring
&aDocumentURI
,
459 nsIDOMStorageObsolete
* aStorage
);
462 // storages bound to an origin hold the principal to
463 // make security checks against it
464 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
466 // Needed for the storage event, this is address of the document this storage
468 nsString mDocumentURI
;
469 nsRefPtr
<nsDOMStorage
> mStorage
;
472 class nsDOMStorageList
: public nsIDOMStorageList
480 virtual ~nsDOMStorageList() {}
486 NS_DECL_NSIDOMSTORAGELIST
488 nsIDOMStorageObsolete
* GetNamedItem(const nsAString
& aDomain
, nsresult
* aResult
);
491 * Check whether aCurrentDomain has access to aRequestedDomain
494 CanAccessDomain(const nsACString
& aRequestedDomain
,
495 const nsACString
& aCurrentDomain
);
500 * Return the global nsIDOMStorageObsolete for a particular domain.
501 * aNoCurrentDomainCheck may be true to skip the domain comparison;
502 * this is used for chrome code so that it may retrieve data from
505 * @param aRequestedDomain domain to return
506 * @param aCurrentDomain domain of current caller
507 * @param aNoCurrentDomainCheck true to skip domain comparison
509 nsIDOMStorageObsolete
*
510 GetStorageForDomain(const nsACString
& aRequestedDomain
,
511 const nsACString
& aCurrentDomain
,
512 PRBool aNoCurrentDomainCheck
,
516 * Convert the domain into an array of its component parts.
519 ConvertDomainToArray(const nsACString
& aDomain
,
520 nsTArray
<nsCString
>* aArray
);
522 nsInterfaceHashtable
<nsCStringHashKey
, nsIDOMStorageObsolete
> mStorages
;
525 class nsDOMStorageItem
: public nsIDOMStorageItem
,
526 public nsIDOMToString
529 nsDOMStorageItem(DOMStorageBase
* aStorage
,
530 const nsAString
& aKey
,
531 const nsAString
& aValue
,
533 virtual ~nsDOMStorageItem();
536 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
537 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorageItem
, nsIDOMStorageItem
)
539 // nsIDOMStorageObsolete
540 NS_DECL_NSIDOMSTORAGEITEM
543 NS_DECL_NSIDOMTOSTRING
550 void SetSecureInternal(PRBool aSecure
)
555 const nsAString
& GetValueInternal()
560 const void SetValueInternal(const nsAString
& aValue
)
572 // true if this value is for secure sites only
581 // If this item came from the db, mStorage points to the storage
582 // object where this item came from.
583 nsRefPtr
<DOMStorageBase
> mStorage
;
586 class nsDOMStorageEvent
: public nsDOMEvent
,
587 public nsIDOMStorageEvent
591 : nsDOMEvent(nsnull
, nsnull
)
595 virtual ~nsDOMStorageEvent()
601 NS_DECL_ISUPPORTS_INHERITED
602 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMStorageEvent
, nsDOMEvent
)
604 NS_DECL_NSIDOMSTORAGEEVENT
605 NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
612 nsCOMPtr
<nsIDOMStorage
> mStorageArea
;
615 class nsDOMStorageEventObsolete
: public nsDOMEvent
,
616 public nsIDOMStorageEventObsolete
619 nsDOMStorageEventObsolete()
620 : nsDOMEvent(nsnull
, nsnull
)
624 virtual ~nsDOMStorageEventObsolete()
629 NS_DECL_NSIDOMSTORAGEEVENTOBSOLETE
630 NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
637 NS_NewDOMStorage(nsISupports
* aOuter
, REFNSIID aIID
, void** aResult
);
640 NS_NewDOMStorage2(nsISupports
* aOuter
, REFNSIID aIID
, void** aResult
);
643 NS_NewDOMStorageList(nsIDOMStorageList
** aResult
);
646 GetOfflinePermission(const nsACString
&aDomain
);
649 IsOfflineAllowed(const nsACString
&aDomain
);
651 #endif /* nsDOMStorage_h___ */