mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 957086 - patch 2 - DataStoreService in C++, r=ehsan, r=bz, r=janv
This commit is contained in:
parent
826262e03b
commit
e717179ace
@ -808,7 +808,6 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
@BINPATH@/components/DataStoreImpl.js
|
||||
@BINPATH@/components/dom_datastore.xpt
|
||||
|
||||
|
@ -861,7 +861,6 @@ bin/libfreebl_32int64_3.so
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
@BINPATH@/components/DataStoreImpl.js
|
||||
@BINPATH@/components/dom_datastore.xpt
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
||||
#endif
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "nsIDataStoreService.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
#include "nsScriptNameSpaceManager.h"
|
||||
@ -1466,8 +1466,7 @@ Navigator::GetDataStores(nsPIDOMWindow* aWindow,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDataStoreService> service =
|
||||
do_GetService("@mozilla.org/datastore-service;1");
|
||||
nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
|
||||
if (!service) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
|
@ -1,4 +1,2 @@
|
||||
component {db5c9602-030f-4bff-a3de-881a8de370f2} DataStoreImpl.js
|
||||
contract @mozilla.org/dom/datastore;1 {db5c9602-030f-4bff-a3de-881a8de370f2}
|
||||
component {d193d0e2-c677-4a7b-bb0a-19155b470f2e} DataStoreService.js
|
||||
contract @mozilla.org/datastore-service;1 {d193d0e2-c677-4a7b-bb0a-19155b470f2e}
|
||||
|
48
dom/datastore/DataStoreCallbacks.h
Normal file
48
dom/datastore/DataStoreCallbacks.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 mozilla_dom_DataStoreCallbacks_h
|
||||
#define mozilla_dom_DataStoreCallbacks_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreDB;
|
||||
|
||||
class DataStoreDBCallback
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
virtual void Run(DataStoreDB* aDb, bool aSuccess) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataStoreDBCallback()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DataStoreRevisionCallback
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
virtual void Run(const nsAString& aRevisionID) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataStoreRevisionCallback()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_dom_DataStoreCallbacks_h
|
319
dom/datastore/DataStoreDB.cpp
Normal file
319
dom/datastore/DataStoreDB.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 "DataStoreDB.h"
|
||||
|
||||
#include "DataStoreCallbacks.h"
|
||||
#include "mozilla/dom/IDBDatabaseBinding.h"
|
||||
#include "mozilla/dom/IDBFactoryBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBDatabase.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/dom/indexedDB/IDBIndex.h"
|
||||
#include "mozilla/dom/indexedDB/IDBObjectStore.h"
|
||||
#include "mozilla/dom/indexedDB/IDBRequest.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
#define DATASTOREDB_VERSION 1
|
||||
#define DATASTOREDB_NAME "DataStoreDB"
|
||||
#define DATASTOREDB_REVISION_INDEX "revisionIndex"
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(DataStoreDB, nsIDOMEventListener)
|
||||
|
||||
DataStoreDB::DataStoreDB(const nsAString& aManifestURL, const nsAString& aName)
|
||||
: mState(Inactive)
|
||||
{
|
||||
mDatabaseName.Assign(aName);
|
||||
mDatabaseName.AppendASCII("|");
|
||||
mDatabaseName.Append(aManifestURL);
|
||||
}
|
||||
|
||||
DataStoreDB::~DataStoreDB()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::CreateFactoryIfNeeded()
|
||||
{
|
||||
if (!mFactory) {
|
||||
nsresult rv = IDBFactory::Create(nullptr, getter_AddRefs(mFactory));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::Open(IDBTransactionMode aMode, const Sequence<nsString>& aDbs,
|
||||
DataStoreDBCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(mState == Inactive);
|
||||
|
||||
nsresult rv = CreateFactoryIfNeeded();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
mRequest = mFactory->Open(mDatabaseName, DATASTOREDB_VERSION, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
rv = AddEventListeners();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mState = Active;
|
||||
mTransactionMode = aMode;
|
||||
mObjectStores = aDbs;
|
||||
mCallback = aCallback;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("success")) {
|
||||
RemoveEventListeners();
|
||||
mState = Inactive;
|
||||
|
||||
rv = DatabaseOpened();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mCallback->Run(this, false);
|
||||
} else {
|
||||
mCallback->Run(this, true);
|
||||
}
|
||||
|
||||
mRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("upgradeneeded")) {
|
||||
return UpgradeSchema();
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
|
||||
RemoveEventListeners();
|
||||
mState = Inactive;
|
||||
mCallback->Run(this, false);
|
||||
mRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("This should not happen");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::UpgradeSchema()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(cx, mRequest->GetResult(error));
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(result.isObject());
|
||||
|
||||
IDBDatabase* database = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Didn't get the object we expected!");
|
||||
return rv;
|
||||
}
|
||||
|
||||
{
|
||||
IDBObjectStoreParameters params;
|
||||
params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true }"));
|
||||
nsRefPtr<IDBObjectStore> store =
|
||||
database->CreateObjectStore(cx, NS_LITERAL_STRING(DATASTOREDB_NAME),
|
||||
params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<IDBObjectStore> store;
|
||||
|
||||
{
|
||||
IDBObjectStoreParameters params;
|
||||
params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true, \"keyPath\": \"internalRevisionId\" }"));
|
||||
|
||||
store =
|
||||
database->CreateObjectStore(cx, NS_LITERAL_STRING(DATASTOREDB_REVISION),
|
||||
params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
IDBIndexParameters params;
|
||||
params.Init(NS_LITERAL_STRING("{ \"unique\": true }"));
|
||||
nsRefPtr<IDBIndex> index =
|
||||
store->CreateIndex(cx, NS_LITERAL_STRING(DATASTOREDB_REVISION_INDEX),
|
||||
NS_LITERAL_STRING("revisionId"), params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::DatabaseOpened()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(cx, mRequest->GetResult(error));
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(result.isObject());
|
||||
|
||||
nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), mDatabase);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Didn't get the object we expected!");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBTransaction> txn = mDatabase->Transaction(mObjectStores,
|
||||
mTransactionMode,
|
||||
error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
mTransaction = txn.forget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::Delete()
|
||||
{
|
||||
MOZ_ASSERT(mState == Inactive);
|
||||
|
||||
nsresult rv = CreateFactoryIfNeeded();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mTransaction = nullptr;
|
||||
|
||||
if (mDatabase) {
|
||||
rv = mDatabase->Close();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDatabase = nullptr;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
nsRefPtr<IDBOpenDBRequest> request =
|
||||
mFactory->DeleteDatabase(mDatabaseName, IDBOpenDBOptions(), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
indexedDB::IDBTransaction*
|
||||
DataStoreDB::Transaction() const
|
||||
{
|
||||
MOZ_ASSERT(mTransaction);
|
||||
MOZ_ASSERT(mTransaction->IsOpen());
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::AddEventListeners()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("upgradeneeded"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("error"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("blocked"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::RemoveEventListeners()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("upgradeneeded"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("error"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("blocked"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
82
dom/datastore/DataStoreDB.h
Normal file
82
dom/datastore/DataStoreDB.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 mozilla_dom_DataStoreDB_h
|
||||
#define mozilla_dom_DataStoreDB_h
|
||||
|
||||
#include "mozilla/dom/IDBTransactionBinding.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#define DATASTOREDB_REVISION "revision"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace indexedDB {
|
||||
class IDBDatabase;
|
||||
class IDBFactory;
|
||||
class IDBObjectStore;
|
||||
class IDBOpenDBRequest;
|
||||
class IDBTransaction;
|
||||
}
|
||||
|
||||
class DataStoreDBCallback;
|
||||
|
||||
class DataStoreDB MOZ_FINAL : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
DataStoreDB(const nsAString& aManifestURL, const nsAString& aName);
|
||||
~DataStoreDB();
|
||||
|
||||
nsresult Open(IDBTransactionMode aMode, const Sequence<nsString>& aDb,
|
||||
DataStoreDBCallback* aCallback);
|
||||
|
||||
nsresult Delete();
|
||||
|
||||
indexedDB::IDBTransaction* Transaction() const;
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
private:
|
||||
nsresult CreateFactoryIfNeeded();
|
||||
|
||||
nsresult UpgradeSchema();
|
||||
|
||||
nsresult DatabaseOpened();
|
||||
|
||||
nsresult AddEventListeners();
|
||||
|
||||
nsresult RemoveEventListeners();
|
||||
|
||||
nsString mDatabaseName;
|
||||
|
||||
nsRefPtr<indexedDB::IDBFactory> mFactory;
|
||||
nsRefPtr<indexedDB::IDBOpenDBRequest> mRequest;
|
||||
nsRefPtr<indexedDB::IDBDatabase> mDatabase;
|
||||
nsRefPtr<indexedDB::IDBTransaction> mTransaction;
|
||||
|
||||
nsRefPtr<DataStoreDBCallback> mCallback;
|
||||
|
||||
// Internal state to avoid strange use of this class.
|
||||
enum StateType {
|
||||
Inactive,
|
||||
Active
|
||||
} mState;
|
||||
|
||||
IDBTransactionMode mTransactionMode;
|
||||
Sequence<nsString> mObjectStores;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreDB_h
|
@ -59,7 +59,6 @@ function validateId(aId) {
|
||||
/* DataStore object */
|
||||
function DataStore() {
|
||||
debug("DataStore created");
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
DataStore.prototype = {
|
||||
|
102
dom/datastore/DataStoreRevision.cpp
Normal file
102
dom/datastore/DataStoreRevision.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 "DataStoreRevision.h"
|
||||
|
||||
#include "DataStoreCallbacks.h"
|
||||
#include "DataStoreService.h"
|
||||
#include "mozilla/dom/DataStoreBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBObjectStore.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace indexedDB;
|
||||
|
||||
NS_IMPL_ISUPPORTS(DataStoreRevision, nsIDOMEventListener)
|
||||
|
||||
// Note: this code in it must not assume anything about the compartment cx is
|
||||
// in.
|
||||
nsresult
|
||||
DataStoreRevision::AddRevision(JSContext* aCx,
|
||||
IDBObjectStore* aStore,
|
||||
uint32_t aObjectId,
|
||||
RevisionType aRevisionType,
|
||||
DataStoreRevisionCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aStore);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
nsRefPtr<DataStoreService> service = DataStoreService::Get();
|
||||
if (!service) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsString id;
|
||||
nsresult rv = service->GenerateUUID(mRevisionID);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DataStoreRevisionData data;
|
||||
data.mRevisionId = mRevisionID;
|
||||
data.mObjectId = aObjectId;
|
||||
|
||||
switch (aRevisionType) {
|
||||
case RevisionVoid:
|
||||
data.mOperation = NS_LITERAL_STRING("void");
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("This should not happen");
|
||||
break;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!data.ToObject(aCx, &value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
mRequest = aStore->Put(aCx, value, JS::UndefinedHandleValue, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.ErrorCode();
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreRevision::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!type.EqualsASCII("success")) {
|
||||
MOZ_ASSUME_UNREACHABLE("This should not happen");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mRequest->RemoveEventListener(NS_LITERAL_STRING("success"), this, false);
|
||||
mRequest = nullptr;
|
||||
|
||||
mCallback->Run(mRevisionID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
52
dom/datastore/DataStoreRevision.h
Normal file
52
dom/datastore/DataStoreRevision.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 mozilla_dom_DataStoreRevision_h
|
||||
#define mozilla_dom_DataStoreRevision_h
|
||||
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace indexedDB {
|
||||
class IDBObjectStore;
|
||||
class IDBRequest;
|
||||
}
|
||||
|
||||
class DataStoreRevisionCallback;
|
||||
|
||||
class DataStoreRevision MOZ_FINAL : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
enum RevisionType {
|
||||
RevisionVoid
|
||||
};
|
||||
|
||||
nsresult AddRevision(JSContext* aCx,
|
||||
indexedDB::IDBObjectStore* aStore,
|
||||
uint32_t aObjectId,
|
||||
RevisionType aRevisionType,
|
||||
DataStoreRevisionCallback* aCallback);
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
private:
|
||||
nsRefPtr<DataStoreRevisionCallback> mCallback;
|
||||
nsRefPtr<indexedDB::IDBRequest> mRequest;
|
||||
nsString mRevisionID;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreRevision_h
|
1277
dom/datastore/DataStoreService.cpp
Normal file
1277
dom/datastore/DataStoreService.cpp
Normal file
File diff suppressed because it is too large
Load Diff
103
dom/datastore/DataStoreService.h
Normal file
103
dom/datastore/DataStoreService.h
Normal file
@ -0,0 +1,103 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 mozilla_dom_DataStoreService_h
|
||||
#define mozilla_dom_DataStoreService_h
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIDataStoreService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
class nsIUUIDGenerator;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreInfo;
|
||||
class FirstRevisionIdCallback;
|
||||
class PendingRequest;
|
||||
class Promise;
|
||||
class RetrieveRevisionsCounter;
|
||||
class RevisionAddedEnableStoreCallback;
|
||||
|
||||
class DataStoreService MOZ_FINAL : public nsIDataStoreService
|
||||
, public nsIObserver
|
||||
{
|
||||
friend class FirstRevisionIdCallback;
|
||||
friend class RetrieveRevisionsCounter;
|
||||
friend class RevisionAddedEnableStoreCallback;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDATASTORESERVICE
|
||||
|
||||
// Returns the DataStoreService singleton. Only to be called from main
|
||||
// thread.
|
||||
static already_AddRefed<DataStoreService> GetOrCreate();
|
||||
|
||||
static already_AddRefed<DataStoreService> Get();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
nsresult GenerateUUID(nsAString& aID);
|
||||
|
||||
private:
|
||||
DataStoreService();
|
||||
~DataStoreService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
typedef nsClassHashtable<nsUint32HashKey, DataStoreInfo> HashApp;
|
||||
|
||||
nsresult AddPermissions(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aOriginURL,
|
||||
const nsAString& aManifestURL,
|
||||
bool aReadOnly);
|
||||
|
||||
nsresult AddAccessPermissions(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aOriginURL,
|
||||
const nsAString& aManifestURL,
|
||||
bool aReadOnly);
|
||||
|
||||
nsresult CreateFirstRevisionId(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aManifestURL);
|
||||
|
||||
void GetDataStoresCreate(nsPIDOMWindow* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void GetDataStoresResolve(nsPIDOMWindow* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
nsresult GetDataStoreInfos(const nsAString& aName, uint32_t aAppId,
|
||||
nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void DeleteDataStores(uint32_t aAppId);
|
||||
|
||||
nsresult EnableDataStore(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aManifestURL);
|
||||
|
||||
already_AddRefed<RetrieveRevisionsCounter> GetCounter(uint32_t aId) const;
|
||||
|
||||
void RemoveCounter(uint32_t aId);
|
||||
|
||||
nsClassHashtable<nsStringHashKey, HashApp> mStores;
|
||||
nsClassHashtable<nsStringHashKey, HashApp> mAccessStores;
|
||||
|
||||
typedef nsTArray<PendingRequest> PendingRequests;
|
||||
nsClassHashtable<nsStringHashKey, PendingRequests> mPendingRequests;
|
||||
|
||||
nsRefPtrHashtable<nsUint32HashKey, RetrieveRevisionsCounter> mPendingCounters;
|
||||
|
||||
nsCOMPtr<nsIUUIDGenerator> mUUIDGenerator;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreService_h
|
@ -1,527 +0,0 @@
|
||||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* vim: set ft=javascript ts=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/. */
|
||||
|
||||
'use strict'
|
||||
|
||||
/* static functions */
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStoreService: ' + s + '\n');
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import("resource://gre/modules/DataStoreDB.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "permissionManager",
|
||||
"@mozilla.org/permissionmanager;1",
|
||||
"nsIPermissionManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "secMan",
|
||||
"@mozilla.org/scriptsecuritymanager;1",
|
||||
"nsIScriptSecurityManager");
|
||||
|
||||
/* DataStoreService */
|
||||
|
||||
const DATASTORESERVICE_CID = Components.ID('{d193d0e2-c677-4a7b-bb0a-19155b470f2e}');
|
||||
const REVISION_VOID = "void";
|
||||
|
||||
function DataStoreService() {
|
||||
debug('DataStoreService Constructor');
|
||||
|
||||
this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
if (this.inParent) {
|
||||
let obs = Services.obs;
|
||||
if (!obs) {
|
||||
debug("DataStore Error: observer-service is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
obs.addObserver(this, 'webapps-clear-data', false);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
cpmm.addMessageListener("datastore-first-revision-created",
|
||||
function(aMsg) { self.receiveMessage(aMsg); });
|
||||
}
|
||||
|
||||
DataStoreService.prototype = {
|
||||
inParent: false,
|
||||
|
||||
// Hash of DataStores
|
||||
stores: {},
|
||||
accessStores: {},
|
||||
pendingRequests: {},
|
||||
|
||||
installDataStore: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
debug('installDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOrigin: ' + aOrigin + ', aOwner:' + aOwner +
|
||||
', aReadOnly: ' + aReadOnly);
|
||||
|
||||
this.checkIfInParent();
|
||||
|
||||
if (aName in this.stores && aAppId in this.stores[aName]) {
|
||||
debug('This should not happen');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aName in this.stores)) {
|
||||
this.stores[aName] = {};
|
||||
}
|
||||
|
||||
// A DataStore is enabled when it has a first valid revision.
|
||||
this.stores[aName][aAppId] = { origin: aOrigin, owner: aOwner,
|
||||
readOnly: aReadOnly, enabled: false };
|
||||
|
||||
this.addPermissions(aAppId, aName, aOrigin, aOwner, aReadOnly);
|
||||
|
||||
this.createFirstRevisionId(aAppId, aName, aOwner);
|
||||
},
|
||||
|
||||
installAccessDataStore: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
debug('installAccessDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOrigin: ' + aOrigin + ', aOwner:' + aOwner +
|
||||
', aReadOnly: ' + aReadOnly);
|
||||
|
||||
this.checkIfInParent();
|
||||
|
||||
if (aName in this.accessStores && aAppId in this.accessStores[aName]) {
|
||||
debug('This should not happen');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aName in this.accessStores)) {
|
||||
this.accessStores[aName] = {};
|
||||
}
|
||||
|
||||
this.accessStores[aName][aAppId] = { origin: aOrigin, owner: aOwner,
|
||||
readOnly: aReadOnly };
|
||||
this.addAccessPermissions(aAppId, aName, aOrigin, aOwner, aReadOnly);
|
||||
},
|
||||
|
||||
checkIfInParent: function() {
|
||||
if (!this.inParent) {
|
||||
throw "DataStore can execute this operation just in the parent process";
|
||||
}
|
||||
},
|
||||
|
||||
createFirstRevisionId: function(aAppId, aName, aOwner) {
|
||||
debug("createFirstRevisionId database: " + aName);
|
||||
|
||||
let self = this;
|
||||
let db = new DataStoreDB();
|
||||
db.init(aOwner, aName);
|
||||
db.revisionTxn(
|
||||
'readwrite',
|
||||
function(aTxn, aRevisionStore) {
|
||||
debug("createFirstRevisionId - transaction success");
|
||||
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (cursor) {
|
||||
debug("First revision already created.");
|
||||
self.enableDataStore(aAppId, aName, aOwner);
|
||||
} else {
|
||||
// If the revision doesn't exist, let's create the first one.
|
||||
db.addRevision(aRevisionStore, 0, REVISION_VOID, function() {
|
||||
debug("First revision created.");
|
||||
self.enableDataStore(aAppId, aName, aOwner);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
enableDataStore: function(aAppId, aName, aOwner) {
|
||||
if (aName in this.stores && aAppId in this.stores[aName]) {
|
||||
this.stores[aName][aAppId].enabled = true;
|
||||
ppmm.broadcastAsyncMessage('datastore-first-revision-created',
|
||||
{ name: aName, owner: aOwner });
|
||||
}
|
||||
},
|
||||
|
||||
addPermissions: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
// When a new DataStore is installed, the permissions must be set for the
|
||||
// owner app.
|
||||
let permission = "indexedDB-chrome-" + aName + '|' + aOwner;
|
||||
this.resetPermissions(aAppId, aOrigin, aOwner, permission, aReadOnly);
|
||||
|
||||
// For any app that wants to have access to this DataStore we add the
|
||||
// permissions.
|
||||
if (aName in this.accessStores) {
|
||||
for (let appId in this.accessStores[aName]) {
|
||||
// ReadOnly is decided by the owner first.
|
||||
let readOnly = aReadOnly || this.accessStores[aName][appId].readOnly;
|
||||
this.resetPermissions(appId, this.accessStores[aName][appId].origin,
|
||||
this.accessStores[aName][appId].owner,
|
||||
permission, readOnly);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addAccessPermissions: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
// When an app wants to have access to a DataStore, the permissions must be
|
||||
// set.
|
||||
if (!(aName in this.stores)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let appId in this.stores[aName]) {
|
||||
let permission = "indexedDB-chrome-" + aName + '|' + this.stores[aName][appId].owner;
|
||||
// The ReadOnly is decied by the owenr first.
|
||||
let readOnly = this.stores[aName][appId].readOnly || aReadOnly;
|
||||
this.resetPermissions(aAppId, aOrigin, aOwner, permission, readOnly);
|
||||
}
|
||||
},
|
||||
|
||||
resetPermissions: function(aAppId, aOrigin, aOwner, aPermission, aReadOnly) {
|
||||
debug("ResetPermissions - appId: " + aAppId + " - origin: " + aOrigin +
|
||||
" - owner: " + aOwner + " - permissions: " + aPermission +
|
||||
" - readOnly: " + aReadOnly);
|
||||
|
||||
let uri = Services.io.newURI(aOrigin, null, null);
|
||||
let principal = secMan.getAppCodebasePrincipal(uri, aAppId, false);
|
||||
|
||||
let result = permissionManager.testExactPermissionFromPrincipal(principal,
|
||||
aPermission + '-write');
|
||||
|
||||
if (aReadOnly && result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Write permission removed");
|
||||
permissionManager.removeFromPrincipal(principal, aPermission + '-write');
|
||||
} else if (!aReadOnly && result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Write permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission + '-write',
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
result = permissionManager.testExactPermissionFromPrincipal(principal,
|
||||
aPermission + '-read');
|
||||
if (result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Read permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission + '-read',
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
|
||||
if (result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Generic permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
},
|
||||
|
||||
getDataStores: function(aWindow, aName) {
|
||||
debug('getDataStores - aName: ' + aName);
|
||||
|
||||
let self = this;
|
||||
return new aWindow.Promise(function(resolve, reject) {
|
||||
// If this request comes from the main process, we have access to the
|
||||
// window, so we can skip the ipc communication.
|
||||
if (self.inParent) {
|
||||
let stores = self.getDataStoresInfo(aName, aWindow.document.nodePrincipal.appId);
|
||||
if (stores === null) {
|
||||
reject(new aWindow.DOMError("SecurityError", "Access denied"));
|
||||
return;
|
||||
}
|
||||
self.getDataStoreCreate(aWindow, resolve, stores);
|
||||
} else {
|
||||
// This method can be called in the child so we need to send a request
|
||||
// to the parent and create DataStore object here.
|
||||
new DataStoreServiceChild(aWindow, aName, function(aStores) {
|
||||
debug("DataStoreServiceChild success callback!");
|
||||
self.getDataStoreCreate(aWindow, resolve, aStores);
|
||||
}, function() {
|
||||
debug("DataStoreServiceChild error callback!");
|
||||
reject(new aWindow.DOMError("SecurityError", "Access denied"));
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getDataStoresInfo: function(aName, aAppId) {
|
||||
debug('GetDataStoresInfo');
|
||||
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
let app = appsService.getAppByLocalId(aAppId);
|
||||
if (!app) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let prefName = "dom.testing.datastore_enabled_for_hosted_apps";
|
||||
if (app.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED &&
|
||||
(Services.prefs.getPrefType(prefName) == Services.prefs.PREF_INVALID ||
|
||||
!Services.prefs.getBoolPref(prefName))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let results = [];
|
||||
|
||||
if (aName in this.stores) {
|
||||
if (aAppId in this.stores[aName]) {
|
||||
results.push({ name: aName,
|
||||
owner: this.stores[aName][aAppId].owner,
|
||||
readOnly: false,
|
||||
enabled: this.stores[aName][aAppId].enabled });
|
||||
}
|
||||
|
||||
for (var i in this.stores[aName]) {
|
||||
if (i == aAppId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let access = this.getDataStoreAccess(aName, aAppId);
|
||||
if (!access) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let readOnly = this.stores[aName][i].readOnly || access.readOnly;
|
||||
results.push({ name: aName,
|
||||
owner: this.stores[aName][i].owner,
|
||||
readOnly: readOnly,
|
||||
enabled: this.stores[aName][i].enabled });
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
getDataStoreCreate: function(aWindow, aResolve, aStores) {
|
||||
debug("GetDataStoreCreate");
|
||||
|
||||
let results = new aWindow.Array();
|
||||
|
||||
if (!aStores.length) {
|
||||
aResolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
let pendingDataStores = [];
|
||||
|
||||
for (let i = 0; i < aStores.length; ++i) {
|
||||
if (!aStores[i].enabled) {
|
||||
pendingDataStores.push(aStores[i].owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pendingDataStores.length) {
|
||||
this.getDataStoreResolve(aWindow, aResolve, aStores);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aStores[0].name in this.pendingRequests)) {
|
||||
this.pendingRequests[aStores[0].name] = [];
|
||||
}
|
||||
|
||||
this.pendingRequests[aStores[0].name].push({ window: aWindow,
|
||||
resolve: aResolve,
|
||||
stores: aStores,
|
||||
pendingDataStores: pendingDataStores });
|
||||
},
|
||||
|
||||
getDataStoreResolve: function(aWindow, aResolve, aStores) {
|
||||
debug("GetDataStoreResolve");
|
||||
|
||||
let callbackPending = aStores.length;
|
||||
let results = new aWindow.Array();
|
||||
|
||||
if (!callbackPending) {
|
||||
aResolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < aStores.length; ++i) {
|
||||
let obj = Cc["@mozilla.org/dom/datastore;1"]
|
||||
.createInstance(Ci.nsIDataStore);
|
||||
if (!obj || !obj.wrappedJSObject) {
|
||||
dump("Failed to create a DataStore object.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
obj.init(aWindow, aStores[i].name, aStores[i].owner, aStores[i].readOnly);
|
||||
|
||||
let storeImpl = aWindow.DataStoreImpl._create(aWindow, obj.wrappedJSObject);
|
||||
|
||||
let exposedStore = new aWindow.DataStore();
|
||||
exposedStore.setDataStoreImpl(storeImpl);
|
||||
|
||||
obj.exposedObject = exposedStore;
|
||||
|
||||
results.push(exposedStore);
|
||||
|
||||
obj.retrieveRevisionId(
|
||||
function() {
|
||||
--callbackPending;
|
||||
if (!callbackPending) {
|
||||
aResolve(results);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getDataStoreAccess: function(aName, aAppId) {
|
||||
if (!(aName in this.accessStores) ||
|
||||
!(aAppId in this.accessStores[aName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.accessStores[aName][aAppId];
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
debug('observe - aTopic: ' + aTopic);
|
||||
if (aTopic != 'webapps-clear-data') {
|
||||
return;
|
||||
}
|
||||
|
||||
let params =
|
||||
aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
|
||||
|
||||
// DataStore is explosed to apps, not browser content.
|
||||
if (params.browserOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
function isEmpty(aMap) {
|
||||
for (var key in aMap) {
|
||||
if (aMap.hasOwnProperty(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let key in this.stores) {
|
||||
if (params.appId in this.stores[key]) {
|
||||
this.deleteDatabase(key, this.stores[key][params.appId].owner);
|
||||
delete this.stores[key][params.appId];
|
||||
}
|
||||
|
||||
if (isEmpty(this.stores[key])) {
|
||||
delete this.stores[key];
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in this.accessStores) {
|
||||
if (params.appId in this.accessStores[key]) {
|
||||
delete this.accessStores[key][params.appId];
|
||||
}
|
||||
|
||||
if (isEmpty(this.accessStores[key])) {
|
||||
delete this.accessStores[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
deleteDatabase: function(aName, aOwner) {
|
||||
debug("delete database: " + aName);
|
||||
|
||||
let db = new DataStoreDB();
|
||||
db.init(aOwner, aName);
|
||||
db.delete();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMsg) {
|
||||
debug("receiveMessage");
|
||||
let data = aMsg.json;
|
||||
|
||||
if (!(data.name in this.pendingRequests)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.pendingRequests[data.name].length;) {
|
||||
let pos = this.pendingRequests[data.name][i].pendingDataStores.indexOf(data.owner);
|
||||
if (pos != -1) {
|
||||
this.pendingRequests[data.name][i].pendingDataStores.splice(pos, 1);
|
||||
if (!this.pendingRequests[data.name][i].pendingDataStores.length) {
|
||||
this.getDataStoreResolve(this.pendingRequests[data.name][i].window,
|
||||
this.pendingRequests[data.name][i].resolve,
|
||||
this.pendingRequests[data.name][i].stores);
|
||||
this.pendingRequests[data.name].splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (!this.pendingRequests[data.name].length) {
|
||||
delete this.pendingRequests[data.name];
|
||||
}
|
||||
},
|
||||
|
||||
classID : DATASTORESERVICE_CID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataStoreService,
|
||||
Ci.nsIObserver]),
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: DATASTORESERVICE_CID,
|
||||
contractID: '@mozilla.org/datastore-service;1',
|
||||
interfaces: [Ci.nsIDataStoreService, Ci.nsIObserver],
|
||||
flags: Ci.nsIClassInfo.SINGLETON
|
||||
})
|
||||
};
|
||||
|
||||
/* DataStoreServiceChild */
|
||||
|
||||
function DataStoreServiceChild(aWindow, aName, aSuccessCb, aErrorCb) {
|
||||
debug("DataStoreServiceChild created");
|
||||
this.init(aWindow, aName, aSuccessCb, aErrorCb);
|
||||
}
|
||||
|
||||
DataStoreServiceChild.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow, aName, aSuccessCb, aErrorCb) {
|
||||
debug("DataStoreServiceChild init");
|
||||
this._successCb = aSuccessCb;
|
||||
this._errorCb = aErrorCb;
|
||||
this._name = aName;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return:OK",
|
||||
"DataStore:Get:Return:KO" ]);
|
||||
|
||||
cpmm.sendAsyncMessage("DataStore:Get",
|
||||
{ name: aName }, null, aWindow.document.nodePrincipal );
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("DataStoreServiceChild receiveMessage");
|
||||
|
||||
if (aMessage.data.name != this._name) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case 'DataStore:Get:Return:OK':
|
||||
this.destroyDOMRequestHelper();
|
||||
this._successCb(aMessage.data.stores);
|
||||
break;
|
||||
|
||||
case 'DataStore:Get:Return:KO':
|
||||
this.destroyDOMRequestHelper();
|
||||
this._errorCb();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataStoreService]);
|
@ -14,11 +14,15 @@ XPIDL_MODULE = 'dom_datastore'
|
||||
EXPORTS.mozilla.dom += [
|
||||
'DataStore.h',
|
||||
'DataStoreCursor.h',
|
||||
'DataStoreService.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'DataStore.cpp',
|
||||
'DataStoreCursor.cpp',
|
||||
'DataStoreDB.cpp',
|
||||
'DataStoreRevision.cpp',
|
||||
'DataStoreService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
@ -28,7 +32,6 @@ LOCAL_INCLUDES += [
|
||||
EXTRA_COMPONENTS += [
|
||||
'DataStore.manifest',
|
||||
'DataStoreImpl.js',
|
||||
'DataStoreService.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
@ -40,4 +43,7 @@ EXTRA_JS_MODULES += [
|
||||
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(bd02d09c-41ab-47b7-9319-57aa8e5059b0)]
|
||||
[scriptable, uuid(0a050c4f-d292-4a14-8712-09bc1019840a)]
|
||||
interface nsIDataStoreService : nsISupports
|
||||
{
|
||||
void installDataStore(in unsigned long appId,
|
||||
@ -24,12 +24,4 @@ interface nsIDataStoreService : nsISupports
|
||||
|
||||
nsISupports getDataStores(in nsIDOMWindow window,
|
||||
in DOMString name);
|
||||
|
||||
// This is an array of objects composed by:
|
||||
// - readOnly: boolean
|
||||
// - name: DOMString
|
||||
// - owner: DOMString
|
||||
// - enabled: true/false - true if this dataStore is ready to be used.
|
||||
jsval getDataStoresInfo(in DOMString name,
|
||||
in unsigned long appId);
|
||||
};
|
||||
|
@ -235,9 +235,6 @@ IDBFactory::Create(ContentParent* aContentParent,
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
|
||||
NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
|
||||
NS_ASSERTION(aContentParent, "Null ContentParent!");
|
||||
|
||||
NS_ASSERTION(!nsContentUtils::GetCurrentJSContext(), "Should be called from C++");
|
||||
|
||||
// We need to get this information before we push a null principal to avoid
|
||||
// IsCallerChrome() assertion in quota manager.
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
IDBFactory** aFactory);
|
||||
|
||||
// Called when using IndexedDB from a JS component or a JSM in a different
|
||||
// process.
|
||||
// process or from a C++ component.
|
||||
static nsresult Create(ContentParent* aContentParent,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
|
@ -327,7 +327,7 @@ IDBRequest::WrapObject(JSContext* aCx)
|
||||
}
|
||||
|
||||
JS::Value
|
||||
IDBRequest::GetResult(JSContext* aCx, mozilla::ErrorResult& aRv) const
|
||||
IDBRequest::GetResult(mozilla::ErrorResult& aRv) const
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
|
@ -132,7 +132,13 @@ public:
|
||||
}
|
||||
|
||||
JS::Value
|
||||
GetResult(JSContext* aCx, ErrorResult& aRv) const;
|
||||
GetResult(ErrorResult& aRv) const;
|
||||
|
||||
JS::Value
|
||||
GetResult(JSContext* aCx, ErrorResult& aRv) const
|
||||
{
|
||||
return GetResult(aRv);
|
||||
}
|
||||
|
||||
IDBTransaction*
|
||||
GetTransaction() const
|
||||
|
@ -108,3 +108,10 @@ dictionary DataStoreTask {
|
||||
DataStoreKey? id;
|
||||
any data;
|
||||
};
|
||||
|
||||
// For internal use.
|
||||
dictionary DataStoreRevisionData {
|
||||
DOMString revisionId = "";
|
||||
unsigned long objectId = 0;
|
||||
DOMString operation = "";
|
||||
};
|
||||
|
@ -229,6 +229,8 @@ static void Shutdown();
|
||||
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
|
||||
#include "mozilla/dom/power/PowerManagerService.h"
|
||||
#include "mozilla/dom/alarm/AlarmHalService.h"
|
||||
#include "mozilla/dom/time/TimeService.h"
|
||||
@ -584,10 +586,15 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(Geolocation, Init)
|
||||
#define NS_AUDIOCHANNEL_SERVICE_CID \
|
||||
{ 0xf712e983, 0x048a, 0x443f, { 0x88, 0x02, 0xfc, 0xc3, 0xd9, 0x27, 0xce, 0xac }}
|
||||
|
||||
#define NS_DATASTORE_SERVICE_CID \
|
||||
{ 0x0d4285fe, 0xf1b3, 0x49fa, { 0xbc, 0x51, 0xa4, 0xa8, 0x3f, 0x0a, 0xaf, 0x85 }}
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AudioChannelService, AudioChannelService::GetAudioChannelService)
|
||||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DataStoreService, DataStoreService::GetOrCreate)
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(FakeSpeechRecognitionService)
|
||||
#endif
|
||||
@ -737,6 +744,7 @@ NS_DEFINE_NAMED_CID(NS_TEXTSERVICESDOCUMENT_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_GEOLOCATION_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_GEOLOCATION_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_AUDIOCHANNEL_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DATASTORE_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FOCUSMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(CSPSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_CSPCONTEXT_CID);
|
||||
@ -1025,6 +1033,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
||||
{ &kNS_GEOLOCATION_SERVICE_CID, false, nullptr, nsGeolocationServiceConstructor },
|
||||
{ &kNS_GEOLOCATION_CID, false, nullptr, GeolocationConstructor },
|
||||
{ &kNS_AUDIOCHANNEL_SERVICE_CID, false, nullptr, AudioChannelServiceConstructor },
|
||||
{ &kNS_DATASTORE_SERVICE_CID, false, nullptr, DataStoreServiceConstructor },
|
||||
{ &kNS_FOCUSMANAGER_CID, false, nullptr, CreateFocusManager },
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
{ &kNS_FAKE_SPEECH_RECOGNITION_SERVICE_CID, false, nullptr, FakeSpeechRecognitionServiceConstructor },
|
||||
@ -1180,6 +1189,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
||||
{ "@mozilla.org/geolocation/service;1", &kNS_GEOLOCATION_SERVICE_CID },
|
||||
{ "@mozilla.org/geolocation;1", &kNS_GEOLOCATION_CID },
|
||||
{ "@mozilla.org/audiochannel/service;1", &kNS_AUDIOCHANNEL_SERVICE_CID },
|
||||
{ "@mozilla.org/datastore-service;1", &kNS_DATASTORE_SERVICE_CID },
|
||||
{ "@mozilla.org/focus-manager;1", &kNS_FOCUSMANAGER_CID },
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
{ NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "fake", &kNS_FAKE_SPEECH_RECOGNITION_SERVICE_CID },
|
||||
|
@ -65,6 +65,7 @@
|
||||
#include "ActiveLayerTracker.h"
|
||||
|
||||
#include "AudioChannelService.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPopupManager.h"
|
||||
@ -411,6 +412,8 @@ nsLayoutStatics::Shutdown()
|
||||
|
||||
AudioChannelService::Shutdown();
|
||||
|
||||
DataStoreService::Shutdown();
|
||||
|
||||
ContentParent::ShutDown();
|
||||
|
||||
nsRefreshDriver::Shutdown();
|
||||
|
@ -624,6 +624,5 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/DataStore.manifest
|
||||
@BINPATH@/components/DataStoreService.js
|
||||
@BINPATH@/components/DataStoreImpl.js
|
||||
@BINPATH@/components/dom_datastore.xpt
|
||||
|
Loading…
Reference in New Issue
Block a user