☠☠ backed out by c6ba385c4435 ☠ ☠ | |
author | Honza Bambas <honzab.moz@firemni.cz> |
Mon, 25 Oct 2010 20:40:55 +0200 | |
changeset 56447 | 2ccadd55dc4c338acd480c9731463c0889dcbfe6 |
parent 56446 | 142c7b20fd8c0141acbb8860b8450fe241d5117b |
child 56448 | c6ba385c44350ab6b117a2779ebb5f2adb76d68d |
push id | 16551 |
push user | honzab.moz@firemni.cz |
push date | Mon, 25 Oct 2010 18:41:59 +0000 |
treeherder | mozilla-central@2ccadd55dc4c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | blocking2.0 |
bugs | 527667 |
milestone | 2.0b8pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/sanitize.js +++ b/browser/base/content/sanitize.js @@ -147,16 +147,21 @@ Sanitizer.prototype = { var cookiesEnum = cookieMgr.enumerator; while (cookiesEnum.hasMoreElements()) { var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2); if (cookie.creationTime > this.range[0]) // This cookie was created after our cutoff, clear it cookieMgr.remove(cookie.host, cookie.name, cookie.path, false); } + + // Also handle all DOM storage data created after the cutoff. + var domStorageManager = Components.classes["@mozilla.org/dom/storagemanager;1"] + .getService(Ci.nsIDOMStorageManager); + domStorageManager.clearStorageDataSince(this.range[0]); } else { // Remove everything cookieMgr.removeAll(); } // clear any network geolocation provider sessions var psvc = Components.classes["@mozilla.org/preferences-service;1"]
--- a/dom/interfaces/storage/nsIDOMStorageManager.idl +++ b/dom/interfaces/storage/nsIDOMStorageManager.idl @@ -35,17 +35,17 @@ * * ***** END LICENSE BLOCK ***** */ #include "nsISupports.idl" interface nsIDOMStorage; interface nsIPrincipal; -[scriptable, uuid(fd91ec36-7da8-43bb-b8f2-4b57a862a467)] +[scriptable, uuid(9b729267-00ed-4e5c-a3d2-b5572ca0934d)] interface nsIDOMStorageManager : nsISupports { /** * Return the amount of disk space used by a domain. Usage is checked * against the domain of the page that set the key (the owner domain), not * the domain of the storage object. * * @param aOwnerDomain The domain to check. @@ -55,15 +55,24 @@ interface nsIDOMStorageManager : nsISupp /** * Clear keys owned by offline applications. All data owned by a domain * with the "offline-app" permission will be removed from the database. */ void clearOfflineApps(); /** + * Clears any data stored in DOM storage since the provided time + * @param since + * Any storage value that has been inserted after the time specified + * with 'since' will be deleted. The time is in microseconds, defined + * as PR_Now() function result. + */ + void clearStorageDataSince(in PRInt64 since); + + /** * Returns instance of localStorage object for aURI's origin. * This method ensures there is always only a single instance * for a single origin. */ nsIDOMStorage getLocalStorageForPrincipal(in nsIPrincipal aPrincipal, in DOMString aDocumentURI); };
--- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -60,16 +60,17 @@ #include "nsIPermissionManager.h" #include "nsCycleCollectionParticipant.h" #include "nsIOfflineCacheUpdate.h" #include "nsIJSContextStack.h" #include "nsIPrivateBrowsingService.h" #include "nsDOMString.h" #include "nsNetCID.h" #include "nsIProxyObjectManager.h" +#include "nsISupportsPrimitives.h" static const PRUint32 ASK_BEFORE_ACCEPT = 1; static const PRUint32 ACCEPT_SESSION = 2; static const PRUint32 BEHAVIOR_REJECT = 2; static const PRUint32 DEFAULT_QUOTA = 5 * 1024; // Be generous with offline apps by default... static const PRUint32 DEFAULT_OFFLINE_APP_QUOTA = 200 * 1024; @@ -434,16 +435,43 @@ nsDOMStorageManager::GetUsage(const nsAS nsresult rv = nsDOMStorage::InitDB(); NS_ENSURE_SUCCESS(rv, rv); return nsDOMStorage::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain), PR_FALSE, aUsage); } NS_IMETHODIMP +nsDOMStorageManager::ClearStorageDataSince(PRInt64 aSince) +{ + nsresult rv; + + rv = nsDOMStorage::InitDB(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = nsDOMStorage::gStorageDB->RemoveTimeRange(aSince); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService(); + if (obsserv) { + nsCOMPtr<nsISupportsPRTime> time = do_CreateInstance( + "@mozilla.org/supports-PRTime;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = time->SetData(aSince); + NS_ENSURE_SUCCESS(rv, rv); + + rv = obsserv->NotifyObservers(time, NS_DOMSTORAGE_CUTOFF_OBSERVER, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +NS_IMETHODIMP nsDOMStorageManager::ClearOfflineApps() { nsresult rv = nsDOMStorage::InitDB(); NS_ENSURE_SUCCESS(rv, rv); nsTArray<nsString> domains; rv = GetOfflineDomains(domains); NS_ENSURE_SUCCESS(rv, rv); @@ -655,16 +683,18 @@ nsDOMStorage::InitAsSessionStorage(nsIPr mDocumentURI = aDocumentURI; #ifdef MOZ_STORAGE mUseDB = PR_FALSE; mScopeDBKey.Truncate(); mQuotaDomainDBKey.Truncate(); #endif + RegisterObservers(false); + mStorageType = SessionStorage; return NS_OK; } nsresult nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) { nsCOMPtr<nsIURI> domainURI; @@ -698,17 +728,17 @@ nsDOMStorage::InitAsLocalStorage(nsIPrin mStorageType = LocalStorage; nsCOMPtr<nsIURI> URI; if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) { mCanUseChromePersist = URICanUseChromePersist(URI); } - RegisterObservers(); + RegisterObservers(true); return NS_OK; } nsresult nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded) { mDomain = aDomainDemanded; @@ -726,17 +756,17 @@ nsDOMStorage::InitAsGlobalStorage(const PR_TRUE, PR_FALSE, mQuotaDomainDBKey); nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded, PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey); #endif mStorageType = GlobalStorage; mEventBroadcaster = this; - RegisterObservers(); + RegisterObservers(true); return NS_OK; } static PLDHashOperator CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg) { nsDOMStorage* newstorage = static_cast<nsDOMStorage*>(userArg); @@ -1086,16 +1116,22 @@ nsDOMStorage::SetItem(const nsAString& a new nsDOMStorageItem(this, aKey, aData, isCallerSecure); if (!newitem) return NS_ERROR_OUT_OF_MEMORY; entry = mItems.PutEntry(aKey); NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); entry->mItem = newitem; } + if (!UseDB()) { + // This is used only for sessionStorage, no need to setup the time also when + // loading items from the database etc. + entry->mItem->SetInsertTimeToNow(); + } + if ((oldValue != aData || mStorageType == GlobalStorage) && mEventBroadcaster) mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, aData); return NS_OK; } NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) { @@ -1527,23 +1563,26 @@ nsDOMStorage::MaybeCommitTemporaryTable( return gStorageDB->FlushAndDeleteTemporaryTableForStorage(this); #endif return NS_OK; } nsresult -nsDOMStorage::RegisterObservers() +nsDOMStorage::RegisterObservers(bool persistent) { nsCOMPtr<nsIObserverService> obsserv = mozilla::services::GetObserverService(); if (obsserv) { - obsserv->AddObserver(this, "profile-before-change", PR_TRUE); - obsserv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE); - obsserv->AddObserver(this, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, PR_TRUE); + if (persistent) { + obsserv->AddObserver(this, "profile-before-change", PR_TRUE); + obsserv->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE); + obsserv->AddObserver(this, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER, PR_TRUE); + } + obsserv->AddObserver(this, NS_DOMSTORAGE_CUTOFF_OBSERVER, PR_TRUE); } return NS_OK; } bool nsDOMStorage::WasTemporaryTableLoaded() { return mLoadedTemporaryTable; @@ -1556,16 +1595,27 @@ nsDOMStorage::SetTemporaryTableLoaded(bo mLastTemporaryTableAccessTime = TimeStamp::Now(); if (!mLoadedTemporaryTable) mTemporaryTableAge = mLastTemporaryTableAccessTime; } mLoadedTemporaryTable = loaded; } +static PLDHashOperator +StorageCutOffEnum(nsSessionStorageEntry* aEntry, void* userArg) +{ + PRInt64 since = *(PRInt64*)userArg; + + if (aEntry->mItem->ShouldBeCutOff(since)) + return PL_DHASH_REMOVE; + + return PL_DHASH_NEXT; +} + NS_IMETHODIMP nsDOMStorage::Observe(nsISupports *subject, const char *topic, const PRUnichar *data) { bool isProfileBeforeChange = !strcmp(topic, "profile-before-change"); bool isXPCOMShutdown = !strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID); bool isFlushTimer = !strcmp(topic, NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER); @@ -1574,16 +1624,40 @@ nsDOMStorage::Observe(nsISupports *subje nsresult rv = MaybeCommitTemporaryTable(isXPCOMShutdown || isProfileBeforeChange); if (NS_FAILED(rv)) { NS_WARNING("DOMStorage: temporary table commit failed"); } return NS_OK; } + if (!strcmp(topic, NS_DOMSTORAGE_CUTOFF_OBSERVER)) { + if (UseDB()) { + // If this storage is using the database (localStorage, globalStorage) + // then just re-cache the items from the database, database is now up to + // date. + mItemsCached = PR_FALSE; + CacheKeysFromDB(); + } + else { + // This is sessionStorage. In that case we need to prune the mItems hash + // table. Insert times are properly set in nsDOMStorage::SetItem. + nsresult rv; + nsCOMPtr<nsISupportsPRTime> time = do_QueryInterface(subject, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + PRInt64 since; + rv = time->GetData(&since); + NS_ENSURE_SUCCESS(rv, rv); + + mItems.EnumerateEntries(StorageCutOffEnum, &since); + } + return NS_OK; + } + NS_WARNING("Unrecognized topic in nsDOMStorage::Observe"); return NS_OK; } // // nsDOMStorage2 // @@ -2026,16 +2100,17 @@ NS_INTERFACE_MAP_END nsDOMStorageItem::nsDOMStorageItem(nsDOMStorage* aStorage, const nsAString& aKey, const nsAString& aValue, PRBool aSecure) : mSecure(aSecure), mKey(aKey), mValue(aValue), + mInsertTime(0), mStorage(aStorage) { } nsDOMStorageItem::~nsDOMStorageItem() { }
--- a/dom/src/storage/nsDOMStorage.h +++ b/dom/src/storage/nsDOMStorage.h @@ -59,16 +59,17 @@ #include "nsIDOMStorageManager.h" #include "nsCycleCollectionParticipant.h" #include "nsIObserver.h" #include "nsITimer.h" #include "nsWeakReference.h" #include "mozilla/TimeStamp.h" #define NS_DOMSTORAGE_FLUSH_TIMER_OBSERVER "domstorage-flush-timer" +#define NS_DOMSTORAGE_CUTOFF_OBSERVER "domstorage-cutoff" #ifdef MOZ_STORAGE #include "nsDOMStorageDBWrapper.h" #endif #define IS_PERMISSION_ALLOWED(perm) \ ((perm) != nsIPermissionManager::UNKNOWN_ACTION && \ (perm) != nsIPermissionManager::DENY_ACTION) @@ -237,17 +238,17 @@ public: nsIDOMStorageItem* GetNamedItem(const nsAString& aKey, nsresult* aResult); static nsDOMStorage* FromSupports(nsISupports* aSupports) { return static_cast<nsDOMStorage*>(static_cast<nsIDOMStorageObsolete*>(aSupports)); } - nsresult RegisterObservers(); + nsresult RegisterObservers(bool persistent); nsresult MaybeCommitTemporaryTable(bool force); bool WasTemporaryTableLoaded(); void SetTemporaryTableLoaded(bool loaded); protected: friend class nsDOMStorageManager; @@ -459,27 +460,40 @@ public: mValue = aValue; } void ClearValue() { mValue.Truncate(); } + void SetInsertTimeToNow() + { + mInsertTime = PR_Now(); + } + + bool ShouldBeCutOff(PRInt64 since) + { + return mInsertTime > since; + } + protected: // true if this value is for secure sites only PRBool mSecure; // key for the item nsString mKey; // value of the item nsString mValue; + // insertion/update time + PRInt64 mInsertTime; + // If this item came from the db, mStorage points to the storage // object where this item came from. nsRefPtr<nsDOMStorage> mStorage; }; class nsDOMStorageEvent : public nsDOMEvent, public nsIDOMStorageEvent {
--- a/dom/src/storage/nsDOMStorageDBWrapper.cpp +++ b/dom/src/storage/nsDOMStorageDBWrapper.cpp @@ -258,16 +258,35 @@ nsDOMStorageDBWrapper::RemoveOwner(const NS_ENSURE_SUCCESS(rv, rv); rv = mPersistentDB.RemoveOwner(aOwner, aIncludeSubDomains); NS_ENSURE_SUCCESS(rv, rv); return rv; } +nsresult +nsDOMStorageDBWrapper::RemoveTimeRange(PRInt64 aSince) +{ + nsresult rv; + + rv = mPrivateBrowsingDB.RemoveTimeRange(aSince); + NS_ENSURE_SUCCESS(rv, rv); + + if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) + return NS_OK; + + rv = mSessionOnlyDB.RemoveTimeRange(aSince); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mPersistentDB.RemoveTimeRange(aSince); + NS_ENSURE_SUCCESS(rv, rv); + + return rv; +} nsresult nsDOMStorageDBWrapper::RemoveOwners(const nsTArray<nsString> &aOwners, PRBool aIncludeSubDomains, PRBool aMatch) { nsresult rv; rv = mPrivateBrowsingDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
--- a/dom/src/storage/nsDOMStorageDBWrapper.h +++ b/dom/src/storage/nsDOMStorageDBWrapper.h @@ -173,16 +173,23 @@ public: * Removes keys owned by domains that either match or don't match the * list. */ nsresult RemoveOwners(const nsTArray<nsString>& aOwners, PRBool aIncludeSubDomains, PRBool aMatch); /** + * Removes all keys that were created after the time specified by 'aSince'. + * 'aSince' value is compatible with PR_Now() function. + */ + nsresult + RemoveTimeRange(PRInt64 aSince); + + /** * Removes all keys from storage. Used when clearing storage. */ nsresult RemoveAll(); /** * Returns usage for a storage using its GetQuotaDomainDBKey() as a key. */
--- a/dom/src/storage/nsDOMStorageMemoryDB.cpp +++ b/dom/src/storage/nsDOMStorageMemoryDB.cpp @@ -225,16 +225,17 @@ nsDOMStorageMemoryDB::SetKey(nsDOMStorag return NS_ERROR_DOM_QUOTA_REACHED; } } storage->mUsageDelta += aValue.Length() - item->mValue.Length(); item->mValue = aValue; item->mSecure = aSecure; + item->mInsertTime = PR_Now(); *aNewUsage = usage; return NS_OK; } nsresult nsDOMStorageMemoryDB::SetSecure(nsDOMStorage* aStorage, @@ -374,16 +375,44 @@ nsDOMStorageMemoryDB::RemoveOwners(const struc.mSubDomain = "aKey; struc.mMatch = aMatch; mData.Enumerate(RemoveOwnersEnum, &struc); } return NS_OK; } +static PLDHashOperator +RemoveTimeRangeEnum(const nsAString& keyname, + nsAutoPtr<nsDOMStorageMemoryDB::nsInMemoryItem>& item, + void *closure) +{ + if (item->mInsertTime > *(PRInt64*)closure) + return PL_DHASH_REMOVE; + + return PL_DHASH_NEXT; +} + +static PLDHashOperator +RemoveTimeRangeStoragesEnum(const nsACString& key, + nsAutoPtr<nsDOMStorageMemoryDB::nsInMemoryStorage>& storage, + void *closure) +{ + storage->mTable.Enumerate(RemoveTimeRangeEnum, closure); + return PL_DHASH_NEXT; +} + +nsresult +nsDOMStorageMemoryDB::RemoveTimeRange(PRInt64 since) +{ + mData.Enumerate(RemoveTimeRangeStoragesEnum, &since); + + return NS_OK; +} + nsresult nsDOMStorageMemoryDB::RemoveAll() { mData.Clear(); // XXX Check this releases all instances return NS_OK; } nsresult
--- a/dom/src/storage/nsDOMStorageMemoryDB.h +++ b/dom/src/storage/nsDOMStorageMemoryDB.h @@ -51,16 +51,17 @@ public: nsDOMStorageMemoryDB() : mPreloading(PR_FALSE) {} ~nsDOMStorageMemoryDB() {} class nsInMemoryItem { public: PRBool mSecure; nsString mValue; + PRInt64 mInsertTime; }; typedef nsClassHashtable<nsStringHashKey, nsInMemoryItem> nsStorageItemsTable; class nsInMemoryStorage { public: nsStorageItemsTable mTable; @@ -155,16 +156,24 @@ public: * Removes keys owned by domains that either match or don't match the * list. */ nsresult RemoveOwners(const nsTArray<nsString>& aOwners, PRBool aIncludeSubDomains, PRBool aMatch); /** + * Remove all values from all scopes not marked as offline that has been + * created after the time specified with 'aSince'. Used by the Clear Private + * Data dialog. 'aSince' value is compatible with PR_Now() function. + */ + nsresult + RemoveTimeRange(PRInt64 aSince); + + /** * Removes all keys from storage. Used when clearing storage. */ nsresult RemoveAll(); /** * Returns usage for a storage using its GetQuotaDomainDBKey() as a key. */
--- a/dom/src/storage/nsDOMStoragePersistentDB.cpp +++ b/dom/src/storage/nsDOMStoragePersistentDB.cpp @@ -200,47 +200,85 @@ nsDOMStoragePersistentDB::Init(const nsS rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection)); } NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "PRAGMA temp_store = MEMORY")); NS_ENSURE_SUCCESS(rv, rv); + PRInt32 schemaVersion; + rv = mConnection->GetSchemaVersion(&schemaVersion); + NS_ENSURE_SUCCESS(rv, rv); + mozStorageTransaction transaction(mConnection, PR_FALSE); // Ensure Gecko 1.9.1 storage table - rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( - "CREATE TABLE IF NOT EXISTS webappsstore2 (" - "scope TEXT, " - "key TEXT, " - "value TEXT, " - "secure INTEGER, " - "owner TEXT)")); + PRBool exists; + + rv = mConnection->TableExists(NS_LITERAL_CSTRING("webappsstore2"), + &exists); NS_ENSURE_SUCCESS(rv, rv); + if (!exists) { + rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE TABLE webappsstore2 (" + "scope TEXT, " + "key TEXT, " + "value TEXT, " + "secure INTEGER, " + "owner TEXT, " + "inserttime BIGINT DEFAULT 0)")); + NS_ENSURE_SUCCESS(rv, rv); + } + else { + if (schemaVersion == 0) { + rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "ALTER TABLE webappsstore2 " + "ADD COLUMN inserttime BIGINT DEFAULT 0")); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + if (schemaVersion == 0) { + rv = mConnection->SetSchemaVersion(1); + NS_ENSURE_SUCCESS(rv, rv); + } + rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE UNIQUE INDEX IF NOT EXISTS scope_key_index" " ON webappsstore2(scope, key)")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE INDEX IF NOT EXISTS inserttime_index" + " ON webappsstore2(inserttime)")); + NS_ENSURE_SUCCESS(rv, rv); + + + rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TEMPORARY TABLE webappsstore2_temp (" "scope TEXT, " "key TEXT, " "value TEXT, " "secure INTEGER, " - "owner TEXT)")); + "owner TEXT, " + "inserttime BIGINT DEFAULT 0)")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE UNIQUE INDEX scope_key_index_temp" " ON webappsstore2_temp(scope, key)")); NS_ENSURE_SUCCESS(rv, rv); + rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( + "CREATE INDEX IF NOT EXISTS inserttime_index_temp" + " ON webappsstore2_temp(inserttime)")); + NS_ENSURE_SUCCESS(rv, rv); + rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TEMPORARY VIEW webappsstore2_view AS " "SELECT * FROM webappsstore2_temp " "UNION ALL " "SELECT * FROM webappsstore2 " "WHERE NOT EXISTS (" "SELECT scope, key FROM webappsstore2_temp " @@ -266,18 +304,16 @@ nsDOMStoragePersistentDB::Init(const nsS NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageFunction> function2(new nsIsOfflineSQLFunction()); NS_ENSURE_TRUE(function2, NS_ERROR_OUT_OF_MEMORY); rv = mConnection->CreateFunction(NS_LITERAL_CSTRING("ISOFFLINE"), 1, function2); NS_ENSURE_SUCCESS(rv, rv); - PRBool exists; - // Check if there is storage of Gecko 1.9.0 and if so, upgrade that storage // to actual webappsstore2 table and drop the obsolete table. First process // this newer table upgrade to priority potential duplicates from older // storage table. rv = mConnection->TableExists(NS_LITERAL_CSTRING("webappsstore"), &exists); NS_ENSURE_SUCCESS(rv, rv); @@ -350,18 +386,18 @@ nsDOMStoragePersistentDB::Init(const nsS "WHERE scope = :scope " "AND key = :key"), getter_AddRefs(mGetKeyValueStatement)); NS_ENSURE_SUCCESS(rv, rv); // insert a new key rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "INSERT OR REPLACE INTO " - "webappsstore2_temp(scope, key, value, secure) " - "VALUES (:scope, :key, :value, :secure)"), + "webappsstore2_temp(scope, key, value, secure, inserttime) " + "VALUES (:scope, :key, :value, :secure, :inserttime)"), getter_AddRefs(mInsertKeyStatement)); NS_ENSURE_SUCCESS(rv, rv); // update the secure status of an existing key rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "UPDATE webappsstore2_temp " "SET secure = :secure " "WHERE scope = :scope " @@ -386,16 +422,24 @@ nsDOMStoragePersistentDB::Init(const nsS // remove keys belonging exactly only to a specific domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_view " "WHERE scope = :scope"), getter_AddRefs(mRemoveStorageStatement)); NS_ENSURE_SUCCESS(rv, rv); + // remove keys that are junger then a specific time + rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( + "DELETE FROM webappsstore2_view " + "WHERE inserttime > :time " + "AND NOT ISOFFLINE(scope)"), + getter_AddRefs(mRemoveTimeRangeStatement)); + NS_ENSURE_SUCCESS(rv, rv); + // remove all keys rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_view"), getter_AddRefs(mRemoveAllStatement)); NS_ENSURE_SUCCESS(rv, rv); // check the usage for a given owner that is an offline-app allowed domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( @@ -684,16 +728,19 @@ nsDOMStoragePersistentDB::SetKey(nsDOMSt aKey); NS_ENSURE_SUCCESS(rv, rv); rv = binder->BindStringByName(NS_LITERAL_CSTRING("value"), aValue); NS_ENSURE_SUCCESS(rv, rv); rv = binder->BindInt32ByName(NS_LITERAL_CSTRING("secure"), aSecure ? 1 : 0); NS_ENSURE_SUCCESS(rv, rv); + rv = binder->BindInt64ByName(NS_LITERAL_CSTRING("inserttime"), + PR_Now()); + NS_ENSURE_SUCCESS(rv, rv); rv = binder.Add(); NS_ENSURE_SUCCESS(rv, rv); rv = mInsertKeyStatement->Execute(); NS_ENSURE_SUCCESS(rv, rv); if (!aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage).IsEmpty()) { @@ -801,16 +848,42 @@ nsDOMStoragePersistentDB::ClearStorage(n rv = mRemoveStorageStatement->Execute(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } nsresult +nsDOMStoragePersistentDB::RemoveTimeRange(PRInt64 since) +{ + nsresult rv; + + rv = MaybeCommitInsertTransaction(); + NS_ENSURE_SUCCESS(rv, rv); + + mozStorageStatementScoper scope(mRemoveTimeRangeStatement); + + Binder binder(mRemoveTimeRangeStatement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = binder->BindInt64ByName(NS_LITERAL_CSTRING("time"), + since); + NS_ENSURE_SUCCESS(rv, rv); + + rv = binder.Add(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mRemoveTimeRangeStatement->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner, PRBool aIncludeSubDomains) { nsresult rv; rv = MaybeCommitInsertTransaction(); NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/src/storage/nsDOMStoragePersistentDB.h +++ b/dom/src/storage/nsDOMStoragePersistentDB.h @@ -124,16 +124,24 @@ public: * Removes keys owned by domains that either match or don't match the * list. */ nsresult RemoveOwners(const nsTArray<nsString>& aOwners, PRBool aIncludeSubDomains, PRBool aMatch); /** + * Remove all values from all scopes not marked as offline that has been + * created after the time specified with 'aSince'. Used by the Clear Private + * Data dialog. 'aSince' value is compatible with PR_Now() function. + */ + nsresult + RemoveTimeRange(PRInt64 aSince); + + /** * Removes all keys from storage. Used when clearing storage. */ nsresult RemoveAll(); /** * Returns usage for a storage using its GetQuotaDomainDBKey() as a key. */ @@ -171,16 +179,17 @@ protected: nsCOMPtr<mozIStorageStatement> mDeleteTemporaryTableStatement; nsCOMPtr<mozIStorageStatement> mGetAllKeysStatement; nsCOMPtr<mozIStorageStatement> mGetKeyValueStatement; nsCOMPtr<mozIStorageStatement> mInsertKeyStatement; nsCOMPtr<mozIStorageStatement> mSetSecureStatement; nsCOMPtr<mozIStorageStatement> mRemoveKeyStatement; nsCOMPtr<mozIStorageStatement> mRemoveOwnerStatement; nsCOMPtr<mozIStorageStatement> mRemoveStorageStatement; + nsCOMPtr<mozIStorageStatement> mRemoveTimeRangeStatement; nsCOMPtr<mozIStorageStatement> mRemoveAllStatement; nsCOMPtr<mozIStorageStatement> mGetOfflineExcludedUsageStatement; nsCOMPtr<mozIStorageStatement> mGetFullUsageStatement; nsCString mCachedOwner; PRInt32 mCachedUsage; friend class nsDOMStorageDBWrapper;
--- a/dom/tests/mochitest/Makefile.in +++ b/dom/tests/mochitest/Makefile.in @@ -49,16 +49,17 @@ DIRS += \ dom-level2-html \ ajax \ bugs \ chrome \ general \ whatwg \ geolocation \ localstorage \ + globalstorage \ sessionstorage \ storageevent \ $(NULL) #needs IPC support ifneq (mobile,$(MOZ_BUILD_APP)) DIRS += notification endif
new file mode 100644 --- /dev/null +++ b/dom/tests/mochitest/globalstorage/Makefile.in @@ -0,0 +1,54 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Corporation. +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Jan Bambas <honzab@firemni.cz> +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = dom/tests/mochitest/globalstorage + +include $(DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/rules.mk + +_TEST_FILES = \ + test_globalStorageDeleteSinceAPI.html \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/dom/tests/mochitest/globalstorage/test_globalStorageDeleteSinceAPI.html @@ -0,0 +1,73 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>globalStorage delete since API test</title> + +<script type="text/javascript" src="/MochiKit/packed.js"></script> +<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + +<script type="text/javascript"> + +function cleanup() +{ + globalStorage[window.location.hostname].removeItem("key1"); + globalStorage[window.location.hostname].removeItem("key2"); + globalStorage[window.location.hostname].removeItem("key3"); + globalStorage[window.location.hostname].removeItem("key4"); + SimpleTest.finish(); +} + +function doTest() +{ + var since = 0; + + setTimeout('globalStorage[window.location.hostname].key1 = "value1"', 0); + setTimeout('globalStorage[window.location.hostname].key2 = "value2"', 100); + setTimeout('globalStorage[window.location.hostname].key3 = "value3"', 200); + + // Since now, all added/changed items will be deleted + setTimeout(function() { + // Now in microseconds... + since = (new Date()).getTime() * 1000; + }, 300); + + // Rather give the timer chance to move forward, on some systems the + // granularity may be too grainy. + + setTimeout('globalStorage[window.location.hostname].key4 = "value4"', 500); + setTimeout('globalStorage[window.location.hostname].key1 = "value1-2"', 600); + + setTimeout(function() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + is(globalStorage[window.location.hostname].length, 4, "Expected 4 items before delete"); + + try { + var domStorageManager = Components.classes["@mozilla.org/dom/storagemanager;1"] + .getService(Components.interfaces.nsIDOMStorageManager); + domStorageManager.clearStorageDataSince(since); + } + catch(ex) { + ok(false, ex); + } + + todo(globalStorage[window.location.hostname].key1 == null, "key1 deleted (Bug 600366)"); + is(globalStorage[window.location.hostname].key2, "value2", "key2 left"); + is(globalStorage[window.location.hostname].key3, "value3", "key3 left"); + todo(globalStorage[window.location.hostname].key4 == null, "key4 deleted (Bug 600366)"); + is(globalStorage[window.location.hostname].length, 2, "Expected 2 items after delete"); + + cleanup(); + }, 700); +} + +SimpleTest.waitForExplicitFinish(); + +</script> + +</head> + +<body onload="doTest();"> + +</body> +</html>
--- a/dom/tests/mochitest/localstorage/Makefile.in +++ b/dom/tests/mochitest/localstorage/Makefile.in @@ -63,16 +63,18 @@ include $(topsrcdir)/config/rules.mk test_brokenUTF-16.html \ test_cookieBlock.html \ test_cookieSession-phase1.html \ test_cookieSession-phase2.html \ test_embededNulls.html \ test_localStorageBase.html \ test_localStorageBasePrivateBrowsing.html \ test_localStorageBaseSessionOnly.html \ + test_localStorageDeleteSinceAPI.html \ + test_localStorageDeleteSinceAPIPrivateBrowsing.html \ test_localStorageCookieSettings.html \ test_localStorageEnablePref.html \ test_localStorageOriginsEquals.html \ test_localStorageOriginsDiff.html \ test_localStorageOriginsPortDiffs.html \ test_localStorageOriginsDomainDiffs.html \ test_localStorageOriginsSchemaDiffs.html \ test_localStorageReplace.html \
new file mode 100644 --- /dev/null +++ b/dom/tests/mochitest/localstorage/test_localStorageDeleteSinceAPI.html @@ -0,0 +1,70 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>localStorage delete since API test</title> + +<script type="text/javascript" src="/MochiKit/packed.js"></script> +<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + +<script type="text/javascript"> + +function cleanup() +{ + localStorage.clear(); + SimpleTest.finish(); +} + +function doTest() +{ + var since = 0; + + setTimeout('localStorage.key1 = "value1"', 0); + setTimeout('localStorage.key2 = "value2"', 100); + setTimeout('localStorage.key3 = "value3"', 200); + + // Since now, all added/changed items will be deleted + setTimeout(function() { + // Now in microseconds... + since = (new Date()).getTime() * 1000; + }, 300); + + // Rather give the timer chance to move forward, on some systems the + // granularity may be too grainy. + + setTimeout('localStorage.key4 = "value4"', 500); + setTimeout('localStorage.key1 = "value1-2"', 600); + + setTimeout(function() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + is(localStorage.length, 4, "Expected 4 items before delete in localStorage"); + + try { + var domStorageManager = Components.classes["@mozilla.org/dom/storagemanager;1"] + .getService(Components.interfaces.nsIDOMStorageManager); + domStorageManager.clearStorageDataSince(since); + } + catch(ex) { + ok(false, ex); + } + + is(localStorage.key1, null, "key1 deleted (if this fails see bug 600366 first)"); + is(localStorage.key2, "value2", "key2 left"); + is(localStorage.key3, "value3", "key3 left"); + is(localStorage.key4, null, "key4 deleted (if this fails see bug 600366 first)"); + is(localStorage.length, 2, "Expected 2 items after delete in localStorage"); + + cleanup(); + }, 700); +} + +SimpleTest.waitForExplicitFinish(); + +</script> + +</head> + +<body onload="doTest();"> + +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tests/mochitest/localstorage/test_localStorageDeleteSinceAPIPrivateBrowsing.html @@ -0,0 +1,85 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>localStorage delete since API test in Private Browsing</title> + +<script type="text/javascript" src="/MochiKit/packed.js"></script> +<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +<script type="text/javascript" src="pbSwitch.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + +<script type="text/javascript"> + +function cleanup() +{ + localStorage.clear(); + leavePrivateBrowsing(); + + SimpleTest.finish(); +} + +function startTest() +{ + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + if (get_PBSvc()) + doTest(); + else + ok(true, "No private browsing service, test could not be performed"); +} + +function doTest() +{ + var since = 0; + + enterPrivateBrowsing(); + + setTimeout('localStorage.key1 = "value1"', 0); + setTimeout('localStorage.key2 = "value2"', 100); + setTimeout('localStorage.key3 = "value3"', 200); + + // Since now, all added/changed items will be deleted + setTimeout(function() { + // Now in microseconds... + since = (new Date()).getTime() * 1000; + }, 300); + + // Rather give the timer chance to move forward, on some systems the + // granularity may be too grainy. + + setTimeout('localStorage.key4 = "value4"', 500); + setTimeout('localStorage.key1 = "value1-2"', 600); + + setTimeout(function() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + is(localStorage.length, 4, "Expected 4 items before delete in localStorage"); + + try { + var domStorageManager = Components.classes["@mozilla.org/dom/storagemanager;1"] + .getService(Components.interfaces.nsIDOMStorageManager); + domStorageManager.clearStorageDataSince(since); + } + catch(ex) { + ok(false, ex); + } + + is(localStorage.key1, null, "key1 deleted (if this fails see bug 600366 first)"); + is(localStorage.key2, "value2", "key2 left"); + is(localStorage.key3, "value3", "key3 left"); + is(localStorage.key4, null, "key4 deleted (if this fails see bug 600366 first)"); + is(localStorage.length, 2, "Expected 2 items after delete in localStorage"); + + cleanup(); + }, 700); +} + +SimpleTest.waitForExplicitFinish(); + +</script> + +</head> + +<body onload="startTest();"> + +</body> +</html>
--- a/dom/tests/mochitest/sessionstorage/Makefile.in +++ b/dom/tests/mochitest/sessionstorage/Makefile.in @@ -48,16 +48,17 @@ include $(topsrcdir)/config/rules.mk _TEST_FILES = \ frameReplace.html \ frameEqual.html \ frameNotEqual.html \ file_http.html \ file_https.html \ test_sessionStorageBase.html \ test_sessionStorageClone.html \ + test_sessionStorageDeleteSinceAPI.html \ test_sessionStorageReplace.html \ test_sessionStorageHttpHttps.html \ interOriginSlave.js \ interOriginTest.js \ $(NULL) _CHROME_FILES = \ test_sessionStorageFromChrome.xhtml \
new file mode 100644 --- /dev/null +++ b/dom/tests/mochitest/sessionstorage/test_sessionStorageDeleteSinceAPI.html @@ -0,0 +1,67 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>sessionStorage delete since API test</title> + +<script type="text/javascript" src="/MochiKit/packed.js"></script> +<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + +<script type="text/javascript"> + +function cleanup() +{ + sessionStorage.clear(); + SimpleTest.finish(); +} + +function doTest() +{ + var since = 0; + + setTimeout('sessionStorage.key1 = "value1"', 0); + setTimeout('sessionStorage.key2 = "value2"', 100); + setTimeout('sessionStorage.key3 = "value3"', 200); + + // Since now, all added/changed items will be deleted + setTimeout(function() { + // Now in microseconds... + since = (new Date()).getTime() * 1000; + }, 300); + + setTimeout('sessionStorage.key4 = "value4"', 500); + setTimeout('sessionStorage.key1 = "value1-2"', 600); + + setTimeout(function() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + is(sessionStorage.length, 4, "Expected 4 items before delete in sessionStorage"); + + try { + var domStorageManager = Components.classes["@mozilla.org/dom/storagemanager;1"] + .getService(Components.interfaces.nsIDOMStorageManager); + domStorageManager.clearStorageDataSince(since); + } + catch(ex) { + ok(false, ex); + } + + is(sessionStorage.length, 2, "Expected 2 items after delete in sessionStorage"); + is(sessionStorage.key1, null, "key1 deleted"); + is(sessionStorage.key2, "value2", "key2 left"); + is(sessionStorage.key3, "value3", "key3 left"); + is(sessionStorage.key4, null, "key4 deleted"); + + cleanup(); + }, 700); +} + +SimpleTest.waitForExplicitFinish(); + +</script> + +</head> + +<body onload="doTest();"> + +</body> +</html>