Bug 592990 - about:home DOM storage is cleared with cookies and private browsing. r=mayhemer a=blocking

This commit is contained in:
Marco Bonardo 2010-09-09 12:20:05 +02:00
parent 337f5dcdc5
commit e5aa440112
7 changed files with 153 additions and 29 deletions

View File

@ -183,16 +183,20 @@ IsOfflineAllowed(const nsACString &aDomain)
// Returns two quotas - A hard limit for which adding data will be an error,
// and a limit after which a warning event will be sent to the observer
// service. The warn limit may be -1, in which case there will be no warning.
// If aOverrideQuota is set, the larger offline apps quota is used and no
// warning is sent.
static PRUint32
GetQuota(const nsACString &aDomain, PRInt32 *aQuota, PRInt32 *aWarnQuota)
GetQuota(const nsACString &aDomain, PRInt32 *aQuota, PRInt32 *aWarnQuota,
bool aOverrideQuota)
{
PRUint32 perm = GetOfflinePermission(aDomain);
if (IS_PERMISSION_ALLOWED(perm)) {
if (IS_PERMISSION_ALLOWED(perm) || aOverrideQuota) {
// This is an offline app, give more space by default.
*aQuota = ((PRInt32)nsContentUtils::GetIntPref(kOfflineAppQuota,
DEFAULT_OFFLINE_APP_QUOTA) * 1024);
if (perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN) {
if (perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN ||
aOverrideQuota) {
*aWarnQuota = -1;
} else {
*aWarnQuota = ((PRInt32)nsContentUtils::GetIntPref(kOfflineAppWarnQuota,
@ -575,6 +579,7 @@ nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
, mScopeDBKey(aThat.mScopeDBKey)
#endif
, mEventBroadcaster(nsnull)
, mCanUseChromePersist(false)
{
mSecurityChecker = this;
mItems.Init(8);
@ -677,6 +682,15 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aD
#endif
mStorageType = LocalStorage;
nsCOMPtr<nsIURI> URI;
if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) {
PRBool isAbout;
mCanUseChromePersist =
(NS_SUCCEEDED(URI->SchemeIs("moz-safe-about", &isAbout) && isAbout)) ||
(NS_SUCCEEDED(URI->SchemeIs("about", &isAbout), && isAbout));
}
return NS_OK;
}
@ -810,6 +824,11 @@ nsDOMStorage::CacheStoragePermissions()
return mSecurityChecker->CanAccess(subjectPrincipal);
}
bool
nsDOMStorage::CanUseChromePersist()
{
return mCanUseChromePersist;
}
class ItemCounterState
{
@ -1252,7 +1271,8 @@ nsDOMStorage::SetDBValue(const nsAString& aKey,
PRInt32 offlineAppPermission;
PRInt32 quota;
PRInt32 warnQuota;
offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota);
offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota,
CanUseChromePersist());
PRInt32 usage;
rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota,
@ -1982,18 +2002,18 @@ nsDOMStorageItem::ToString(nsAString& aStr)
}
// Cycle collection implementation for nsDOMStorageEvent
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mStorageArea)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStorageArea)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mStorageArea)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStorageArea)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(nsDOMStorageEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMStorageEvent, nsDOMEvent)
DOMCI_DATA(StorageEvent, nsDOMStorageEvent)

View File

@ -175,6 +175,10 @@ public:
return mSessionOnly;
}
// Some privileged internal pages can use a persistent storage even in
// session-only or private-browsing modes.
bool CanUseChromePersist();
// Check whether storage may be used by the caller, and whether it
// is session only. Returns true if storage may be used.
static PRBool
@ -266,6 +270,8 @@ protected:
nsPIDOMStorage* mSecurityChecker;
nsPIDOMStorage* mEventBroadcaster;
bool mCanUseChromePersist;
public:
// e.g. "moc.rab.oof.:" or "moc.rab.oof.:http:80" depending
// on association with a domain (globalStorage) or

View File

@ -74,7 +74,10 @@ nsDOMStorageDBWrapper::Init()
{
nsresult rv;
rv = mPersistentDB.Init();
rv = mPersistentDB.Init(NS_LITERAL_STRING("webappsstore.sqlite"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mChromePersistentDB.Init(NS_LITERAL_STRING("chromeappsstore.sqlite"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mSessionOnlyDB.Init(&mPersistentDB);
@ -90,6 +93,8 @@ nsresult
nsDOMStorageDBWrapper::GetAllKeys(nsDOMStorage* aStorage,
nsTHashtable<nsSessionStorageEntry>* aKeys)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.GetAllKeys(aStorage, aKeys);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.GetAllKeys(aStorage, aKeys);
if (aStorage->SessionOnly())
@ -104,6 +109,8 @@ nsDOMStorageDBWrapper::GetKeyValue(nsDOMStorage* aStorage,
nsAString& aValue,
PRBool* aSecure)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.GetKeyValue(aStorage, aKey, aValue, aSecure);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.GetKeyValue(aStorage, aKey, aValue, aSecure);
if (aStorage->SessionOnly())
@ -121,6 +128,9 @@ nsDOMStorageDBWrapper::SetKey(nsDOMStorage* aStorage,
PRBool aExcludeOfflineFromUsage,
PRInt32 *aNewUsage)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.SetKey(aStorage, aKey, aValue, aSecure,
aQuota, aExcludeOfflineFromUsage, aNewUsage);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.SetKey(aStorage, aKey, aValue, aSecure,
aQuota, aExcludeOfflineFromUsage, aNewUsage);
@ -137,6 +147,8 @@ nsDOMStorageDBWrapper::SetSecure(nsDOMStorage* aStorage,
const nsAString& aKey,
const PRBool aSecure)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.SetSecure(aStorage, aKey, aSecure);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.SetSecure(aStorage, aKey, aSecure);
if (aStorage->SessionOnly())
@ -151,6 +163,8 @@ nsDOMStorageDBWrapper::RemoveKey(nsDOMStorage* aStorage,
PRBool aExcludeOfflineFromUsage,
PRInt32 aKeyUsage)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage);
if (aStorage->SessionOnly())
@ -162,6 +176,8 @@ nsDOMStorageDBWrapper::RemoveKey(nsDOMStorage* aStorage,
nsresult
nsDOMStorageDBWrapper::ClearStorage(nsDOMStorage* aStorage)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.ClearStorage(aStorage);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.ClearStorage(aStorage);
if (aStorage->SessionOnly())
@ -249,6 +265,8 @@ nsresult
nsDOMStorageDBWrapper::GetUsage(nsDOMStorage* aStorage,
PRBool aExcludeOfflineFromUsage, PRInt32 *aUsage)
{
if (aStorage->CanUseChromePersist())
return mChromePersistentDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage);
if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
return mPrivateBrowsingDB.GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage);
if (aStorage->SessionOnly())

View File

@ -217,6 +217,7 @@ public:
nsACString& aDomain);
protected:
nsDOMStoragePersistentDB mChromePersistentDB;
nsDOMStoragePersistentDB mPersistentDB;
nsDOMStorageMemoryDB mSessionOnlyDB;
nsDOMStorageMemoryDB mPrivateBrowsingDB;

View File

@ -124,7 +124,7 @@ nsIsOfflineSQLFunction::OnFunctionCall(
}
nsresult
nsDOMStoragePersistentDB::Init()
nsDOMStoragePersistentDB::Init(const nsString& aDatabaseName)
{
nsresult rv;
@ -132,7 +132,7 @@ nsDOMStoragePersistentDB::Init()
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(storageFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = storageFile->Append(NS_LITERAL_STRING("webappsstore.sqlite"));
rv = storageFile->Append(aDatabaseName);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageService> service;

View File

@ -54,7 +54,7 @@ public:
~nsDOMStoragePersistentDB() {}
nsresult
Init();
Init(const nsString& aDatabaseName);
/**
* Retrieve a list of all the keys associated with a particular domain.

View File

@ -13,20 +13,99 @@ function run_test()
testURI(Services.io.newURI("moz-safe-about:rights", null, null));
}
function testURI(aURI) {
function testURI(aURI)
{
print("Testing: " + aURI.spec);
do_check_true(/about$/.test(aURI.scheme));
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
print("Check that our value is correctly removed.");
storage.removeItem("test-item");
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
testURIWithPrivateBrowsing(aURI);
testURIWithClearCookies(aURI);
}
function testURIWithPrivateBrowsing(aURI) {
print("Testing with private browsing: " + aURI.spec);
// Skip test if PB mode is not supported.
if (!("@mozilla.org/privatebrowsing;1" in Components.classes)) {
print("Skipped.");
return;
}
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
togglePBMode(true);
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
print("Check that our value is correctly removed.");
storage.removeItem("test-item");
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
togglePBMode(false);
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
}
function testURIWithClearCookies(aURI) {
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIObserver);
dsm.observe(null, "cookie-changed", "cleared");
print("Check that our value is still stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
print("Check that we can explicitly clear value.");
storage.clear();
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
}
function getStorageForURI(aURI)
{
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
getService(Components.interfaces.nsIScriptSecurityManager).
getCodebasePrincipal(aURI);
let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
let storage = dsm.getLocalStorageForPrincipal(principal, "");
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.getItem("test-item"), "test-value");
storage.removeItem("test-item");
print("Check that our value has been correctly removed.");
do_check_eq(storage.getItem("test-item"), null);
return dsm.getLocalStorageForPrincipal(principal, "");
}
function togglePBMode(aEnable)
{
let pb = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
if (aEnable) {
Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session",
true);
pb.privateBrowsingEnabled = true;
} else {
try {
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
} catch (ex) {}
pb.privateBrowsingEnabled = false;
}
}