Bug 701634 - Support IndexedDB in Workers, r=khuey+baku.

This commit is contained in:
Ben Turner 2014-12-16 22:26:15 -08:00
parent 76ea507b88
commit 64376d8607
66 changed files with 2612 additions and 1015 deletions

View File

@ -1440,6 +1440,8 @@ nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
void
nsDOMStyleSheetSetList::EnsureFresh()
{
MOZ_ASSERT(NS_IsMainThread());
mNames.Clear();
if (!mDocument) {

View File

@ -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));
}

View File

@ -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();
}

View File

@ -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

View File

@ -514,7 +514,7 @@ public:
#endif
void
SendDeleteMeInternal();
SendDeleteMeInternal(bool aFailedConstructor);
private:
// Only created by BackgroundDatabaseChild.

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -94,6 +94,7 @@ LOCAL_INCLUDES += [
'/db/sqlite3/src',
'/dom/base',
'/dom/storage',
'/dom/workers',
'/ipc/glue',
'/xpcom/build',
]

View File

@ -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" });
}

View File

@ -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",

View File

@ -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;

View File

@ -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() {

View File

@ -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()

View File

@ -4,6 +4,8 @@
*/
"use strict";
let disableWorkerTest = "This test uses SpecialPowers";
var self = this;
var testGenerator = testSteps();

View File

@ -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()

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -3,6 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let disableWorkerTest = "This test uses SpecialPowers";
var testGenerator = testSteps();
function testSteps()

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -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;

View File

@ -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!

View File

@ -6,8 +6,6 @@ include protocol PBlob;
include protocol PFileDescriptorSet;
include InputStreamParams;
using mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {

View File

@ -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',

View File

@ -11,7 +11,7 @@
*/
[Constructor(DOMString name, optional DOMString message = ""),
Exposed=(Window,System)]
Exposed=(Window,Worker,System)]
interface DOMError {
[Constant]
readonly attribute DOMString name;

View File

@ -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);

View File

@ -14,6 +14,7 @@ enum IDBCursorDirection {
"prevunique"
};
[Exposed=(Window,Worker)]
interface IDBCursor {
readonly attribute (IDBObjectStore or IDBIndex) source;

View File

@ -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
};

View File

@ -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;
};

View File

@ -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

View File

@ -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);
};

View File

@ -9,6 +9,7 @@
* liability, trademark and document use rules apply.
*/
[Exposed=(Window,Worker)]
interface IDBKeyRange {
[Throws]
readonly attribute any lower;

View File

@ -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");
};

View File

@ -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;

View File

@ -13,6 +13,7 @@ enum IDBRequestReadyState {
"done"
};
[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
[Throws]
readonly attribute any result;

View File

@ -14,6 +14,7 @@ enum IDBTransactionMode {
"versionchange"
};
[Exposed=(Window,Worker)]
interface IDBTransaction : EventTarget {
[Throws]
readonly attribute IDBTransactionMode mode;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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))) {

View File

@ -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()
{

View File

@ -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,

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -72,6 +72,9 @@ public:
Dispatch(const WorkerThreadFriendKey& aKey,
WorkerRunnable* aWorkerRunnable);
uint32_t
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
NS_DECL_ISUPPORTS_INHERITED
private:

View File

@ -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!

View File

@ -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))) {

View File

@ -89,6 +89,7 @@ struct MIMEInputStreamParams
union OptionalFileDescriptorSet
{
PFileDescriptorSet;
FileDescriptor[];
void_t;
};

View File

@ -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);
}

View File

@ -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);

View File

@ -1,5 +0,0 @@
[idb_webworkers.htm]
type: testharness
[IndexedDB inside of a WebWorker ]
expected: FAIL