mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1165214 - Use OriginAttributes in DOM Storage. r=smaug, r=bholley
--HG-- extra : rebase_source : b63ddb5a24a335f771a856cd20c69cdeb0c92ca0
This commit is contained in:
parent
7cb7d44fc1
commit
a0a6f7e23c
@ -80,8 +80,7 @@ add_task(function* test() {
|
||||
// check each item in the title and validate it meets expectatations
|
||||
for (let part of title) {
|
||||
let [storageMethodName, value] = part.split("=");
|
||||
let is_f = storageMethodName == "cookie" ? is : todo_is;
|
||||
is_f(value, expectedContext,
|
||||
is(value, expectedContext,
|
||||
"the title reflects the expected contextual identity of " +
|
||||
expectedContext + " for method " + storageMethodName + ": " + value);
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
|
||||
}
|
||||
|
||||
if (!mSignedPkg.IsEmpty()) {
|
||||
MOZ_RELEASE_ASSERT(mSignedPkg.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
|
||||
params->Set(NS_LITERAL_STRING("signedPkg"), mSignedPkg);
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ NS_IMETHODIMP_(void) DOMStorageCacheBridge::Release(void)
|
||||
|
||||
// DOMStorageCache
|
||||
|
||||
DOMStorageCache::DOMStorageCache(const nsACString* aScope)
|
||||
: mScope(*aScope)
|
||||
DOMStorageCache::DOMStorageCache(const nsACString* aOriginNoSuffix)
|
||||
: mOriginNoSuffix(*aOriginNoSuffix)
|
||||
, mMonitor("DOMStorageCache")
|
||||
, mLoaded(false)
|
||||
, mLoadResult(NS_OK)
|
||||
@ -124,7 +124,7 @@ void
|
||||
DOMStorageCache::Init(DOMStorageManager* aManager,
|
||||
bool aPersistent,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsACString& aQuotaScope)
|
||||
const nsACString& aQuotaOriginScope)
|
||||
{
|
||||
if (mInitialized) {
|
||||
return;
|
||||
@ -132,15 +132,26 @@ DOMStorageCache::Init(DOMStorageManager* aManager,
|
||||
|
||||
mInitialized = true;
|
||||
mPrincipal = aPrincipal;
|
||||
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(mOriginSuffix);
|
||||
mPersistent = aPersistent;
|
||||
mQuotaScope = aQuotaScope.IsEmpty() ? mScope : aQuotaScope;
|
||||
if (aQuotaOriginScope.IsEmpty()) {
|
||||
mQuotaOriginScope = Origin();
|
||||
} else {
|
||||
mQuotaOriginScope = aQuotaOriginScope;
|
||||
}
|
||||
|
||||
if (mPersistent) {
|
||||
mManager = aManager;
|
||||
Preload();
|
||||
}
|
||||
|
||||
mUsage = aManager->GetScopeUsage(mQuotaScope);
|
||||
// Check the quota string has (or has not) the identical origin suffix as
|
||||
// this storage cache is bound to.
|
||||
MOZ_ASSERT(StringBeginsWith(mQuotaOriginScope, mOriginSuffix));
|
||||
MOZ_ASSERT(mOriginSuffix.IsEmpty() != StringBeginsWith(mQuotaOriginScope,
|
||||
NS_LITERAL_CSTRING("^")));
|
||||
|
||||
mUsage = aManager->GetOriginUsage(mQuotaOriginScope);
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -151,6 +162,12 @@ DOMStorageCache::Persist(const DOMStorage* aStorage) const
|
||||
!aStorage->IsPrivate();
|
||||
}
|
||||
|
||||
const nsCString
|
||||
DOMStorageCache::Origin() const
|
||||
{
|
||||
return DOMStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
|
||||
}
|
||||
|
||||
DOMStorageCache::Data&
|
||||
DOMStorageCache::DataSet(const DOMStorage* aStorage)
|
||||
{
|
||||
@ -658,8 +675,8 @@ DOMStorageCache::LoadWait()
|
||||
|
||||
// DOMStorageUsage
|
||||
|
||||
DOMStorageUsage::DOMStorageUsage(const nsACString& aScope)
|
||||
: mScope(aScope)
|
||||
DOMStorageUsage::DOMStorageUsage(const nsACString& aOriginScope)
|
||||
: mOriginScope(aOriginScope)
|
||||
{
|
||||
mUsage[kDefaultSet] = mUsage[kPrivateSet] = mUsage[kSessionSet] = 0LL;
|
||||
}
|
||||
|
@ -33,8 +33,16 @@ public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
|
||||
NS_IMETHOD_(void) Release(void);
|
||||
|
||||
// The scope (origin) in the database usage format (reversed)
|
||||
virtual const nsCString& Scope() const = 0;
|
||||
// The origin of the cache, result is concatenation of OriginNoSuffix() and OriginSuffix(),
|
||||
// see below.
|
||||
virtual const nsCString Origin() const = 0;
|
||||
|
||||
// The origin attributes suffix alone, this is usually passed as an |aOriginSuffix|
|
||||
// argument to various methods
|
||||
virtual const nsCString& OriginSuffix() const = 0;
|
||||
|
||||
// The origin in the database usage format (reversed) and without the suffix
|
||||
virtual const nsCString& OriginNoSuffix() const = 0;
|
||||
|
||||
// Whether the cache is already fully loaded
|
||||
virtual bool Loaded() = 0;
|
||||
@ -70,14 +78,17 @@ class DOMStorageCache : public DOMStorageCacheBridge
|
||||
public:
|
||||
NS_IMETHOD_(void) Release(void);
|
||||
|
||||
explicit DOMStorageCache(const nsACString* aScope);
|
||||
// Note: We pass aOriginNoSuffix through the ctor here, because
|
||||
// DOMStorageCacheHashKey's ctor is creating this class and
|
||||
// accepts reversed-origin-no-suffix as an argument - the hashing key.
|
||||
explicit DOMStorageCache(const nsACString* aOriginNoSuffix);
|
||||
|
||||
protected:
|
||||
virtual ~DOMStorageCache();
|
||||
|
||||
public:
|
||||
void Init(DOMStorageManager* aManager, bool aPersistent, nsIPrincipal* aPrincipal,
|
||||
const nsACString& aQuotaScope);
|
||||
const nsACString& aQuotaOriginScope);
|
||||
|
||||
// Copies all data from the other storage.
|
||||
void CloneFrom(const DOMStorageCache* aThat);
|
||||
@ -114,7 +125,9 @@ public:
|
||||
|
||||
// DOMStorageCacheBridge
|
||||
|
||||
virtual const nsCString& Scope() const { return mScope; }
|
||||
virtual const nsCString Origin() const;
|
||||
virtual const nsCString& OriginNoSuffix() const { return mOriginNoSuffix; }
|
||||
virtual const nsCString& OriginSuffix() const { return mOriginSuffix; }
|
||||
virtual bool Loaded() { return mLoaded; }
|
||||
virtual uint32_t LoadedCount();
|
||||
virtual bool LoadItem(const nsAString& aKey, const nsString& aValue);
|
||||
@ -188,11 +201,15 @@ private:
|
||||
// origin only.
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
// The scope this cache belongs to in the "DB format", i.e. reversed
|
||||
nsCString mScope;
|
||||
// The origin this cache belongs to in the "DB format", i.e. reversed
|
||||
nsCString mOriginNoSuffix;
|
||||
|
||||
// The eTLD+1 scope used to count quota usage.
|
||||
nsCString mQuotaScope;
|
||||
// The origin attributes suffix
|
||||
nsCString mOriginSuffix;
|
||||
|
||||
// The eTLD+1 scope used to count quota usage. It is in the reversed format
|
||||
// and contains the origin attributes suffix.
|
||||
nsCString mQuotaOriginScope;
|
||||
|
||||
// Non-private Browsing, Private Browsing and Session Only sets.
|
||||
Data mData[kDataSetCount];
|
||||
@ -241,7 +258,7 @@ class DOMStorageUsageBridge
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DOMStorageUsageBridge)
|
||||
|
||||
virtual const nsCString& Scope() = 0;
|
||||
virtual const nsCString& OriginScope() = 0;
|
||||
virtual void LoadUsage(const int64_t aUsage) = 0;
|
||||
|
||||
protected:
|
||||
@ -252,15 +269,15 @@ protected:
|
||||
class DOMStorageUsage : public DOMStorageUsageBridge
|
||||
{
|
||||
public:
|
||||
explicit DOMStorageUsage(const nsACString& aScope);
|
||||
explicit DOMStorageUsage(const nsACString& aOriginScope);
|
||||
|
||||
bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta);
|
||||
|
||||
private:
|
||||
virtual const nsCString& Scope() { return mScope; }
|
||||
virtual const nsCString& OriginScope() { return mOriginScope; }
|
||||
virtual void LoadUsage(const int64_t aUsage);
|
||||
|
||||
nsCString mScope;
|
||||
nsCString mOriginScope;
|
||||
int64_t mUsage[DOMStorageCache::kDataSetCount];
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMStorageDBThread.h"
|
||||
#include "DOMStorageDBUpdater.h"
|
||||
#include "DOMStorageCache.h"
|
||||
#include "DOMStorageManager.h"
|
||||
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
@ -19,10 +21,12 @@
|
||||
#include "mozIStorageBindingParams.h"
|
||||
#include "mozIStorageValueArray.h"
|
||||
#include "mozIStorageFunction.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsVariant.h"
|
||||
#include "mozilla/IOInterposer.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Tokenizer.h"
|
||||
|
||||
// How long we collect write oprerations
|
||||
// before they are flushed to the database
|
||||
@ -32,9 +36,43 @@
|
||||
// Write Ahead Log's maximum size is 512KB
|
||||
#define MAX_WAL_SIZE_BYTES 512 * 1024
|
||||
|
||||
// Current version of the database schema
|
||||
#define CURRENT_SCHEMA_VERSION 1
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace { // anon
|
||||
|
||||
// This is only a compatibility code for schema version 0. Returns the 'scope' key
|
||||
// in the schema version 0 format for the scope column.
|
||||
nsCString
|
||||
Scheme0Scope(DOMStorageCacheBridge* aCache)
|
||||
{
|
||||
nsCString result;
|
||||
|
||||
nsCString suffix = aCache->OriginSuffix();
|
||||
|
||||
PrincipalOriginAttributes oa;
|
||||
if (!suffix.IsEmpty()) {
|
||||
oa.PopulateFromSuffix(suffix);
|
||||
}
|
||||
|
||||
if (oa.mAppId != nsIScriptSecurityManager::NO_APP_ID || oa.mInBrowser) {
|
||||
result.AppendInt(oa.mAppId);
|
||||
result.Append(':');
|
||||
result.Append(oa.mInBrowser ? 't' : 'f');
|
||||
result.Append(':');
|
||||
}
|
||||
|
||||
result.Append(aCache->OriginNoSuffix());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // anon
|
||||
|
||||
|
||||
DOMStorageDBBridge::DOMStorageDBBridge()
|
||||
{
|
||||
}
|
||||
@ -132,8 +170,8 @@ DOMStorageDBThread::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync)
|
||||
bool pendingTasks;
|
||||
{
|
||||
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
|
||||
pendingTasks = mPendingTasks.IsScopeUpdatePending(aCache->Scope()) ||
|
||||
mPendingTasks.IsScopeClearPending(aCache->Scope());
|
||||
pendingTasks = mPendingTasks.IsOriginUpdatePending(aCache->OriginSuffix(), aCache->OriginNoSuffix()) ||
|
||||
mPendingTasks.IsOriginClearPending(aCache->OriginSuffix(), aCache->OriginNoSuffix());
|
||||
}
|
||||
|
||||
if (!pendingTasks) {
|
||||
@ -164,18 +202,18 @@ DOMStorageDBThread::AsyncFlush()
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBThread::ShouldPreloadScope(const nsACString& aScope)
|
||||
DOMStorageDBThread::ShouldPreloadOrigin(const nsACString& aOrigin)
|
||||
{
|
||||
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
|
||||
return mScopesHavingData.Contains(aScope);
|
||||
return mOriginsHavingData.Contains(aOrigin);
|
||||
}
|
||||
|
||||
void
|
||||
DOMStorageDBThread::GetScopesHavingData(InfallibleTArray<nsCString>* aScopes)
|
||||
DOMStorageDBThread::GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins)
|
||||
{
|
||||
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
|
||||
for (auto iter = mScopesHavingData.Iter(); !iter.Done(); iter.Next()) {
|
||||
aScopes->AppendElement(iter.Get()->GetKey());
|
||||
for (auto iter = mOriginsHavingData.Iter(); !iter.Done(); iter.Next()) {
|
||||
aOrigins->AppendElement(iter.Get()->GetKey());
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,14 +240,14 @@ DOMStorageDBThread::InsertDBOp(DOMStorageDBThread::DBOperation* aOperation)
|
||||
switch (aOperation->Type()) {
|
||||
case DBOperation::opPreload:
|
||||
case DBOperation::opPreloadUrgent:
|
||||
if (mPendingTasks.IsScopeUpdatePending(aOperation->Scope())) {
|
||||
if (mPendingTasks.IsOriginUpdatePending(aOperation->OriginSuffix(), aOperation->OriginNoSuffix())) {
|
||||
// If there is a pending update operation for the scope first do the flush
|
||||
// before we preload the cache. This may happen in an extremely rare case
|
||||
// when a child process throws away its cache before flush on the parent
|
||||
// has finished. If we would preloaded the cache as a priority operation
|
||||
// before the pending flush, we would have got an inconsistent cache content.
|
||||
mFlushImmediately = true;
|
||||
} else if (mPendingTasks.IsScopeClearPending(aOperation->Scope())) {
|
||||
} else if (mPendingTasks.IsOriginClearPending(aOperation->OriginSuffix(), aOperation->OriginNoSuffix())) {
|
||||
// The scope is scheduled to be cleared, so just quickly load as empty.
|
||||
// We need to do this to prevent load of the DB data before the scope has
|
||||
// actually been cleared from the database. Preloads are processed
|
||||
@ -378,41 +416,6 @@ DOMStorageDBThread::ThreadObserver::AfterProcessNextEvent(nsIThreadInternal *thr
|
||||
extern void
|
||||
ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult);
|
||||
|
||||
namespace {
|
||||
|
||||
class nsReverseStringSQLFunction final : public mozIStorageFunction
|
||||
{
|
||||
~nsReverseStringSQLFunction() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsReverseStringSQLFunction, mozIStorageFunction)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsReverseStringSQLFunction::OnFunctionCall(
|
||||
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString stringToReverse;
|
||||
rv = aFunctionArguments->GetUTF8String(0, stringToReverse);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString result;
|
||||
ReverseString(stringToReverse, result);
|
||||
|
||||
RefPtr<nsVariant> outVar(new nsVariant());
|
||||
rv = outVar->SetAsAUTF8String(result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
outVar.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
nsresult
|
||||
DOMStorageDBThread::OpenDatabaseConnection()
|
||||
{
|
||||
@ -457,73 +460,7 @@ DOMStorageDBThread::InitDatabase()
|
||||
(void)mWorkerConnection->Clone(true, getter_AddRefs(mReaderConnection));
|
||||
NS_ENSURE_TRUE(mReaderConnection, NS_ERROR_FAILURE);
|
||||
|
||||
mozStorageTransaction transaction(mWorkerConnection, false);
|
||||
|
||||
// Ensure Gecko 1.9.1 storage table
|
||||
rv = mWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE IF NOT EXISTS webappsstore2 ("
|
||||
"scope TEXT, "
|
||||
"key TEXT, "
|
||||
"value TEXT, "
|
||||
"secure INTEGER, "
|
||||
"owner TEXT)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS scope_key_index"
|
||||
" ON webappsstore2(scope, key)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageFunction> function1(new nsReverseStringSQLFunction());
|
||||
NS_ENSURE_TRUE(function1, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = mWorkerConnection->CreateFunction(NS_LITERAL_CSTRING("REVERSESTRING"), 1, function1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool 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 = mWorkerConnection->TableExists(NS_LITERAL_CSTRING("webappsstore"),
|
||||
&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
rv = mWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("INSERT OR IGNORE INTO "
|
||||
"webappsstore2(scope, key, value, secure, owner) "
|
||||
"SELECT REVERSESTRING(domain) || '.:', key, value, secure, owner "
|
||||
"FROM webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DROP TABLE webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Check if there is storage of Gecko 1.8 and if so, upgrade that storage
|
||||
// to actual webappsstore2 table and drop the obsolete table. Potential
|
||||
// duplicates will be ignored.
|
||||
rv = mWorkerConnection->TableExists(NS_LITERAL_CSTRING("moz_webappsstore"),
|
||||
&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
rv = mWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("INSERT OR IGNORE INTO "
|
||||
"webappsstore2(scope, key, value, secure, owner) "
|
||||
"SELECT REVERSESTRING(domain) || '.:', key, value, secure, domain "
|
||||
"FROM moz_webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DROP TABLE moz_webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = transaction.Commit();
|
||||
rv = DOMStorageDBUpdater::Update(mWorkerConnection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Database open and all initiation operation are done. Switching this flag
|
||||
@ -534,18 +471,21 @@ DOMStorageDBThread::InitDatabase()
|
||||
|
||||
// List scopes having any stored data
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
rv = mWorkerConnection->CreateStatement(NS_LITERAL_CSTRING("SELECT DISTINCT scope FROM webappsstore2"),
|
||||
getter_AddRefs(stmt));
|
||||
// Note: result of this select must match DOMStorageManager::CreateOrigin()
|
||||
rv = mWorkerConnection->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT DISTINCT originAttributes || ':' || originKey FROM webappsstore2"),
|
||||
getter_AddRefs(stmt));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
bool exists;
|
||||
while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&exists)) && exists) {
|
||||
nsAutoCString foundScope;
|
||||
rv = stmt->GetUTF8String(0, foundScope);
|
||||
nsAutoCString foundOrigin;
|
||||
rv = stmt->GetUTF8String(0, foundOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MonitorAutoLock monitor(mThreadObserver->GetMonitor());
|
||||
mScopesHavingData.PutEntry(foundScope);
|
||||
mOriginsHavingData.PutEntry(foundOrigin);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -738,6 +678,51 @@ DOMStorageDBThread::NotifyFlushCompletion()
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper SQL function classes
|
||||
|
||||
namespace {
|
||||
|
||||
class OriginAttrsPatternMatchSQLFunction final : public mozIStorageFunction
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
|
||||
explicit OriginAttrsPatternMatchSQLFunction(OriginAttributesPattern const& aPattern)
|
||||
: mPattern(aPattern) {}
|
||||
|
||||
private:
|
||||
OriginAttrsPatternMatchSQLFunction() = delete;
|
||||
~OriginAttrsPatternMatchSQLFunction() {}
|
||||
|
||||
OriginAttributesPattern mPattern;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(OriginAttrsPatternMatchSQLFunction, mozIStorageFunction)
|
||||
|
||||
NS_IMETHODIMP
|
||||
OriginAttrsPatternMatchSQLFunction::OnFunctionCall(
|
||||
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString suffix;
|
||||
rv = aFunctionArguments->GetUTF8String(0, suffix);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PrincipalOriginAttributes oa;
|
||||
oa.PopulateFromSuffix(suffix);
|
||||
bool result = mPattern.Matches(oa);
|
||||
|
||||
RefPtr<nsVariant> outVar(new nsVariant());
|
||||
rv = outVar->SetAsBool(result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
outVar.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// DOMStorageDBThread::DBOperation
|
||||
|
||||
DOMStorageDBThread::DBOperation::DBOperation(const OperationType aType,
|
||||
@ -749,6 +734,13 @@ DOMStorageDBThread::DBOperation::DBOperation(const OperationType aType,
|
||||
, mKey(aKey)
|
||||
, mValue(aValue)
|
||||
{
|
||||
MOZ_ASSERT(mType == opPreload ||
|
||||
mType == opPreloadUrgent ||
|
||||
mType == opAddItem ||
|
||||
mType == opUpdateItem ||
|
||||
mType == opRemoveItem ||
|
||||
mType == opClear ||
|
||||
mType == opClearAll);
|
||||
MOZ_COUNT_CTOR(DOMStorageDBThread::DBOperation);
|
||||
}
|
||||
|
||||
@ -757,15 +749,27 @@ DOMStorageDBThread::DBOperation::DBOperation(const OperationType aType,
|
||||
: mType(aType)
|
||||
, mUsage(aUsage)
|
||||
{
|
||||
MOZ_ASSERT(mType == opGetUsage);
|
||||
MOZ_COUNT_CTOR(DOMStorageDBThread::DBOperation);
|
||||
}
|
||||
|
||||
DOMStorageDBThread::DBOperation::DBOperation(const OperationType aType,
|
||||
const nsACString& aScope)
|
||||
const nsACString& aOriginNoSuffix)
|
||||
: mType(aType)
|
||||
, mCache(nullptr)
|
||||
, mScope(aScope)
|
||||
, mOrigin(aOriginNoSuffix)
|
||||
{
|
||||
MOZ_ASSERT(mType == opClearMatchingOrigin);
|
||||
MOZ_COUNT_CTOR(DOMStorageDBThread::DBOperation);
|
||||
}
|
||||
|
||||
DOMStorageDBThread::DBOperation::DBOperation(const OperationType aType,
|
||||
const OriginAttributesPattern& aOriginNoSuffix)
|
||||
: mType(aType)
|
||||
, mCache(nullptr)
|
||||
, mOriginPattern(aOriginNoSuffix)
|
||||
{
|
||||
MOZ_ASSERT(mType == opClearMatchingOriginAttributes);
|
||||
MOZ_COUNT_CTOR(DOMStorageDBThread::DBOperation);
|
||||
}
|
||||
|
||||
@ -775,26 +779,46 @@ DOMStorageDBThread::DBOperation::~DBOperation()
|
||||
}
|
||||
|
||||
const nsCString
|
||||
DOMStorageDBThread::DBOperation::Scope()
|
||||
DOMStorageDBThread::DBOperation::OriginNoSuffix() const
|
||||
{
|
||||
if (mCache) {
|
||||
return mCache->Scope();
|
||||
return mCache->OriginNoSuffix();
|
||||
}
|
||||
|
||||
return mScope;
|
||||
return EmptyCString();
|
||||
}
|
||||
|
||||
const nsCString
|
||||
DOMStorageDBThread::DBOperation::Target()
|
||||
DOMStorageDBThread::DBOperation::OriginSuffix() const
|
||||
{
|
||||
if (mCache) {
|
||||
return mCache->OriginSuffix();
|
||||
}
|
||||
|
||||
return EmptyCString();
|
||||
}
|
||||
|
||||
const nsCString
|
||||
DOMStorageDBThread::DBOperation::Origin() const
|
||||
{
|
||||
if (mCache) {
|
||||
return mCache->Origin();
|
||||
}
|
||||
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
const nsCString
|
||||
DOMStorageDBThread::DBOperation::Target() const
|
||||
{
|
||||
switch (mType) {
|
||||
case opAddItem:
|
||||
case opUpdateItem:
|
||||
case opRemoveItem:
|
||||
return Scope() + NS_LITERAL_CSTRING("|") + NS_ConvertUTF16toUTF8(mKey);
|
||||
return Origin() + NS_LITERAL_CSTRING("|") + NS_ConvertUTF16toUTF8(mKey);
|
||||
|
||||
default:
|
||||
return Scope();
|
||||
return Origin();
|
||||
}
|
||||
}
|
||||
|
||||
@ -830,13 +854,17 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
// It skips keys we have already loaded.
|
||||
nsCOMPtr<mozIStorageStatement> stmt = statements->GetCachedStatement(
|
||||
"SELECT key, value FROM webappsstore2 "
|
||||
"WHERE scope = :scope ORDER BY key "
|
||||
"LIMIT -1 OFFSET :offset");
|
||||
"WHERE originAttributes = :originAttributes AND originKey = :originKey "
|
||||
"ORDER BY key LIMIT -1 OFFSET :offset");
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
|
||||
mCache->Scope());
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originAttributes"),
|
||||
mCache->OriginSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
|
||||
mCache->OriginNoSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("offset"),
|
||||
@ -865,15 +893,15 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
case opGetUsage:
|
||||
{
|
||||
nsCOMPtr<mozIStorageStatement> stmt = aThread->mWorkerStatements.GetCachedStatement(
|
||||
"SELECT SUM(LENGTH(key) + LENGTH(value)) FROM webappsstore2"
|
||||
" WHERE scope LIKE :scope"
|
||||
"SELECT SUM(LENGTH(key) + LENGTH(value)) FROM webappsstore2 "
|
||||
"WHERE (originAttributes || ':' || originKey) LIKE :usageOrigin"
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
|
||||
mUsage->Scope() + NS_LITERAL_CSTRING("%"));
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("usageOrigin"),
|
||||
mUsage->OriginScope());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool exists;
|
||||
@ -896,15 +924,22 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = aThread->mWorkerStatements.GetCachedStatement(
|
||||
"INSERT OR REPLACE INTO webappsstore2 (scope, key, value) "
|
||||
"VALUES (:scope, :key, :value) "
|
||||
"INSERT OR REPLACE INTO webappsstore2 (originAttributes, originKey, scope, key, value) "
|
||||
"VALUES (:originAttributes, :originKey, :scope, :key, :value) "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originAttributes"),
|
||||
mCache->OriginSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
|
||||
mCache->OriginNoSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Filling the 'scope' column just for downgrade compatibility reasons
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
|
||||
mCache->Scope());
|
||||
Scheme0Scope(mCache));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key"),
|
||||
mKey);
|
||||
@ -916,7 +951,8 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aThread->mScopesHavingData.PutEntry(Scope());
|
||||
MonitorAutoLock monitor(aThread->mThreadObserver->GetMonitor());
|
||||
aThread->mOriginsHavingData.PutEntry(Origin());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -926,14 +962,17 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = aThread->mWorkerStatements.GetCachedStatement(
|
||||
"DELETE FROM webappsstore2 "
|
||||
"WHERE scope = :scope "
|
||||
"WHERE originAttributes = :originAttributes AND originKey = :originKey "
|
||||
"AND key = :key "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
|
||||
mCache->Scope());
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originAttributes"),
|
||||
mCache->OriginSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
|
||||
mCache->OriginNoSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key"),
|
||||
mKey);
|
||||
@ -951,19 +990,23 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = aThread->mWorkerStatements.GetCachedStatement(
|
||||
"DELETE FROM webappsstore2 "
|
||||
"WHERE scope = :scope"
|
||||
"WHERE originAttributes = :originAttributes AND originKey = :originKey"
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
|
||||
mCache->Scope());
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originAttributes"),
|
||||
mCache->OriginSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("originKey"),
|
||||
mCache->OriginNoSuffix());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aThread->mScopesHavingData.RemoveEntry(Scope());
|
||||
MonitorAutoLock monitor(aThread->mThreadObserver->GetMonitor());
|
||||
aThread->mOriginsHavingData.RemoveEntry(Origin());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -980,28 +1023,68 @@ DOMStorageDBThread::DBOperation::Perform(DOMStorageDBThread* aThread)
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aThread->mScopesHavingData.Clear();
|
||||
MonitorAutoLock monitor(aThread->mThreadObserver->GetMonitor());
|
||||
aThread->mOriginsHavingData.Clear();
|
||||
break;
|
||||
}
|
||||
|
||||
case opClearMatchingScope:
|
||||
case opClearMatchingOrigin:
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = aThread->mWorkerStatements.GetCachedStatement(
|
||||
"DELETE FROM webappsstore2"
|
||||
" WHERE scope GLOB :scope"
|
||||
" WHERE originKey GLOB :scope"
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
|
||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
|
||||
mScope + NS_LITERAL_CSTRING("*"));
|
||||
mOrigin + NS_LITERAL_CSTRING("*"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stmt->Execute();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// No need to selectively clear mOriginsHavingData here. That hashtable only
|
||||
// prevents preload for scopes with no data. Leaving a false record in it has
|
||||
// a negligible effect on performance.
|
||||
break;
|
||||
}
|
||||
|
||||
case opClearMatchingOriginAttributes:
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// Register the ORIGIN_ATTRS_PATTERN_MATCH function, initialized with the pattern
|
||||
nsCOMPtr<mozIStorageFunction> patternMatchFunction(
|
||||
new OriginAttrsPatternMatchSQLFunction(mOriginPattern));
|
||||
|
||||
rv = aThread->mWorkerConnection->CreateFunction(
|
||||
NS_LITERAL_CSTRING("ORIGIN_ATTRS_PATTERN_MATCH"), 1, patternMatchFunction);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = aThread->mWorkerStatements.GetCachedStatement(
|
||||
"DELETE FROM webappsstore2"
|
||||
" WHERE ORIGIN_ATTRS_PATTERN_MATCH(originAttributes)"
|
||||
);
|
||||
|
||||
if (stmt) {
|
||||
mozStorageStatementScoper scope(stmt);
|
||||
rv = stmt->Execute();
|
||||
} else {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Always remove the function
|
||||
aThread->mWorkerConnection->RemoveFunction(
|
||||
NS_LITERAL_CSTRING("ORIGIN_ATTRS_PATTERN_MATCH"));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// No need to selectively clear mOriginsHavingData here. That hashtable only
|
||||
// prevents preload for scopes with no data. Leaving a false record in it has
|
||||
// a negligible effect on performance.
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1054,27 +1137,41 @@ DOMStorageDBThread::PendingOperations::PendingOperations()
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBThread::PendingOperations::HasTasks()
|
||||
DOMStorageDBThread::PendingOperations::HasTasks() const
|
||||
{
|
||||
return !!mUpdates.Count() || !!mClears.Count();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool OriginPatternMatches(const nsACString& aOriginSuffix, const OriginAttributesPattern& aPattern)
|
||||
{
|
||||
PrincipalOriginAttributes oa;
|
||||
DebugOnly<bool> rv = oa.PopulateFromSuffix(aOriginSuffix);
|
||||
MOZ_ASSERT(rv);
|
||||
return aPattern.Matches(oa);
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
ForgetUpdatesForScope(const nsACString& aMapping,
|
||||
ForgetUpdatesForOrigin(const nsACString& aMapping,
|
||||
nsAutoPtr<DOMStorageDBThread::DBOperation>& aPendingTask,
|
||||
void* aArg)
|
||||
{
|
||||
DOMStorageDBThread::DBOperation* newOp = static_cast<DOMStorageDBThread::DBOperation*>(aArg);
|
||||
|
||||
if (newOp->Type() == DOMStorageDBThread::DBOperation::opClear &&
|
||||
aPendingTask->Scope() != newOp->Scope()) {
|
||||
(aPendingTask->OriginNoSuffix() != newOp->OriginNoSuffix() ||
|
||||
aPendingTask->OriginSuffix() != newOp->OriginSuffix())) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
if (newOp->Type() == DOMStorageDBThread::DBOperation::opClearMatchingScope &&
|
||||
!StringBeginsWith(aPendingTask->Scope(), newOp->Scope())) {
|
||||
if (newOp->Type() == DOMStorageDBThread::DBOperation::opClearMatchingOrigin &&
|
||||
!StringBeginsWith(aPendingTask->OriginNoSuffix(), newOp->Origin())) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
if (newOp->Type() == DOMStorageDBThread::DBOperation::opClearMatchingOriginAttributes &&
|
||||
!OriginPatternMatches(aPendingTask->OriginSuffix(), newOp->OriginPattern())) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
@ -1108,7 +1205,7 @@ void
|
||||
DOMStorageDBThread::PendingOperations::Add(DOMStorageDBThread::DBOperation* aOperation)
|
||||
{
|
||||
// Optimize: when a key to remove has never been written to disk
|
||||
// just bypass this operation. A kew is new when an operation scheduled
|
||||
// just bypass this operation. A key is new when an operation scheduled
|
||||
// to write it to the database is of type opAddItem.
|
||||
if (CheckForCoalesceOpportunity(aOperation, DBOperation::opAddItem, DBOperation::opRemoveItem)) {
|
||||
mUpdates.Remove(aOperation->Target());
|
||||
@ -1146,12 +1243,13 @@ DOMStorageDBThread::PendingOperations::Add(DOMStorageDBThread::DBOperation* aOpe
|
||||
// Clear operations
|
||||
|
||||
case DBOperation::opClear:
|
||||
case DBOperation::opClearMatchingScope:
|
||||
case DBOperation::opClearMatchingOrigin:
|
||||
case DBOperation::opClearMatchingOriginAttributes:
|
||||
// Drop all update (insert/remove) operations for equivavelent or matching scope.
|
||||
// We do this as an optimization as well as a must based on the logic,
|
||||
// if we would not delete the update tasks, changes would have been stored
|
||||
// to the database after clear operations have been executed.
|
||||
mUpdates.Enumerate(ForgetUpdatesForScope, aOperation);
|
||||
mUpdates.Enumerate(ForgetUpdatesForOrigin, aOperation);
|
||||
mClears.Put(aOperation->Target(), aOperation);
|
||||
break;
|
||||
|
||||
@ -1254,7 +1352,7 @@ DOMStorageDBThread::PendingOperations::Finalize(nsresult aRv)
|
||||
namespace {
|
||||
|
||||
bool
|
||||
FindPendingClearForScope(const nsACString& aScope,
|
||||
FindPendingClearForOrigin(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
|
||||
DOMStorageDBThread::DBOperation* aPendingOperation)
|
||||
{
|
||||
if (aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opClearAll) {
|
||||
@ -1262,12 +1360,18 @@ FindPendingClearForScope(const nsACString& aScope,
|
||||
}
|
||||
|
||||
if (aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opClear &&
|
||||
aScope == aPendingOperation->Scope()) {
|
||||
aOriginNoSuffix == aPendingOperation->OriginNoSuffix() &&
|
||||
aOriginSuffix == aPendingOperation->OriginSuffix()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opClearMatchingScope &&
|
||||
StringBeginsWith(aScope, aPendingOperation->Scope())) {
|
||||
if (aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opClearMatchingOrigin &&
|
||||
StringBeginsWith(aOriginNoSuffix, aPendingOperation->Origin())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opClearMatchingOriginAttributes &&
|
||||
OriginPatternMatches(aOriginSuffix, aPendingOperation->OriginPattern())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1277,18 +1381,19 @@ FindPendingClearForScope(const nsACString& aScope,
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
DOMStorageDBThread::PendingOperations::IsScopeClearPending(const nsACString& aScope)
|
||||
DOMStorageDBThread::PendingOperations::IsOriginClearPending(const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix) const
|
||||
{
|
||||
// Called under the lock
|
||||
|
||||
for (auto iter = mClears.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (FindPendingClearForScope(aScope, iter.UserData())) {
|
||||
for (auto iter = mClears.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (FindPendingClearForOrigin(aOriginSuffix, aOriginNoSuffix, iter.UserData())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mExecList.Length(); ++i) {
|
||||
if (FindPendingClearForScope(aScope, mExecList[i])) {
|
||||
if (FindPendingClearForOrigin(aOriginSuffix, aOriginNoSuffix, mExecList[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1299,13 +1404,14 @@ DOMStorageDBThread::PendingOperations::IsScopeClearPending(const nsACString& aSc
|
||||
namespace {
|
||||
|
||||
bool
|
||||
FindPendingUpdateForScope(const nsACString& aScope,
|
||||
DOMStorageDBThread::DBOperation* aPendingOperation)
|
||||
FindPendingUpdateForOrigin(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix,
|
||||
DOMStorageDBThread::DBOperation* aPendingOperation)
|
||||
{
|
||||
if ((aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opAddItem ||
|
||||
aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opUpdateItem ||
|
||||
aPendingOperation->Type() == DOMStorageDBThread::DBOperation::opRemoveItem) &&
|
||||
aScope == aPendingOperation->Scope()) {
|
||||
aOriginNoSuffix == aPendingOperation->OriginNoSuffix() &&
|
||||
aOriginSuffix == aPendingOperation->OriginSuffix()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1315,18 +1421,19 @@ FindPendingUpdateForScope(const nsACString& aScope,
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
DOMStorageDBThread::PendingOperations::IsScopeUpdatePending(const nsACString& aScope)
|
||||
DOMStorageDBThread::PendingOperations::IsOriginUpdatePending(const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix) const
|
||||
{
|
||||
// Called under the lock
|
||||
|
||||
for (auto iter = mUpdates.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (FindPendingUpdateForScope(aScope, iter.UserData())) {
|
||||
for (auto iter = mUpdates.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (FindPendingUpdateForOrigin(aOriginSuffix, aOriginNoSuffix, iter.UserData())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mExecList.Length(); ++i) {
|
||||
if (FindPendingUpdateForScope(aScope, mExecList[i])) {
|
||||
if (FindPendingUpdateForOrigin(aOriginSuffix, aOriginNoSuffix, mExecList[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/storage/StatementCache.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
@ -73,17 +74,20 @@ public:
|
||||
// Called when chrome deletes e.g. cookies, schedules delete of the whole database
|
||||
virtual void AsyncClearAll() = 0;
|
||||
|
||||
// Called when only a domain and its subdomains or an app data is about to clear
|
||||
virtual void AsyncClearMatchingScope(const nsACString& aScope) = 0;
|
||||
// Called when only a domain and its subdomains is about to clear
|
||||
virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix) = 0;
|
||||
|
||||
// Called when data matching an origin pattern have to be cleared
|
||||
virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern) = 0;
|
||||
|
||||
// Forces scheduled DB operations to be early flushed to the disk
|
||||
virtual void AsyncFlush() = 0;
|
||||
|
||||
// Check whether the scope has any data stored on disk and is thus allowed to preload
|
||||
virtual bool ShouldPreloadScope(const nsACString& aScope) = 0;
|
||||
virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix) = 0;
|
||||
|
||||
// Get the complete list of scopes having data
|
||||
virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes) = 0;
|
||||
virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins) = 0;
|
||||
};
|
||||
|
||||
// The implementation of the the database engine, this directly works
|
||||
@ -114,11 +118,17 @@ public:
|
||||
opAddItem,
|
||||
opUpdateItem,
|
||||
opRemoveItem,
|
||||
// Clears a specific single origin data
|
||||
opClear,
|
||||
|
||||
// Operations invoked by chrome
|
||||
|
||||
// Clear all the data stored in the database, for all scopes, no exceptions
|
||||
opClearAll,
|
||||
opClearMatchingScope,
|
||||
// Clear data under a domain and all its subdomains regardless OriginAttributes value
|
||||
opClearMatchingOrigin,
|
||||
// Clear all data matching an OriginAttributesPattern regardless a domain
|
||||
opClearMatchingOriginAttributes,
|
||||
} OperationType;
|
||||
|
||||
explicit DBOperation(const OperationType aType,
|
||||
@ -128,7 +138,9 @@ public:
|
||||
DBOperation(const OperationType aType,
|
||||
DOMStorageUsageBridge* aUsage);
|
||||
DBOperation(const OperationType aType,
|
||||
const nsACString& aScope);
|
||||
const nsACString& aOriginNoSuffix);
|
||||
DBOperation(const OperationType aType,
|
||||
const OriginAttributesPattern& aOriginNoSuffix);
|
||||
~DBOperation();
|
||||
|
||||
// Executes the operation, doesn't necessarity have to be called on the I/O thread
|
||||
@ -138,13 +150,23 @@ public:
|
||||
void Finalize(nsresult aRv);
|
||||
|
||||
// The operation type
|
||||
OperationType Type() { return mType; }
|
||||
OperationType Type() const { return mType; }
|
||||
|
||||
// The operation scope (=origin)
|
||||
const nsCString Scope();
|
||||
// The origin in the database usage format (reversed)
|
||||
const nsCString OriginNoSuffix() const;
|
||||
|
||||
// |Scope + key| the operation is working with
|
||||
const nsCString Target();
|
||||
// The origin attributes suffix
|
||||
const nsCString OriginSuffix() const;
|
||||
|
||||
// |origin suffix + origin key| the operation is working with
|
||||
// or a scope pattern to delete with simple SQL's "LIKE %" from the database.
|
||||
const nsCString Origin() const;
|
||||
|
||||
// |origin suffix + origin key + key| the operation is working with
|
||||
const nsCString Target() const;
|
||||
|
||||
// Pattern to delete matching data with this op
|
||||
const OriginAttributesPattern& OriginPattern() const { return mOriginPattern; }
|
||||
|
||||
private:
|
||||
// The operation implementation body
|
||||
@ -154,9 +176,10 @@ public:
|
||||
OperationType mType;
|
||||
RefPtr<DOMStorageCacheBridge> mCache;
|
||||
RefPtr<DOMStorageUsageBridge> mUsage;
|
||||
nsString mKey;
|
||||
nsString mValue;
|
||||
nsCString mScope;
|
||||
nsString const mKey;
|
||||
nsString const mValue;
|
||||
nsCString const mOrigin;
|
||||
OriginAttributesPattern const mOriginPattern;
|
||||
};
|
||||
|
||||
// Encapsulation of collective and coalescing logic for all pending operations
|
||||
@ -166,11 +189,11 @@ public:
|
||||
PendingOperations();
|
||||
|
||||
// Method responsible for coalescing redundant update operations with the same
|
||||
// |Target()| or clear operations with the same or matching |Scope()|
|
||||
// |Target()| or clear operations with the same or matching |Origin()|
|
||||
void Add(DBOperation* aOperation);
|
||||
|
||||
// True when there are some scheduled operations to flush on disk
|
||||
bool HasTasks();
|
||||
bool HasTasks() const;
|
||||
|
||||
// Moves collected operations to a local flat list to allow execution of the operation
|
||||
// list out of the thread lock
|
||||
@ -184,12 +207,13 @@ public:
|
||||
// to flush what indicates a long standing issue with the database access.
|
||||
bool Finalize(nsresult aRv);
|
||||
|
||||
// true when a clear that deletes the given |scope| is among the pending operations;
|
||||
// when a preload for that scope is being scheduled, it must be finished right away
|
||||
bool IsScopeClearPending(const nsACString& aScope);
|
||||
// true when a clear that deletes the given origin attr pattern and/or origin key
|
||||
// is among the pending operations; when a preload for that scope is being scheduled,
|
||||
// it must be finished right away
|
||||
bool IsOriginClearPending(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) const;
|
||||
|
||||
// Checks whether there is a pending update (or clear, actually) operation for this scope.
|
||||
bool IsScopeUpdatePending(const nsACString& aScope);
|
||||
// Checks whether there is a pending update operation for this scope.
|
||||
bool IsOriginUpdatePending(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) const;
|
||||
|
||||
private:
|
||||
// Returns true iff new operation is of type newType and there is a pending
|
||||
@ -269,13 +293,16 @@ public:
|
||||
virtual void AsyncClearAll()
|
||||
{ InsertDBOp(new DBOperation(DBOperation::opClearAll)); }
|
||||
|
||||
virtual void AsyncClearMatchingScope(const nsACString& aScope)
|
||||
{ InsertDBOp(new DBOperation(DBOperation::opClearMatchingScope, aScope)); }
|
||||
virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix)
|
||||
{ InsertDBOp(new DBOperation(DBOperation::opClearMatchingOrigin, aOriginNoSuffix)); }
|
||||
|
||||
virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern)
|
||||
{ InsertDBOp(new DBOperation(DBOperation::opClearMatchingOriginAttributes, aPattern)); }
|
||||
|
||||
virtual void AsyncFlush();
|
||||
|
||||
virtual bool ShouldPreloadScope(const nsACString& aScope);
|
||||
virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes);
|
||||
virtual bool ShouldPreloadOrigin(const nsACString& aOrigin);
|
||||
virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFile> mDatabaseFile;
|
||||
@ -298,8 +325,8 @@ private:
|
||||
// State of the database initiation
|
||||
nsresult mStatus;
|
||||
|
||||
// List of scopes having data, for optimization purposes only
|
||||
nsTHashtable<nsCStringHashKey> mScopesHavingData;
|
||||
// List of origins (including origin attributes suffix) having data, for optimization purposes only
|
||||
nsTHashtable<nsCStringHashKey> mOriginsHavingData;
|
||||
|
||||
// Connection used by the worker thread for all read and write ops
|
||||
nsCOMPtr<mozIStorageConnection> mWorkerConnection;
|
||||
@ -328,7 +355,7 @@ private:
|
||||
int32_t mPriorityCounter;
|
||||
|
||||
// Helper to direct an operation to one of the arrays above;
|
||||
// also checks IsScopeClearPending for preloads
|
||||
// also checks IsOriginClearPending for preloads
|
||||
nsresult InsertDBOp(DBOperation* aOperation);
|
||||
|
||||
// Opens the database, first thing we do after start of the thread.
|
||||
|
372
dom/storage/DOMStorageDBUpdater.cpp
Normal file
372
dom/storage/DOMStorageDBUpdater.cpp
Normal file
@ -0,0 +1,372 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMStorageManager.h"
|
||||
|
||||
#include "mozIStorageBindingParamsArray.h"
|
||||
#include "mozIStorageBindingParams.h"
|
||||
#include "mozIStorageValueArray.h"
|
||||
#include "mozIStorageFunction.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "nsVariant.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Tokenizer.h"
|
||||
|
||||
// Current version of the database schema
|
||||
#define CURRENT_SCHEMA_VERSION 1
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
extern void
|
||||
ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult);
|
||||
|
||||
namespace {
|
||||
|
||||
class nsReverseStringSQLFunction final : public mozIStorageFunction
|
||||
{
|
||||
~nsReverseStringSQLFunction() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsReverseStringSQLFunction, mozIStorageFunction)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsReverseStringSQLFunction::OnFunctionCall(
|
||||
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString stringToReverse;
|
||||
rv = aFunctionArguments->GetUTF8String(0, stringToReverse);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString result;
|
||||
ReverseString(stringToReverse, result);
|
||||
|
||||
RefPtr<nsVariant> outVar(new nsVariant());
|
||||
rv = outVar->SetAsAUTF8String(result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
outVar.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// "scope" to "origin attributes suffix" and "origin key" convertor
|
||||
|
||||
class ExtractOriginData : protected mozilla::Tokenizer
|
||||
{
|
||||
public:
|
||||
ExtractOriginData(const nsACString& scope, nsACString& suffix, nsACString& origin)
|
||||
: mozilla::Tokenizer(scope)
|
||||
{
|
||||
using mozilla::OriginAttributes;
|
||||
|
||||
// Parse optional appId:isInBrowserElement: string, in case
|
||||
// we don't find it, the scope is our new origin key and suffix
|
||||
// is empty.
|
||||
suffix.Truncate();
|
||||
origin.Assign(scope);
|
||||
|
||||
// Bail out if it isn't appId.
|
||||
uint32_t appId;
|
||||
if (!ReadInteger(&appId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Should be followed by a colon.
|
||||
if (!CheckChar(':')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail out if it isn't 'browserFlag'.
|
||||
nsDependentCSubstring browserFlag;
|
||||
if (!ReadWord(browserFlag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool inBrowser = browserFlag == "t";
|
||||
bool notInBrowser = browserFlag == "f";
|
||||
if (!inBrowser && !notInBrowser) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Should be followed by a colon.
|
||||
if (!CheckChar(':')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// OK, we have found appId and inBrowser flag, create the suffix from it
|
||||
// and take the rest as the origin key.
|
||||
|
||||
PrincipalOriginAttributes attrs(appId, inBrowser);
|
||||
attrs.CreateSuffix(suffix);
|
||||
|
||||
// Consume the rest of the input as "origin".
|
||||
origin.Assign(Substring(mCursor, mEnd));
|
||||
}
|
||||
};
|
||||
|
||||
class GetOriginParticular final : public mozIStorageFunction
|
||||
{
|
||||
public:
|
||||
enum EParticular {
|
||||
ORIGIN_ATTRIBUTES_SUFFIX,
|
||||
ORIGIN_KEY
|
||||
};
|
||||
|
||||
explicit GetOriginParticular(EParticular aParticular)
|
||||
: mParticular(aParticular) {}
|
||||
|
||||
private:
|
||||
GetOriginParticular() = delete;
|
||||
~GetOriginParticular() {}
|
||||
|
||||
EParticular mParticular;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GetOriginParticular, mozIStorageFunction)
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetOriginParticular::OnFunctionCall(
|
||||
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString scope;
|
||||
rv = aFunctionArguments->GetUTF8String(0, scope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString suffix, origin;
|
||||
ExtractOriginData(scope, suffix, origin);
|
||||
|
||||
nsCOMPtr<nsIWritableVariant> outVar(new nsVariant());
|
||||
|
||||
switch (mParticular) {
|
||||
case EParticular::ORIGIN_ATTRIBUTES_SUFFIX:
|
||||
rv = outVar->SetAsAUTF8String(suffix);
|
||||
break;
|
||||
case EParticular::ORIGIN_KEY:
|
||||
rv = outVar->SetAsAUTF8String(origin);
|
||||
break;
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
outVar.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace DOMStorageDBUpdater {
|
||||
|
||||
nsresult CreateSchema1Tables(mozIStorageConnection *aWorkerConnection)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE IF NOT EXISTS webappsstore2 ("
|
||||
"originAttributes TEXT, "
|
||||
"originKey TEXT, "
|
||||
"scope TEXT, " // Only for schema0 downgrade compatibility
|
||||
"key TEXT, "
|
||||
"value TEXT)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS origin_key_index"
|
||||
" ON webappsstore2(originAttributes, originKey, key)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Update(mozIStorageConnection *aWorkerConnection)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mozStorageTransaction transaction(aWorkerConnection, false);
|
||||
|
||||
bool doVacuum = false;
|
||||
|
||||
int32_t schemaVer;
|
||||
rv = aWorkerConnection->GetSchemaVersion(&schemaVer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// downgrade (v0) -> upgrade (v1+) specific code
|
||||
if (schemaVer >= 1) {
|
||||
bool schema0IndexExists;
|
||||
rv = aWorkerConnection->IndexExists(NS_LITERAL_CSTRING("scope_key_index"),
|
||||
&schema0IndexExists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (schema0IndexExists) {
|
||||
// If this index exists, the database (already updated to schema >1)
|
||||
// has been run again on schema 0 code. That recreated that index
|
||||
// and might store some new rows while updating only the 'scope' column.
|
||||
// For such added rows we must fill the new 'origin*' columns correctly
|
||||
// otherwise there would be a data loss. The safest way to do it is to
|
||||
// simply run the whole update to schema 1 again.
|
||||
schemaVer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (schemaVer) {
|
||||
case 0: {
|
||||
bool webappsstore2Exists, webappsstoreExists, moz_webappsstoreExists;
|
||||
|
||||
rv = aWorkerConnection->TableExists(NS_LITERAL_CSTRING("webappsstore2"),
|
||||
&webappsstore2Exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aWorkerConnection->TableExists(NS_LITERAL_CSTRING("webappsstore"),
|
||||
&webappsstoreExists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aWorkerConnection->TableExists(NS_LITERAL_CSTRING("moz_webappsstore"),
|
||||
&moz_webappsstoreExists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!webappsstore2Exists && !webappsstoreExists && !moz_webappsstoreExists) {
|
||||
// The database is empty, this is the first start. Just create the schema table
|
||||
// and break to the next version to update to, i.e. bypass update from the old version.
|
||||
|
||||
rv = CreateSchema1Tables(aWorkerConnection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->SetSchemaVersion(CURRENT_SCHEMA_VERSION);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
doVacuum = true;
|
||||
|
||||
// Ensure Gecko 1.9.1 storage table
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE TABLE IF NOT EXISTS webappsstore2 ("
|
||||
"scope TEXT, "
|
||||
"key TEXT, "
|
||||
"value TEXT, "
|
||||
"secure INTEGER, "
|
||||
"owner TEXT)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS scope_key_index"
|
||||
" ON webappsstore2(scope, key)"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageFunction> function1(new nsReverseStringSQLFunction());
|
||||
NS_ENSURE_TRUE(function1, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = aWorkerConnection->CreateFunction(NS_LITERAL_CSTRING("REVERSESTRING"), 1, function1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// 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.
|
||||
if (webappsstoreExists) {
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("INSERT OR IGNORE INTO "
|
||||
"webappsstore2(scope, key, value, secure, owner) "
|
||||
"SELECT REVERSESTRING(domain) || '.:', key, value, secure, owner "
|
||||
"FROM webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DROP TABLE webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Check if there is storage of Gecko 1.8 and if so, upgrade that storage
|
||||
// to actual webappsstore2 table and drop the obsolete table. Potential
|
||||
// duplicates will be ignored.
|
||||
if (moz_webappsstoreExists) {
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("INSERT OR IGNORE INTO "
|
||||
"webappsstore2(scope, key, value, secure, owner) "
|
||||
"SELECT REVERSESTRING(domain) || '.:', key, value, secure, domain "
|
||||
"FROM moz_webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DROP TABLE moz_webappsstore"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
aWorkerConnection->RemoveFunction(NS_LITERAL_CSTRING("REVERSESTRING"));
|
||||
|
||||
// Update the scoping to match the new implememntation: split to oa suffix and origin key
|
||||
// First rename the old table, we want to remove some columns no longer needed.
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"ALTER TABLE webappsstore2 RENAME TO webappsstore2_old"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageFunction> oaSuffixFunc(
|
||||
new GetOriginParticular(GetOriginParticular::ORIGIN_ATTRIBUTES_SUFFIX));
|
||||
rv = aWorkerConnection->CreateFunction(NS_LITERAL_CSTRING("GET_ORIGIN_SUFFIX"), 1, oaSuffixFunc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<mozIStorageFunction> originKeyFunc(
|
||||
new GetOriginParticular(GetOriginParticular::ORIGIN_KEY));
|
||||
rv = aWorkerConnection->CreateFunction(NS_LITERAL_CSTRING("GET_ORIGIN_KEY"), 1, originKeyFunc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Here we ensure this schema tables when we are updating.
|
||||
rv = CreateSchema1Tables(aWorkerConnection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||
"INSERT OR IGNORE INTO "
|
||||
"webappsstore2 (originAttributes, originKey, scope, key, value) "
|
||||
"SELECT GET_ORIGIN_SUFFIX(scope), GET_ORIGIN_KEY(scope), scope, key, value "
|
||||
"FROM webappsstore2_old"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("DROP TABLE webappsstore2_old"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aWorkerConnection->RemoveFunction(NS_LITERAL_CSTRING("GET_ORIGIN_SUFFIX"));
|
||||
aWorkerConnection->RemoveFunction(NS_LITERAL_CSTRING("GET_ORIGIN_KEY"));
|
||||
|
||||
rv = aWorkerConnection->SetSchemaVersion(1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
case CURRENT_SCHEMA_VERSION:
|
||||
// Nothing more to do here, this is the current schema version
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
break;
|
||||
} // switch
|
||||
|
||||
rv = transaction.Commit();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (doVacuum) {
|
||||
// In some cases this can make the disk file of the database significantly smaller.
|
||||
// VACUUM cannot be executed inside a transaction.
|
||||
rv = aWorkerConnection->ExecuteSimpleSQL(
|
||||
NS_LITERAL_CSTRING("VACUUM"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace DOMStorageDBUpdater
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
22
dom/storage/DOMStorageDBUpdater.h
Normal file
22
dom/storage/DOMStorageDBUpdater.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DOMStorageDBUpdater_h___
|
||||
#define DOMStorageDBUpdater_h___
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace DOMStorageDBUpdater {
|
||||
|
||||
nsresult Update(mozIStorageConnection *aWorkerConnection);
|
||||
|
||||
} // DOMStorageDBUpdater
|
||||
|
||||
} // dom
|
||||
} // mozilla
|
||||
|
||||
#endif
|
@ -68,13 +68,13 @@ DOMStorageDBChild::~DOMStorageDBChild()
|
||||
}
|
||||
|
||||
nsTHashtable<nsCStringHashKey>&
|
||||
DOMStorageDBChild::ScopesHavingData()
|
||||
DOMStorageDBChild::OriginsHavingData()
|
||||
{
|
||||
if (!mScopesHavingData) {
|
||||
mScopesHavingData = new nsTHashtable<nsCStringHashKey>;
|
||||
if (!mOriginsHavingData) {
|
||||
mOriginsHavingData = new nsTHashtable<nsCStringHashKey>;
|
||||
}
|
||||
|
||||
return *mScopesHavingData;
|
||||
return *mOriginsHavingData;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -102,7 +102,7 @@ DOMStorageDBChild::AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority)
|
||||
// Adding ref to cache for the time of preload. This ensures a reference to
|
||||
// to the cache and that all keys will load into this cache object.
|
||||
mLoadingCaches.PutEntry(aCache);
|
||||
SendAsyncPreload(aCache->Scope(), aPriority);
|
||||
SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(), aPriority);
|
||||
} else {
|
||||
// No IPC, no love. But the LoadDone call is expected.
|
||||
aCache->LoadDone(NS_ERROR_UNEXPECTED);
|
||||
@ -113,7 +113,7 @@ void
|
||||
DOMStorageDBChild::AsyncGetUsage(DOMStorageUsageBridge* aUsage)
|
||||
{
|
||||
if (mIPCOpen) {
|
||||
SendAsyncGetUsage(aUsage->Scope());
|
||||
SendAsyncGetUsage(aUsage->OriginScope());
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +136,8 @@ DOMStorageDBChild::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync)
|
||||
// case the async preload has already loaded some keys.
|
||||
InfallibleTArray<nsString> keys, values;
|
||||
nsresult rv;
|
||||
SendPreload(aCache->Scope(), aCache->LoadedCount(), &keys, &values, &rv);
|
||||
SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(), aCache->LoadedCount(),
|
||||
&keys, &values, &rv);
|
||||
|
||||
for (uint32_t i = 0; i < keys.Length(); ++i) {
|
||||
aCache->LoadItem(keys[i], values[i]);
|
||||
@ -154,8 +155,9 @@ DOMStorageDBChild::AsyncAddItem(DOMStorageCacheBridge* aCache,
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
SendAsyncAddItem(aCache->Scope(), nsString(aKey), nsString(aValue));
|
||||
ScopesHavingData().PutEntry(aCache->Scope());
|
||||
SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
|
||||
nsString(aKey), nsString(aValue));
|
||||
OriginsHavingData().PutEntry(aCache->Origin());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -168,8 +170,9 @@ DOMStorageDBChild::AsyncUpdateItem(DOMStorageCacheBridge* aCache,
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
SendAsyncUpdateItem(aCache->Scope(), nsString(aKey), nsString(aValue));
|
||||
ScopesHavingData().PutEntry(aCache->Scope());
|
||||
SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
|
||||
nsString(aKey), nsString(aValue));
|
||||
OriginsHavingData().PutEntry(aCache->Origin());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -181,7 +184,8 @@ DOMStorageDBChild::AsyncRemoveItem(DOMStorageCacheBridge* aCache,
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
SendAsyncRemoveItem(aCache->Scope(), nsString(aKey));
|
||||
SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
|
||||
nsString(aKey));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -192,44 +196,47 @@ DOMStorageDBChild::AsyncClear(DOMStorageCacheBridge* aCache)
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
SendAsyncClear(aCache->Scope());
|
||||
ScopesHavingData().RemoveEntry(aCache->Scope());
|
||||
SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
|
||||
OriginsHavingData().RemoveEntry(aCache->Origin());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBChild::ShouldPreloadScope(const nsACString& aScope)
|
||||
DOMStorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin)
|
||||
{
|
||||
// Return true if we didn't receive the aScope list yet.
|
||||
// Return true if we didn't receive the origins list yet.
|
||||
// I tend to rather preserve a bit of early-after-start performance
|
||||
// then a bit of memory here.
|
||||
return !mScopesHavingData || mScopesHavingData->Contains(aScope);
|
||||
// than a bit of memory here.
|
||||
return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBChild::RecvObserve(const nsCString& aTopic,
|
||||
const nsCString& aScopePrefix)
|
||||
const nsString& aOriginAttributesPattern,
|
||||
const nsCString& aOriginScope)
|
||||
{
|
||||
DOMStorageObserver::Self()->Notify(aTopic.get(), aScopePrefix);
|
||||
DOMStorageObserver::Self()->Notify(
|
||||
aTopic.get(), aOriginAttributesPattern, aOriginScope);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBChild::RecvScopesHavingData(nsTArray<nsCString>&& aScopes)
|
||||
DOMStorageDBChild::RecvOriginsHavingData(nsTArray<nsCString>&& aOrigins)
|
||||
{
|
||||
for (uint32_t i = 0; i < aScopes.Length(); ++i) {
|
||||
ScopesHavingData().PutEntry(aScopes[i]);
|
||||
for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
|
||||
OriginsHavingData().PutEntry(aOrigins[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBChild::RecvLoadItem(const nsCString& aScope,
|
||||
DOMStorageDBChild::RecvLoadItem(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsString& aKey,
|
||||
const nsString& aValue)
|
||||
{
|
||||
DOMStorageCache* aCache = mManager->GetCache(aScope);
|
||||
DOMStorageCache* aCache = mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
|
||||
if (aCache) {
|
||||
aCache->LoadItem(aKey, aValue);
|
||||
}
|
||||
@ -238,9 +245,11 @@ DOMStorageDBChild::RecvLoadItem(const nsCString& aScope,
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBChild::RecvLoadDone(const nsCString& aScope, const nsresult& aRv)
|
||||
DOMStorageDBChild::RecvLoadDone(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsresult& aRv)
|
||||
{
|
||||
DOMStorageCache* aCache = mManager->GetCache(aScope);
|
||||
DOMStorageCache* aCache = mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
|
||||
if (aCache) {
|
||||
aCache->LoadDone(aRv);
|
||||
|
||||
@ -252,9 +261,9 @@ DOMStorageDBChild::RecvLoadDone(const nsCString& aScope, const nsresult& aRv)
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBChild::RecvLoadUsage(const nsCString& aScope, const int64_t& aUsage)
|
||||
DOMStorageDBChild::RecvLoadUsage(const nsCString& aOriginNoSuffix, const int64_t& aUsage)
|
||||
{
|
||||
RefPtr<DOMStorageUsageBridge> scopeUsage = mManager->GetScopeUsage(aScope);
|
||||
RefPtr<DOMStorageUsageBridge> scopeUsage = mManager->GetOriginUsage(aOriginNoSuffix);
|
||||
scopeUsage->LoadUsage(aUsage);
|
||||
return true;
|
||||
}
|
||||
@ -308,8 +317,8 @@ private:
|
||||
DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
|
||||
if (db) {
|
||||
InfallibleTArray<nsCString> scopes;
|
||||
db->GetScopesHavingData(&scopes);
|
||||
mozilla::Unused << mParent->SendScopesHavingData(scopes);
|
||||
db->GetOriginsHavingData(&scopes);
|
||||
mozilla::Unused << mParent->SendOriginsHavingData(scopes);
|
||||
}
|
||||
|
||||
// We need to check if the device is in a low disk space situation, so
|
||||
@ -317,14 +326,15 @@ private:
|
||||
nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcher =
|
||||
do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
|
||||
if (!diskSpaceWatcher) {
|
||||
NS_WARNING("Could not get disk information from DiskSpaceWatcher");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool lowDiskSpace = false;
|
||||
diskSpaceWatcher->GetIsDiskFull(&lowDiskSpace);
|
||||
|
||||
if (lowDiskSpace) {
|
||||
mozilla::Unused << mParent->SendObserve(
|
||||
nsDependentCString("low-disk-space"), EmptyCString());
|
||||
nsDependentCString("low-disk-space"), EmptyString(), EmptyCString());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -374,9 +384,9 @@ DOMStorageDBParent::CloneProtocol(Channel* aChannel,
|
||||
}
|
||||
|
||||
DOMStorageDBParent::CacheParentBridge*
|
||||
DOMStorageDBParent::NewCache(const nsACString& aScope)
|
||||
DOMStorageDBParent::NewCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix)
|
||||
{
|
||||
return new CacheParentBridge(this, aScope);
|
||||
return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
|
||||
}
|
||||
|
||||
void
|
||||
@ -386,19 +396,21 @@ DOMStorageDBParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvAsyncPreload(const nsCString& aScope, const bool& aPriority)
|
||||
DOMStorageDBParent::RecvAsyncPreload(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const bool& aPriority)
|
||||
{
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
db->AsyncPreload(NewCache(aScope), aPriority);
|
||||
db->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix), aPriority);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvAsyncGetUsage(const nsCString& aScope)
|
||||
DOMStorageDBParent::RecvAsyncGetUsage(const nsCString& aOriginNoSuffix)
|
||||
{
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
@ -406,7 +418,7 @@ DOMStorageDBParent::RecvAsyncGetUsage(const nsCString& aScope)
|
||||
}
|
||||
|
||||
// The object releases it self in LoadUsage method
|
||||
RefPtr<UsageParentBridge> usage = new UsageParentBridge(this, aScope);
|
||||
RefPtr<UsageParentBridge> usage = new UsageParentBridge(this, aOriginNoSuffix);
|
||||
db->AsyncGetUsage(usage);
|
||||
return true;
|
||||
}
|
||||
@ -420,13 +432,15 @@ namespace {
|
||||
class SyncLoadCacheHelper : public DOMStorageCacheBridge
|
||||
{
|
||||
public:
|
||||
SyncLoadCacheHelper(const nsCString& aScope,
|
||||
SyncLoadCacheHelper(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
uint32_t aAlreadyLoadedCount,
|
||||
InfallibleTArray<nsString>* aKeys,
|
||||
InfallibleTArray<nsString>* aValues,
|
||||
nsresult* rv)
|
||||
: mMonitor("DOM Storage SyncLoad IPC")
|
||||
, mScope(aScope)
|
||||
, mSuffix(aOriginSuffix)
|
||||
, mOrigin(aOriginNoSuffix)
|
||||
, mKeys(aKeys)
|
||||
, mValues(aValues)
|
||||
, mRv(rv)
|
||||
@ -437,7 +451,12 @@ public:
|
||||
*mRv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
virtual const nsCString& Scope() const { return mScope; }
|
||||
virtual const nsCString Origin() const
|
||||
{
|
||||
return DOMStorageManager::CreateOrigin(mSuffix, mOrigin);
|
||||
}
|
||||
virtual const nsCString& OriginNoSuffix() const { return mOrigin; }
|
||||
virtual const nsCString& OriginSuffix() const { return mSuffix; }
|
||||
virtual bool Loaded() { return mLoaded; }
|
||||
virtual uint32_t LoadedCount() { return mLoadedCount; }
|
||||
virtual bool LoadItem(const nsAString& aKey, const nsString& aValue)
|
||||
@ -473,7 +492,7 @@ public:
|
||||
|
||||
private:
|
||||
Monitor mMonitor;
|
||||
nsCString mScope;
|
||||
nsCString mSuffix, mOrigin;
|
||||
InfallibleTArray<nsString>* mKeys;
|
||||
InfallibleTArray<nsString>* mValues;
|
||||
nsresult* mRv;
|
||||
@ -484,7 +503,8 @@ private:
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvPreload(const nsCString& aScope,
|
||||
DOMStorageDBParent::RecvPreload(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const uint32_t& aAlreadyLoadedCount,
|
||||
InfallibleTArray<nsString>* aKeys,
|
||||
InfallibleTArray<nsString>* aValues,
|
||||
@ -496,14 +516,15 @@ DOMStorageDBParent::RecvPreload(const nsCString& aScope,
|
||||
}
|
||||
|
||||
RefPtr<SyncLoadCacheHelper> cache(
|
||||
new SyncLoadCacheHelper(aScope, aAlreadyLoadedCount, aKeys, aValues, aRv));
|
||||
new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix, aAlreadyLoadedCount, aKeys, aValues, aRv));
|
||||
|
||||
db->SyncPreload(cache, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvAsyncAddItem(const nsCString& aScope,
|
||||
DOMStorageDBParent::RecvAsyncAddItem(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsString& aKey,
|
||||
const nsString& aValue)
|
||||
{
|
||||
@ -512,7 +533,7 @@ DOMStorageDBParent::RecvAsyncAddItem(const nsCString& aScope,
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncAddItem(NewCache(aScope), aKey, aValue);
|
||||
nsresult rv = db->AsyncAddItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -521,7 +542,8 @@ DOMStorageDBParent::RecvAsyncAddItem(const nsCString& aScope,
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvAsyncUpdateItem(const nsCString& aScope,
|
||||
DOMStorageDBParent::RecvAsyncUpdateItem(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsString& aKey,
|
||||
const nsString& aValue)
|
||||
{
|
||||
@ -530,7 +552,7 @@ DOMStorageDBParent::RecvAsyncUpdateItem(const nsCString& aScope,
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncUpdateItem(NewCache(aScope), aKey, aValue);
|
||||
nsresult rv = db->AsyncUpdateItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -539,7 +561,8 @@ DOMStorageDBParent::RecvAsyncUpdateItem(const nsCString& aScope,
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvAsyncRemoveItem(const nsCString& aScope,
|
||||
DOMStorageDBParent::RecvAsyncRemoveItem(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsString& aKey)
|
||||
{
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
@ -547,7 +570,7 @@ DOMStorageDBParent::RecvAsyncRemoveItem(const nsCString& aScope,
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncRemoveItem(NewCache(aScope), aKey);
|
||||
nsresult rv = db->AsyncRemoveItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -556,14 +579,15 @@ DOMStorageDBParent::RecvAsyncRemoveItem(const nsCString& aScope,
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::RecvAsyncClear(const nsCString& aScope)
|
||||
DOMStorageDBParent::RecvAsyncClear(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix)
|
||||
{
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
if (!db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult rv = db->AsyncClear(NewCache(aScope));
|
||||
nsresult rv = db->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
|
||||
if (NS_FAILED(rv) && mIPCOpen) {
|
||||
mozilla::Unused << SendError(rv);
|
||||
}
|
||||
@ -587,7 +611,8 @@ DOMStorageDBParent::RecvAsyncFlush()
|
||||
|
||||
nsresult
|
||||
DOMStorageDBParent::Observe(const char* aTopic,
|
||||
const nsACString& aScopePrefix)
|
||||
const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope)
|
||||
{
|
||||
if (mIPCOpen) {
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
@ -595,7 +620,8 @@ DOMStorageDBParent::Observe(const char* aTopic,
|
||||
ContentParent::IsNuwaReady())) {
|
||||
#endif
|
||||
mozilla::Unused << SendObserve(nsDependentCString(aTopic),
|
||||
nsCString(aScopePrefix));
|
||||
nsString(aOriginAttributesPattern),
|
||||
nsCString(aOriginScope));
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
}
|
||||
#endif
|
||||
@ -617,30 +643,34 @@ public:
|
||||
|
||||
LoadRunnable(DOMStorageDBParent* aParent,
|
||||
TaskType aType,
|
||||
const nsACString& aScope,
|
||||
const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix,
|
||||
const nsAString& aKey = EmptyString(),
|
||||
const nsAString& aValue = EmptyString())
|
||||
: mParent(aParent)
|
||||
, mType(aType)
|
||||
, mScope(aScope)
|
||||
, mSuffix(aOriginSuffix)
|
||||
, mOrigin(aOriginNoSuffix)
|
||||
, mKey(aKey)
|
||||
, mValue(aValue)
|
||||
{ }
|
||||
|
||||
LoadRunnable(DOMStorageDBParent* aParent,
|
||||
TaskType aType,
|
||||
const nsACString& aScope,
|
||||
const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix,
|
||||
nsresult aRv)
|
||||
: mParent(aParent)
|
||||
, mType(aType)
|
||||
, mScope(aScope)
|
||||
, mSuffix(aOriginSuffix)
|
||||
, mOrigin(aOriginNoSuffix)
|
||||
, mRv(aRv)
|
||||
{ }
|
||||
|
||||
private:
|
||||
RefPtr<DOMStorageDBParent> mParent;
|
||||
TaskType mType;
|
||||
nsCString mScope;
|
||||
nsCString mSuffix, mOrigin;
|
||||
nsString mKey;
|
||||
nsString mValue;
|
||||
nsresult mRv;
|
||||
@ -654,10 +684,10 @@ private:
|
||||
switch (mType)
|
||||
{
|
||||
case loadItem:
|
||||
mozilla::Unused << mParent->SendLoadItem(mScope, mKey, mValue);
|
||||
mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey, mValue);
|
||||
break;
|
||||
case loadDone:
|
||||
mozilla::Unused << mParent->SendLoadDone(mScope, mRv);
|
||||
mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -669,6 +699,12 @@ private:
|
||||
|
||||
// DOMStorageDBParent::CacheParentBridge
|
||||
|
||||
const nsCString
|
||||
DOMStorageDBParent::CacheParentBridge::Origin() const
|
||||
{
|
||||
return DOMStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
|
||||
}
|
||||
|
||||
bool
|
||||
DOMStorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey, const nsString& aValue)
|
||||
{
|
||||
@ -679,7 +715,7 @@ DOMStorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey, const nsS
|
||||
++mLoadedCount;
|
||||
|
||||
RefPtr<LoadRunnable> r =
|
||||
new LoadRunnable(mParent, LoadRunnable::loadItem, mScope, aKey, aValue);
|
||||
new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix, mOriginNoSuffix, aKey, aValue);
|
||||
NS_DispatchToMainThread(r);
|
||||
return true;
|
||||
}
|
||||
@ -695,7 +731,7 @@ DOMStorageDBParent::CacheParentBridge::LoadDone(nsresult aRv)
|
||||
mLoaded = true;
|
||||
|
||||
RefPtr<LoadRunnable> r =
|
||||
new LoadRunnable(mParent, LoadRunnable::loadDone, mScope, aRv);
|
||||
new LoadRunnable(mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
@ -713,9 +749,9 @@ namespace {
|
||||
class UsageRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
UsageRunnable(DOMStorageDBParent* aParent, const nsACString& aScope, const int64_t& aUsage)
|
||||
UsageRunnable(DOMStorageDBParent* aParent, const nsACString& aOriginScope, const int64_t& aUsage)
|
||||
: mParent(aParent)
|
||||
, mScope(aScope)
|
||||
, mOriginScope(aOriginScope)
|
||||
, mUsage(aUsage)
|
||||
{}
|
||||
|
||||
@ -726,12 +762,12 @@ private:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::Unused << mParent->SendLoadUsage(mScope, mUsage);
|
||||
mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<DOMStorageDBParent> mParent;
|
||||
nsCString mScope;
|
||||
nsCString mOriginScope;
|
||||
int64_t mUsage;
|
||||
};
|
||||
|
||||
@ -740,7 +776,7 @@ private:
|
||||
void
|
||||
DOMStorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage)
|
||||
{
|
||||
RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mScope, aUsage);
|
||||
RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OriginAttributesPattern;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class DOMLocalStorageManager;
|
||||
@ -52,35 +55,41 @@ public:
|
||||
|
||||
virtual void AsyncClearAll()
|
||||
{
|
||||
if (mScopesHavingData) {
|
||||
mScopesHavingData->Clear(); /* NO-OP on the child process otherwise */
|
||||
if (mOriginsHavingData) {
|
||||
mOriginsHavingData->Clear(); /* NO-OP on the child process otherwise */
|
||||
}
|
||||
}
|
||||
|
||||
virtual void AsyncClearMatchingScope(const nsACString& aScope)
|
||||
virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix)
|
||||
{ /* NO-OP on the child process */ }
|
||||
|
||||
virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern)
|
||||
{ /* NO-OP on the child process */ }
|
||||
|
||||
virtual void AsyncFlush()
|
||||
{ SendAsyncFlush(); }
|
||||
|
||||
virtual bool ShouldPreloadScope(const nsACString& aScope);
|
||||
virtual void GetScopesHavingData(InfallibleTArray<nsCString>* aScopes)
|
||||
virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix);
|
||||
virtual void GetOriginsHavingData(InfallibleTArray<nsCString>* aOrigins)
|
||||
{ NS_NOTREACHED("Not implemented for child process"); }
|
||||
|
||||
private:
|
||||
bool RecvObserve(const nsCString& aTopic,
|
||||
const nsCString& aScopePrefix);
|
||||
bool RecvLoadItem(const nsCString& aScope,
|
||||
const nsString& aOriginAttributesPattern,
|
||||
const nsCString& aOriginScope);
|
||||
bool RecvLoadItem(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsString& aKey,
|
||||
const nsString& aValue);
|
||||
bool RecvLoadDone(const nsCString& aScope,
|
||||
bool RecvLoadDone(const nsCString& aOriginSuffix,
|
||||
const nsCString& aOriginNoSuffix,
|
||||
const nsresult& aRv);
|
||||
bool RecvScopesHavingData(nsTArray<nsCString>&& aScopes);
|
||||
bool RecvLoadUsage(const nsCString& aScope,
|
||||
bool RecvOriginsHavingData(nsTArray<nsCString>&& aOrigins);
|
||||
bool RecvLoadUsage(const nsCString& aOriginNoSuffix,
|
||||
const int64_t& aUsage);
|
||||
bool RecvError(const nsresult& aRv);
|
||||
|
||||
nsTHashtable<nsCStringHashKey>& ScopesHavingData();
|
||||
nsTHashtable<nsCStringHashKey>& OriginsHavingData();
|
||||
|
||||
ThreadSafeAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
@ -88,12 +97,12 @@ private:
|
||||
// Held to get caches to forward answers to.
|
||||
RefPtr<DOMLocalStorageManager> mManager;
|
||||
|
||||
// Scopes having data hash, for optimization purposes only
|
||||
nsAutoPtr<nsTHashtable<nsCStringHashKey> > mScopesHavingData;
|
||||
// Origins having data hash, for optimization purposes only
|
||||
nsAutoPtr<nsTHashtable<nsCStringHashKey>> mOriginsHavingData;
|
||||
|
||||
// List of caches waiting for preload. This ensures the contract that
|
||||
// AsyncPreload call references the cache for time of the preload.
|
||||
nsTHashtable<nsRefPtrHashKey<DOMStorageCacheBridge> > mLoadingCaches;
|
||||
nsTHashtable<nsRefPtrHashKey<DOMStorageCacheBridge>> mLoadingCaches;
|
||||
|
||||
// Status of the remote database
|
||||
nsresult mStatus;
|
||||
@ -132,13 +141,20 @@ public:
|
||||
// them back to appropriate cache object on the child process.
|
||||
class CacheParentBridge : public DOMStorageCacheBridge {
|
||||
public:
|
||||
CacheParentBridge(DOMStorageDBParent* aParentDB, const nsACString& aScope)
|
||||
: mParent(aParentDB), mScope(aScope), mLoaded(false), mLoadedCount(0) {}
|
||||
CacheParentBridge(DOMStorageDBParent* aParentDB,
|
||||
const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix)
|
||||
: mParent(aParentDB)
|
||||
, mOriginSuffix(aOriginSuffix), mOriginNoSuffix(aOriginNoSuffix)
|
||||
, mLoaded(false), mLoadedCount(0) {}
|
||||
virtual ~CacheParentBridge() {}
|
||||
|
||||
// DOMStorageCacheBridge
|
||||
virtual const nsCString& Scope() const
|
||||
{ return mScope; }
|
||||
virtual const nsCString Origin() const;
|
||||
virtual const nsCString& OriginNoSuffix() const
|
||||
{ return mOriginNoSuffix; }
|
||||
virtual const nsCString& OriginSuffix() const
|
||||
{ return mOriginSuffix; }
|
||||
virtual bool Loaded()
|
||||
{ return mLoaded; }
|
||||
virtual uint32_t LoadedCount()
|
||||
@ -150,7 +166,7 @@ public:
|
||||
|
||||
private:
|
||||
RefPtr<DOMStorageDBParent> mParent;
|
||||
nsCString mScope;
|
||||
nsCString mOriginSuffix, mOriginNoSuffix;
|
||||
bool mLoaded;
|
||||
uint32_t mLoadedCount;
|
||||
};
|
||||
@ -159,38 +175,38 @@ public:
|
||||
class UsageParentBridge : public DOMStorageUsageBridge
|
||||
{
|
||||
public:
|
||||
UsageParentBridge(DOMStorageDBParent* aParentDB, const nsACString& aScope)
|
||||
: mParent(aParentDB), mScope(aScope) {}
|
||||
UsageParentBridge(DOMStorageDBParent* aParentDB, const nsACString& aOriginScope)
|
||||
: mParent(aParentDB), mOriginScope(aOriginScope) {}
|
||||
virtual ~UsageParentBridge() {}
|
||||
|
||||
// DOMStorageUsageBridge
|
||||
virtual const nsCString& Scope() { return mScope; }
|
||||
virtual const nsCString& OriginScope() { return mOriginScope; }
|
||||
virtual void LoadUsage(const int64_t usage);
|
||||
|
||||
private:
|
||||
RefPtr<DOMStorageDBParent> mParent;
|
||||
nsCString mScope;
|
||||
nsCString mOriginScope;
|
||||
};
|
||||
|
||||
private:
|
||||
// IPC
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
bool RecvAsyncPreload(const nsCString& aScope, const bool& aPriority) override;
|
||||
bool RecvPreload(const nsCString& aScope, const uint32_t& aAlreadyLoadedCount,
|
||||
bool RecvAsyncPreload(const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix, const bool& aPriority) override;
|
||||
bool RecvPreload(const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix, const uint32_t& aAlreadyLoadedCount,
|
||||
InfallibleTArray<nsString>* aKeys, InfallibleTArray<nsString>* aValues,
|
||||
nsresult* aRv) override;
|
||||
bool RecvAsyncGetUsage(const nsCString& aScope) override;
|
||||
bool RecvAsyncAddItem(const nsCString& aScope, const nsString& aKey, const nsString& aValue) override;
|
||||
bool RecvAsyncUpdateItem(const nsCString& aScope, const nsString& aKey, const nsString& aValue) override;
|
||||
bool RecvAsyncRemoveItem(const nsCString& aScope, const nsString& aKey) override;
|
||||
bool RecvAsyncClear(const nsCString& aScope) override;
|
||||
bool RecvAsyncGetUsage(const nsCString& aOriginNoSuffix) override;
|
||||
bool RecvAsyncAddItem(const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix, const nsString& aKey, const nsString& aValue) override;
|
||||
bool RecvAsyncUpdateItem(const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix, const nsString& aKey, const nsString& aValue) override;
|
||||
bool RecvAsyncRemoveItem(const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix, const nsString& aKey) override;
|
||||
bool RecvAsyncClear(const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix) override;
|
||||
bool RecvAsyncFlush() override;
|
||||
|
||||
// DOMStorageObserverSink
|
||||
virtual nsresult Observe(const char* aTopic, const nsACString& aScopePrefix) override;
|
||||
virtual nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern, const nsACString& aOriginScope) override;
|
||||
|
||||
private:
|
||||
CacheParentBridge* NewCache(const nsACString& aScope);
|
||||
CacheParentBridge* NewCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix);
|
||||
|
||||
ThreadSafeAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
@ -124,64 +124,54 @@ DOMStorageManager::~DOMStorageManager()
|
||||
namespace {
|
||||
|
||||
nsresult
|
||||
CreateScopeKey(nsIPrincipal* aPrincipal,
|
||||
nsACString& aKey)
|
||||
AppendOriginNoSuffix(nsIPrincipal* aPrincipal,
|
||||
nsACString& aKey)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!uri) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsAutoCString domainScope;
|
||||
rv = uri->GetAsciiHost(domainScope);
|
||||
nsAutoCString domainOrigin;
|
||||
rv = uri->GetAsciiHost(domainOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (domainScope.IsEmpty()) {
|
||||
if (domainOrigin.IsEmpty()) {
|
||||
// For the file:/// protocol use the exact directory as domain.
|
||||
bool isScheme = false;
|
||||
if (NS_SUCCEEDED(uri->SchemeIs("file", &isScheme)) && isScheme) {
|
||||
nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = url->GetDirectory(domainScope);
|
||||
rv = url->GetDirectory(domainOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString key;
|
||||
|
||||
rv = CreateReversedDomain(domainScope, key);
|
||||
// Append reversed domain
|
||||
nsAutoCString reverseDomain;
|
||||
rv = CreateReversedDomain(domainOrigin, reverseDomain);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aKey.Append(reverseDomain);
|
||||
|
||||
// Append scheme
|
||||
nsAutoCString scheme;
|
||||
rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
key.Append(':');
|
||||
key.Append(scheme);
|
||||
aKey.Append(':');
|
||||
aKey.Append(scheme);
|
||||
|
||||
// Append port if any
|
||||
int32_t port = NS_GetRealPort(uri);
|
||||
if (port != -1) {
|
||||
key.Append(nsPrintfCString(":%d", port));
|
||||
}
|
||||
|
||||
if (!aPrincipal->GetUnknownAppId()) {
|
||||
uint32_t appId = aPrincipal->GetAppId();
|
||||
bool isInBrowserElement = aPrincipal->GetIsInBrowserElement();
|
||||
if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) {
|
||||
aKey.Assign(key);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aKey.Truncate();
|
||||
aKey.AppendInt(appId);
|
||||
aKey.Append(':');
|
||||
aKey.Append(isInBrowserElement ? 't' : 'f');
|
||||
aKey.Append(':');
|
||||
aKey.Append(key);
|
||||
aKey.Append(nsPrintfCString(":%d", port));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -193,7 +183,6 @@ CreateQuotaDBKey(nsIPrincipal* aPrincipal,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString subdomainsDBKey;
|
||||
nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
|
||||
NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -211,33 +200,40 @@ CreateQuotaDBKey(nsIPrincipal* aPrincipal,
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aKey.Truncate();
|
||||
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(aKey);
|
||||
|
||||
nsAutoCString subdomainsDBKey;
|
||||
CreateReversedDomain(eTLDplusOne, subdomainsDBKey);
|
||||
|
||||
if (!aPrincipal->GetUnknownAppId()) {
|
||||
uint32_t appId = aPrincipal->GetAppId();
|
||||
bool isInBrowserElement = aPrincipal->GetIsInBrowserElement();
|
||||
if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) {
|
||||
aKey.Assign(subdomainsDBKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aKey.Truncate();
|
||||
aKey.AppendInt(appId);
|
||||
aKey.Append(':');
|
||||
aKey.Append(isInBrowserElement ? 't' : 'f');
|
||||
aKey.Append(':');
|
||||
aKey.Append(subdomainsDBKey);
|
||||
}
|
||||
aKey.Append(':');
|
||||
aKey.Append(subdomainsDBKey);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DOMStorageCache*
|
||||
DOMStorageManager::GetCache(const nsACString& aScope) const
|
||||
// static
|
||||
nsCString
|
||||
DOMStorageManager::CreateOrigin(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix)
|
||||
{
|
||||
DOMStorageCacheHashKey* entry = mCaches.GetEntry(aScope);
|
||||
// Note: some hard-coded sqlite statements are dependent on the format this
|
||||
// method returns. Changing this without updating those sqlite statements
|
||||
// will cause malfunction.
|
||||
|
||||
nsAutoCString scope;
|
||||
scope.Append(aOriginSuffix);
|
||||
scope.Append(':');
|
||||
scope.Append(aOriginNoSuffix);
|
||||
return scope;
|
||||
}
|
||||
|
||||
DOMStorageCache*
|
||||
DOMStorageManager::GetCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix)
|
||||
{
|
||||
CacheOriginHashtable* table = mCaches.LookupOrAdd(aOriginSuffix);
|
||||
DOMStorageCacheHashKey* entry = table->GetEntry(aOriginNoSuffix);
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -246,14 +242,14 @@ DOMStorageManager::GetCache(const nsACString& aScope) const
|
||||
}
|
||||
|
||||
already_AddRefed<DOMStorageUsage>
|
||||
DOMStorageManager::GetScopeUsage(const nsACString& aScope)
|
||||
DOMStorageManager::GetOriginUsage(const nsACString& aOriginNoSuffix)
|
||||
{
|
||||
RefPtr<DOMStorageUsage> usage;
|
||||
if (mUsages.Get(aScope, &usage)) {
|
||||
if (mUsages.Get(aOriginNoSuffix, &usage)) {
|
||||
return usage.forget();
|
||||
}
|
||||
|
||||
usage = new DOMStorageUsage(aScope);
|
||||
usage = new DOMStorageUsage(aOriginNoSuffix);
|
||||
|
||||
if (mType == LocalStorage) {
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
@ -262,31 +258,33 @@ DOMStorageManager::GetScopeUsage(const nsACString& aScope)
|
||||
}
|
||||
}
|
||||
|
||||
mUsages.Put(aScope, usage);
|
||||
mUsages.Put(aOriginNoSuffix, usage);
|
||||
|
||||
return usage.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMStorageCache>
|
||||
DOMStorageManager::PutCache(const nsACString& aScope,
|
||||
DOMStorageManager::PutCache(const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
DOMStorageCacheHashKey* entry = mCaches.PutEntry(aScope);
|
||||
CacheOriginHashtable* table = mCaches.LookupOrAdd(aOriginSuffix);
|
||||
DOMStorageCacheHashKey* entry = table->PutEntry(aOriginNoSuffix);
|
||||
RefPtr<DOMStorageCache> cache = entry->cache();
|
||||
|
||||
nsAutoCString quotaScope;
|
||||
CreateQuotaDBKey(aPrincipal, quotaScope);
|
||||
nsAutoCString quotaOrigin;
|
||||
CreateQuotaDBKey(aPrincipal, quotaOrigin);
|
||||
|
||||
switch (mType) {
|
||||
case SessionStorage:
|
||||
// Lifetime handled by the manager, don't persist
|
||||
entry->HardRef();
|
||||
cache->Init(this, false, aPrincipal, quotaScope);
|
||||
cache->Init(this, false, aPrincipal, quotaOrigin);
|
||||
break;
|
||||
|
||||
case LocalStorage:
|
||||
// Lifetime handled by the cache, do persist
|
||||
cache->Init(this, true, aPrincipal, quotaScope);
|
||||
cache->Init(this, true, aPrincipal, quotaOrigin);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -303,7 +301,8 @@ DOMStorageManager::DropCache(DOMStorageCache* aCache)
|
||||
NS_WARNING("DOMStorageManager::DropCache called on a non-main thread, shutting down?");
|
||||
}
|
||||
|
||||
mCaches.RemoveEntry(aCache->Scope());
|
||||
CacheOriginHashtable* table = mCaches.LookupOrAdd(aCache->OriginSuffix());
|
||||
table->RemoveEntry(aCache->OriginNoSuffix());
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -316,13 +315,16 @@ DOMStorageManager::GetStorageInternal(bool aCreate,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString scope;
|
||||
rv = CreateScopeKey(aPrincipal, scope);
|
||||
nsAutoCString originAttrSuffix;
|
||||
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(originAttrSuffix);
|
||||
|
||||
nsAutoCString originKey;
|
||||
rv = AppendOriginNoSuffix(aPrincipal, originKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
RefPtr<DOMStorageCache> cache = GetCache(scope);
|
||||
RefPtr<DOMStorageCache> cache = GetCache(originAttrSuffix, originKey);
|
||||
|
||||
// Get or create a cache for the given scope
|
||||
if (!cache) {
|
||||
@ -332,15 +334,15 @@ DOMStorageManager::GetStorageInternal(bool aCreate,
|
||||
}
|
||||
|
||||
if (!aRetval) {
|
||||
// This is demand to just preload the cache, if the scope has
|
||||
// This is a demand to just preload the cache, if the scope has
|
||||
// no data stored, bypass creation and preload of the cache.
|
||||
DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
|
||||
if (db) {
|
||||
if (!db->ShouldPreloadScope(scope)) {
|
||||
if (!db->ShouldPreloadOrigin(DOMStorageManager::CreateOrigin(originAttrSuffix, originKey))) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
if (scope.EqualsLiteral("knalb.:about")) {
|
||||
if (originKey.EqualsLiteral("knalb.:about")) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -348,7 +350,7 @@ DOMStorageManager::GetStorageInternal(bool aCreate,
|
||||
|
||||
// There is always a single instance of a cache per scope
|
||||
// in a single instance of a DOM storage manager.
|
||||
cache = PutCache(scope, aPrincipal);
|
||||
cache = PutCache(originAttrSuffix, originKey, aPrincipal);
|
||||
} else if (mType == SessionStorage) {
|
||||
if (!cache->CheckPrincipal(aPrincipal)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
@ -407,7 +409,8 @@ DOMStorageManager::CloneStorage(nsIDOMStorage* aStorage)
|
||||
|
||||
const DOMStorageCache* origCache = storage->GetCache();
|
||||
|
||||
DOMStorageCache* existingCache = GetCache(origCache->Scope());
|
||||
DOMStorageCache* existingCache = GetCache(origCache->OriginSuffix(),
|
||||
origCache->OriginNoSuffix());
|
||||
if (existingCache) {
|
||||
// Do not replace an existing sessionStorage.
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
@ -415,8 +418,9 @@ DOMStorageManager::CloneStorage(nsIDOMStorage* aStorage)
|
||||
|
||||
// Since this manager is sessionStorage manager, PutCache hard references
|
||||
// the cache in our hashtable.
|
||||
RefPtr<DOMStorageCache> newCache = PutCache(origCache->Scope(),
|
||||
origCache->Principal());
|
||||
RefPtr<DOMStorageCache> newCache = PutCache(origCache->OriginSuffix(),
|
||||
origCache->OriginNoSuffix(),
|
||||
origCache->Principal());
|
||||
|
||||
newCache->CloneFrom(origCache);
|
||||
return NS_OK;
|
||||
@ -427,6 +431,8 @@ DOMStorageManager::CheckStorage(nsIPrincipal* aPrincipal,
|
||||
nsIDOMStorage* aStorage,
|
||||
bool* aRetval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
RefPtr<DOMStorage> storage = static_cast<DOMStorage*>(aStorage);
|
||||
if (!storage) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
@ -438,13 +444,16 @@ DOMStorageManager::CheckStorage(nsIPrincipal* aPrincipal,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsAutoCString scope;
|
||||
nsresult rv = CreateScopeKey(aPrincipal, scope);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsAutoCString suffix;
|
||||
BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(suffix);
|
||||
|
||||
nsAutoCString origin;
|
||||
rv = AppendOriginNoSuffix(aPrincipal, origin);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DOMStorageCache* cache = GetCache(scope);
|
||||
DOMStorageCache* cache = GetCache(suffix, origin);
|
||||
if (cache != storage->GetCache()) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -474,62 +483,79 @@ DOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
|
||||
void
|
||||
DOMStorageManager::ClearCaches(uint32_t aUnloadFlags,
|
||||
const nsACString& aKeyPrefix)
|
||||
const OriginAttributesPattern& aPattern,
|
||||
const nsACString& aOriginScope)
|
||||
{
|
||||
for (auto iter = mCaches.Iter(); !iter.Done(); iter.Next()) {
|
||||
DOMStorageCache* cache = iter.Get()->cache();
|
||||
nsCString& key = const_cast<nsCString&>(cache->Scope());
|
||||
for (auto iter1 = mCaches.Iter(); !iter1.Done(); iter1.Next()) {
|
||||
PrincipalOriginAttributes oa;
|
||||
DebugOnly<bool> rv = oa.PopulateFromSuffix(iter1.Key());
|
||||
MOZ_ASSERT(rv);
|
||||
if (!aPattern.Matches(oa)) {
|
||||
// This table doesn't match the given origin attributes pattern
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aKeyPrefix.IsEmpty() || StringBeginsWith(key, aKeyPrefix)) {
|
||||
cache->UnloadItems(aUnloadFlags);
|
||||
CacheOriginHashtable* table = iter1.Data();
|
||||
|
||||
for (auto iter2 = table->Iter(); !iter2.Done(); iter2.Next()) {
|
||||
DOMStorageCache* cache = iter2.Get()->cache();
|
||||
|
||||
if (aOriginScope.IsEmpty() ||
|
||||
StringBeginsWith(cache->OriginNoSuffix(), aOriginScope)) {
|
||||
cache->UnloadItems(aUnloadFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
DOMStorageManager::Observe(const char* aTopic, const nsACString& aScopePrefix)
|
||||
DOMStorageManager::Observe(const char* aTopic,
|
||||
const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope)
|
||||
{
|
||||
OriginAttributesPattern pattern;
|
||||
pattern.Init(aOriginAttributesPattern);
|
||||
|
||||
// Clear everything, caches + database
|
||||
if (!strcmp(aTopic, "cookie-cleared")) {
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, EmptyCString());
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, pattern, EmptyCString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Clear from caches everything that has been stored
|
||||
// while in session-only mode
|
||||
if (!strcmp(aTopic, "session-only-cleared")) {
|
||||
ClearCaches(DOMStorageCache::kUnloadSession, aScopePrefix);
|
||||
ClearCaches(DOMStorageCache::kUnloadSession, pattern, aOriginScope);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Clear everything (including so and pb data) from caches and database
|
||||
// for the gived domain and subdomains.
|
||||
if (!strcmp(aTopic, "domain-data-cleared")) {
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, aScopePrefix);
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, pattern, aOriginScope);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Clear all private-browsing caches
|
||||
if (!strcmp(aTopic, "private-browsing-data-cleared")) {
|
||||
ClearCaches(DOMStorageCache::kUnloadPrivate, EmptyCString());
|
||||
ClearCaches(DOMStorageCache::kUnloadPrivate, pattern, EmptyCString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Clear localStorage data beloging to an app.
|
||||
if (!strcmp(aTopic, "app-data-cleared")) {
|
||||
|
||||
// Clear localStorage data beloging to an origin pattern
|
||||
if (!strcmp(aTopic, "origin-attr-pattern-cleared")) {
|
||||
// sessionStorage is expected to stay
|
||||
if (mType == SessionStorage) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, aScopePrefix);
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, pattern, EmptyCString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp(aTopic, "profile-change")) {
|
||||
// For case caches are still referenced - clear them completely
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, EmptyCString());
|
||||
ClearCaches(DOMStorageCache::kUnloadComplete, pattern, EmptyCString());
|
||||
mCaches.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
@ -557,7 +583,7 @@ DOMStorageManager::Observe(const char* aTopic, const nsACString& aScopePrefix)
|
||||
}
|
||||
|
||||
// This immediately completely reloads all caches from the database.
|
||||
ClearCaches(DOMStorageCache::kTestReload, EmptyCString());
|
||||
ClearCaches(DOMStorageCache::kTestReload, pattern, EmptyCString());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -15,11 +15,15 @@
|
||||
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class nsIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class OriginAttributesPattern;
|
||||
|
||||
namespace dom {
|
||||
|
||||
const DOMStorage::StorageType SessionStorage = DOMStorage::SessionStorage;
|
||||
@ -37,9 +41,11 @@ public:
|
||||
// Reads the preference for DOM storage quota
|
||||
static uint32_t GetQuota();
|
||||
// Gets (but not ensures) cache for the given scope
|
||||
DOMStorageCache* GetCache(const nsACString& aScope) const;
|
||||
DOMStorageCache* GetCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix);
|
||||
// Returns object keeping usage cache for the scope.
|
||||
already_AddRefed<DOMStorageUsage> GetScopeUsage(const nsACString& aScope);
|
||||
already_AddRefed<DOMStorageUsage> GetOriginUsage(const nsACString& aOriginNoSuffix);
|
||||
|
||||
static nsCString CreateOrigin(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix);
|
||||
|
||||
protected:
|
||||
explicit DOMStorageManager(DOMStorage::StorageType aType);
|
||||
@ -47,7 +53,9 @@ protected:
|
||||
|
||||
private:
|
||||
// DOMStorageObserverSink, handler to various chrome clearing notification
|
||||
virtual nsresult Observe(const char* aTopic, const nsACString& aScopePrefix) override;
|
||||
virtual nsresult Observe(const char* aTopic,
|
||||
const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope) override;
|
||||
|
||||
// Since nsTHashtable doesn't like multiple inheritance, we have to aggregate
|
||||
// DOMStorageCache into the entry.
|
||||
@ -78,7 +86,8 @@ private:
|
||||
|
||||
// Ensures cache for a scope, when it doesn't exist it is created and initalized,
|
||||
// this also starts preload of persistent data.
|
||||
already_AddRefed<DOMStorageCache> PutCache(const nsACString& aScope,
|
||||
already_AddRefed<DOMStorageCache> PutCache(const nsACString& aOriginSuffix,
|
||||
const nsACString& aOriginNoSuffix,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
// Helper for creation of DOM storage objects
|
||||
@ -89,8 +98,10 @@ private:
|
||||
bool aPrivate,
|
||||
nsIDOMStorage** aRetval);
|
||||
|
||||
// Scope->cache map
|
||||
nsTHashtable<DOMStorageCacheHashKey> mCaches;
|
||||
// Suffix->origin->cache map
|
||||
typedef nsTHashtable<DOMStorageCacheHashKey> CacheOriginHashtable;
|
||||
nsClassHashtable<nsCStringHashKey, CacheOriginHashtable> mCaches;
|
||||
|
||||
const DOMStorage::StorageType mType;
|
||||
|
||||
// If mLowDiskSpace is true it indicates a low device storage situation and
|
||||
@ -99,7 +110,9 @@ private:
|
||||
bool mLowDiskSpace;
|
||||
bool IsLowDiskSpace() const { return mLowDiskSpace; };
|
||||
|
||||
void ClearCaches(uint32_t aUnloadFlags, const nsACString& aKeyPrefix);
|
||||
void ClearCaches(uint32_t aUnloadFlags,
|
||||
const OriginAttributesPattern& aPattern,
|
||||
const nsACString& aKeyPrefix);
|
||||
|
||||
protected:
|
||||
// Keeps usage cache objects for eTLD+1 scopes we have touched.
|
||||
|
@ -9,13 +9,13 @@
|
||||
#include "DOMStorageDBThread.h"
|
||||
#include "DOMStorageCache.h"
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIPermission.h"
|
||||
#include "nsIIDNService.h"
|
||||
#include "mozIApplicationClearPrivateDataParams.h"
|
||||
#include "nsICookiePermission.h"
|
||||
|
||||
#include "nsPrintfCString.h"
|
||||
@ -62,7 +62,7 @@ DOMStorageObserver::Init()
|
||||
obs->AddObserver(sSelf, "perm-changed", true);
|
||||
obs->AddObserver(sSelf, "browser:purge-domain-data", true);
|
||||
obs->AddObserver(sSelf, "last-pb-context-exited", true);
|
||||
obs->AddObserver(sSelf, "webapps-clear-data", true);
|
||||
obs->AddObserver(sSelf, "clear-origin-data", true);
|
||||
|
||||
// Shutdown
|
||||
obs->AddObserver(sSelf, "profile-after-change", true);
|
||||
@ -111,11 +111,13 @@ DOMStorageObserver::RemoveSink(DOMStorageObserverSink* aObs)
|
||||
}
|
||||
|
||||
void
|
||||
DOMStorageObserver::Notify(const char* aTopic, const nsACString& aData)
|
||||
DOMStorageObserver::Notify(const char* aTopic,
|
||||
const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope)
|
||||
{
|
||||
for (uint32_t i = 0; i < mSinks.Length(); ++i) {
|
||||
DOMStorageObserverSink* sink = mSinks[i];
|
||||
sink->Observe(aTopic, aData);
|
||||
sink->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,6 +204,9 @@ DOMStorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString originSuffix;
|
||||
BasePrincipal::Cast(principal)->OriginAttributesRef().CreateSuffix(originSuffix);
|
||||
|
||||
nsCOMPtr<nsIURI> origin;
|
||||
principal->GetURI(getter_AddRefs(origin));
|
||||
if (!origin) {
|
||||
@ -214,11 +219,11 @@ DOMStorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString scope;
|
||||
rv = CreateReversedDomain(host, scope);
|
||||
nsAutoCString originScope;
|
||||
rv = CreateReversedDomain(host, originScope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Notify("session-only-cleared", scope);
|
||||
Notify("session-only-cleared", NS_ConvertUTF8toUTF16(originSuffix), originScope);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -239,16 +244,16 @@ DOMStorageObserver::Observe(nsISupports* aSubject,
|
||||
aceDomain);
|
||||
}
|
||||
|
||||
nsAutoCString scopePrefix;
|
||||
rv = CreateReversedDomain(aceDomain, scopePrefix);
|
||||
nsAutoCString originScope;
|
||||
rv = CreateReversedDomain(aceDomain, originScope);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
db->AsyncClearMatchingScope(scopePrefix);
|
||||
db->AsyncClearMatchingOrigin(originScope);
|
||||
|
||||
Notify("domain-data-cleared", scopePrefix);
|
||||
Notify("domain-data-cleared", EmptyString(), originScope);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -260,42 +265,20 @@ DOMStorageObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Clear data beloging to an app.
|
||||
if (!strcmp(aTopic, "webapps-clear-data")) {
|
||||
nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
|
||||
do_QueryInterface(aSubject);
|
||||
if (!params) {
|
||||
NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
// Clear data of the origins whose prefixes will match the suffix.
|
||||
if (!strcmp(aTopic, "clear-origin-data")) {
|
||||
OriginAttributesPattern pattern;
|
||||
if (!pattern.Init(nsDependentString(aData))) {
|
||||
NS_ERROR("Cannot parse origin attributes pattern");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t appId;
|
||||
bool browserOnly;
|
||||
|
||||
rv = params->GetAppId(&appId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = params->GetBrowserOnly(&browserOnly);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
|
||||
|
||||
DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
|
||||
NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
|
||||
|
||||
nsAutoCString scope;
|
||||
scope.AppendInt(appId);
|
||||
scope.AppendLiteral(":t:");
|
||||
db->AsyncClearMatchingScope(scope);
|
||||
Notify("app-data-cleared", scope);
|
||||
db->AsyncClearMatchingOriginAttributes(pattern);
|
||||
|
||||
if (!browserOnly) {
|
||||
scope.Truncate();
|
||||
scope.AppendInt(appId);
|
||||
scope.AppendLiteral(":f:");
|
||||
db->AsyncClearMatchingScope(scope);
|
||||
Notify("app-data-cleared", scope);
|
||||
}
|
||||
Notify("origin-attr-pattern-cleared", nsDependentString(aData));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -27,7 +27,9 @@ public:
|
||||
|
||||
private:
|
||||
friend class DOMStorageObserver;
|
||||
virtual nsresult Observe(const char* aTopic, const nsACString& aScopePrefix) = 0;
|
||||
virtual nsresult Observe(const char* aTopic,
|
||||
const nsAString& aOriginAttributesPattern,
|
||||
const nsACString& aOriginScope) = 0;
|
||||
};
|
||||
|
||||
// Statically (though layout statics) initialized observer receiving and processing
|
||||
@ -45,7 +47,9 @@ public:
|
||||
|
||||
void AddSink(DOMStorageObserverSink* aObs);
|
||||
void RemoveSink(DOMStorageObserverSink* aObs);
|
||||
void Notify(const char* aTopic, const nsACString& aData = EmptyCString());
|
||||
void Notify(const char* aTopic,
|
||||
const nsAString& aOriginAttributesPattern = EmptyString(),
|
||||
const nsACString& aOriginScope = EmptyCString());
|
||||
|
||||
private:
|
||||
virtual ~DOMStorageObserver() {}
|
||||
|
@ -19,22 +19,24 @@ prio(normal upto urgent) sync protocol PStorage
|
||||
parent:
|
||||
async __delete__();
|
||||
|
||||
prio(urgent) sync Preload(nsCString scope, uint32_t alreadyLoadedCount)
|
||||
prio(urgent) sync Preload(nsCString originSuffix, nsCString originNoSuffix, uint32_t alreadyLoadedCount)
|
||||
returns (nsString[] keys, nsString[] values, nsresult rv);
|
||||
|
||||
async AsyncPreload(nsCString scope, bool priority);
|
||||
async AsyncPreload(nsCString originSuffix, nsCString originNoSuffix, bool priority);
|
||||
async AsyncGetUsage(nsCString scope);
|
||||
async AsyncAddItem(nsCString scope, nsString key, nsString value);
|
||||
async AsyncUpdateItem(nsCString scope, nsString key, nsString value);
|
||||
async AsyncRemoveItem(nsCString scope, nsString key);
|
||||
async AsyncClear(nsCString scope);
|
||||
async AsyncAddItem(nsCString originSuffix, nsCString originNoSuffix, nsString key, nsString value);
|
||||
async AsyncUpdateItem(nsCString originSuffix, nsCString originNoSuffix, nsString key, nsString value);
|
||||
async AsyncRemoveItem(nsCString originSuffix, nsCString originNoSuffix, nsString key);
|
||||
async AsyncClear(nsCString originSuffix, nsCString originNoSuffix);
|
||||
async AsyncFlush();
|
||||
|
||||
child:
|
||||
async Observe(nsCString topic, nsCString scopePrefix);
|
||||
async ScopesHavingData(nsCString[] scopes);
|
||||
async LoadItem(nsCString scope, nsString key, nsString value);
|
||||
async LoadDone(nsCString scope, nsresult rv);
|
||||
async Observe(nsCString topic,
|
||||
nsString originAttributesPattern,
|
||||
nsCString originScope);
|
||||
async OriginsHavingData(nsCString[] origins);
|
||||
async LoadItem(nsCString originSuffix, nsCString originNoSuffix, nsString key, nsString value);
|
||||
async LoadDone(nsCString originSuffix, nsCString originNoSuffix, nsresult rv);
|
||||
async LoadUsage(nsCString scope, int64_t usage);
|
||||
async Error(nsresult rv);
|
||||
};
|
||||
|
@ -13,6 +13,7 @@ UNIFIED_SOURCES += [
|
||||
'DOMStorage.cpp',
|
||||
'DOMStorageCache.cpp',
|
||||
'DOMStorageDBThread.cpp',
|
||||
'DOMStorageDBUpdater.cpp',
|
||||
'DOMStorageIPC.cpp',
|
||||
'DOMStorageManager.cpp',
|
||||
'DOMStorageObserver.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user