mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 701634 - Support IndexedDB in Workers, r=khuey+baku.
This commit is contained in:
parent
8e36934a09
commit
2be368dceb
@ -1440,6 +1440,8 @@ nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
|
||||
void
|
||||
nsDOMStyleSheetSetList::EnsureFresh()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mNames.Clear();
|
||||
|
||||
if (!mDocument) {
|
||||
|
@ -172,7 +172,6 @@
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsXPCOMCID.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "prlog.h"
|
||||
#include "prenv.h"
|
||||
#include "prprf.h"
|
||||
@ -260,6 +259,7 @@ using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::ipc;
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::TimeDuration;
|
||||
using mozilla::dom::indexedDB::IDBFactory;
|
||||
|
||||
nsGlobalWindow::WindowByIdTable *nsGlobalWindow::sWindowsById = nullptr;
|
||||
bool nsGlobalWindow::sWarnedAboutWindowInternal = false;
|
||||
@ -10584,71 +10584,11 @@ nsGlobalWindow::GetLocalStorage(nsISupports** aLocalStorage)
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
static bool
|
||||
GetIndexedDBEnabledForAboutURI(nsIURI *aURI)
|
||||
{
|
||||
nsCOMPtr<nsIAboutModule> module;
|
||||
nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(module));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
uint32_t flags;
|
||||
rv = module->GetURIFlags(aURI, &flags);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return flags & nsIAboutModule::ENABLE_INDEXED_DB;
|
||||
}
|
||||
|
||||
mozilla::dom::indexedDB::IDBFactory*
|
||||
IDBFactory*
|
||||
nsGlobalWindow::GetIndexedDB(ErrorResult& aError)
|
||||
{
|
||||
using mozilla::dom::indexedDB::IDBFactory;
|
||||
|
||||
if (!mIndexedDB) {
|
||||
// If the document has the sandboxed origin flag set
|
||||
// don't allow access to indexedDB.
|
||||
if (mDoc && (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN)) {
|
||||
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!IsChromeWindow()) {
|
||||
// Whitelist about:home, since it doesn't have a base domain it would not
|
||||
// pass the thirdPartyUtil check, though it should be able to use
|
||||
// indexedDB.
|
||||
bool skipThirdPartyCheck = false;
|
||||
nsIPrincipal *principal = GetPrincipal();
|
||||
if (principal) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
principal->GetURI(getter_AddRefs(uri));
|
||||
|
||||
if (uri) {
|
||||
bool isAbout = false;
|
||||
if (NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
|
||||
skipThirdPartyCheck = GetIndexedDBEnabledForAboutURI(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipThirdPartyCheck) {
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
if (!thirdPartyUtil) {
|
||||
aError.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isThirdParty;
|
||||
aError = thirdPartyUtil->IsThirdPartyWindow(this, nullptr,
|
||||
&isThirdParty);
|
||||
if (aError.Failed() || isThirdParty) {
|
||||
NS_WARN_IF_FALSE(aError.Failed(),
|
||||
"IndexedDB is not permitted in a third-party window.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This may be null if being created from a file.
|
||||
// This may keep mIndexedDB null without setting an error.
|
||||
aError = IDBFactory::CreateForWindow(this, getter_AddRefs(mIndexedDB));
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "mozilla/dom/HTMLPropertiesCollectionBinding.h"
|
||||
#include "jsapi.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -509,6 +511,8 @@ NS_INTERFACE_MAP_END_INHERITING(DOMStringList)
|
||||
void
|
||||
PropertyStringList::EnsureFresh()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mCollection->EnsureFresh();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "IndexedDatabaseInlines.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
|
||||
@ -187,7 +188,9 @@ class MOZ_STACK_CLASS ResultHelper MOZ_FINAL
|
||||
|
||||
union
|
||||
{
|
||||
nsISupports* mISupports;
|
||||
IDBDatabase* mDatabase;
|
||||
IDBCursor* mCursor;
|
||||
IDBMutableFile* mMutableFile;
|
||||
StructuredCloneReadInfo* mStructuredClone;
|
||||
const nsTArray<StructuredCloneReadInfo>* mStructuredCloneArray;
|
||||
const Key* mKey;
|
||||
@ -198,7 +201,9 @@ class MOZ_STACK_CLASS ResultHelper MOZ_FINAL
|
||||
|
||||
enum
|
||||
{
|
||||
ResultTypeISupports,
|
||||
ResultTypeDatabase,
|
||||
ResultTypeCursor,
|
||||
ResultTypeMutableFile,
|
||||
ResultTypeStructuredClone,
|
||||
ResultTypeStructuredCloneArray,
|
||||
ResultTypeKey,
|
||||
@ -210,16 +215,39 @@ class MOZ_STACK_CLASS ResultHelper MOZ_FINAL
|
||||
public:
|
||||
ResultHelper(IDBRequest* aRequest,
|
||||
IDBTransaction* aTransaction,
|
||||
nsISupports* aResult)
|
||||
IDBDatabase* aResult)
|
||||
: mRequest(aRequest)
|
||||
, mAutoTransaction(aTransaction)
|
||||
, mResultType(ResultTypeISupports)
|
||||
, mResultType(ResultTypeDatabase)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This won't work off the main thread!");
|
||||
MOZ_ASSERT(aRequest);
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
mResult.mISupports = aResult;
|
||||
mResult.mDatabase = aResult;
|
||||
}
|
||||
|
||||
ResultHelper(IDBRequest* aRequest,
|
||||
IDBTransaction* aTransaction,
|
||||
IDBCursor* aResult)
|
||||
: mRequest(aRequest)
|
||||
, mAutoTransaction(aTransaction)
|
||||
, mResultType(ResultTypeCursor)
|
||||
{
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
mResult.mCursor = aResult;
|
||||
}
|
||||
|
||||
ResultHelper(IDBRequest* aRequest,
|
||||
IDBTransaction* aTransaction,
|
||||
IDBMutableFile* aResult)
|
||||
: mRequest(aRequest)
|
||||
, mAutoTransaction(aTransaction)
|
||||
, mResultType(ResultTypeMutableFile)
|
||||
{
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
mResult.mMutableFile = aResult;
|
||||
}
|
||||
|
||||
ResultHelper(IDBRequest* aRequest,
|
||||
@ -318,8 +346,14 @@ public:
|
||||
MOZ_ASSERT(mRequest);
|
||||
|
||||
switch (mResultType) {
|
||||
case ResultTypeISupports:
|
||||
return GetResult(aCx, mResult.mISupports, aResult);
|
||||
case ResultTypeDatabase:
|
||||
return GetResult(aCx, mResult.mDatabase, aResult);
|
||||
|
||||
case ResultTypeCursor:
|
||||
return GetResult(aCx, mResult.mCursor, aResult);
|
||||
|
||||
case ResultTypeMutableFile:
|
||||
return GetResult(aCx, mResult.mMutableFile, aResult);
|
||||
|
||||
case ResultTypeStructuredClone:
|
||||
return GetResult(aCx, mResult.mStructuredClone, aResult);
|
||||
@ -349,20 +383,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult
|
||||
template <class T>
|
||||
typename EnableIf<IsSame<T, IDBDatabase>::value ||
|
||||
IsSame<T, IDBCursor>::value ||
|
||||
IsSame<T, IDBMutableFile>::value,
|
||||
nsresult>::Type
|
||||
GetResult(JSContext* aCx,
|
||||
nsISupports* aSupports,
|
||||
T* aDOMObject,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This won't work off the main thread!");
|
||||
|
||||
if (!aSupports) {
|
||||
if (!aDOMObject) {
|
||||
aResult.setNull();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, aSupports, aResult);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
bool ok = GetOrCreateDOMReflector(aCx, aDOMObject, aResult);
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
@ -609,9 +645,7 @@ DispatchErrorEvent(IDBRequest* aRequest,
|
||||
nsDependentString(kErrorEventType),
|
||||
eDoesBubble,
|
||||
eCancelable);
|
||||
if (NS_WARN_IF(!errorEvent)) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(errorEvent);
|
||||
|
||||
aEvent = errorEvent;
|
||||
}
|
||||
@ -687,9 +721,7 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
|
||||
nsDependentString(kSuccessEventType),
|
||||
eDoesNotBubble,
|
||||
eNotCancelable);
|
||||
if (NS_WARN_IF(!successEvent)) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(successEvent);
|
||||
|
||||
aEvent = successEvent;
|
||||
}
|
||||
@ -987,8 +1019,7 @@ BackgroundFactoryRequestChild::HandleResponse(
|
||||
IDBDatabase* database = databaseActor->GetDOMObject();
|
||||
MOZ_ASSERT(database);
|
||||
|
||||
ResultHelper helper(mRequest, nullptr,
|
||||
static_cast<IDBWrapperCache*>(database));
|
||||
ResultHelper helper(mRequest, nullptr, database);
|
||||
|
||||
DispatchSuccessEvent(&helper);
|
||||
|
||||
@ -1009,9 +1040,7 @@ BackgroundFactoryRequestChild::HandleResponse(
|
||||
IDBVersionChangeEvent::Create(mRequest,
|
||||
nsDependentString(kSuccessEventType),
|
||||
aResponse.previousVersion());
|
||||
if (NS_WARN_IF(!successEvent)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(successEvent);
|
||||
|
||||
DispatchSuccessEvent(&helper, successEvent);
|
||||
|
||||
@ -1026,6 +1055,13 @@ BackgroundFactoryRequestChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
MaybeCollectGarbageOnIPCMessage();
|
||||
|
||||
NoteActorDestroyed();
|
||||
|
||||
if (aWhy != Deletion) {
|
||||
IDBOpenDBRequest* openRequest = GetOpenDBRequest();
|
||||
if (openRequest) {
|
||||
openRequest->NoteComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1037,21 +1073,35 @@ BackgroundFactoryRequestChild::Recv__delete__(
|
||||
|
||||
MaybeCollectGarbageOnIPCMessage();
|
||||
|
||||
bool result;
|
||||
|
||||
switch (aResponse.type()) {
|
||||
case FactoryRequestResponse::Tnsresult:
|
||||
return HandleResponse(aResponse.get_nsresult());
|
||||
result = HandleResponse(aResponse.get_nsresult());
|
||||
break;
|
||||
|
||||
case FactoryRequestResponse::TOpenDatabaseRequestResponse:
|
||||
return HandleResponse(aResponse.get_OpenDatabaseRequestResponse());
|
||||
result = HandleResponse(aResponse.get_OpenDatabaseRequestResponse());
|
||||
break;
|
||||
|
||||
case FactoryRequestResponse::TDeleteDatabaseRequestResponse:
|
||||
return HandleResponse(aResponse.get_DeleteDatabaseRequestResponse());
|
||||
result = HandleResponse(aResponse.get_DeleteDatabaseRequestResponse());
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown response type!");
|
||||
}
|
||||
|
||||
MOZ_CRASH("Should never get here!");
|
||||
IDBOpenDBRequest* request = GetOpenDBRequest();
|
||||
MOZ_ASSERT(request);
|
||||
|
||||
request->NoteComplete();
|
||||
|
||||
if (NS_WARN_IF(!result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1121,16 +1171,14 @@ BackgroundFactoryRequestChild::RecvBlocked(const uint64_t& aCurrentVersion)
|
||||
if (mIsDeleteOp) {
|
||||
blockedEvent =
|
||||
IDBVersionChangeEvent::Create(mRequest, type, aCurrentVersion);
|
||||
MOZ_ASSERT(blockedEvent);
|
||||
} else {
|
||||
blockedEvent =
|
||||
IDBVersionChangeEvent::Create(mRequest,
|
||||
type,
|
||||
aCurrentVersion,
|
||||
mRequestedVersion);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!blockedEvent)) {
|
||||
return false;
|
||||
MOZ_ASSERT(blockedEvent);
|
||||
}
|
||||
|
||||
nsRefPtr<IDBRequest> kungFuDeathGrip = mRequest;
|
||||
@ -1315,7 +1363,7 @@ BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
|
||||
|
||||
EnsureDOMObject();
|
||||
|
||||
auto actor = static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
|
||||
auto* actor = static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
|
||||
|
||||
nsRefPtr<IDBOpenDBRequest> request = mOpenRequestActor->GetOpenDBRequest();
|
||||
MOZ_ASSERT(request);
|
||||
@ -1327,7 +1375,15 @@ BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
|
||||
aNextObjectStoreId,
|
||||
aNextIndexId);
|
||||
if (NS_WARN_IF(!transaction)) {
|
||||
return false;
|
||||
// This can happen if we receive events after a worker has begun its
|
||||
// shutdown process.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// Report this to the console.
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
|
||||
MOZ_ALWAYS_TRUE(aActor->SendDeleteMe());
|
||||
return true;
|
||||
}
|
||||
|
||||
transaction->AssertIsOnOwningThread();
|
||||
@ -1343,12 +1399,9 @@ BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
|
||||
nsDependentString(kUpgradeNeededEventType),
|
||||
aCurrentVersion,
|
||||
aRequestedVersion);
|
||||
if (NS_WARN_IF(!upgradeNeededEvent)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(upgradeNeededEvent);
|
||||
|
||||
ResultHelper helper(request, transaction,
|
||||
static_cast<IDBWrapperCache*>(mDatabase));
|
||||
ResultHelper helper(request, transaction, mDatabase);
|
||||
|
||||
DispatchSuccessEvent(&helper, upgradeNeededEvent);
|
||||
|
||||
@ -1411,6 +1464,7 @@ BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
|
||||
case NullableVersion::Tnull_t:
|
||||
versionChangeEvent =
|
||||
IDBVersionChangeEvent::Create(mDatabase, type, aOldVersion);
|
||||
MOZ_ASSERT(versionChangeEvent);
|
||||
break;
|
||||
|
||||
case NullableVersion::Tuint64_t:
|
||||
@ -1419,16 +1473,13 @@ BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
|
||||
type,
|
||||
aOldVersion,
|
||||
aNewVersion.get_uint64_t());
|
||||
MOZ_ASSERT(versionChangeEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!versionChangeEvent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IDB_LOG_MARK("IndexedDB %s: Child : Firing \"versionchange\" event",
|
||||
"IndexedDB %s: C: IDBDatabase \"versionchange\" event",
|
||||
IDB_LOG_ID_STRING());
|
||||
@ -1670,11 +1721,12 @@ BackgroundVersionChangeTransactionChild::AssertIsOnOwningThread() const
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
BackgroundVersionChangeTransactionChild::SendDeleteMeInternal()
|
||||
BackgroundVersionChangeTransactionChild::SendDeleteMeInternal(
|
||||
bool aFailedConstructor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (mTransaction) {
|
||||
if (mTransaction || aFailedConstructor) {
|
||||
NoteActorDestroyed();
|
||||
|
||||
MOZ_ALWAYS_TRUE(PBackgroundIDBVersionChangeTransactionChild::
|
||||
@ -2014,13 +2066,14 @@ BackgroundRequestChild::Recv__delete__(const RequestResponse& aResponse)
|
||||
******************************************************************************/
|
||||
|
||||
class BackgroundCursorChild::DelayedDeleteRunnable MOZ_FINAL
|
||||
: public nsIRunnable
|
||||
: public nsICancelableRunnable
|
||||
{
|
||||
BackgroundCursorChild* mActor;
|
||||
nsRefPtr<IDBRequest> mRequest;
|
||||
|
||||
public:
|
||||
explicit DelayedDeleteRunnable(BackgroundCursorChild* aActor)
|
||||
explicit
|
||||
DelayedDeleteRunnable(BackgroundCursorChild* aActor)
|
||||
: mActor(aActor)
|
||||
, mRequest(aActor->mRequest)
|
||||
{
|
||||
@ -2037,6 +2090,7 @@ private:
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSICANCELABLERUNNABLE
|
||||
};
|
||||
|
||||
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
|
||||
@ -2405,7 +2459,8 @@ DispatchMutableFileResult(IDBRequest* aRequest,
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BackgroundCursorChild::DelayedDeleteRunnable,
|
||||
nsIRunnable)
|
||||
nsIRunnable,
|
||||
nsICancelableRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
BackgroundCursorChild::
|
||||
@ -2423,6 +2478,20 @@ DelayedDeleteRunnable::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BackgroundCursorChild::
|
||||
DelayedDeleteRunnable::Cancel()
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// This must always run to clean up our state.
|
||||
Run();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace indexedDB
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -514,7 +514,7 @@ public:
|
||||
#endif
|
||||
|
||||
void
|
||||
SendDeleteMeInternal();
|
||||
SendDeleteMeInternal(bool aFailedConstructor);
|
||||
|
||||
private:
|
||||
// Only created by BackgroundDatabaseChild.
|
||||
|
@ -7821,13 +7821,8 @@ bool
|
||||
NormalTransaction::SendCompleteNotification(nsresult aResult)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!IsActorDestroyed());
|
||||
|
||||
if (NS_WARN_IF(!SendComplete(aResult))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return IsActorDestroyed() || !NS_WARN_IF(!SendComplete(aResult));
|
||||
}
|
||||
|
||||
void
|
||||
@ -8106,7 +8101,6 @@ VersionChangeTransaction::SendCompleteNotification(nsresult aResult)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mOpenDatabaseOp);
|
||||
MOZ_ASSERT(!IsActorDestroyed());
|
||||
|
||||
nsRefPtr<OpenDatabaseOp> openDatabaseOp;
|
||||
mOpenDatabaseOp.swap(openDatabaseOp);
|
||||
@ -8117,7 +8111,7 @@ VersionChangeTransaction::SendCompleteNotification(nsresult aResult)
|
||||
|
||||
openDatabaseOp->mState = OpenDatabaseOp::State_SendingResults;
|
||||
|
||||
bool result = SendComplete(aResult);
|
||||
bool result = IsActorDestroyed() || !NS_WARN_IF(!SendComplete(aResult));
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(openDatabaseOp->Run()));
|
||||
|
||||
@ -10550,10 +10544,23 @@ FactoryOp::Open()
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
// This has to be started on the main thread currently.
|
||||
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
{
|
||||
// These services have to be started on the main thread currently.
|
||||
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIStorageService> ss;
|
||||
if (NS_WARN_IF(!(ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID)))) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!QuotaManager::GetOrCreate())) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
const DatabaseMetadata& metadata = mCommonParams.metadata();
|
||||
@ -11936,8 +11943,7 @@ OpenDatabaseOp::SendResults()
|
||||
mVersionChangeTransaction = nullptr;
|
||||
}
|
||||
|
||||
if (!IsActorDestroyed() &&
|
||||
(!mDatabase || !mDatabase->IsInvalidated())) {
|
||||
if (!IsActorDestroyed()) {
|
||||
FactoryRequestResponse response;
|
||||
|
||||
if (NS_SUCCEEDED(mResultCode)) {
|
||||
@ -11977,6 +11983,10 @@ OpenDatabaseOp::SendResults()
|
||||
DatabaseOfflineStorage::UnregisterOnOwningThread(mOfflineStorage.forget());
|
||||
}
|
||||
|
||||
// Make sure to release the database on this thread.
|
||||
nsRefPtr<Database> database;
|
||||
mDatabase.swap(database);
|
||||
|
||||
FinishSendResults();
|
||||
}
|
||||
|
||||
@ -13377,9 +13387,7 @@ CommitOp::TransactionFinishedAfterUnblock()
|
||||
|
||||
mTransaction->ReleaseBackgroundThreadObjects();
|
||||
|
||||
if (!mTransaction->IsActorDestroyed()) {
|
||||
mTransaction->SendCompleteNotification(ClampResultCode(mResultCode));
|
||||
}
|
||||
mTransaction->SendCompleteNotification(ClampResultCode(mResultCode));
|
||||
|
||||
mTransaction->GetDatabase()->UnregisterTransaction(mTransaction);
|
||||
|
||||
|
@ -67,6 +67,29 @@ const char kCycleCollectionObserverTopic[] = "cycle-collector-end";
|
||||
const char kMemoryPressureObserverTopic[] = "memory-pressure";
|
||||
const char kWindowObserverTopic[] = "inner-window-destroyed";
|
||||
|
||||
class CancelableRunnableWrapper MOZ_FINAL
|
||||
: public nsICancelableRunnable
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
public:
|
||||
explicit
|
||||
CancelableRunnableWrapper(nsIRunnable* aRunnable)
|
||||
: mRunnable(aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
private:
|
||||
~CancelableRunnableWrapper()
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSICANCELABLERUNNABLE
|
||||
};
|
||||
|
||||
// XXX This should either be ported to PBackground or removed someday.
|
||||
class CreateFileHelper MOZ_FINAL
|
||||
: public nsRunnable
|
||||
@ -156,6 +179,46 @@ private:
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class IDBDatabase::LogWarningRunnable MOZ_FINAL
|
||||
: public nsRunnable
|
||||
{
|
||||
nsCString mMessageName;
|
||||
nsString mFilename;
|
||||
uint32_t mLineNumber;
|
||||
uint64_t mInnerWindowID;
|
||||
bool mIsChrome;
|
||||
|
||||
public:
|
||||
LogWarningRunnable(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
bool aIsChrome,
|
||||
uint64_t aInnerWindowID)
|
||||
: mMessageName(aMessageName)
|
||||
, mFilename(aFilename)
|
||||
, mLineNumber(aLineNumber)
|
||||
, mInnerWindowID(aInnerWindowID)
|
||||
, mIsChrome(aIsChrome)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
}
|
||||
|
||||
static void
|
||||
LogWarning(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
bool aIsChrome,
|
||||
uint64_t aInnerWindowID);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
private:
|
||||
~LogWarningRunnable()
|
||||
{ }
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
class IDBDatabase::Observer MOZ_FINAL
|
||||
: public nsIObserver
|
||||
{
|
||||
@ -680,7 +743,11 @@ IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
|
||||
|
||||
nsRefPtr<IDBTransaction> transaction =
|
||||
IDBTransaction::Create(this, sortedStoreNames, mode);
|
||||
MOZ_ASSERT(transaction);
|
||||
if (NS_WARN_IF(!transaction)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BackgroundTransactionChild* actor =
|
||||
new BackgroundTransactionChild(transaction);
|
||||
@ -1006,6 +1073,12 @@ IDBDatabase::DelayedMaybeExpireFileActors()
|
||||
/* aExpireAll */ false);
|
||||
MOZ_ASSERT(runnable);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
// Wrap as a nsICancelableRunnable to make workers happy.
|
||||
nsCOMPtr<nsIRunnable> cancelable = new CancelableRunnableWrapper(runnable);
|
||||
cancelable.swap(runnable);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
|
||||
}
|
||||
|
||||
@ -1170,10 +1243,9 @@ IDBDatabase::NoteFinishedMutableFile(IDBMutableFile* aMutableFile)
|
||||
void
|
||||
IDBDatabase::InvalidateMutableFiles()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mLiveMutableFiles.IsEmpty()) {
|
||||
MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (uint32_t count = mLiveMutableFiles.Length(), index = 0;
|
||||
index < count;
|
||||
@ -1205,55 +1277,21 @@ IDBDatabase::LogWarning(const char* aMessageName,
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aMessageName);
|
||||
|
||||
// For now this is main-thread only.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsXPIDLString localizedMessage;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessageName,
|
||||
localizedMessage)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString category;
|
||||
if (mFactory->IsChrome()) {
|
||||
category.AssignLiteral("chrome ");
|
||||
if (NS_IsMainThread()) {
|
||||
LogWarningRunnable::LogWarning(aMessageName,
|
||||
aFilename,
|
||||
aLineNumber,
|
||||
mFactory->IsChrome(),
|
||||
mFactory->InnerWindowID());
|
||||
} else {
|
||||
category.AssignLiteral("content ");
|
||||
nsRefPtr<LogWarningRunnable> runnable =
|
||||
new LogWarningRunnable(aMessageName,
|
||||
aFilename,
|
||||
aLineNumber,
|
||||
mFactory->IsChrome(),
|
||||
mFactory->InnerWindowID());
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
}
|
||||
category.AppendLiteral("javascript");
|
||||
|
||||
nsCOMPtr<nsIConsoleService> consoleService =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(consoleService);
|
||||
|
||||
nsCOMPtr<nsIScriptError> scriptError =
|
||||
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
|
||||
MOZ_ASSERT(consoleService);
|
||||
|
||||
if (mFactory->GetParentObject()) {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
scriptError->InitWithWindowID(localizedMessage,
|
||||
aFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
aLineNumber,
|
||||
/* aColumnNumber */ 0,
|
||||
nsIScriptError::warningFlag,
|
||||
category,
|
||||
mFactory->InnerWindowID())));
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
scriptError->Init(localizedMessage,
|
||||
aFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
aLineNumber,
|
||||
/* aColumnNumber */ 0,
|
||||
nsIScriptError::warningFlag,
|
||||
category.get())));
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
|
||||
@ -1295,7 +1333,13 @@ IDBDatabase::LastRelease()
|
||||
nsresult
|
||||
IDBDatabase::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
|
||||
nsresult rv =
|
||||
IndexedDatabaseManager::CommonPostHandleEvent(this, mFactory, aVisitor);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -1304,6 +1348,32 @@ IDBDatabase::WrapObject(JSContext* aCx)
|
||||
return IDBDatabaseBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(CancelableRunnableWrapper, nsIRunnable, nsICancelableRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CancelableRunnableWrapper::Run()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable;
|
||||
mRunnable.swap(runnable);
|
||||
|
||||
if (runnable) {
|
||||
return runnable->Run();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CancelableRunnableWrapper::Cancel()
|
||||
{
|
||||
if (mRunnable) {
|
||||
mRunnable = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
CreateFileHelper::CreateFileHelper(IDBDatabase* aDatabase,
|
||||
IDBRequest* aRequest,
|
||||
const nsAString& aName,
|
||||
@ -1486,6 +1556,84 @@ CreateFileHelper::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void
|
||||
IDBDatabase::
|
||||
LogWarningRunnable::LogWarning(const char* aMessageName,
|
||||
const nsAString& aFilename,
|
||||
uint32_t aLineNumber,
|
||||
bool aIsChrome,
|
||||
uint64_t aInnerWindowID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aMessageName);
|
||||
|
||||
nsXPIDLString localizedMessage;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessageName,
|
||||
localizedMessage)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString category;
|
||||
if (aIsChrome) {
|
||||
category.AssignLiteral("chrome ");
|
||||
} else {
|
||||
category.AssignLiteral("content ");
|
||||
}
|
||||
category.AppendLiteral("javascript");
|
||||
|
||||
nsCOMPtr<nsIConsoleService> consoleService =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(consoleService);
|
||||
|
||||
nsCOMPtr<nsIScriptError> scriptError =
|
||||
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
|
||||
MOZ_ASSERT(consoleService);
|
||||
|
||||
if (aInnerWindowID) {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
scriptError->InitWithWindowID(localizedMessage,
|
||||
aFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
aLineNumber,
|
||||
/* aColumnNumber */ 0,
|
||||
nsIScriptError::warningFlag,
|
||||
category,
|
||||
aInnerWindowID)));
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
scriptError->Init(localizedMessage,
|
||||
aFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
aLineNumber,
|
||||
/* aColumnNumber */ 0,
|
||||
nsIScriptError::warningFlag,
|
||||
category.get())));
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(IDBDatabase::LogWarningRunnable, nsRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
IDBDatabase::
|
||||
LogWarningRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
LogWarning(mMessageName.get(),
|
||||
mFilename,
|
||||
mLineNumber,
|
||||
mIsChrome,
|
||||
mInnerWindowID);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(IDBDatabase::Observer, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -52,6 +52,9 @@ class IDBDatabase MOZ_FINAL
|
||||
typedef mozilla::dom::StorageType StorageType;
|
||||
typedef mozilla::dom::quota::PersistenceType PersistenceType;
|
||||
|
||||
class LogWarningRunnable;
|
||||
friend class LogWarningRunnable;
|
||||
|
||||
class Observer;
|
||||
friend class Observer;
|
||||
|
||||
|
@ -33,18 +33,12 @@ CreateGenericEvent(EventTarget* aOwner,
|
||||
Bubbles aBubbles,
|
||||
Cancelable aCancelable)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), aOwner, nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<Event> event = new Event(aOwner, nullptr, nullptr);
|
||||
|
||||
rv = event->InitEvent(aType,
|
||||
aBubbles == eDoesBubble ? true : false,
|
||||
aCancelable == eCancelable ? true : false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
event->InitEvent(aType,
|
||||
aBubbles == eDoesBubble ? true : false,
|
||||
aCancelable == eCancelable ? true : false)));
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
@ -64,10 +58,7 @@ IDBVersionChangeEvent::CreateInternal(EventTarget* aOwner,
|
||||
event->mNewVersion.SetValue(aNewVersion.Value());
|
||||
}
|
||||
|
||||
nsresult rv = event->InitEvent(aType, false, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(event->InitEvent(aType, false, false)));
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
|
@ -18,12 +18,18 @@
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackground.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsAboutProtocolUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIAboutModule.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "ProfilerHelpers.h"
|
||||
#include "ReportInternalError.h"
|
||||
@ -46,33 +52,6 @@ namespace {
|
||||
|
||||
const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
|
||||
|
||||
nsresult
|
||||
GetPrincipalInfoFromPrincipal(nsIPrincipal* aPrincipal,
|
||||
PrincipalInfo* aPrincipalInfo)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aPrincipalInfo);
|
||||
|
||||
bool isNullPrincipal;
|
||||
nsresult rv = aPrincipal->GetIsNullPrincipal(&isNullPrincipal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (isNullPrincipal) {
|
||||
NS_WARNING("IndexedDB not supported from this principal!");
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
rv = PrincipalToPrincipalInfo(aPrincipal, aPrincipalInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class IDBFactory::BackgroundCreateCallback MOZ_FINAL
|
||||
@ -155,44 +134,43 @@ IDBFactory::CreateForWindow(nsPIDOMWindow* aWindow,
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
|
||||
if (NS_WARN_IF(!sop)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(GetPrincipalInfoFromPrincipal(principal,
|
||||
principalInfo)))) {
|
||||
// Not allowed.
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
|
||||
if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) {
|
||||
NS_WARNING("IndexedDB is not permitted in a third-party window.");
|
||||
*aFactory = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
|
||||
if (NS_WARN_IF(!mgr)) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (rv == NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
|
||||
rv = PrincipalToPrincipalInfo(principal, principalInfo);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
|
||||
principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
|
||||
|
||||
bool privateBrowsingMode = loadContext && loadContext->UsePrivateBrowsing();
|
||||
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mPrincipalInfo = Move(principalInfo);
|
||||
factory->mWindow = aWindow;
|
||||
factory->mTabChild = TabChild::GetFrom(aWindow);
|
||||
factory->mInnerWindowID = aWindow->WindowID();
|
||||
factory->mPrivateBrowsingMode = privateBrowsingMode;
|
||||
factory->mPrivateBrowsingMode =
|
||||
loadContext && loadContext->UsePrivateBrowsing();
|
||||
|
||||
factory.forget(aFactory);
|
||||
return NS_OK;
|
||||
@ -211,7 +189,7 @@ IDBFactory::CreateForChromeJS(JSContext* aCx,
|
||||
new PrincipalInfo(SystemPrincipalInfo()));
|
||||
|
||||
nsresult rv =
|
||||
CreateForJSInternal(aCx, aOwningObject, principalInfo, aFactory);
|
||||
CreateForMainThreadJSInternal(aCx, aOwningObject, principalInfo, aFactory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -221,6 +199,7 @@ IDBFactory::CreateForChromeJS(JSContext* aCx,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBFactory::CreateForDatastore(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
@ -235,7 +214,7 @@ IDBFactory::CreateForDatastore(JSContext* aCx,
|
||||
new PrincipalInfo(SystemPrincipalInfo()));
|
||||
|
||||
nsresult rv =
|
||||
CreateForJSInternal(aCx, aOwningObject, principalInfo, aFactory);
|
||||
CreateForMainThreadJSInternal(aCx, aOwningObject, principalInfo, aFactory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@ -247,22 +226,42 @@ IDBFactory::CreateForDatastore(JSContext* aCx,
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBFactory::CreateForJSInternal(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
|
||||
IDBFactory** aFactory)
|
||||
IDBFactory::CreateForWorker(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
uint64_t aInnerWindowID,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aOwningObject);
|
||||
MOZ_ASSERT(aPrincipalInfo);
|
||||
MOZ_ASSERT(aFactory);
|
||||
MOZ_ASSERT(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
|
||||
"Not a global object!");
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_CRASH("Not yet supported off the main thread!");
|
||||
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo(aPrincipalInfo));
|
||||
|
||||
nsresult rv =
|
||||
CreateForJSInternal(aCx,
|
||||
aOwningObject,
|
||||
principalInfo,
|
||||
aInnerWindowID,
|
||||
aFactory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!principalInfo);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBFactory::CreateForMainThreadJSInternal(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
|
||||
*aFactory = nullptr;
|
||||
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
|
||||
@ -274,15 +273,152 @@ IDBFactory::CreateForJSInternal(JSContext* aCx,
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
CreateForJSInternal(aCx,
|
||||
aOwningObject,
|
||||
aPrincipalInfo,
|
||||
/* aInnerWindowID */ 0,
|
||||
aFactory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBFactory::CreateForJSInternal(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
|
||||
uint64_t aInnerWindowID,
|
||||
IDBFactory** aFactory)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aOwningObject);
|
||||
MOZ_ASSERT(aPrincipalInfo);
|
||||
MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
|
||||
MOZ_ASSERT(aFactory);
|
||||
MOZ_ASSERT(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
|
||||
"Not a global object!");
|
||||
|
||||
if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
|
||||
aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
|
||||
NS_WARNING("IndexedDB not allowed for this principal!");
|
||||
*aFactory = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<IDBFactory> factory = new IDBFactory();
|
||||
factory->mPrincipalInfo = aPrincipalInfo.forget();
|
||||
factory->mOwningObject = aOwningObject;
|
||||
mozilla::HoldJSObjects(factory.get());
|
||||
factory->mInnerWindowID = aInnerWindowID;
|
||||
|
||||
factory.forget(aFactory);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IDBFactory::AllowedForWindow(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aWindow->IsInnerWindow());
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IDBFactory::AllowedForWindowInternal(nsPIDOMWindow* aWindow,
|
||||
nsIPrincipal** aPrincipal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aWindow->IsInnerWindow());
|
||||
|
||||
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
nsIDocument* document = aWindow->GetExtantDoc();
|
||||
if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(sop);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
principal.forget(aPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool isNullPrincipal;
|
||||
if (NS_WARN_IF(NS_FAILED(principal->GetIsNullPrincipal(&isNullPrincipal))) ||
|
||||
isNullPrincipal) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
// Whitelist about:home, since it doesn't have a base domain it would not
|
||||
// pass the ThirdPartyUtil check, though it should be able to use indexedDB.
|
||||
bool skipThirdPartyCheck = false;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))));
|
||||
|
||||
bool isAbout;
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)));
|
||||
|
||||
if (isAbout) {
|
||||
nsCOMPtr<nsIAboutModule> module;
|
||||
if (NS_SUCCEEDED(NS_GetAboutModule(uri, getter_AddRefs(module)))) {
|
||||
uint32_t flags;
|
||||
if (NS_SUCCEEDED(module->GetURIFlags(uri, &flags))) {
|
||||
skipThirdPartyCheck = flags & nsIAboutModule::ENABLE_INDEXED_DB;
|
||||
} else {
|
||||
NS_WARNING("GetURIFlags failed!");
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("NS_GetAboutModule failed!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipThirdPartyCheck) {
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
MOZ_ASSERT(thirdPartyUtil);
|
||||
|
||||
bool isThirdParty;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
thirdPartyUtil->IsThirdPartyWindow(aWindow,
|
||||
nullptr,
|
||||
&isThirdParty)))) {
|
||||
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
if (isThirdParty) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
principal.forget(aPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void
|
||||
@ -468,8 +604,15 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
|
||||
}
|
||||
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(GetPrincipalInfoFromPrincipal(aPrincipal,
|
||||
&principalInfo)))) {
|
||||
if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
|
||||
&principalInfo)))) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
|
||||
principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
return nullptr;
|
||||
@ -626,8 +769,6 @@ IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor,
|
||||
{
|
||||
BackgroundFactoryChild* actor = new BackgroundFactoryChild(this);
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Fix this windowId stuff for workers!");
|
||||
|
||||
mBackgroundActor =
|
||||
static_cast<BackgroundFactoryChild*>(
|
||||
aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor,
|
||||
|
@ -35,6 +35,7 @@ class PrincipalInfo;
|
||||
namespace dom {
|
||||
|
||||
struct IDBOpenDBOptions;
|
||||
template <typename> class Optional;
|
||||
class TabChild;
|
||||
|
||||
namespace indexedDB {
|
||||
@ -94,6 +95,16 @@ public:
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
static nsresult
|
||||
CreateForWorker(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
const PrincipalInfo& aPrincipalInfo,
|
||||
uint64_t aInnerWindowID,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
static bool
|
||||
AllowedForWindow(nsPIDOMWindow* aWindow);
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
#ifdef DEBUG
|
||||
@ -197,12 +208,23 @@ private:
|
||||
IDBFactory();
|
||||
~IDBFactory();
|
||||
|
||||
static nsresult
|
||||
CreateForMainThreadJSInternal(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
static nsresult
|
||||
CreateForJSInternal(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aOwningObject,
|
||||
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
|
||||
uint64_t aInnerWindowID,
|
||||
IDBFactory** aFactory);
|
||||
|
||||
static nsresult
|
||||
AllowedForWindowInternal(nsPIDOMWindow* aWindow,
|
||||
nsIPrincipal** aPrincipal);
|
||||
|
||||
already_AddRefed<IDBOpenDBRequest>
|
||||
OpenInternal(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aName,
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "ProfilerHelpers.h"
|
||||
#include "ReportInternalError.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
// Include this last to avoid path problems on Windows.
|
||||
#include "ActorsChild.h"
|
||||
@ -52,6 +54,7 @@ namespace dom {
|
||||
namespace indexedDB {
|
||||
|
||||
using namespace mozilla::dom::quota;
|
||||
using namespace mozilla::dom::workers;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
struct IDBObjectStore::StructuredCloneWriteInfo
|
||||
@ -295,8 +298,6 @@ StructuredCloneWriteCallback(JSContext* aCx,
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This can't work off the main thread!");
|
||||
|
||||
{
|
||||
File* blob = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
|
||||
@ -605,16 +606,23 @@ public:
|
||||
aData.tag == SCTAG_DOM_BLOB);
|
||||
MOZ_ASSERT(aFile.mFile);
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"This wrapping currently only works on the main thread!");
|
||||
|
||||
// It can happen that this IDB is chrome code, so there is no parent, but
|
||||
// still we want to set a correct parent for the new File object.
|
||||
nsCOMPtr<nsISupports> parent;
|
||||
if (aDatabase && aDatabase->GetParentObject()) {
|
||||
parent = aDatabase->GetParentObject();
|
||||
if (NS_IsMainThread()) {
|
||||
if (aDatabase && aDatabase->GetParentObject()) {
|
||||
parent = aDatabase->GetParentObject();
|
||||
} else {
|
||||
parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
}
|
||||
} else {
|
||||
parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(globalScope);
|
||||
|
||||
parent = do_QueryObject(globalScope);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(parent);
|
||||
@ -974,9 +982,6 @@ IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's something to clear, we should be on the main thread.
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer);
|
||||
aReadInfo.mFiles.Clear();
|
||||
}
|
||||
@ -1515,8 +1520,6 @@ IDBObjectStore::GetKeyPath(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!mCachedKeyPath.isUndefined()) {
|
||||
JS::ExposeValueToActiveJS(mCachedKeyPath);
|
||||
aResult.set(mCachedKeyPath);
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include "IDBIndex.h"
|
||||
#include "IDBObjectStore.h"
|
||||
#include "IDBTransaction.h"
|
||||
#include "IndexedDatabaseManager.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/ErrorEventBinding.h"
|
||||
#include "mozilla/dom/IDBOpenDBRequestBinding.h"
|
||||
@ -28,6 +30,8 @@
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsString.h"
|
||||
#include "ReportInternalError.h"
|
||||
#include "WorkerFeature.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
// Include this last to avoid path problems on Windows.
|
||||
#include "ActorsChild.h"
|
||||
@ -36,6 +40,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
||||
using namespace mozilla::dom::workers;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
IDBRequest::IDBRequest(IDBDatabase* aDatabase)
|
||||
@ -223,9 +228,7 @@ IDBRequest::DispatchNonTransactionError(nsresult aErrorCode)
|
||||
nsDependentString(kErrorEventType),
|
||||
eDoesBubble,
|
||||
eCancelable);
|
||||
if (NS_WARN_IF(!event)) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(event);
|
||||
|
||||
bool ignored;
|
||||
if (NS_FAILED(DispatchEvent(event, &ignored))) {
|
||||
@ -259,6 +262,15 @@ IDBRequest::GetErrorCode() const
|
||||
return mErrorCode;
|
||||
}
|
||||
|
||||
DOMError*
|
||||
IDBRequest::GetErrorAfterResult() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mHaveResultOrErrorCode);
|
||||
|
||||
return mError;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
@ -419,6 +431,36 @@ IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class IDBOpenDBRequest::WorkerFeature MOZ_FINAL
|
||||
: public mozilla::dom::workers::WorkerFeature
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
public:
|
||||
explicit
|
||||
WorkerFeature(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
MOZ_COUNT_CTOR(IDBOpenDBRequest::WorkerFeature);
|
||||
}
|
||||
|
||||
~WorkerFeature()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
MOZ_COUNT_DTOR(IDBOpenDBRequest::WorkerFeature);
|
||||
|
||||
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool
|
||||
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
IDBOpenDBRequest::IDBOpenDBRequest(IDBFactory* aFactory, nsPIDOMWindow* aOwner)
|
||||
: IDBRequest(aOwner)
|
||||
, mFactory(aFactory)
|
||||
@ -467,6 +509,23 @@ IDBOpenDBRequest::CreateForJS(IDBFactory* aFactory,
|
||||
|
||||
request->SetScriptOwner(aScriptOwner);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
JSContext* cx = workerPrivate->GetJSContext();
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
nsAutoPtr<WorkerFeature> feature(new WorkerFeature(workerPrivate));
|
||||
if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
request->mWorkerFeature = Move(feature);
|
||||
}
|
||||
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
@ -480,6 +539,17 @@ IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
|
||||
mTransaction = aTransaction;
|
||||
}
|
||||
|
||||
void
|
||||
IDBOpenDBRequest::NoteComplete()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerFeature);
|
||||
|
||||
// If we have a WorkerFeature installed on the worker then nulling this out
|
||||
// will uninstall it from the worker.
|
||||
mWorkerFeature = nullptr;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
|
||||
@ -501,10 +571,13 @@ NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
|
||||
nsresult
|
||||
IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
// XXX Fix me!
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv =
|
||||
IndexedDatabaseManager::CommonPostHandleEvent(this, mFactory, aVisitor);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -515,6 +588,20 @@ IDBOpenDBRequest::WrapObject(JSContext* aCx)
|
||||
return IDBOpenDBRequestBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
bool
|
||||
IDBOpenDBRequest::
|
||||
WorkerFeature::Notify(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aStatus > Running);
|
||||
|
||||
// There's nothing we can really do here at the moment...
|
||||
NS_WARNING("Worker closing but IndexedDB is waiting to open a database!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace indexedDB
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -114,6 +114,16 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
DOMError*
|
||||
GetErrorAfterResult() const
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
{
|
||||
return mError;
|
||||
}
|
||||
#endif
|
||||
|
||||
DOMError*
|
||||
GetError(ErrorResult& aRv);
|
||||
|
||||
@ -212,9 +222,13 @@ protected:
|
||||
class IDBOpenDBRequest MOZ_FINAL
|
||||
: public IDBRequest
|
||||
{
|
||||
class WorkerFeature;
|
||||
|
||||
// Only touched on the owning thread.
|
||||
nsRefPtr<IDBFactory> mFactory;
|
||||
|
||||
nsAutoPtr<WorkerFeature> mWorkerFeature;
|
||||
|
||||
public:
|
||||
static already_AddRefed<IDBOpenDBRequest>
|
||||
CreateForWindow(IDBFactory* aFactory,
|
||||
@ -228,16 +242,13 @@ public:
|
||||
void
|
||||
SetTransaction(IDBTransaction* aTransaction);
|
||||
|
||||
void
|
||||
NoteComplete();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult
|
||||
PostHandleEvent(EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
|
||||
DOMError*
|
||||
GetError(ErrorResult& aRv)
|
||||
{
|
||||
return IDBRequest::GetError(aRv);
|
||||
}
|
||||
|
||||
IDBFactory*
|
||||
Factory() const
|
||||
{
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "ProfilerHelpers.h"
|
||||
#include "ReportInternalError.h"
|
||||
#include "WorkerFeature.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
// Include this last to avoid path problems on Windows.
|
||||
#include "ActorsChild.h"
|
||||
@ -32,14 +34,75 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
||||
using namespace mozilla::dom::workers;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace {
|
||||
|
||||
NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
||||
bool
|
||||
RunBeforeNextEvent(IDBTransaction* aTransaction)
|
||||
{
|
||||
MOZ_ASSERT(aTransaction);
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||
MOZ_ASSERT(appShell);
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(appShell->RunBeforeNextEvent(aTransaction)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
if (NS_WARN_IF(!workerPrivate->RunBeforeNextEvent(aTransaction))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class IDBTransaction::WorkerFeature MOZ_FINAL
|
||||
: public mozilla::dom::workers::WorkerFeature
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
// The IDBTransaction owns this object so we only need a weak reference back
|
||||
// to it.
|
||||
IDBTransaction* mTransaction;
|
||||
|
||||
public:
|
||||
WorkerFeature(WorkerPrivate* aWorkerPrivate, IDBTransaction* aTransaction)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
, mTransaction(aTransaction)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aTransaction);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
aTransaction->AssertIsOnOwningThread();
|
||||
|
||||
MOZ_COUNT_CTOR(IDBTransaction::WorkerFeature);
|
||||
}
|
||||
|
||||
~WorkerFeature()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
MOZ_COUNT_DTOR(IDBTransaction::WorkerFeature);
|
||||
|
||||
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool
|
||||
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
|
||||
const nsTArray<nsString>& aObjectStoreNames,
|
||||
Mode aMode)
|
||||
@ -55,6 +118,7 @@ IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
|
||||
, mReadyState(IDBTransaction::INITIAL)
|
||||
, mMode(aMode)
|
||||
, mCreating(false)
|
||||
, mRegistered(false)
|
||||
, mAbortedByScript(false)
|
||||
#ifdef DEBUG
|
||||
, mSentCommitOrAbort(false)
|
||||
@ -110,11 +174,16 @@ IDBTransaction::~IDBTransaction()
|
||||
mBackgroundActor.mNormalBackgroundActor,
|
||||
mFiredCompleteOrAbort);
|
||||
|
||||
mDatabase->UnregisterTransaction(this);
|
||||
if (mRegistered) {
|
||||
mDatabase->UnregisterTransaction(this);
|
||||
#ifdef DEBUG
|
||||
mRegistered = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mMode == VERSION_CHANGE) {
|
||||
if (auto* actor = mBackgroundActor.mVersionChangeBackgroundActor) {
|
||||
actor->SendDeleteMeInternal();
|
||||
actor->SendDeleteMeInternal(/* aFailedConstructor */ false);
|
||||
|
||||
MOZ_ASSERT(!mBackgroundActor.mVersionChangeBackgroundActor,
|
||||
"SendDeleteMeInternal should have cleared!");
|
||||
@ -151,22 +220,24 @@ IDBTransaction::CreateVersionChange(
|
||||
&transaction->mLineNo);
|
||||
|
||||
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
|
||||
transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
|
||||
transaction->mNextObjectStoreId = aNextObjectStoreId;
|
||||
transaction->mNextIndexId = aNextIndexId;
|
||||
|
||||
// XXX Fix!
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
|
||||
|
||||
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||
if (NS_WARN_IF(!appShell) ||
|
||||
NS_WARN_IF(NS_FAILED(appShell->RunBeforeNextEvent(transaction)))) {
|
||||
if (NS_WARN_IF(!RunBeforeNextEvent(transaction))) {
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
#ifdef DEBUG
|
||||
// Silence assertions.
|
||||
transaction->mSentCommitOrAbort = true;
|
||||
#endif
|
||||
aActor->SendDeleteMeInternal(/* aFailedConstructor */ true);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
transaction->mBackgroundActor.mVersionChangeBackgroundActor = aActor;
|
||||
transaction->mNextObjectStoreId = aNextObjectStoreId;
|
||||
transaction->mNextIndexId = aNextIndexId;
|
||||
transaction->mCreating = true;
|
||||
|
||||
aDatabase->RegisterTransaction(transaction);
|
||||
transaction->mRegistered = true;
|
||||
|
||||
return transaction.forget();
|
||||
}
|
||||
@ -188,18 +259,28 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
|
||||
|
||||
transaction->SetScriptOwner(aDatabase->GetScriptOwner());
|
||||
|
||||
// XXX Fix!
|
||||
MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
|
||||
|
||||
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||
if (NS_WARN_IF(!appShell) ||
|
||||
NS_WARN_IF(NS_FAILED(appShell->RunBeforeNextEvent(transaction)))) {
|
||||
if (NS_WARN_IF(!RunBeforeNextEvent(transaction))) {
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
transaction->mCreating = true;
|
||||
|
||||
aDatabase->RegisterTransaction(transaction);
|
||||
transaction->mRegistered = true;
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
JSContext* cx = workerPrivate->GetJSContext();
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
transaction->mWorkerFeature = new WorkerFeature(workerPrivate, transaction);
|
||||
MOZ_ALWAYS_TRUE(workerPrivate->AddFeature(cx, transaction->mWorkerFeature));
|
||||
}
|
||||
|
||||
return transaction.forget();
|
||||
}
|
||||
@ -679,12 +760,16 @@ IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult)
|
||||
mFiredCompleteOrAbort = true;
|
||||
#endif
|
||||
|
||||
// Make sure we drop the WorkerFeature when this function completes.
|
||||
nsAutoPtr<WorkerFeature> workerFeature = Move(mWorkerFeature);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
event = CreateGenericEvent(this,
|
||||
nsDependentString(kCompleteEventType),
|
||||
eDoesNotBubble,
|
||||
eNotCancelable);
|
||||
MOZ_ASSERT(event);
|
||||
} else {
|
||||
if (!mError && !mAbortedByScript) {
|
||||
mError = new DOMError(GetOwner(), aResult);
|
||||
@ -694,10 +779,7 @@ IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult)
|
||||
nsDependentString(kAbortEventType),
|
||||
eDoesBubble,
|
||||
eNotCancelable);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!event)) {
|
||||
return;
|
||||
MOZ_ASSERT(event);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(mAbortCode)) {
|
||||
@ -910,6 +992,27 @@ IDBTransaction::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
IDBTransaction::
|
||||
WorkerFeature::Notify(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aStatus > Running);
|
||||
|
||||
if (mTransaction && aStatus > Terminating) {
|
||||
mTransaction->AssertIsOnOwningThread();
|
||||
|
||||
nsRefPtr<IDBTransaction> transaction = mTransaction;
|
||||
mTransaction = nullptr;
|
||||
|
||||
IDB_REPORT_INTERNAL_ERR();
|
||||
transaction->AbortInternal(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace indexedDB
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -49,6 +49,9 @@ class IDBTransaction MOZ_FINAL
|
||||
: public IDBWrapperCache
|
||||
, public nsIRunnable
|
||||
{
|
||||
class WorkerFeature;
|
||||
friend class WorkerFeature;
|
||||
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
@ -74,6 +77,7 @@ private:
|
||||
nsTArray<nsString> mObjectStoreNames;
|
||||
nsTArray<nsRefPtr<IDBObjectStore>> mObjectStores;
|
||||
nsTArray<nsRefPtr<IDBObjectStore>> mDeletedObjectStores;
|
||||
nsAutoPtr<WorkerFeature> mWorkerFeature;
|
||||
|
||||
// Tagged with mMode. If mMode is VERSION_CHANGE then mBackgroundActor will be
|
||||
// a BackgroundVersionChangeTransactionChild. Otherwise it will be a
|
||||
@ -99,6 +103,7 @@ private:
|
||||
Mode mMode;
|
||||
|
||||
bool mCreating;
|
||||
bool mRegistered;
|
||||
bool mAbortedByScript;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -16,21 +16,22 @@
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "mozilla/dom/ErrorEventBinding.h"
|
||||
#include "mozilla/dom/PBlobChild.h"
|
||||
#include "mozilla/dom/quota/OriginOrPatternString.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/dom/quota/Utilities.h"
|
||||
#include "mozilla/dom/TabContext.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prlog.h"
|
||||
|
||||
@ -39,6 +40,8 @@
|
||||
#include "IDBKeyRange.h"
|
||||
#include "IDBRequest.h"
|
||||
#include "ProfilerHelpers.h"
|
||||
#include "WorkerScope.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
// Bindings for ResolveConstructors
|
||||
#include "mozilla/dom/IDBCursorBinding.h"
|
||||
@ -65,6 +68,7 @@ namespace dom {
|
||||
namespace indexedDB {
|
||||
|
||||
using namespace mozilla::dom::quota;
|
||||
using namespace mozilla::dom::workers;
|
||||
|
||||
class FileManagerInfo
|
||||
{
|
||||
@ -116,6 +120,7 @@ namespace {
|
||||
#define IDB_PREF_BRANCH_ROOT "dom.indexedDB."
|
||||
|
||||
const char kTestingPref[] = IDB_PREF_BRANCH_ROOT "testing";
|
||||
const char kPrefExperimental[] = IDB_PREF_BRANCH_ROOT "experimental";
|
||||
|
||||
#define IDB_PREF_LOGGING_BRANCH_ROOT IDB_PREF_BRANCH_ROOT "logging."
|
||||
|
||||
@ -130,11 +135,12 @@ const char kPrefLoggingProfiler[] =
|
||||
#undef IDB_PREF_LOGGING_BRANCH_ROOT
|
||||
#undef IDB_PREF_BRANCH_ROOT
|
||||
|
||||
mozilla::StaticRefPtr<IndexedDatabaseManager> gDBManager;
|
||||
StaticRefPtr<IndexedDatabaseManager> gDBManager;
|
||||
|
||||
mozilla::Atomic<bool> gInitialized(false);
|
||||
mozilla::Atomic<bool> gClosed(false);
|
||||
mozilla::Atomic<bool> gTestingMode(false);
|
||||
Atomic<bool> gInitialized(false);
|
||||
Atomic<bool> gClosed(false);
|
||||
Atomic<bool> gTestingMode(false);
|
||||
Atomic<bool> gExperimentalFeaturesEnabled(false);
|
||||
|
||||
class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
|
||||
{
|
||||
@ -198,13 +204,12 @@ private:
|
||||
};
|
||||
|
||||
void
|
||||
TestingPrefChangedCallback(const char* aPrefName, void* aClosure)
|
||||
AtomicBoolPrefChangedCallback(const char* aPrefName, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!strcmp(aPrefName, kTestingPref));
|
||||
MOZ_ASSERT(!aClosure);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
gTestingMode = Preferences::GetBool(aPrefName);
|
||||
*static_cast<Atomic<bool>*>(aClosure) = Preferences::GetBool(aPrefName);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@ -297,18 +302,9 @@ IndexedDatabaseManager::Init()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
// Make sure that the quota manager is up.
|
||||
QuotaManager* qm = QuotaManager::GetOrCreate();
|
||||
NS_ENSURE_STATE(qm);
|
||||
|
||||
// During Init() we can't yet call IsMainProcess(), just check sIsMainProcess
|
||||
// directly.
|
||||
if (sIsMainProcess) {
|
||||
// Must initialize the storage service on the main thread.
|
||||
nsCOMPtr<mozIStorageService> ss =
|
||||
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_STATE(ss);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
NS_ENSURE_STATE(obs);
|
||||
|
||||
@ -317,8 +313,12 @@ IndexedDatabaseManager::Init()
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
Preferences::RegisterCallbackAndCall(TestingPrefChangedCallback,
|
||||
kTestingPref);
|
||||
Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
|
||||
kTestingPref,
|
||||
&gTestingMode);
|
||||
Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
|
||||
kPrefExperimental,
|
||||
&gExperimentalFeaturesEnabled);
|
||||
|
||||
// By default IndexedDB uses SQLite with PRAGMA synchronous = NORMAL. This
|
||||
// guarantees (unlike synchronous = OFF) atomicity and consistency, but not
|
||||
@ -349,7 +349,12 @@ IndexedDatabaseManager::Destroy()
|
||||
NS_ERROR("Shutdown more than once?!");
|
||||
}
|
||||
|
||||
Preferences::UnregisterCallback(TestingPrefChangedCallback, kTestingPref);
|
||||
Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
|
||||
kTestingPref,
|
||||
&gTestingMode);
|
||||
Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
|
||||
kPrefExperimental,
|
||||
&gExperimentalFeaturesEnabled);
|
||||
|
||||
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
|
||||
kPrefLoggingDetails);
|
||||
@ -365,13 +370,14 @@ IndexedDatabaseManager::Destroy()
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
|
||||
EventChainPostVisitor& aVisitor)
|
||||
IndexedDatabaseManager::CommonPostHandleEvent(
|
||||
DOMEventTargetHelper* aEventTarget,
|
||||
IDBFactory* aFactory,
|
||||
EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
NS_ENSURE_TRUE(aVisitor.mDOMEvent, NS_ERROR_UNEXPECTED);
|
||||
if (!aOwner) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(aEventTarget);
|
||||
MOZ_ASSERT(aFactory);
|
||||
MOZ_ASSERT(aVisitor.mDOMEvent);
|
||||
|
||||
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
return NS_OK;
|
||||
@ -379,23 +385,25 @@ IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
|
||||
|
||||
nsString type;
|
||||
nsresult rv = aVisitor.mDOMEvent->GetType(type);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (nsDependentString(kErrorEventType) != type) {
|
||||
NS_NAMED_LITERAL_STRING(errorType, "error");
|
||||
|
||||
MOZ_ASSERT(nsDependentString(kErrorEventType) == errorType);
|
||||
|
||||
if (type != errorType) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<EventTarget> eventTarget =
|
||||
aVisitor.mDOMEvent->InternalDOMEvent()->GetTarget();
|
||||
MOZ_ASSERT(eventTarget);
|
||||
|
||||
IDBRequest* request = static_cast<IDBRequest*>(eventTarget.get());
|
||||
NS_ENSURE_TRUE(request, NS_ERROR_UNEXPECTED);
|
||||
auto* request = static_cast<IDBRequest*>(eventTarget.get());
|
||||
|
||||
ErrorResult ret;
|
||||
nsRefPtr<DOMError> error = request->GetError(ret);
|
||||
if (ret.Failed()) {
|
||||
return ret.ErrorCode();
|
||||
}
|
||||
nsRefPtr<DOMError> error = request->GetErrorAfterResult();
|
||||
|
||||
nsString errorName;
|
||||
if (error) {
|
||||
@ -410,40 +418,91 @@ IndexedDatabaseManager::FireWindowOnError(nsPIDOMWindow* aOwner,
|
||||
init.mCancelable = true;
|
||||
init.mBubbles = true;
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aOwner));
|
||||
NS_ASSERTION(sgo, "How can this happen?!");
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
if (NS_FAILED(sgo->HandleScriptError(init, &status))) {
|
||||
NS_WARNING("Failed to dispatch script error event");
|
||||
status = nsEventStatus_eIgnore;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
if (nsPIDOMWindow* window = aEventTarget->GetOwner()) {
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(window);
|
||||
MOZ_ASSERT(sgo);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(sgo->HandleScriptError(init, &status)))) {
|
||||
status = nsEventStatus_eIgnore;
|
||||
}
|
||||
} else {
|
||||
// We don't fire error events at any global for non-window JS on the main
|
||||
// thread.
|
||||
}
|
||||
} else {
|
||||
// Not on the main thread, must be in a worker.
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsRefPtr<WorkerGlobalScope> globalScope = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(globalScope);
|
||||
|
||||
nsRefPtr<ErrorEvent> errorEvent =
|
||||
ErrorEvent::Constructor(globalScope, errorType, init);
|
||||
MOZ_ASSERT(errorEvent);
|
||||
|
||||
errorEvent->SetTrusted(true);
|
||||
|
||||
auto* target = static_cast<EventTarget*>(globalScope.get());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
EventDispatcher::DispatchDOMEvent(target,
|
||||
/* aWidgetEvent */ nullptr,
|
||||
errorEvent,
|
||||
/* aPresContext */ nullptr,
|
||||
&status)))) {
|
||||
status = nsEventStatus_eIgnore;
|
||||
}
|
||||
}
|
||||
|
||||
bool preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
|
||||
if (preventDefaultCalled) {
|
||||
if (status == nsEventStatus_eConsumeNoDefault) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Log an error to the error console.
|
||||
nsCOMPtr<nsIScriptError> scriptError =
|
||||
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoCString category;
|
||||
if (aFactory->IsChrome()) {
|
||||
category.AssignLiteral("chrome ");
|
||||
} else {
|
||||
category.AssignLiteral("content ");
|
||||
}
|
||||
category.AppendLiteral("javascript");
|
||||
|
||||
if (NS_FAILED(scriptError->InitWithWindowID(errorName,
|
||||
init.mFilename,
|
||||
EmptyString(), init.mLineno,
|
||||
0, 0,
|
||||
"IndexedDB",
|
||||
aOwner->WindowID()))) {
|
||||
NS_WARNING("Failed to init script error!");
|
||||
return NS_ERROR_FAILURE;
|
||||
// Log the error to the error console.
|
||||
nsCOMPtr<nsIConsoleService> consoleService =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(consoleService);
|
||||
|
||||
nsCOMPtr<nsIScriptError> scriptError =
|
||||
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
|
||||
MOZ_ASSERT(consoleService);
|
||||
|
||||
if (uint64_t innerWindowID = aFactory->InnerWindowID()) {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
scriptError->InitWithWindowID(errorName,
|
||||
init.mFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
init.mLineno,
|
||||
/* aColumnNumber */ 0,
|
||||
nsIScriptError::errorFlag,
|
||||
category,
|
||||
innerWindowID)));
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
scriptError->Init(errorName,
|
||||
init.mFilename,
|
||||
/* aSourceLine */ EmptyString(),
|
||||
init.mLineno,
|
||||
/* aColumnNumber */ 0,
|
||||
nsIScriptError::errorFlag,
|
||||
category.get())));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIConsoleService> consoleService =
|
||||
do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(consoleService->LogMessage(scriptError)));
|
||||
|
||||
return consoleService->LogMessage(scriptError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -475,6 +534,12 @@ IndexedDatabaseManager::DefineIndexedDB(JSContext* aCx,
|
||||
MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
|
||||
"Passed object is not a global object!");
|
||||
|
||||
// We need to ensure that the manager has been created already here so that we
|
||||
// load preferences that may control which properties are exposed.
|
||||
if (NS_WARN_IF(!GetOrCreate())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IDBCursorBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!IDBCursorWithValueBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!IDBDatabaseBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
@ -582,6 +647,24 @@ IndexedDatabaseManager::FullSynchronous()
|
||||
return sFullSynchronousMode;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IndexedDatabaseManager::ExperimentalFeaturesEnabled(JSContext* aCx,
|
||||
JSObject* aGlobal)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
if (NS_WARN_IF(!GetOrCreate())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(Get(),
|
||||
"ExperimentalFeaturesEnabled() called off the main thread "
|
||||
"before indexedDB has been initialized!");
|
||||
}
|
||||
|
||||
return gExperimentalFeaturesEnabled;
|
||||
}
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
IndexedDatabaseManager::GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
|
@ -21,6 +21,7 @@ struct PRLogModuleInfo;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class DOMEventTargetHelper;
|
||||
class EventChainPostVisitor;
|
||||
|
||||
namespace dom {
|
||||
@ -31,6 +32,7 @@ namespace indexedDB {
|
||||
|
||||
class FileManager;
|
||||
class FileManagerInfo;
|
||||
class IDBFactory;
|
||||
|
||||
class IndexedDatabaseManager MOZ_FINAL : public nsIObserver
|
||||
{
|
||||
@ -106,6 +108,9 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
ExperimentalFeaturesEnabled(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
already_AddRefed<FileManager>
|
||||
GetFileManager(PersistenceType aPersistenceType,
|
||||
const nsACString& aOrigin,
|
||||
@ -153,8 +158,9 @@ public:
|
||||
}
|
||||
|
||||
static nsresult
|
||||
FireWindowOnError(nsPIDOMWindow* aOwner,
|
||||
EventChainPostVisitor& aVisitor);
|
||||
CommonPostHandleEvent(DOMEventTargetHelper* aEventTarget,
|
||||
IDBFactory* aFactory,
|
||||
EventChainPostVisitor& aVisitor);
|
||||
|
||||
static bool
|
||||
TabContextMayAccessOrigin(const mozilla::dom::TabContext& aContext,
|
||||
|
@ -94,6 +94,7 @@ LOCAL_INCLUDES += [
|
||||
'/db/sqlite3/src',
|
||||
'/dom/base',
|
||||
'/dom/storage',
|
||||
'/dom/workers',
|
||||
'/ipc/glue',
|
||||
'/xpcom/build',
|
||||
]
|
||||
|
@ -44,39 +44,167 @@ function clearAllDatabases(callback) {
|
||||
SpecialPowers.clearStorageForURI(document.documentURI, callback, appId, inBrowser);
|
||||
}
|
||||
|
||||
let testHarnessGenerator = testHarnessSteps();
|
||||
testHarnessGenerator.next();
|
||||
|
||||
function testHarnessSteps() {
|
||||
function nextTestHarnessStep(val) {
|
||||
testHarnessGenerator.send(val);
|
||||
}
|
||||
|
||||
let testScriptPath;
|
||||
let testScriptFilename;
|
||||
|
||||
let scripts = document.getElementsByTagName("script");
|
||||
for (let i = 0; i < scripts.length; i++) {
|
||||
let src = scripts[i].src;
|
||||
let match = src.match(/indexedDB\/test\/unit\/(test_[^\/]+\.js)$/);
|
||||
if (match && match.length == 2) {
|
||||
testScriptPath = src;
|
||||
testScriptFilename = match[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let limitedQuota = yield undefined;
|
||||
|
||||
info("Running" +
|
||||
(testScriptFilename ? " '" + testScriptFilename + "'" : "") +
|
||||
" with " +
|
||||
(limitedQuota ? "" : "un") + "limited quota");
|
||||
|
||||
info("Pushing preferences");
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{
|
||||
"set": [
|
||||
["dom.indexedDB.testing", true],
|
||||
["dom.indexedDB.experimental", true],
|
||||
["dom.archivereader.enabled", true],
|
||||
["dom.workers.latestJSVersion", true]
|
||||
]
|
||||
},
|
||||
nextTestHarnessStep
|
||||
);
|
||||
yield undefined;
|
||||
|
||||
info("Pushing permissions");
|
||||
|
||||
SpecialPowers.pushPermissions(
|
||||
[
|
||||
{
|
||||
type: "indexedDB",
|
||||
allow: true,
|
||||
context: document
|
||||
}, {
|
||||
type: "indexedDB-unlimited",
|
||||
allow: !limitedQuota,
|
||||
context: document
|
||||
}
|
||||
],
|
||||
nextTestHarnessStep
|
||||
);
|
||||
yield undefined;
|
||||
|
||||
info("Clearing old databases");
|
||||
|
||||
clearAllDatabases(nextTestHarnessStep);
|
||||
yield undefined;
|
||||
|
||||
if (testScriptFilename && !window.disableWorkerTest) {
|
||||
info("Running test in a worker");
|
||||
|
||||
let workerScriptBlob =
|
||||
new Blob([ "(" + workerScript.toString() + ")();" ],
|
||||
{ type: "text/javascript;version=1.7" });
|
||||
let workerScriptURL = URL.createObjectURL(workerScriptBlob);
|
||||
|
||||
let worker = new Worker(workerScriptURL);
|
||||
|
||||
worker.onerror = function(event) {
|
||||
ok(false, "Worker had an error: " + event.message);
|
||||
worker.terminate();
|
||||
nextTestHarnessStep();
|
||||
};
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
let message = event.data;
|
||||
switch (message.op) {
|
||||
case "ok":
|
||||
ok(message.condition, message.name, message.diag);
|
||||
break;
|
||||
|
||||
case "todo":
|
||||
todo(message.condition, message.name, message.diag);
|
||||
break;
|
||||
|
||||
case "info":
|
||||
info(message.msg);
|
||||
break;
|
||||
|
||||
case "ready":
|
||||
worker.postMessage({ op: "load", files: [ testScriptPath ] });
|
||||
break;
|
||||
|
||||
case "loaded":
|
||||
worker.postMessage({ op: "start" });
|
||||
break;
|
||||
|
||||
case "done":
|
||||
ok(true, "Worker finished");
|
||||
nextTestHarnessStep();
|
||||
break;
|
||||
|
||||
default:
|
||||
ok(false,
|
||||
"Received a bad message from worker: " + JSON.stringify(message));
|
||||
nextTestHarnessStep();
|
||||
}
|
||||
};
|
||||
|
||||
URL.revokeObjectURL(workerScriptURL);
|
||||
|
||||
yield undefined;
|
||||
|
||||
worker.terminate();
|
||||
worker = null;
|
||||
|
||||
clearAllDatabases(nextTestHarnessStep);
|
||||
yield undefined;
|
||||
} else if (testScriptFilename) {
|
||||
todo(false,
|
||||
"Skipping test in a worker because it is explicitly disabled: " +
|
||||
disableWorkerTest);
|
||||
} else {
|
||||
todo(false,
|
||||
"Skipping test in a worker because it's not structured properly");
|
||||
}
|
||||
|
||||
info("Running test in main thread");
|
||||
|
||||
// Now run the test script in the main thread.
|
||||
testGenerator.next();
|
||||
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
if (!window.runTest) {
|
||||
window.runTest = function(limitedQuota)
|
||||
{
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
allowIndexedDB();
|
||||
if (limitedQuota) {
|
||||
denyUnlimitedQuota();
|
||||
}
|
||||
else {
|
||||
allowUnlimitedQuota();
|
||||
}
|
||||
|
||||
enableTesting();
|
||||
enableExperimental();
|
||||
enableArchiveReader();
|
||||
|
||||
clearAllDatabases(function () { testGenerator.next(); });
|
||||
testHarnessGenerator.send(limitedQuota);
|
||||
}
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
resetArchiveReader();
|
||||
resetExperimental();
|
||||
resetTesting();
|
||||
resetUnlimitedQuota();
|
||||
resetIndexedDB();
|
||||
SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher",
|
||||
SpecialPowers.notifyObserversInParentProcess(null,
|
||||
"disk-space-watcher",
|
||||
"free");
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
testGenerator.close();
|
||||
testHarnessGenerator.close();
|
||||
clearAllDatabases(function() { SimpleTest.finish(); });
|
||||
});
|
||||
}
|
||||
@ -154,26 +282,26 @@ ExpectError.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function compareKeys(k1, k2) {
|
||||
let t = typeof k1;
|
||||
if (t != typeof k2)
|
||||
function compareKeys(_k1_, _k2_) {
|
||||
let t = typeof _k1_;
|
||||
if (t != typeof _k2_)
|
||||
return false;
|
||||
|
||||
if (t !== "object")
|
||||
return k1 === k2;
|
||||
return _k1_ === _k2_;
|
||||
|
||||
if (k1 instanceof Date) {
|
||||
return (k2 instanceof Date) &&
|
||||
k1.getTime() === k2.getTime();
|
||||
if (_k1_ instanceof Date) {
|
||||
return (_k2_ instanceof Date) &&
|
||||
_k1_.getTime() === _k2_.getTime();
|
||||
}
|
||||
|
||||
if (k1 instanceof Array) {
|
||||
if (!(k2 instanceof Array) ||
|
||||
k1.length != k2.length)
|
||||
if (_k1_ instanceof Array) {
|
||||
if (!(_k2_ instanceof Array) ||
|
||||
_k1_.length != _k2_.length)
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < k1.length; ++i) {
|
||||
if (!compareKeys(k1[i], k2[i]))
|
||||
for (let i = 0; i < _k1_.length; ++i) {
|
||||
if (!compareKeys(_k1_[i], _k2_[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -183,14 +311,6 @@ function compareKeys(k1, k2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function addPermission(type, allow, url)
|
||||
{
|
||||
if (!url) {
|
||||
url = window.document;
|
||||
}
|
||||
SpecialPowers.addPermission(type, allow, url);
|
||||
}
|
||||
|
||||
function removePermission(type, url)
|
||||
{
|
||||
if (!url) {
|
||||
@ -199,62 +319,6 @@ function removePermission(type, url)
|
||||
SpecialPowers.removePermission(type, url);
|
||||
}
|
||||
|
||||
function allowIndexedDB(url)
|
||||
{
|
||||
addPermission("indexedDB", true, url);
|
||||
}
|
||||
|
||||
function resetIndexedDB(url)
|
||||
{
|
||||
removePermission("indexedDB", url);
|
||||
}
|
||||
|
||||
function allowUnlimitedQuota(url)
|
||||
{
|
||||
addPermission("indexedDB-unlimited", true, url);
|
||||
}
|
||||
|
||||
function denyUnlimitedQuota(url)
|
||||
{
|
||||
addPermission("indexedDB-unlimited", false, url);
|
||||
}
|
||||
|
||||
function resetUnlimitedQuota(url)
|
||||
{
|
||||
removePermission("indexedDB-unlimited", url);
|
||||
}
|
||||
|
||||
function enableArchiveReader()
|
||||
{
|
||||
archiveReaderEnabled = SpecialPowers.getBoolPref("dom.archivereader.enabled");
|
||||
SpecialPowers.setBoolPref("dom.archivereader.enabled", true);
|
||||
}
|
||||
|
||||
function resetArchiveReader()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.archivereader.enabled", archiveReaderEnabled);
|
||||
}
|
||||
|
||||
function enableExperimental()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
|
||||
}
|
||||
|
||||
function resetExperimental()
|
||||
{
|
||||
SpecialPowers.clearUserPref("dom.indexedDB.experimental");
|
||||
}
|
||||
|
||||
function enableTesting()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.indexedDB.testing", true);
|
||||
}
|
||||
|
||||
function resetTesting()
|
||||
{
|
||||
SpecialPowers.clearUserPref("dom.indexedDB.testing");
|
||||
}
|
||||
|
||||
function gc()
|
||||
{
|
||||
SpecialPowers.forceGC();
|
||||
@ -265,3 +329,188 @@ function scheduleGC()
|
||||
{
|
||||
SpecialPowers.exactGC(window, continueToNextStep);
|
||||
}
|
||||
|
||||
function workerScript() {
|
||||
"use strict";
|
||||
|
||||
self.repr = function(_thing_) {
|
||||
if (typeof(_thing_) == "undefined") {
|
||||
return "undefined";
|
||||
}
|
||||
|
||||
if (o === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
let str;
|
||||
|
||||
try {
|
||||
str = _thing_ + "";
|
||||
} catch (e) {
|
||||
return "[" + typeof(_thing_) + "]";
|
||||
}
|
||||
|
||||
if (typeof(_thing_) == "function") {
|
||||
str = str.replace(/^\s+/, "");
|
||||
let idx = str.indexOf("{");
|
||||
if (idx != -1) {
|
||||
str = str.substr(0, idx) + "{...}";
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
self.ok = function(_condition_, _name_, _diag_) {
|
||||
self.postMessage({ op: "ok",
|
||||
condition: !!_condition_,
|
||||
name: _name_,
|
||||
diag: _diag_ });
|
||||
};
|
||||
|
||||
self.is = function(_a_, _b_, _name_) {
|
||||
let pass = (_a_ == _b_);
|
||||
let diag = pass ? "" : "got " + repr(_a_) + ", expected " + repr(_b_);
|
||||
ok(pass, _name_, diag);
|
||||
};
|
||||
|
||||
self.isnot = function(_a_, _b_, _name_) {
|
||||
let pass = (_a_ != _b_);
|
||||
let diag = pass ? "" : "didn't expect " + repr(_a_) + ", but got it";
|
||||
ok(pass, _name_, diag);
|
||||
};
|
||||
|
||||
self.todo = function(_condition_, _name_, _diag_) {
|
||||
self.postMessage({ op: "todo",
|
||||
condition: !!_condition_,
|
||||
name: _name_,
|
||||
diag: _diag_ });
|
||||
};
|
||||
|
||||
self.info = function(_msg_) {
|
||||
self.postMessage({ op: "info", msg: _msg_ });
|
||||
};
|
||||
|
||||
self.executeSoon = function(_fun_) {
|
||||
setTimeout(_fun_, 0);
|
||||
};
|
||||
|
||||
self.finishTest = function() {
|
||||
self.postMessage({ op: "done" });
|
||||
};
|
||||
|
||||
self.grabEventAndContinueHandler = function(_event_) {
|
||||
testGenerator.send(_event_);
|
||||
};
|
||||
|
||||
self.continueToNextStep = function() {
|
||||
executeSoon(function() {
|
||||
testGenerator.next();
|
||||
});
|
||||
};
|
||||
|
||||
self.continueToNextStepSync = function() {
|
||||
testGenerator.next();
|
||||
};
|
||||
|
||||
self.errorHandler = function(_event_) {
|
||||
ok(false, "indexedDB error, '" + _event_.target.error.name + "'");
|
||||
finishTest();
|
||||
};
|
||||
|
||||
self.unexpectedSuccessHandler = function()
|
||||
{
|
||||
ok(false, "Got success, but did not expect it!");
|
||||
finishTest();
|
||||
};
|
||||
|
||||
self.expectedErrorHandler = function(_name_)
|
||||
{
|
||||
return function(_event_) {
|
||||
is(_event_.type, "error", "Got an error event");
|
||||
is(_event_.target.error.name, _name_, "Expected error was thrown.");
|
||||
_event_.preventDefault();
|
||||
grabEventAndContinueHandler(_event_);
|
||||
};
|
||||
};
|
||||
|
||||
self.ExpectError = function(_name_, _preventDefault_)
|
||||
{
|
||||
this._name = _name_;
|
||||
this._preventDefault = _preventDefault_;
|
||||
}
|
||||
self.ExpectError.prototype = {
|
||||
handleEvent: function(_event_)
|
||||
{
|
||||
is(_event_.type, "error", "Got an error event");
|
||||
is(_event_.target.error.name, this._name, "Expected error was thrown.");
|
||||
if (this._preventDefault) {
|
||||
_event_.preventDefault();
|
||||
_event_.stopPropagation();
|
||||
}
|
||||
grabEventAndContinueHandler(_event_);
|
||||
}
|
||||
};
|
||||
|
||||
self.compareKeys = function(_k1_, _k2_) {
|
||||
let t = typeof _k1_;
|
||||
if (t != typeof _k2_)
|
||||
return false;
|
||||
|
||||
if (t !== "object")
|
||||
return _k1_ === _k2_;
|
||||
|
||||
if (_k1_ instanceof Date) {
|
||||
return (_k2_ instanceof Date) &&
|
||||
_k1_.getTime() === _k2_.getTime();
|
||||
}
|
||||
|
||||
if (_k1_ instanceof Array) {
|
||||
if (!(_k2_ instanceof Array) ||
|
||||
_k1_.length != _k2_.length)
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < _k1_.length; ++i) {
|
||||
if (!compareKeys(_k1_[i], _k2_[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
self.onerror = function(_message_, _file_, _line_) {
|
||||
ok(false,
|
||||
"Worker: uncaught exception [" + _file_ + ":" + _line_ + "]: '" +
|
||||
_message_ + "'");
|
||||
self.finishTest();
|
||||
self.close();
|
||||
return true;
|
||||
};
|
||||
|
||||
self.onmessage = function(_event_) {
|
||||
let message = _event_.data;
|
||||
switch (message.op) {
|
||||
case "load":
|
||||
info("Worker: loading " + JSON.stringify(message.files));
|
||||
self.importScripts(message.files);
|
||||
self.postMessage({ op: "loaded" });
|
||||
break;
|
||||
|
||||
case "start":
|
||||
executeSoon(function() {
|
||||
info("Worker: starting tests");
|
||||
testGenerator.next();
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Received a bad message from parent: " +
|
||||
JSON.stringify(message));
|
||||
}
|
||||
};
|
||||
|
||||
self.postMessage({ op: "ready" });
|
||||
}
|
||||
|
@ -27,7 +27,6 @@
|
||||
let iframe = document.getElementById("iframe1");
|
||||
window.addEventListener("message", grabEventAndContinueHandler, false);
|
||||
// Put it in a different origin to be safe
|
||||
//allowUnlimitedQuota("http://example.org/");
|
||||
iframe.src = //"http://example.org" +
|
||||
window.location.pathname.replace(
|
||||
"test_blob_worker_crash.html",
|
||||
|
@ -3,6 +3,8 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
let disableWorkerTest = "Need to implement a gc() function for worker tests";
|
||||
|
||||
if (!this.window) {
|
||||
this.runTest = function() {
|
||||
todo(false, "Test disabled in xpcshell test suite for now");
|
||||
@ -373,7 +375,7 @@ function testSteps()
|
||||
yield undefined; yield undefined;
|
||||
db.close();
|
||||
|
||||
SpecialPowers.gc();
|
||||
gc();
|
||||
|
||||
openRequest = indexedDB.open(dbname, 2);
|
||||
openRequest.onerror = errorHandler;
|
||||
|
@ -2,6 +2,9 @@
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
let disableWorkerTest = "This test uses SpecialPowers";
|
||||
|
||||
let testGenerator = testSteps();
|
||||
|
||||
function createFileReader() {
|
||||
|
@ -3,6 +3,8 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
let disableWorkerTest = "Need to implement a gc() function for worker tests";
|
||||
|
||||
let testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
|
@ -4,6 +4,8 @@
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
let disableWorkerTest = "This test uses SpecialPowers";
|
||||
|
||||
var self = this;
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
@ -3,13 +3,6 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
if (!this.window) {
|
||||
this.runTest = function() {
|
||||
todo(false, "Test disabled in xpcshell test suite for now");
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
|
@ -49,12 +49,8 @@ function testSteps()
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
request.onblocked = errorHandler;
|
||||
}
|
||||
else {
|
||||
todo(false, "Need to fix blocked events in child processes!");
|
||||
}
|
||||
request.onblocked = errorHandler;
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
// Test the upgradeneeded event.
|
||||
@ -86,12 +82,8 @@ function testSteps()
|
||||
request = indexedDB.open(name, 2);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = grabEventAndContinueHandler;
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
request.onblocked = errorHandler;
|
||||
}
|
||||
else {
|
||||
todo(false, "Need to fix blocked events in child processes!");
|
||||
}
|
||||
request.onblocked = errorHandler;
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
db3 = event.target.result;
|
||||
@ -130,12 +122,7 @@ function testSteps()
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
request.onblocked = errorHandler;
|
||||
}
|
||||
else {
|
||||
todo(false, "Need to fix blocked events in child processes!");
|
||||
}
|
||||
request.onblocked = errorHandler;
|
||||
|
||||
event = yield undefined;
|
||||
|
||||
|
@ -15,8 +15,6 @@ function abortListener(evt)
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const name = this.window ? window.location.pathname : "Splendid Test";
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
|
@ -82,6 +82,18 @@ function testSteps() {
|
||||
|
||||
if ("SimpleTest" in this) {
|
||||
SimpleTest.expectUncaughtException();
|
||||
} else if ("DedicatedWorkerGlobalScope" in self &&
|
||||
self instanceof DedicatedWorkerGlobalScope) {
|
||||
let oldErrorFunction = self.onerror;
|
||||
self.onerror = function(message, file, line) {
|
||||
self.onerror = oldErrorFunction;
|
||||
oldErrorFunction = null;
|
||||
|
||||
is(message,
|
||||
"ConstraintError",
|
||||
"Got expected ConstraintError on DedicatedWorkerGlobalScope");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
request = objectStore.add(data, dataKey);
|
||||
|
@ -3,6 +3,8 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
let disableWorkerTest = "This test uses SpecialPowers";
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
|
@ -5,6 +5,10 @@
|
||||
|
||||
const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu } = Components;
|
||||
|
||||
if (!("self" in this)) {
|
||||
this.self = this;
|
||||
}
|
||||
|
||||
const DOMException = Ci.nsIDOMDOMException;
|
||||
|
||||
function is(a, b, msg) {
|
||||
@ -176,16 +180,6 @@ function disallowIndexedDB(url)
|
||||
throw "disallowIndexedDB";
|
||||
}
|
||||
|
||||
function allowUnlimitedQuota(url)
|
||||
{
|
||||
throw "allowUnlimitedQuota";
|
||||
}
|
||||
|
||||
function disallowUnlimitedQuota(url)
|
||||
{
|
||||
throw "disallowUnlimitedQuota";
|
||||
}
|
||||
|
||||
function enableExperimental()
|
||||
{
|
||||
SpecialPowers.setBoolPref("dom.indexedDB.experimental", true);
|
||||
|
1017
dom/ipc/Blob.cpp
1017
dom/ipc/Blob.cpp
File diff suppressed because it is too large
Load Diff
@ -135,7 +135,7 @@ private:
|
||||
|
||||
BlobChild(nsIContentChild* aManager, BlobChild* aOther);
|
||||
|
||||
BlobChild(PBackgroundChild* aManager, BlobChild* aOther);
|
||||
BlobChild(PBackgroundChild* aManager, BlobChild* aOther, FileImpl* aBlobImpl);
|
||||
|
||||
// These constructors are called on the receiving side.
|
||||
BlobChild(nsIContentChild* aManager,
|
||||
@ -160,7 +160,7 @@ private:
|
||||
CommonInit(FileImpl* aBlobImpl);
|
||||
|
||||
void
|
||||
CommonInit(BlobChild* aOther);
|
||||
CommonInit(BlobChild* aOther, FileImpl* aBlobImpl);
|
||||
|
||||
void
|
||||
CommonInit(const ChildBlobConstructorParams& aParams);
|
||||
@ -185,11 +185,13 @@ private:
|
||||
|
||||
static BlobChild*
|
||||
MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
|
||||
nsIContentChild* aManager);
|
||||
nsIContentChild* aManager,
|
||||
FileImpl* aBlobImpl);
|
||||
|
||||
static BlobChild*
|
||||
MaybeGetActorFromRemoteBlob(nsIRemoteBlob* aRemoteBlob,
|
||||
PBackgroundChild* aManager);
|
||||
PBackgroundChild* aManager,
|
||||
FileImpl* aBlobImpl);
|
||||
|
||||
void
|
||||
NoteDyingRemoteBlobImpl();
|
||||
|
@ -220,6 +220,12 @@ private:
|
||||
virtual bool
|
||||
RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvBlobStreamSync(const uint64_t& aStart,
|
||||
const uint64_t& aLength,
|
||||
InputStreamParams* aParams,
|
||||
OptionalFileDescriptorSet* aFDs) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvWaitForSliceCreation() MOZ_OVERRIDE;
|
||||
|
||||
|
@ -6,8 +6,10 @@ include protocol PBackground;
|
||||
include protocol PBlobStream;
|
||||
include protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
include protocol PFileDescriptorSet;
|
||||
|
||||
include DOMTypes;
|
||||
include InputStreamParams;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -31,6 +33,9 @@ parent:
|
||||
|
||||
ResolveMystery(ResolveMysteryParams params);
|
||||
|
||||
sync BlobStreamSync(uint64_t begin, uint64_t length)
|
||||
returns (InputStreamParams params, OptionalFileDescriptorSet fds);
|
||||
|
||||
sync WaitForSliceCreation();
|
||||
|
||||
// Use only for testing!
|
||||
|
@ -6,8 +6,6 @@ include protocol PBlob;
|
||||
include protocol PFileDescriptorSet;
|
||||
include InputStreamParams;
|
||||
|
||||
using mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -114,6 +114,7 @@ LOCAL_INCLUDES += [
|
||||
'/dom/media/webspeech/synth/ipc',
|
||||
'/dom/mobilemessage/ipc',
|
||||
'/dom/storage',
|
||||
'/dom/workers',
|
||||
'/editor/libeditor',
|
||||
'/embedding/components/printingui/ipc',
|
||||
'/extensions/cookie',
|
||||
|
@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
[Constructor(DOMString name, optional DOMString message = ""),
|
||||
Exposed=(Window,System)]
|
||||
Exposed=(Window,Worker,System)]
|
||||
interface DOMError {
|
||||
[Constant]
|
||||
readonly attribute DOMString name;
|
||||
|
@ -10,6 +10,7 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface DOMStringList {
|
||||
readonly attribute unsigned long length;
|
||||
getter DOMString? item(unsigned long index);
|
||||
|
@ -14,6 +14,7 @@ enum IDBCursorDirection {
|
||||
"prevunique"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBCursor {
|
||||
readonly attribute (IDBObjectStore or IDBIndex) source;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBDatabase : EventTarget {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute unsigned long long version;
|
||||
@ -40,13 +41,13 @@ interface IDBDatabase : EventTarget {
|
||||
};
|
||||
|
||||
partial interface IDBDatabase {
|
||||
[Pref="dom.indexedDB.experimental"]
|
||||
[Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
readonly attribute StorageType storage;
|
||||
|
||||
[Throws]
|
||||
[Exposed=Window, Throws]
|
||||
IDBRequest createMutableFile (DOMString name, optional DOMString type);
|
||||
|
||||
// this is deprecated due to renaming in the spec
|
||||
[Throws]
|
||||
[Exposed=Window, Throws]
|
||||
IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type); // now createMutableFile
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
* https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html
|
||||
*/
|
||||
|
||||
[NoInterfaceObject]
|
||||
[Exposed=(Window,Worker), NoInterfaceObject]
|
||||
interface IDBEnvironment {
|
||||
//[Throws] readonly attribute IDBFactory indexedDB;
|
||||
[Throws] readonly attribute IDBFactory? indexedDB;
|
||||
@ -15,5 +15,6 @@ interface IDBEnvironment {
|
||||
|
||||
// Mozilla-specific stuff
|
||||
partial interface IDBEnvironment {
|
||||
[Throws] readonly attribute IDBFactory? mozIndexedDB;
|
||||
[Exposed=Window, Throws]
|
||||
readonly attribute IDBFactory? mozIndexedDB;
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ dictionary IDBOpenDBOptions
|
||||
* http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
|
||||
* for more information.
|
||||
*/
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBFactory {
|
||||
[Throws]
|
||||
IDBOpenDBRequest
|
||||
|
@ -12,6 +12,7 @@ dictionary IDBIndexParameters {
|
||||
boolean multiEntry = false;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBIndex {
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute IDBObjectStore objectStore;
|
||||
@ -45,9 +46,11 @@ partial interface IDBIndex {
|
||||
[Throws]
|
||||
IDBRequest mozGetAllKeys (optional any key, optional unsigned long limit);
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
[Throws,
|
||||
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
IDBRequest getAll (optional any key, optional unsigned long limit);
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
[Throws,
|
||||
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
IDBRequest getAllKeys (optional any key, optional unsigned long limit);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBKeyRange {
|
||||
[Throws]
|
||||
readonly attribute any lower;
|
||||
|
@ -12,6 +12,7 @@ dictionary IDBObjectStoreParameters {
|
||||
boolean autoIncrement = false;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBObjectStore {
|
||||
readonly attribute DOMString name;
|
||||
|
||||
@ -64,12 +65,15 @@ partial interface IDBObjectStore {
|
||||
[Throws]
|
||||
IDBRequest mozGetAll (optional any key, optional unsigned long limit);
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
[Throws,
|
||||
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
IDBRequest getAll (optional any key, optional unsigned long limit);
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
[Throws,
|
||||
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
IDBRequest getAllKeys (optional any key, optional unsigned long limit);
|
||||
|
||||
[Pref="dom.indexedDB.experimental", Throws]
|
||||
[Throws,
|
||||
Func="mozilla::dom::indexedDB::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
IDBRequest openKeyCursor (optional any range, optional IDBCursorDirection direction = "next");
|
||||
};
|
||||
|
@ -7,6 +7,7 @@
|
||||
* https://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBOpenDBRequest : IDBRequest {
|
||||
attribute EventHandler onblocked;
|
||||
|
||||
|
@ -13,6 +13,7 @@ enum IDBRequestReadyState {
|
||||
"done"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBRequest : EventTarget {
|
||||
[Throws]
|
||||
readonly attribute any result;
|
||||
|
@ -14,6 +14,7 @@ enum IDBTransactionMode {
|
||||
"versionchange"
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface IDBTransaction : EventTarget {
|
||||
[Throws]
|
||||
readonly attribute IDBTransactionMode mode;
|
||||
|
@ -15,7 +15,8 @@ dictionary IDBVersionChangeEventInit : EventInit {
|
||||
unsigned long long? newVersion = null;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
|
||||
[Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict),
|
||||
Exposed=(Window,Worker)]
|
||||
interface IDBVersionChangeEvent : Event {
|
||||
readonly attribute unsigned long long oldVersion;
|
||||
readonly attribute unsigned long long? newVersion;
|
||||
|
@ -39,6 +39,7 @@ partial interface WorkerGlobalScope {
|
||||
WorkerGlobalScope implements WindowTimers;
|
||||
WorkerGlobalScope implements WindowBase64;
|
||||
WorkerGlobalScope implements GlobalFetch;
|
||||
WorkerGlobalScope implements IDBEnvironment;
|
||||
|
||||
// Not implemented yet: bug 1072107.
|
||||
// WorkerGlobalScope implements FontFaceSource;
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
@ -71,12 +73,14 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
using mozilla::MutexAutoLock;
|
||||
using mozilla::MutexAutoUnlock;
|
||||
using mozilla::Preferences;
|
||||
using mozilla::dom::indexedDB::IndexedDatabaseManager;
|
||||
|
||||
// The size of the worker runtime heaps in bytes. May be changed via pref.
|
||||
#define WORKER_DEFAULT_RUNTIME_HEAPSIZE 32 * 1024 * 1024
|
||||
@ -1121,6 +1125,40 @@ PlatformOverrideChanged(const char* /* aPrefName */, void* /* aClosure */)
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundChildCallback MOZ_FINAL
|
||||
: public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
public:
|
||||
BackgroundChildCallback()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
private:
|
||||
~BackgroundChildCallback()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
virtual void
|
||||
ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aActor);
|
||||
}
|
||||
|
||||
virtual void
|
||||
ActorFailed() MOZ_OVERRIDE
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_CRASH("Unable to connect PBackground actor for the main thread!");
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(BackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
@ -1639,6 +1677,15 @@ RuntimeService::Init()
|
||||
|
||||
nsLayoutStatics::AddRef();
|
||||
|
||||
// Make sure PBackground actors are connected as soon as possible for the main
|
||||
// thread in case workers clone remote blobs here.
|
||||
if (!BackgroundChild::GetForCurrentThread()) {
|
||||
nsRefPtr<BackgroundChildCallback> callback = new BackgroundChildCallback();
|
||||
if (!BackgroundChild::GetOrCreateForCurrentThread(callback)) {
|
||||
MOZ_CRASH("Unable to connect PBackground actor for the main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize JSSettings.
|
||||
if (!sDefaultJSSettings.gcSettings[0].IsSet()) {
|
||||
sDefaultJSSettings.runtimeOptions = JS::RuntimeOptions();
|
||||
@ -1776,6 +1823,10 @@ RuntimeService::Init()
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2160,7 +2211,7 @@ RuntimeService::CreateServiceWorker(const GlobalObject& aGlobal,
|
||||
|
||||
nsresult
|
||||
RuntimeService::CreateServiceWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerPrivate::LoadInfo aLoadInfo,
|
||||
WorkerPrivate::LoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aScope,
|
||||
ServiceWorker** aServiceWorker)
|
||||
@ -2205,21 +2256,21 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
|
||||
false, &loadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CreateSharedWorkerFromLoadInfo(cx, loadInfo, aScriptURL, aName, aType,
|
||||
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,
|
||||
aSharedWorker);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerPrivate::LoadInfo aLoadInfo,
|
||||
WorkerPrivate::LoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
WorkerType aType,
|
||||
SharedWorker** aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MOZ_ASSERT(aLoadInfo.mResolvedScriptURI);
|
||||
MOZ_ASSERT(aLoadInfo);
|
||||
MOZ_ASSERT(aLoadInfo->mResolvedScriptURI);
|
||||
|
||||
nsRefPtr<WorkerPrivate> workerPrivate;
|
||||
{
|
||||
@ -2229,13 +2280,13 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
SharedWorkerInfo* sharedWorkerInfo;
|
||||
|
||||
nsCString scriptSpec;
|
||||
nsresult rv = aLoadInfo.mResolvedScriptURI->GetSpec(scriptSpec);
|
||||
nsresult rv = aLoadInfo->mResolvedScriptURI->GetSpec(scriptSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(scriptSpec, aName, key);
|
||||
|
||||
if (mDomainMap.Get(aLoadInfo.mDomain, &domainInfo) &&
|
||||
if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo) &&
|
||||
domainInfo->mSharedWorkerInfos.Get(key, &sharedWorkerInfo)) {
|
||||
workerPrivate = sharedWorkerInfo->mWorkerPrivate;
|
||||
}
|
||||
@ -2245,14 +2296,14 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
// a Shared/Service worker and the worker script loads and executes before
|
||||
// the SharedWorker object itself is created before then WorkerScriptLoaded()
|
||||
// will reset the loadInfo's window.
|
||||
nsCOMPtr<nsPIDOMWindow> window = aLoadInfo.mWindow;
|
||||
nsCOMPtr<nsPIDOMWindow> window = aLoadInfo->mWindow;
|
||||
|
||||
bool created = false;
|
||||
if (!workerPrivate) {
|
||||
ErrorResult rv;
|
||||
workerPrivate =
|
||||
WorkerPrivate::Constructor(aCx, aScriptURL, false,
|
||||
aType, aName, &aLoadInfo, rv);
|
||||
aType, aName, aLoadInfo, rv);
|
||||
NS_ENSURE_TRUE(workerPrivate, rv.ErrorCode());
|
||||
|
||||
created = true;
|
||||
|
@ -155,7 +155,7 @@ public:
|
||||
|
||||
nsresult
|
||||
CreateServiceWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerPrivate::LoadInfo aLoadInfo,
|
||||
WorkerPrivate::LoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aScope,
|
||||
ServiceWorker** aServiceWorker);
|
||||
@ -308,7 +308,7 @@ private:
|
||||
|
||||
nsresult
|
||||
CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
WorkerPrivate::LoadInfo aLoadInfo,
|
||||
WorkerPrivate::LoadInfo* aLoadInfo,
|
||||
const nsAString& aScriptURL,
|
||||
const nsACString& aName,
|
||||
WorkerType aType,
|
||||
|
@ -2122,7 +2122,7 @@ ServiceWorkerManager::CreateServiceWorker(const nsACString& aScriptSpec,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = rs->CreateServiceWorkerFromLoadInfo(cx, info, NS_ConvertUTF8toUTF16(aScriptSpec), aScope,
|
||||
rv = rs->CreateServiceWorkerFromLoadInfo(cx, &info, NS_ConvertUTF8toUTF16(aScriptSpec), aScope,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -20,8 +20,6 @@
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsITimer.h"
|
||||
@ -29,6 +27,8 @@
|
||||
#include "nsIURL.h"
|
||||
#include "nsIWorkerDebugger.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "jsfriendapi.h"
|
||||
@ -54,6 +54,12 @@
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/StructuredClone.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/nsIRemoteBlob.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -90,6 +96,10 @@
|
||||
#include "WorkerScope.h"
|
||||
#include "WorkerThread.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#undef PostMessage
|
||||
#endif
|
||||
|
||||
// JS_MaybeGC will run once every second during normal execution.
|
||||
#define PERIODIC_GC_TIMER_DELAY_SEC 1
|
||||
|
||||
@ -106,6 +116,8 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(JsWorkerMallocSizeOf)
|
||||
@ -295,6 +307,105 @@ LogErrorToConsole(const nsAString& aMessage,
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void
|
||||
ReadBlobOrFile(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
bool aIsMainThread,
|
||||
JS::MutableHandle<JSObject*> aBlobOrFile)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aReader);
|
||||
MOZ_ASSERT(!aBlobOrFile);
|
||||
|
||||
nsRefPtr<FileImpl> blobImpl;
|
||||
{
|
||||
FileImpl* rawBlobImpl;
|
||||
MOZ_ALWAYS_TRUE(JS_ReadBytes(aReader, &rawBlobImpl, sizeof(rawBlobImpl)));
|
||||
|
||||
MOZ_ASSERT(rawBlobImpl);
|
||||
|
||||
blobImpl = rawBlobImpl;
|
||||
}
|
||||
|
||||
DebugOnly<bool> isMutable;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)));
|
||||
MOZ_ASSERT(!isMutable);
|
||||
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(blobImpl)) {
|
||||
PBackgroundChild* backgroundManager =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(backgroundManager);
|
||||
|
||||
// Always make sure we have a blob from an actor we can use on this thread.
|
||||
BlobChild* blobChild = BlobChild::GetOrCreate(backgroundManager, blobImpl);
|
||||
MOZ_ASSERT(blobChild);
|
||||
|
||||
blobImpl = blobChild->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> parent;
|
||||
if (aIsMainThread) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> scriptGlobal =
|
||||
nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
parent = do_QueryInterface(scriptGlobal);
|
||||
} else {
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(globalScope);
|
||||
|
||||
parent = do_QueryObject(globalScope);
|
||||
}
|
||||
|
||||
nsRefPtr<File> blob = new File(parent, blobImpl);
|
||||
aBlobOrFile.set(blob->WrapObject(aCx));
|
||||
}
|
||||
|
||||
bool
|
||||
WriteBlobOrFile(JSContext* aCx,
|
||||
JSStructuredCloneWriter* aWriter,
|
||||
FileImpl* aBlobOrFileImpl,
|
||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aBlobOrFileImpl);
|
||||
|
||||
nsRefPtr<FileImpl> newBlobOrFileImpl;
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryObject(aBlobOrFileImpl)) {
|
||||
PBackgroundChild* backgroundManager =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(backgroundManager);
|
||||
|
||||
// Always make sure we have a blob from an actor we can use on this thread.
|
||||
BlobChild* blobChild =
|
||||
BlobChild::GetOrCreate(backgroundManager, aBlobOrFileImpl);
|
||||
MOZ_ASSERT(blobChild);
|
||||
|
||||
newBlobOrFileImpl = blobChild->GetBlobImpl();
|
||||
MOZ_ASSERT(newBlobOrFileImpl);
|
||||
|
||||
aBlobOrFileImpl = newBlobOrFileImpl;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aBlobOrFileImpl->SetMutable(false)));
|
||||
|
||||
if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0)) ||
|
||||
NS_WARN_IF(!JS_WriteBytes(aWriter,
|
||||
&aBlobOrFileImpl,
|
||||
sizeof(aBlobOrFileImpl)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aClonedObjects.AppendElement(aBlobOrFileImpl);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct WorkerStructuredCloneCallbacks
|
||||
{
|
||||
static JSObject*
|
||||
@ -307,31 +418,10 @@ struct WorkerStructuredCloneCallbacks
|
||||
if (aTag == DOMWORKER_SCTAG_BLOB) {
|
||||
MOZ_ASSERT(!aData);
|
||||
|
||||
FileImpl* blobImpl;
|
||||
if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
|
||||
MOZ_ASSERT(blobImpl);
|
||||
JS::Rooted<JSObject*> blobOrFile(aCx);
|
||||
ReadBlobOrFile(aCx, aReader, /* aIsMainThread */ false, &blobOrFile);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Blob should not be mutable.
|
||||
bool isMutable;
|
||||
NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
|
||||
!isMutable,
|
||||
"Only immutable blob should be passed to worker");
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// New scope to protect |result| from a moving GC during ~nsRefPtr.
|
||||
nsRefPtr<File> blob = new File(nullptr, blobImpl);
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
if (GetOrCreateDOMReflector(aCx, blob, &val)) {
|
||||
result = val.toObjectOrNull();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return blobOrFile;
|
||||
}
|
||||
// See if the object is an ImageData.
|
||||
else if (aTag == SCTAG_DOM_IMAGEDATA) {
|
||||
@ -350,18 +440,17 @@ struct WorkerStructuredCloneCallbacks
|
||||
NS_ASSERTION(aClosure, "Null pointer!");
|
||||
|
||||
// We'll stash any nsISupports pointers that need to be AddRef'd here.
|
||||
nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
|
||||
static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
|
||||
auto* clonedObjects =
|
||||
static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
|
||||
|
||||
// See if this is a Blob/File object.
|
||||
{
|
||||
File* blob = nullptr;
|
||||
nsRefPtr<File> blob;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
|
||||
FileImpl* blobImpl = blob->Impl();
|
||||
if (blobImpl && NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
|
||||
JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
|
||||
JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
|
||||
clonedObjects->AppendElement(blobImpl);
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -407,35 +496,10 @@ struct MainThreadWorkerStructuredCloneCallbacks
|
||||
if (aTag == DOMWORKER_SCTAG_BLOB) {
|
||||
MOZ_ASSERT(!aData);
|
||||
|
||||
FileImpl* blobImpl;
|
||||
if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
|
||||
MOZ_ASSERT(blobImpl);
|
||||
JS::Rooted<JSObject*> blobOrFile(aCx);
|
||||
ReadBlobOrFile(aCx, aReader, /* aIsMainThread */ true, &blobOrFile);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Blob should not be mutable.
|
||||
bool isMutable;
|
||||
NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
|
||||
!isMutable,
|
||||
"Only immutable blob should be passed to worker");
|
||||
}
|
||||
#endif
|
||||
|
||||
// nsRefPtr<File> needs to go out of scope before toObjectOrNull() is
|
||||
// called because the static analysis thinks dereferencing XPCOM objects
|
||||
// can GC (because in some cases it can!), and a return statement with a
|
||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||
// while destructors are running.
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
nsRefPtr<File> blob = new File(nullptr, blobImpl);
|
||||
if (!GetOrCreateDOMReflector(aCx, blob, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
}
|
||||
return blobOrFile;
|
||||
}
|
||||
|
||||
JS_ClearPendingException(aCx);
|
||||
@ -451,20 +515,19 @@ struct MainThreadWorkerStructuredCloneCallbacks
|
||||
NS_ASSERTION(aClosure, "Null pointer!");
|
||||
|
||||
// We'll stash any nsISupports pointers that need to be AddRef'd here.
|
||||
nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
|
||||
static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
|
||||
auto* clonedObjects =
|
||||
static_cast<nsTArray<nsCOMPtr<nsISupports>>*>(aClosure);
|
||||
|
||||
// See if this is a Blob/File object.
|
||||
{
|
||||
File* blob = nullptr;
|
||||
nsRefPtr<File> blob;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
|
||||
FileImpl* blobImpl = blob->Impl();
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
if (blobImpl->IsCCed()) {
|
||||
NS_WARNING("Cycle collected blob objects are not supported!");
|
||||
} else if (NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
|
||||
JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
|
||||
JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
|
||||
clonedObjects->AppendElement(blobImpl);
|
||||
} else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1224,7 +1287,7 @@ private:
|
||||
// check is only going to succeed when the worker is accepting events.
|
||||
if (workerIsAcceptingEvents) {
|
||||
aWorkerPrivate->AssertInnerWindowIsCorrect();
|
||||
innerWindowId = aWorkerPrivate->GetInnerWindowId();
|
||||
innerWindowId = aWorkerPrivate->WindowID();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1710,6 +1773,46 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class DummyRunnable MOZ_FINAL
|
||||
: public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
DummyRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
private:
|
||||
~DummyRunnable()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
virtual bool
|
||||
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Should never call Dispatch on this!");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void
|
||||
PostDispatch(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Should never call Dispatch on this!");
|
||||
}
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
|
||||
{
|
||||
// Do nothing.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
PRThread*
|
||||
PRThreadFromThread(nsIThread* aThread)
|
||||
{
|
||||
@ -1730,6 +1833,29 @@ NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, nsRunnable)
|
||||
|
||||
NS_IMPL_ISUPPORTS(TimerThreadEventTarget, nsIEventTarget)
|
||||
|
||||
template <class Derived>
|
||||
WorkerPrivateParent<Derived>::
|
||||
LoadInfo::LoadInfo()
|
||||
: mWindowID(UINT64_MAX)
|
||||
, mFromWindow(false)
|
||||
, mEvalAllowed(false)
|
||||
, mReportCSPViolations(false)
|
||||
, mXHRParamsAllowed(false)
|
||||
, mPrincipalIsSystem(false)
|
||||
, mIsInPrivilegedApp(false)
|
||||
, mIsInCertifiedApp(false)
|
||||
, mIndexedDBAllowed(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(WorkerPrivateParent<Derived>::LoadInfo);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
WorkerPrivateParent<Derived>::
|
||||
LoadInfo::~LoadInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WorkerPrivateParent<Derived>::LoadInfo);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
class WorkerPrivateParent<Derived>::SynchronizeAndResumeRunnable MOZ_FINAL
|
||||
: public nsRunnable
|
||||
@ -2009,6 +2135,22 @@ WorkerPrivate::SyncLoopInfo::SyncLoopInfo(EventTarget* aEventTarget)
|
||||
{
|
||||
}
|
||||
|
||||
struct WorkerPrivate::PreemptingRunnableInfo MOZ_FINAL
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
uint32_t mRecursionDepth;
|
||||
|
||||
PreemptingRunnableInfo()
|
||||
{
|
||||
MOZ_COUNT_CTOR(WorkerPrivate::PreemptingRunnableInfo);
|
||||
}
|
||||
|
||||
~PreemptingRunnableInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WorkerPrivate::PreemptingRunnableInfo);
|
||||
}
|
||||
};
|
||||
|
||||
// Can't use NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerPrivateParent) because of the
|
||||
// templates.
|
||||
template <class Derived>
|
||||
@ -2806,16 +2948,6 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
uint64_t
|
||||
WorkerPrivateParent<Derived>::GetInnerWindowId()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
NS_ASSERTION(!mLoadInfo.mWindow || mLoadInfo.mWindow->IsInnerWindow(),
|
||||
"Outer window?");
|
||||
return mLoadInfo.mWindow ? mLoadInfo.mWindow->WindowID() : 0;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::UpdateRuntimeOptions(
|
||||
@ -3367,6 +3499,7 @@ WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal,
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
|
||||
MOZ_ASSERT(!mLoadInfo.mPrincipalInfo);
|
||||
|
||||
mLoadInfo.mPrincipal = aPrincipal;
|
||||
mLoadInfo.mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
|
||||
@ -3377,6 +3510,11 @@ WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal,
|
||||
mLoadInfo.mIsInCertifiedApp = (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
|
||||
|
||||
mLoadInfo.mLoadGroup = aLoadGroup;
|
||||
|
||||
mLoadInfo.mPrincipalInfo = new PrincipalInfo();
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
PrincipalToPrincipalInfo(aPrincipal, mLoadInfo.mPrincipalInfo)));
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
@ -3908,6 +4046,7 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||
bool aIsChromeWorker, LoadInfo* aLoadInfo)
|
||||
{
|
||||
using namespace mozilla::dom::workers::scriptloader;
|
||||
using mozilla::dom::indexedDB::IDBFactory;
|
||||
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT_IF(NS_IsMainThread(), aCx == nsContentUtils::GetCurrentJSContext());
|
||||
@ -3958,6 +4097,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||
}
|
||||
|
||||
loadInfo.mDomain = aParent->Domain();
|
||||
loadInfo.mFromWindow = aParent->IsFromWindow();
|
||||
loadInfo.mWindowID = aParent->WindowID();
|
||||
loadInfo.mIndexedDBAllowed = aParent->IsIndexedDBAllowed();
|
||||
} else {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
@ -4071,6 +4213,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||
(appStatus == nsIPrincipal::APP_STATUS_CERTIFIED ||
|
||||
appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED);
|
||||
loadInfo.mIsInCertifiedApp = (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED);
|
||||
loadInfo.mFromWindow = true;
|
||||
loadInfo.mWindowID = globalWindow->WindowID();
|
||||
loadInfo.mIndexedDBAllowed = IDBFactory::AllowedForWindow(globalWindow);
|
||||
} else {
|
||||
// Not a window
|
||||
MOZ_ASSERT(isChrome);
|
||||
@ -4109,6 +4254,9 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||
}
|
||||
}
|
||||
loadInfo.mXHRParamsAllowed = true;
|
||||
loadInfo.mFromWindow = false;
|
||||
loadInfo.mWindowID = UINT64_MAX;
|
||||
loadInfo.mIndexedDBAllowed = true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(loadInfo.mPrincipal);
|
||||
@ -4293,6 +4441,29 @@ WorkerPrivate::OnProcessNextEvent(uint32_t aRecursionDepth)
|
||||
mSyncLoopStack.Length() < aRecursionDepth - 1) {
|
||||
ProcessAllControlRunnables();
|
||||
}
|
||||
|
||||
// Run any preempting runnables that match this depth.
|
||||
if (!mPreemptingRunnableInfos.IsEmpty()) {
|
||||
nsTArray<PreemptingRunnableInfo> pendingRunnableInfos;
|
||||
|
||||
for (uint32_t index = 0;
|
||||
index < mPreemptingRunnableInfos.Length();
|
||||
index++) {
|
||||
PreemptingRunnableInfo& preemptingRunnableInfo =
|
||||
mPreemptingRunnableInfos[index];
|
||||
|
||||
if (preemptingRunnableInfo.mRecursionDepth == aRecursionDepth) {
|
||||
preemptingRunnableInfo.mRunnable->Run();
|
||||
preemptingRunnableInfo.mRunnable = nullptr;
|
||||
} else {
|
||||
PreemptingRunnableInfo* pending = pendingRunnableInfos.AppendElement();
|
||||
pending->mRunnable.swap(preemptingRunnableInfo.mRunnable);
|
||||
pending->mRecursionDepth = preemptingRunnableInfo.mRecursionDepth;
|
||||
}
|
||||
}
|
||||
|
||||
mPreemptingRunnableInfos.SwapElements(pendingRunnableInfos);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -4302,6 +4473,42 @@ WorkerPrivate::AfterProcessNextEvent(uint32_t aRecursionDepth)
|
||||
MOZ_ASSERT(aRecursionDepth);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aRunnable);
|
||||
MOZ_ASSERT_IF(!mPreemptingRunnableInfos.IsEmpty(),
|
||||
NS_HasPendingEvents(mThread));
|
||||
|
||||
const uint32_t recursionDepth =
|
||||
mThread->RecursionDepth(WorkerThreadFriendKey());
|
||||
|
||||
PreemptingRunnableInfo* preemptingRunnableInfo =
|
||||
mPreemptingRunnableInfos.AppendElement();
|
||||
|
||||
preemptingRunnableInfo->mRunnable = aRunnable;
|
||||
|
||||
// Due to the weird way that the thread recursion counter is implemented we
|
||||
// subtract one from the recursion level if we have one.
|
||||
preemptingRunnableInfo->mRecursionDepth =
|
||||
recursionDepth ? recursionDepth - 1 : 0;
|
||||
|
||||
// Ensure that we have a pending event so that the runnable will be guaranteed
|
||||
// to run.
|
||||
if (mPreemptingRunnableInfos.Length() == 1 && !NS_HasPendingEvents(mThread)) {
|
||||
nsRefPtr<DummyRunnable> dummyRunnable = new DummyRunnable(this);
|
||||
if (NS_FAILED(Dispatch(dummyRunnable))) {
|
||||
NS_WARNING("RunBeforeNextEvent called after the thread is shutting "
|
||||
"down!");
|
||||
mPreemptingRunnableInfos.Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::InitializeGCTimers()
|
||||
{
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
@ -48,6 +49,9 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
class Function;
|
||||
}
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
}
|
||||
}
|
||||
|
||||
struct PRThread;
|
||||
@ -131,6 +135,8 @@ protected:
|
||||
class EventTarget;
|
||||
friend class EventTarget;
|
||||
|
||||
typedef mozilla::ipc::PrincipalInfo PrincipalInfo;
|
||||
|
||||
public:
|
||||
struct LocationInfo
|
||||
{
|
||||
@ -157,20 +163,22 @@ public:
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
nsAutoPtr<PrincipalInfo> mPrincipalInfo;
|
||||
nsCString mDomain;
|
||||
|
||||
uint64_t mWindowID;
|
||||
|
||||
bool mFromWindow;
|
||||
bool mEvalAllowed;
|
||||
bool mReportCSPViolations;
|
||||
bool mXHRParamsAllowed;
|
||||
bool mPrincipalIsSystem;
|
||||
bool mIsInPrivilegedApp;
|
||||
bool mIsInCertifiedApp;
|
||||
bool mIndexedDBAllowed;
|
||||
|
||||
LoadInfo()
|
||||
: mEvalAllowed(false), mReportCSPViolations(false),
|
||||
mXHRParamsAllowed(false), mPrincipalIsSystem(false),
|
||||
mIsInPrivilegedApp(false), mIsInCertifiedApp(false)
|
||||
{ }
|
||||
LoadInfo();
|
||||
~LoadInfo();
|
||||
|
||||
void
|
||||
StealFrom(LoadInfo& aOther)
|
||||
@ -199,13 +207,19 @@ public:
|
||||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mPrincipalInfo);
|
||||
mPrincipalInfo = aOther.mPrincipalInfo.forget();
|
||||
|
||||
mDomain = aOther.mDomain;
|
||||
mWindowID = aOther.mWindowID;
|
||||
mFromWindow = aOther.mFromWindow;
|
||||
mEvalAllowed = aOther.mEvalAllowed;
|
||||
mReportCSPViolations = aOther.mReportCSPViolations;
|
||||
mXHRParamsAllowed = aOther.mXHRParamsAllowed;
|
||||
mPrincipalIsSystem = aOther.mPrincipalIsSystem;
|
||||
mIsInPrivilegedApp = aOther.mIsInPrivilegedApp;
|
||||
mIsInCertifiedApp = aOther.mIsInCertifiedApp;
|
||||
mIndexedDBAllowed = aOther.mIndexedDBAllowed;
|
||||
}
|
||||
};
|
||||
|
||||
@ -404,9 +418,6 @@ public:
|
||||
JSAutoStructuredCloneBuffer&& aBuffer,
|
||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
|
||||
|
||||
uint64_t
|
||||
GetInnerWindowId();
|
||||
|
||||
void
|
||||
UpdateRuntimeOptions(JSContext* aCx,
|
||||
const JS::RuntimeOptions& aRuntimeOptions);
|
||||
@ -511,6 +522,18 @@ public:
|
||||
return mLoadInfo.mDomain;
|
||||
}
|
||||
|
||||
bool
|
||||
IsFromWindow() const
|
||||
{
|
||||
return mLoadInfo.mFromWindow;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
WindowID() const
|
||||
{
|
||||
return mLoadInfo.mWindowID;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
GetBaseURI() const
|
||||
{
|
||||
@ -582,6 +605,12 @@ public:
|
||||
return mLoadInfo.mIsInCertifiedApp;
|
||||
}
|
||||
|
||||
const PrincipalInfo&
|
||||
GetPrincipalInfo() const
|
||||
{
|
||||
return *mLoadInfo.mPrincipalInfo;
|
||||
}
|
||||
|
||||
already_AddRefed<nsIChannel>
|
||||
ForgetWorkerChannel()
|
||||
{
|
||||
@ -713,6 +742,12 @@ public:
|
||||
return mMessagePortSerial++;
|
||||
}
|
||||
|
||||
bool
|
||||
IsIndexedDBAllowed() const
|
||||
{
|
||||
return mLoadInfo.mIndexedDBAllowed;
|
||||
}
|
||||
|
||||
void
|
||||
GetAllSharedWorkers(nsTArray<nsRefPtr<SharedWorker>>& aSharedWorkers);
|
||||
|
||||
@ -833,6 +868,9 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
// modifications are done with mMutex held *only* in DEBUG builds.
|
||||
nsTArray<nsAutoPtr<SyncLoopInfo>> mSyncLoopStack;
|
||||
|
||||
struct PreemptingRunnableInfo;
|
||||
nsTArray<PreemptingRunnableInfo> mPreemptingRunnableInfos;
|
||||
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
nsCOMPtr<nsITimer> mGCTimer;
|
||||
@ -1167,6 +1205,11 @@ public:
|
||||
return mWorkerScriptExecutedSuccessfully;
|
||||
}
|
||||
|
||||
// Just like nsIAppShell::RunBeforeNextEvent. May only be called on the worker
|
||||
// thread.
|
||||
bool
|
||||
RunBeforeNextEvent(nsIRunnable* aRunnable);
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/Console.h"
|
||||
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/Fetch.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
@ -43,6 +45,9 @@ using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
using mozilla::dom::indexedDB::IDBFactory;
|
||||
using mozilla::ipc::PrincipalInfo;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
||||
@ -65,6 +70,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
@ -74,6 +80,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope,
|
||||
@ -312,6 +319,44 @@ WorkerGlobalScope::Fetch(const RequestOrUSVString& aInput,
|
||||
return FetchRequest(this, aInput, aInit, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<IDBFactory>
|
||||
WorkerGlobalScope::GetIndexedDB(ErrorResult& aErrorResult)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<IDBFactory> indexedDB = mIndexedDB;
|
||||
|
||||
if (!indexedDB) {
|
||||
if (!mWorkerPrivate->IsIndexedDBAllowed()) {
|
||||
NS_WARNING("IndexedDB is not allowed in this worker!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSContext* cx = mWorkerPrivate->GetJSContext();
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
JS::Rooted<JSObject*> owningObject(cx, GetGlobalJSObject());
|
||||
MOZ_ASSERT(owningObject);
|
||||
|
||||
const PrincipalInfo& principalInfo = mWorkerPrivate->GetPrincipalInfo();
|
||||
|
||||
nsresult rv =
|
||||
IDBFactory::CreateForWorker(cx,
|
||||
owningObject,
|
||||
principalInfo,
|
||||
mWorkerPrivate->WindowID(),
|
||||
getter_AddRefs(indexedDB));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aErrorResult = rv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mIndexedDB = indexedDB;
|
||||
}
|
||||
|
||||
return indexedDB.forget();
|
||||
}
|
||||
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerGlobalScope(aWorkerPrivate)
|
||||
{
|
||||
|
@ -19,6 +19,12 @@ class Function;
|
||||
class Promise;
|
||||
class RequestOrUSVString;
|
||||
|
||||
namespace indexedDB {
|
||||
|
||||
class IDBFactory;
|
||||
|
||||
} // namespace indexedDB
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@ -33,10 +39,13 @@ class Performance;
|
||||
class WorkerGlobalScope : public DOMEventTargetHelper,
|
||||
public nsIGlobalObject
|
||||
{
|
||||
typedef mozilla::dom::indexedDB::IDBFactory IDBFactory;
|
||||
|
||||
nsRefPtr<Console> mConsole;
|
||||
nsRefPtr<WorkerLocation> mLocation;
|
||||
nsRefPtr<WorkerNavigator> mNavigator;
|
||||
nsRefPtr<Performance> mPerformance;
|
||||
nsRefPtr<IDBFactory> mIndexedDB;
|
||||
|
||||
protected:
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
@ -127,6 +136,9 @@ public:
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Fetch(const RequestOrUSVString& aInput, const RequestInit& aInit, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<IDBFactory>
|
||||
GetIndexedDB(ErrorResult& aErrorResult);
|
||||
};
|
||||
|
||||
class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
|
||||
|
@ -284,6 +284,14 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
WorkerThread::RecursionDepth(const WorkerThreadFriendKey& /* aKey */) const
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
|
||||
|
||||
return mRunningEvent;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerThread::Observer, nsIThreadObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
Dispatch(const WorkerThreadFriendKey& aKey,
|
||||
WorkerRunnable* aWorkerRunnable);
|
||||
|
||||
uint32_t
|
||||
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
private:
|
||||
|
@ -93,8 +93,12 @@ var interfaceNamesInGlobalScope =
|
||||
{ name: "DataStore", b2g: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "DataStoreCursor", b2g: true },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DOMError",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DOMException",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"DOMStringList",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"Event",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
@ -105,6 +109,26 @@ var interfaceNamesInGlobalScope =
|
||||
"FileReaderSync",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "Headers", pref: "dom.fetch.enabled" },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBCursor",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBDatabase",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBFactory",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBIndex",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBKeyRange",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBObjectStore",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBOpenDBRequest",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBRequest",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBTransaction",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"IDBVersionChangeEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"ImageData",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -139,12 +139,22 @@ PrincipalToPrincipalInfo(nsIPrincipal* aPrincipal,
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t appId;
|
||||
rv = aPrincipal->GetAppId(&appId);
|
||||
bool isUnknownAppId;
|
||||
rv = aPrincipal->GetUnknownAppId(&isUnknownAppId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t appId;
|
||||
if (isUnknownAppId) {
|
||||
appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
|
||||
} else {
|
||||
rv = aPrincipal->GetAppId(&appId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
bool isInBrowserElement;
|
||||
rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -89,6 +89,7 @@ struct MIMEInputStreamParams
|
||||
union OptionalFileDescriptorSet
|
||||
{
|
||||
PFileDescriptorSet;
|
||||
FileDescriptor[];
|
||||
void_t;
|
||||
};
|
||||
|
||||
|
@ -34,12 +34,28 @@
|
||||
#include "nsPerformance.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
|
||||
#ifdef OS_POSIX
|
||||
#include "chrome/common/file_descriptor_set_posix.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kMaxFileDescriptorsPerMessage = 250;
|
||||
|
||||
#ifdef OS_POSIX
|
||||
// Keep this in sync with other platforms.
|
||||
static_assert(FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE == 250,
|
||||
"MAX_DESCRIPTORS_PER_MESSAGE mismatch!");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelChild
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1483,21 +1499,23 @@ HttpChannelChild::ContinueAsyncOpen()
|
||||
nsTArray<mozilla::ipc::FileDescriptor> fds;
|
||||
SerializeInputStream(mUploadStream, openArgs.uploadStream(), fds);
|
||||
|
||||
PFileDescriptorSetChild* fdSet = nullptr;
|
||||
if (!fds.IsEmpty()) {
|
||||
OptionalFileDescriptorSet optionalFDs;
|
||||
|
||||
if (fds.IsEmpty()) {
|
||||
optionalFDs = mozilla::void_t();
|
||||
} else if (fds.Length() <= kMaxFileDescriptorsPerMessage) {
|
||||
optionalFDs = nsTArray<mozilla::ipc::FileDescriptor>();
|
||||
optionalFDs.get_ArrayOfFileDescriptor().SwapElements(fds);
|
||||
} else {
|
||||
MOZ_ASSERT(gNeckoChild->Manager());
|
||||
|
||||
fdSet = gNeckoChild->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
PFileDescriptorSetChild* fdSet =
|
||||
gNeckoChild->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
|
||||
for (uint32_t i = 1; i < fds.Length(); ++i) {
|
||||
unused << fdSet->SendAddFileDescriptor(fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
OptionalFileDescriptorSet optionalFDs;
|
||||
if (fdSet) {
|
||||
optionalFDs = fdSet;
|
||||
} else {
|
||||
optionalFDs = mozilla::void_t();
|
||||
}
|
||||
|
||||
nsCOMPtr<mozIThirdPartyUtil> util(do_GetService(THIRDPARTYUTIL_CONTRACTID));
|
||||
@ -1546,9 +1564,11 @@ HttpChannelChild::ContinueAsyncOpen()
|
||||
IPC::SerializedLoadContext(this),
|
||||
openArgs);
|
||||
|
||||
if (fdSet) {
|
||||
if (optionalFDs.type() ==
|
||||
OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
|
||||
FileDescriptorSetChild* fdSetActor =
|
||||
static_cast<FileDescriptorSetChild*>(fdSet);
|
||||
static_cast<FileDescriptorSetChild*>(
|
||||
optionalFDs.get_PFileDescriptorSetChild());
|
||||
|
||||
fdSetActor->ForgetFileDescriptors(fds);
|
||||
}
|
||||
|
@ -304,6 +304,9 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
|
||||
MOZ_ASSERT(!fds.IsEmpty());
|
||||
|
||||
unused << fdSetActor->Send__delete__(fdSetActor);
|
||||
} else if (aFds.type() == OptionalFileDescriptorSet::TArrayOfFileDescriptor) {
|
||||
const_cast<OptionalFileDescriptorSet&>(aFds).
|
||||
get_ArrayOfFileDescriptor().SwapElements(fds);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(uploadStream, fds);
|
||||
|
@ -1,5 +0,0 @@
|
||||
[idb_webworkers.htm]
|
||||
type: testharness
|
||||
[IndexedDB inside of a WebWorker ]
|
||||
expected: FAIL
|
||||
|
Loading…
Reference in New Issue
Block a user