mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
69d1f32ff7
- Bug 1268085 - Remove unused post barrier callbacks r=terrence (0ab13411c9) - Bug 1267699 - Move some public types to the right namespace; r=sfink (3d5008e610) - Bug 1267550 (part 1) - Rename MOZ_MUST_USE as MOZ_MUST_USE_TYPE. r=ehsan. (6f47375796) - Bug 1259021 - Rename Vector::extractRawBuffer to extractOrCopyRawBuffer r=Waldo (97ca94495b) - Bug 1259021 - Add Vector::extractRawBuffer method that doesn't copy the buffer r=Waldo (e58deec48f) - Bug 1265892 - Change Vector to use Impl::new_ consistently. r=Waldo (7a52d21b29) - Bug 1267912 - Rename nsNetUtil.inl as nsNetUtilInlines.h. r=valentin. (548a41b293) - Bug 1265690 part 1 - Mark StringBuffer methods WARN_UNUSED_RESULT, fix OOM issues. r=jonco (0d7e6837e3) - Bug 1265690 part 2 - Fix some more OOM issues in TypedObject code. r=jonco (b60902453e) - Bug 1263490 - Part 2: Add GetFirstDollarIndex intrinsic and use it inRegExpReplace. r=till (4ba19db8c4) - Bug 1263490 - Part 3: Inline GetFirstDollarIndex intrinsic. r=h4writer (e7d9b5d1cc) - Bug 1263490 - Part 4: Fold GetFirstDollarIndex into a integer constant. r=h4writer (3479c7d1af) - Bug 1267269 - Make MIRType an enum class. r=bbouvier (d580ef372a) - Bug 1259295 - BaldrMonkey: Postorder (r=luke) (6ef7a77663) - Bug 1254142: BaldrMonkey: make br_table yield (r=luke) (80e7635e58) - Bug 1263202 - BaldrMonkey: switch to arities on branches, calls and return (r=bbouvier) (f5a0358634) - Bug 1236358 - Improper reading of string16 in Pickle::ReadString16. r=jld (8370ba6a0b) - Bug 1263205 - BaldrMonkey: Update section headers for proposed spec changes (r=luke) (0def2e6bc2) - Bug 1263205 - BaldrMonkey: Update for proposed new section names (r=luke) (e57f0e3367) - Bug 1263205 - BaldrMonkey: Add 'form' field to types section (r=bbouvier) (794edc890f) - Bug 1259021 - Use in-place storage in AutoStableStringChars to avoid allocation for short strings r=jandem r=Waldo (ffb53cbcf4) - Bug 1267550 (part 2) - Rename MOZ_WARN_UNUSED_RESULT as MOZ_MUST_USE. r=froydnj. (47bc674b86) - Bug 1268518: Baldr: implement int32/int64 rotations; r=luke (0d5eedccce) - Bug 1255008: IonMonkey - Add a by default disabled flow sensitive alias analysis pass, r=jandem (521c585d75) - Bug 1266781: Baldr: implement proper checked truncations to integer types; r=sunfish (46078fb3d3) - Bug 1266781: Rename MTruncateToInt64 into MWasmTruncateInt64; r=sunfish (c7d7d1ac11) - Bug 1266781: Add new traps; r=luke (b7ed3d44e6) - Bug 1268024: Pass the atomic attribute down to EmitHeapAccess; r=luke (6195f7d7a3) - Bug 1268024: A few cleanups related to loads/stores; r=luke (88141e3a01) - Bug 1258312 - Make Pickle::Resize infallible r=jld (241ee9b60d) - Bug 1162772, part 1 - Allow CompartmentCreationOptions to store Secure Context state. r=jorendorff (ff666384cf) - Bug 1162772, part 2 - Expose whether SEC_FORCE_INHERIT_PRINCIPAL was dropped from an nsILoadInfo. r=bz (ada46f86bf) - Bug 1162772, part 3 - Add a getChannelResultPrincipalIfNotSandboxed method to nsIScriptSecurityManager. r=bz (5b1d9f6807) - Bug 1162772, part 4 - Implement nsGlobalWindow::IsSecureContext. r=bz (f392f439c9) - Bug 1162772, part 5 - Expose Window.isSecureContext to content. r=bz (e7296e2cf1) - Bug 1267509 - Make nsContentSecurityManager::IsURIPotentiallyTrustworthy act on an nsIPrincipal. r=bz (83de80350a) - Bug 1219098 - Use UniquePtr in UncompressedSourceCache, for it is good (r=jandem) (b68769c729) - Bug 1244279 - Part 1: Take a bit in ObjectElements::Flags to indicate whether the object is in the whole cell store buffer. r=terrence (968cf373f9) - Bug 1244279 - Part 0: Add a GC ubench for large arrays with both elements and properties. r=terrence (ec76b48323) - Bug 1255925 - Give a name to getters/setters and integer-named methods. r=efaust (f978cc6916) - Bug 888969 - Make the getPrototypeOf/setPrototypeOf traps scriptable. r=efaust, r=bholley (eb2325a9ea) - Bug 1267557 part 0 - Move JS poison constants to jsutil.h. r=jonco (65afc690d2) - Bug 1267557 part 1 - Also poison bytes allocated before the actual jitcode. r=nbp (70f0b327d3) - Bug 1267557 part 2 - Use different jitcode poison values. r=nbp (08008ab9dc) - Bug 1267557 part 3 - Define JS_SWEPT_CODE_PATTERN for mips. r=nbp (17e894d59d) - Bug 1267449 - Do not infinite loop in js_fputs; r=jimb (67f961b6cd) - Bug 1219098 - Reenable compression on large sources, but revert to uncompressed if decompression happens (r=jandem) (b44ee8d77d) - Bug 1267551 (part 1) - Use MOZ_MUST_USE more in jsnum.h. r=jonco. (d2476bf8f4) - Bug 1267551 (part 2) - Use MOZ_MUST_USE more in js/src/ds/. r=jonco. (4ff5d9aa88) - Bug 1267412 - Use MutableHandleValue instead of pointer-to-AutoValueVector; r=sfink (3f6dd284bb) - Bug 1266406 - Use EnumSet<AllocKind> to simplify GC sweeping phase information r=terrence (64811500e7) - Bug 1266457 - Update pointers in GC things in two phases when compacting r=terrence (f6f5bc4e4d) - Bug 1266457 - Simplify typed object trace hook r=terence (3b06c8d1e5) - Bug 1268541 - Compact arenas containing base shapes r=terrence (b458b92eea) - Bug 1268805 - Implement PrivateGCThingValue. (r=terrence) (deec9a83ae) - Bug 1268415: Initialize members in UpdatePointerTasks; r=jonco (6cb219005a) - Bug 1268501 - Release the GC lock periodically when releasing arenas on the backgound thread r=terrence (37f0997682) - Bug 1263572 - Wait for background sweeping to finish before checking base shapes r=terrence (354801a411) - Bug 1266887 - Store Rooted heads on the Zone; r=sfink (91c0101ee3) - Bug 1266402 - Add iteration to EnumSet<T> so that it can be used in range-based for loops r=Waldo (e9507a2524) - Bug 1266404 - Allow construction of an EnumSet<T> using an initializer list r=Waldo (1b6d340e99) - Bug 1254020 - Always compute theme scaling factor when per-monitor dpi aware, even if only a single display is currently present. r=emk (a00cda21f4) - Bug 1263525 - Add dedicated function for std_Array self-hosted intrinsic. r=efaust (449d8bb7eb) - Bug 1255925 - Change JSFunction::name to return a JSAtom. r=efaust (5ab396ce83) - Bug 888969 - Make our tree's sole implementation of nsIRemoteTagService.getRemoteObjectTag not depend upon the infallibility of [[GetPrototypeOf]] on the object provided to it. r=bz (f388f4bf1f) - Bug 1264896 - Kill off nsIRemoteTagService and do what it does, in its sole caller, in far-faster C++. r=billm (5ed3fb103d) - Bug 1268246 - Add a simple Poison class lifetime checker. r=froydnj (7b237bc70e) - Bug 1249496 - Don't apply dpi-based scaling for window titlebar dimensions when on a secondary display, because windows doesn't scale it. r=emk (64dd706dbc) - Bug 1164518 - Avoid unnecessary DB updates when caching Safe Browsing results. r=gcp (3cafd9a4df) - Bug 1264472 - Use nsRunnables in FIDO U2F. r=keeler (3aa9570132) - Bug 1236060 - Dispatch error should advance queue. r=smaug (74155b75dd) - Bug 1251697 part 1. Thread an ErrorResult reference through the worker XHR WorkerThreadProxySyncRunnable implementations. r=khuey (77804cbb7c) - Bug 1251697 part 2. Have WorkerThreadProxySyncRunnable hand the ErrorResult reference it holds to its ResponseRunnable so it can report exceptions on there instead of on a JSContext. r=khuey (355c9ee313) - Bug 1251697 part 3. Remove the JSContext argument of StopSyncLoopRunnable::MaybeSetException. r=khuey (010f5b1058) - Bug 1155328. r=smaug (e1f8dac304) - Bug 1265927: Move nsRunnable to mozilla::Runnable, CancelableRunnable to mozilla::CancelableRunnable. r=froydnj (f83bfcae02) - Bug 1239946 - Change test to return error on Speak. r=eeejay (1d402beb02) - Bug 1254378 - Update synth tests and introduce no voiceschanged test. r=smaug (f5823bb70e) - Bug 1251627. Fix XMLHttpRequest.send() to follow the spec better in terms of the exceptions it throws. r=khuey (cd0e321948) - Bug 1268868: [MSE] P1. Re-enable gap detection within a media segment. r=gerald (b8b8df4bc2) - Bug 1268868: [MSE] P2. Reset longest duration after keyframe is seen. r=gerald (2b1401465c) - Bug 1268868: [MSE] P3. Prevent crash should gap be detected in content. r=gerald (063d9376fc) - Bug 1254378 - Implement nsISynthVoiceRegistry.notifyVoicesChanged. r=smaug (4b63b1c360) - Bug 1266804 - Un-inline js::Unbox(); r=jorendorff (0f288b6173) - Bug 1268863 - Report ScriptSources that are only reachable via AsmJSModule (r=njn) (5ba40acb64) - bump version to 45.1b1 (1414db0ca8) - Bug 1262062 - remove old futex names. r=bbouvier (62662bdd2e) - memory: build fix after renaming MOZ_WARN_UNUSED_RESULT (7254dc8d53) - import from mozilla: - Bug 1268725 - BaldrMonkey: Refactor away the internal storage from ExprIter. r=luke (1931bd636f17) - Bug 1268725 - BaldrMonkey: Convert default arguments into explicit arguments. r=luke (c8a11b8b6bbd) (867ec715d6)
3043 lines
79 KiB
C++
3043 lines
79 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "ActorsChild.h"
|
|
|
|
#include "BackgroundChildImpl.h"
|
|
#include "IDBDatabase.h"
|
|
#include "IDBEvents.h"
|
|
#include "IDBFactory.h"
|
|
#include "IDBIndex.h"
|
|
#include "IDBMutableFile.h"
|
|
#include "IDBObjectStore.h"
|
|
#include "IDBMutableFile.h"
|
|
#include "IDBRequest.h"
|
|
#include "IDBTransaction.h"
|
|
#include "IndexedDatabase.h"
|
|
#include "IndexedDatabaseInlines.h"
|
|
#include "mozilla/BasicEvents.h"
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/TypeTraits.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "mozilla/dom/PermissionMessageUtils.h"
|
|
#include "mozilla/dom/TabChild.h"
|
|
#include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
|
|
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
|
|
#include "mozilla/dom/ipc/BlobChild.h"
|
|
#include "mozilla/ipc/BackgroundUtils.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsIBFCacheEntry.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDOMEvent.h"
|
|
#include "nsIEventTarget.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsTraceRefcnt.h"
|
|
#include "PermissionRequestBase.h"
|
|
#include "ProfilerHelpers.h"
|
|
#include "ReportInternalError.h"
|
|
#include "WorkerPrivate.h"
|
|
#include "WorkerRunnable.h"
|
|
|
|
#ifdef DEBUG
|
|
#include "IndexedDatabaseManager.h"
|
|
#endif
|
|
|
|
#define GC_ON_IPC_MESSAGES 0
|
|
|
|
#if defined(DEBUG) || GC_ON_IPC_MESSAGES
|
|
|
|
#include "js/GCAPI.h"
|
|
#include "nsJSEnvironment.h"
|
|
|
|
#define BUILD_GC_ON_IPC_MESSAGES
|
|
|
|
#endif // DEBUG || GC_ON_IPC_MESSAGES
|
|
|
|
namespace mozilla {
|
|
|
|
using ipc::PrincipalInfo;
|
|
|
|
namespace dom {
|
|
|
|
using namespace workers;
|
|
|
|
namespace indexedDB {
|
|
|
|
/*******************************************************************************
|
|
* ThreadLocal
|
|
******************************************************************************/
|
|
|
|
ThreadLocal::ThreadLocal(const nsID& aBackgroundChildLoggingId)
|
|
: mLoggingInfo(aBackgroundChildLoggingId, 1, -1, 1)
|
|
, mCurrentTransaction(0)
|
|
#ifdef DEBUG
|
|
, mOwningThread(PR_GetCurrentThread())
|
|
#endif
|
|
{
|
|
MOZ_ASSERT(mOwningThread);
|
|
|
|
MOZ_COUNT_CTOR(mozilla::dom::indexedDB::ThreadLocal);
|
|
|
|
// NSID_LENGTH counts the null terminator, SetLength() does not.
|
|
mLoggingIdString.SetLength(NSID_LENGTH - 1);
|
|
|
|
aBackgroundChildLoggingId.ToProvidedString(
|
|
*reinterpret_cast<char(*)[NSID_LENGTH]>(mLoggingIdString.BeginWriting()));
|
|
}
|
|
|
|
ThreadLocal::~ThreadLocal()
|
|
{
|
|
MOZ_COUNT_DTOR(mozilla::dom::indexedDB::ThreadLocal);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
ThreadLocal::AssertIsOnOwningThread() const
|
|
{
|
|
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
/*******************************************************************************
|
|
* Helpers
|
|
******************************************************************************/
|
|
|
|
namespace {
|
|
|
|
void
|
|
MaybeCollectGarbageOnIPCMessage()
|
|
{
|
|
#ifdef BUILD_GC_ON_IPC_MESSAGES
|
|
static const bool kCollectGarbageOnIPCMessages =
|
|
#if GC_ON_IPC_MESSAGES
|
|
true;
|
|
#else
|
|
false;
|
|
#endif // GC_ON_IPC_MESSAGES
|
|
|
|
if (!kCollectGarbageOnIPCMessages) {
|
|
return;
|
|
}
|
|
|
|
static bool haveWarnedAboutGC = false;
|
|
static bool haveWarnedAboutNonMainThread = false;
|
|
|
|
if (!haveWarnedAboutGC) {
|
|
haveWarnedAboutGC = true;
|
|
NS_WARNING("IndexedDB child actor GC debugging enabled!");
|
|
}
|
|
|
|
if (!NS_IsMainThread()) {
|
|
if (!haveWarnedAboutNonMainThread) {
|
|
haveWarnedAboutNonMainThread = true;
|
|
NS_WARNING("Don't know how to GC on a non-main thread yet.");
|
|
}
|
|
return;
|
|
}
|
|
|
|
nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
|
|
nsJSContext::CycleCollectNow();
|
|
#endif // BUILD_GC_ON_IPC_MESSAGES
|
|
}
|
|
|
|
class MOZ_STACK_CLASS AutoSetCurrentTransaction final
|
|
{
|
|
typedef mozilla::ipc::BackgroundChildImpl BackgroundChildImpl;
|
|
|
|
IDBTransaction* const mTransaction;
|
|
IDBTransaction* mPreviousTransaction;
|
|
ThreadLocal* mThreadLocal;
|
|
|
|
public:
|
|
explicit AutoSetCurrentTransaction(IDBTransaction* aTransaction)
|
|
: mTransaction(aTransaction)
|
|
, mPreviousTransaction(nullptr)
|
|
, mThreadLocal(nullptr)
|
|
{
|
|
if (aTransaction) {
|
|
BackgroundChildImpl::ThreadLocal* threadLocal =
|
|
BackgroundChildImpl::GetThreadLocalForCurrentThread();
|
|
MOZ_ASSERT(threadLocal);
|
|
|
|
// Hang onto this for resetting later.
|
|
mThreadLocal = threadLocal->mIndexedDBThreadLocal;
|
|
MOZ_ASSERT(mThreadLocal);
|
|
|
|
// Save the current value.
|
|
mPreviousTransaction = mThreadLocal->GetCurrentTransaction();
|
|
|
|
// Set the new value.
|
|
mThreadLocal->SetCurrentTransaction(aTransaction);
|
|
}
|
|
}
|
|
|
|
~AutoSetCurrentTransaction()
|
|
{
|
|
MOZ_ASSERT_IF(mThreadLocal, mTransaction);
|
|
MOZ_ASSERT_IF(mThreadLocal,
|
|
mThreadLocal->GetCurrentTransaction() == mTransaction);
|
|
|
|
if (mThreadLocal) {
|
|
// Reset old value.
|
|
mThreadLocal->SetCurrentTransaction(mPreviousTransaction);
|
|
}
|
|
}
|
|
|
|
IDBTransaction*
|
|
Transaction() const
|
|
{
|
|
return mTransaction;
|
|
}
|
|
};
|
|
|
|
class MOZ_STACK_CLASS ResultHelper final
|
|
: public IDBRequest::ResultCallback
|
|
{
|
|
IDBRequest* mRequest;
|
|
AutoSetCurrentTransaction mAutoTransaction;
|
|
|
|
union
|
|
{
|
|
IDBDatabase* mDatabase;
|
|
IDBCursor* mCursor;
|
|
IDBMutableFile* mMutableFile;
|
|
StructuredCloneReadInfo* mStructuredClone;
|
|
const nsTArray<StructuredCloneReadInfo>* mStructuredCloneArray;
|
|
const Key* mKey;
|
|
const nsTArray<Key>* mKeyArray;
|
|
const JS::Value* mJSVal;
|
|
const JS::Handle<JS::Value>* mJSValHandle;
|
|
} mResult;
|
|
|
|
enum
|
|
{
|
|
ResultTypeDatabase,
|
|
ResultTypeCursor,
|
|
ResultTypeMutableFile,
|
|
ResultTypeStructuredClone,
|
|
ResultTypeStructuredCloneArray,
|
|
ResultTypeKey,
|
|
ResultTypeKeyArray,
|
|
ResultTypeJSVal,
|
|
ResultTypeJSValHandle,
|
|
} mResultType;
|
|
|
|
public:
|
|
ResultHelper(IDBRequest* aRequest,
|
|
IDBTransaction* aTransaction,
|
|
IDBDatabase* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeDatabase)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
MOZ_ASSERT(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,
|
|
IDBTransaction* aTransaction,
|
|
StructuredCloneReadInfo* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeStructuredClone)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
MOZ_ASSERT(aResult);
|
|
|
|
mResult.mStructuredClone = aResult;
|
|
}
|
|
|
|
ResultHelper(IDBRequest* aRequest,
|
|
IDBTransaction* aTransaction,
|
|
const nsTArray<StructuredCloneReadInfo>* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeStructuredCloneArray)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
MOZ_ASSERT(aResult);
|
|
|
|
mResult.mStructuredCloneArray = aResult;
|
|
}
|
|
|
|
ResultHelper(IDBRequest* aRequest,
|
|
IDBTransaction* aTransaction,
|
|
const Key* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeKey)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
MOZ_ASSERT(aResult);
|
|
|
|
mResult.mKey = aResult;
|
|
}
|
|
|
|
ResultHelper(IDBRequest* aRequest,
|
|
IDBTransaction* aTransaction,
|
|
const nsTArray<Key>* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeKeyArray)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
MOZ_ASSERT(aResult);
|
|
|
|
mResult.mKeyArray = aResult;
|
|
}
|
|
|
|
ResultHelper(IDBRequest* aRequest,
|
|
IDBTransaction* aTransaction,
|
|
const JS::Value* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeJSVal)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
MOZ_ASSERT(!aResult->isGCThing());
|
|
|
|
mResult.mJSVal = aResult;
|
|
}
|
|
|
|
ResultHelper(IDBRequest* aRequest,
|
|
IDBTransaction* aTransaction,
|
|
const JS::Handle<JS::Value>* aResult)
|
|
: mRequest(aRequest)
|
|
, mAutoTransaction(aTransaction)
|
|
, mResultType(ResultTypeJSValHandle)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
|
|
mResult.mJSValHandle = aResult;
|
|
}
|
|
|
|
IDBRequest*
|
|
Request() const
|
|
{
|
|
return mRequest;
|
|
}
|
|
|
|
IDBTransaction*
|
|
Transaction() const
|
|
{
|
|
return mAutoTransaction.Transaction();
|
|
}
|
|
|
|
virtual nsresult
|
|
GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult) override
|
|
{
|
|
MOZ_ASSERT(aCx);
|
|
MOZ_ASSERT(mRequest);
|
|
|
|
switch (mResultType) {
|
|
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);
|
|
|
|
case ResultTypeStructuredCloneArray:
|
|
return GetResult(aCx, mResult.mStructuredCloneArray, aResult);
|
|
|
|
case ResultTypeKey:
|
|
return GetResult(aCx, mResult.mKey, aResult);
|
|
|
|
case ResultTypeKeyArray:
|
|
return GetResult(aCx, mResult.mKeyArray, aResult);
|
|
|
|
case ResultTypeJSVal:
|
|
aResult.set(*mResult.mJSVal);
|
|
return NS_OK;
|
|
|
|
case ResultTypeJSValHandle:
|
|
aResult.set(*mResult.mJSValHandle);
|
|
return NS_OK;
|
|
|
|
default:
|
|
MOZ_CRASH("Unknown result type!");
|
|
}
|
|
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
|
|
private:
|
|
template <class T>
|
|
typename EnableIf<IsSame<T, IDBDatabase>::value ||
|
|
IsSame<T, IDBCursor>::value ||
|
|
IsSame<T, IDBMutableFile>::value,
|
|
nsresult>::Type
|
|
GetResult(JSContext* aCx,
|
|
T* aDOMObject,
|
|
JS::MutableHandle<JS::Value> aResult)
|
|
{
|
|
if (!aDOMObject) {
|
|
aResult.setNull();
|
|
return NS_OK;
|
|
}
|
|
|
|
bool ok = GetOrCreateDOMReflector(aCx, aDOMObject, aResult);
|
|
if (NS_WARN_IF(!ok)) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GetResult(JSContext* aCx,
|
|
StructuredCloneReadInfo* aCloneInfo,
|
|
JS::MutableHandle<JS::Value> aResult)
|
|
{
|
|
bool ok = IDBObjectStore::DeserializeValue(aCx, *aCloneInfo, aResult);
|
|
|
|
aCloneInfo->mCloneBuffer.clear();
|
|
|
|
if (NS_WARN_IF(!ok)) {
|
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GetResult(JSContext* aCx,
|
|
const nsTArray<StructuredCloneReadInfo>* aCloneInfos,
|
|
JS::MutableHandle<JS::Value> aResult)
|
|
{
|
|
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
|
|
if (NS_WARN_IF(!array)) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
|
|
if (!aCloneInfos->IsEmpty()) {
|
|
const uint32_t count = aCloneInfos->Length();
|
|
|
|
if (NS_WARN_IF(!JS_SetArrayLength(aCx, array, count))) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
|
|
for (uint32_t index = 0; index < count; index++) {
|
|
auto& cloneInfo =
|
|
const_cast<StructuredCloneReadInfo&>(aCloneInfos->ElementAt(index));
|
|
|
|
JS::Rooted<JS::Value> value(aCx);
|
|
|
|
nsresult rv = GetResult(aCx, &cloneInfo, &value);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(!JS_DefineElement(aCx, array, index, value,
|
|
JSPROP_ENUMERATE))) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
}
|
|
}
|
|
|
|
aResult.setObject(*array);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GetResult(JSContext* aCx,
|
|
const Key* aKey,
|
|
JS::MutableHandle<JS::Value> aResult)
|
|
{
|
|
nsresult rv = aKey->ToJSVal(aCx, aResult);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GetResult(JSContext* aCx,
|
|
const nsTArray<Key>* aKeys,
|
|
JS::MutableHandle<JS::Value> aResult)
|
|
{
|
|
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
|
|
if (NS_WARN_IF(!array)) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
|
|
if (!aKeys->IsEmpty()) {
|
|
const uint32_t count = aKeys->Length();
|
|
|
|
if (NS_WARN_IF(!JS_SetArrayLength(aCx, array, count))) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
|
|
for (uint32_t index = 0; index < count; index++) {
|
|
const Key& key = aKeys->ElementAt(index);
|
|
MOZ_ASSERT(!key.IsUnset());
|
|
|
|
JS::Rooted<JS::Value> value(aCx);
|
|
|
|
nsresult rv = GetResult(aCx, &key, &value);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
if (NS_WARN_IF(!JS_DefineElement(aCx, array, index, value,
|
|
JSPROP_ENUMERATE))) {
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
}
|
|
}
|
|
}
|
|
|
|
aResult.setObject(*array);
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
class PermissionRequestMainProcessHelper final
|
|
: public PermissionRequestBase
|
|
{
|
|
BackgroundFactoryRequestChild* mActor;
|
|
RefPtr<IDBFactory> mFactory;
|
|
|
|
public:
|
|
PermissionRequestMainProcessHelper(BackgroundFactoryRequestChild* aActor,
|
|
IDBFactory* aFactory,
|
|
Element* aOwnerElement,
|
|
nsIPrincipal* aPrincipal)
|
|
: PermissionRequestBase(aOwnerElement, aPrincipal)
|
|
, mActor(aActor)
|
|
, mFactory(aFactory)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
MOZ_ASSERT(aFactory);
|
|
aActor->AssertIsOnOwningThread();
|
|
}
|
|
|
|
protected:
|
|
~PermissionRequestMainProcessHelper()
|
|
{ }
|
|
|
|
private:
|
|
virtual void
|
|
OnPromptComplete(PermissionValue aPermissionValue) override;
|
|
};
|
|
|
|
class PermissionRequestChildProcessActor final
|
|
: public PIndexedDBPermissionRequestChild
|
|
{
|
|
BackgroundFactoryRequestChild* mActor;
|
|
RefPtr<IDBFactory> mFactory;
|
|
|
|
public:
|
|
PermissionRequestChildProcessActor(BackgroundFactoryRequestChild* aActor,
|
|
IDBFactory* aFactory)
|
|
: mActor(aActor)
|
|
, mFactory(aFactory)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
MOZ_ASSERT(aFactory);
|
|
aActor->AssertIsOnOwningThread();
|
|
}
|
|
|
|
protected:
|
|
~PermissionRequestChildProcessActor()
|
|
{ }
|
|
|
|
virtual bool
|
|
Recv__delete__(const uint32_t& aPermission) override;
|
|
};
|
|
|
|
void
|
|
ConvertActorsToBlobs(IDBDatabase* aDatabase,
|
|
const SerializedStructuredCloneReadInfo& aCloneReadInfo,
|
|
nsTArray<StructuredCloneFile>& aFiles)
|
|
{
|
|
MOZ_ASSERT(aFiles.IsEmpty());
|
|
|
|
const nsTArray<BlobOrMutableFile>& blobs = aCloneReadInfo.blobs();
|
|
|
|
if (!blobs.IsEmpty()) {
|
|
const uint32_t count = blobs.Length();
|
|
aFiles.SetCapacity(count);
|
|
|
|
for (uint32_t index = 0; index < count; index++) {
|
|
const BlobOrMutableFile& blobOrMutableFile = blobs[index];
|
|
|
|
switch (blobOrMutableFile.type()) {
|
|
case BlobOrMutableFile::TPBlobChild: {
|
|
auto* actor =
|
|
static_cast<BlobChild*>(blobOrMutableFile.get_PBlobChild());
|
|
|
|
RefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
|
|
MOZ_ASSERT(blobImpl);
|
|
|
|
RefPtr<Blob> blob = Blob::Create(aDatabase->GetOwner(), blobImpl);
|
|
|
|
aDatabase->NoteReceivedBlob(blob);
|
|
|
|
StructuredCloneFile* file = aFiles.AppendElement();
|
|
MOZ_ASSERT(file);
|
|
|
|
file->mMutable = false;
|
|
file->mBlob.swap(blob);
|
|
|
|
break;
|
|
}
|
|
|
|
case BlobOrMutableFile::TNullableMutableFile: {
|
|
const NullableMutableFile& nullableMutableFile =
|
|
blobOrMutableFile.get_NullableMutableFile();
|
|
|
|
switch (nullableMutableFile.type()) {
|
|
case NullableMutableFile::Tnull_t: {
|
|
StructuredCloneFile* file = aFiles.AppendElement();
|
|
MOZ_ASSERT(file);
|
|
|
|
file->mMutable = true;
|
|
|
|
break;
|
|
}
|
|
|
|
case NullableMutableFile::TPBackgroundMutableFileChild: {
|
|
auto* actor =
|
|
static_cast<BackgroundMutableFileChild*>(
|
|
nullableMutableFile.get_PBackgroundMutableFileChild());
|
|
MOZ_ASSERT(actor);
|
|
|
|
actor->EnsureDOMObject();
|
|
|
|
auto* mutableFile =
|
|
static_cast<IDBMutableFile*>(actor->GetDOMObject());
|
|
MOZ_ASSERT(mutableFile);
|
|
|
|
StructuredCloneFile* file = aFiles.AppendElement();
|
|
MOZ_ASSERT(file);
|
|
|
|
file->mMutable = true;
|
|
file->mMutableFile = mutableFile;
|
|
|
|
actor->ReleaseDOMObject();
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DispatchErrorEvent(IDBRequest* aRequest,
|
|
nsresult aErrorCode,
|
|
IDBTransaction* aTransaction = nullptr,
|
|
nsIDOMEvent* aEvent = nullptr)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
aRequest->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(NS_FAILED(aErrorCode));
|
|
MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_INDEXEDDB);
|
|
|
|
PROFILER_LABEL("IndexedDB",
|
|
"DispatchErrorEvent",
|
|
js::ProfileEntry::Category::STORAGE);
|
|
|
|
RefPtr<IDBRequest> request = aRequest;
|
|
RefPtr<IDBTransaction> transaction = aTransaction;
|
|
|
|
request->SetError(aErrorCode);
|
|
|
|
nsCOMPtr<nsIDOMEvent> errorEvent;
|
|
if (!aEvent) {
|
|
// Make an error event and fire it at the target.
|
|
errorEvent = CreateGenericEvent(request,
|
|
nsDependentString(kErrorEventType),
|
|
eDoesBubble,
|
|
eCancelable);
|
|
MOZ_ASSERT(errorEvent);
|
|
|
|
aEvent = errorEvent;
|
|
}
|
|
|
|
Maybe<AutoSetCurrentTransaction> asct;
|
|
if (aTransaction) {
|
|
asct.emplace(aTransaction);
|
|
}
|
|
|
|
if (transaction) {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"Firing %s event with error 0x%x",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: %s (0x%x)",
|
|
IDB_LOG_ID_STRING(),
|
|
transaction->LoggingSerialNumber(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(aEvent, kErrorEventType),
|
|
aErrorCode);
|
|
} else {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
|
|
"Firing %s event with error 0x%x",
|
|
"IndexedDB %s: C R[%llu]: %s (0x%x)",
|
|
IDB_LOG_ID_STRING(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(aEvent, kErrorEventType),
|
|
aErrorCode);
|
|
}
|
|
|
|
bool doDefault;
|
|
nsresult rv = request->DispatchEvent(aEvent, &doDefault);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(!transaction || transaction->IsOpen() || transaction->IsAborted());
|
|
|
|
if (transaction && transaction->IsOpen()) {
|
|
WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
|
|
MOZ_ASSERT(internalEvent);
|
|
|
|
if (internalEvent->mFlags.mExceptionHasBeenRisen) {
|
|
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
|
} else if (doDefault) {
|
|
transaction->Abort(request);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
DispatchSuccessEvent(ResultHelper* aResultHelper,
|
|
nsIDOMEvent* aEvent = nullptr)
|
|
{
|
|
MOZ_ASSERT(aResultHelper);
|
|
|
|
PROFILER_LABEL("IndexedDB",
|
|
"DispatchSuccessEvent",
|
|
js::ProfileEntry::Category::STORAGE);
|
|
|
|
RefPtr<IDBRequest> request = aResultHelper->Request();
|
|
MOZ_ASSERT(request);
|
|
request->AssertIsOnOwningThread();
|
|
|
|
RefPtr<IDBTransaction> transaction = aResultHelper->Transaction();
|
|
|
|
if (transaction && transaction->IsAborted()) {
|
|
DispatchErrorEvent(request, transaction->AbortCode(), transaction);
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMEvent> successEvent;
|
|
if (!aEvent) {
|
|
successEvent = CreateGenericEvent(request,
|
|
nsDependentString(kSuccessEventType),
|
|
eDoesNotBubble,
|
|
eNotCancelable);
|
|
MOZ_ASSERT(successEvent);
|
|
|
|
aEvent = successEvent;
|
|
}
|
|
|
|
request->SetResultCallback(aResultHelper);
|
|
|
|
MOZ_ASSERT(aEvent);
|
|
MOZ_ASSERT_IF(transaction, transaction->IsOpen());
|
|
|
|
if (transaction) {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
"Firing %s event",
|
|
"IndexedDB %s: C T[%lld] R[%llu]: %s",
|
|
IDB_LOG_ID_STRING(),
|
|
transaction->LoggingSerialNumber(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
|
|
} else {
|
|
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: Firing %s event",
|
|
"IndexedDB %s: C R[%llu]: %s",
|
|
IDB_LOG_ID_STRING(),
|
|
request->LoggingSerialNumber(),
|
|
IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
|
|
}
|
|
|
|
bool dummy;
|
|
nsresult rv = request->DispatchEvent(aEvent, &dummy);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT_IF(transaction,
|
|
transaction->IsOpen() || transaction->IsAborted());
|
|
|
|
WidgetEvent* internalEvent = aEvent->WidgetEventPtr();
|
|
MOZ_ASSERT(internalEvent);
|
|
|
|
if (transaction &&
|
|
transaction->IsOpen() &&
|
|
internalEvent->mFlags.mExceptionHasBeenRisen) {
|
|
transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
|
}
|
|
}
|
|
|
|
class WorkerPermissionChallenge;
|
|
|
|
// This class calles WorkerPermissionChallenge::OperationCompleted() in the
|
|
// worker thread.
|
|
class WorkerPermissionOperationCompleted final : public WorkerControlRunnable
|
|
{
|
|
RefPtr<WorkerPermissionChallenge> mChallenge;
|
|
|
|
public:
|
|
WorkerPermissionOperationCompleted(WorkerPrivate* aWorkerPrivate,
|
|
WorkerPermissionChallenge* aChallenge)
|
|
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
|
, mChallenge(aChallenge)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
}
|
|
|
|
virtual bool
|
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
|
};
|
|
|
|
// This class used to do prompting in the main thread and main process.
|
|
class WorkerPermissionRequest final : public PermissionRequestBase
|
|
{
|
|
RefPtr<WorkerPermissionChallenge> mChallenge;
|
|
|
|
public:
|
|
WorkerPermissionRequest(Element* aElement,
|
|
nsIPrincipal* aPrincipal,
|
|
WorkerPermissionChallenge* aChallenge)
|
|
: PermissionRequestBase(aElement, aPrincipal)
|
|
, mChallenge(aChallenge)
|
|
{
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aChallenge);
|
|
}
|
|
|
|
private:
|
|
~WorkerPermissionRequest()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
}
|
|
|
|
virtual void
|
|
OnPromptComplete(PermissionValue aPermissionValue) override;
|
|
};
|
|
|
|
// This class is used in the main thread of all child processes.
|
|
class WorkerPermissionRequestChildProcessActor final
|
|
: public PIndexedDBPermissionRequestChild
|
|
{
|
|
RefPtr<WorkerPermissionChallenge> mChallenge;
|
|
|
|
public:
|
|
explicit WorkerPermissionRequestChildProcessActor(
|
|
WorkerPermissionChallenge* aChallenge)
|
|
: mChallenge(aChallenge)
|
|
{
|
|
MOZ_ASSERT(!XRE_IsParentProcess());
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aChallenge);
|
|
}
|
|
|
|
protected:
|
|
~WorkerPermissionRequestChildProcessActor()
|
|
{}
|
|
|
|
virtual bool
|
|
Recv__delete__(const uint32_t& aPermission) override;
|
|
};
|
|
|
|
class WorkerPermissionChallenge final : public Runnable
|
|
, public WorkerFeature
|
|
{
|
|
public:
|
|
WorkerPermissionChallenge(WorkerPrivate* aWorkerPrivate,
|
|
BackgroundFactoryRequestChild* aActor,
|
|
IDBFactory* aFactory,
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
: mWorkerPrivate(aWorkerPrivate)
|
|
, mActor(aActor)
|
|
, mFactory(aFactory)
|
|
, mPrincipalInfo(aPrincipalInfo)
|
|
{
|
|
MOZ_ASSERT(mWorkerPrivate);
|
|
MOZ_ASSERT(aActor);
|
|
MOZ_ASSERT(aFactory);
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
}
|
|
|
|
NS_IMETHOD
|
|
Run() override
|
|
{
|
|
bool completed = RunInternal();
|
|
if (completed) {
|
|
OperationCompleted();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
virtual bool
|
|
Notify(workers::Status aStatus) override
|
|
{
|
|
// We don't care about the notification. We just want to keep the
|
|
// mWorkerPrivate alive.
|
|
return true;
|
|
}
|
|
|
|
void
|
|
OperationCompleted()
|
|
{
|
|
if (NS_IsMainThread()) {
|
|
RefPtr<WorkerPermissionOperationCompleted> runnable =
|
|
new WorkerPermissionOperationCompleted(mWorkerPrivate, this);
|
|
|
|
MOZ_ALWAYS_TRUE(runnable->Dispatch());
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(mActor);
|
|
mActor->AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
RefPtr<IDBFactory> factory;
|
|
mFactory.swap(factory);
|
|
|
|
mActor->SendPermissionRetry();
|
|
mActor = nullptr;
|
|
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
mWorkerPrivate->RemoveFeature(this);
|
|
}
|
|
|
|
private:
|
|
bool
|
|
RunInternal()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// Walk up to our containing page
|
|
WorkerPrivate* wp = mWorkerPrivate;
|
|
while (wp->GetParent()) {
|
|
wp = wp->GetParent();
|
|
}
|
|
|
|
nsPIDOMWindow* window = wp->GetWindow();
|
|
if (!window) {
|
|
return true;
|
|
}
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIPrincipal> principal =
|
|
mozilla::ipc::PrincipalInfoToPrincipal(mPrincipalInfo, &rv);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return true;
|
|
}
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
nsCOMPtr<Element> ownerElement =
|
|
do_QueryInterface(window->GetChromeEventHandler());
|
|
if (NS_WARN_IF(!ownerElement)) {
|
|
return true;
|
|
}
|
|
|
|
RefPtr<WorkerPermissionRequest> helper =
|
|
new WorkerPermissionRequest(ownerElement, principal, this);
|
|
|
|
PermissionRequestBase::PermissionValue permission;
|
|
if (NS_WARN_IF(NS_FAILED(helper->PromptIfNeeded(&permission)))) {
|
|
return true;
|
|
}
|
|
|
|
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
|
|
permission == PermissionRequestBase::kPermissionDenied ||
|
|
permission == PermissionRequestBase::kPermissionPrompt);
|
|
|
|
return permission != PermissionRequestBase::kPermissionPrompt;
|
|
}
|
|
|
|
TabChild* tabChild = TabChild::GetFrom(window);
|
|
MOZ_ASSERT(tabChild);
|
|
|
|
IPC::Principal ipcPrincipal(principal);
|
|
|
|
auto* actor = new WorkerPermissionRequestChildProcessActor(this);
|
|
tabChild->SendPIndexedDBPermissionRequestConstructor(actor, ipcPrincipal);
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
WorkerPrivate* mWorkerPrivate;
|
|
BackgroundFactoryRequestChild* mActor;
|
|
RefPtr<IDBFactory> mFactory;
|
|
PrincipalInfo mPrincipalInfo;
|
|
};
|
|
|
|
void
|
|
WorkerPermissionRequest::OnPromptComplete(PermissionValue aPermissionValue)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
mChallenge->OperationCompleted();
|
|
}
|
|
|
|
bool
|
|
WorkerPermissionOperationCompleted::WorkerRun(JSContext* aCx,
|
|
WorkerPrivate* aWorkerPrivate)
|
|
{
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
|
mChallenge->OperationCompleted();
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
WorkerPermissionRequestChildProcessActor::Recv__delete__(
|
|
const uint32_t& /* aPermission */)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
mChallenge->OperationCompleted();
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/*******************************************************************************
|
|
* Local class implementations
|
|
******************************************************************************/
|
|
|
|
void
|
|
PermissionRequestMainProcessHelper::OnPromptComplete(
|
|
PermissionValue aPermissionValue)
|
|
{
|
|
MOZ_ASSERT(mActor);
|
|
mActor->AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
mActor->SendPermissionRetry();
|
|
|
|
mActor = nullptr;
|
|
mFactory = nullptr;
|
|
}
|
|
|
|
bool
|
|
PermissionRequestChildProcessActor::Recv__delete__(
|
|
const uint32_t& /* aPermission */)
|
|
{
|
|
MOZ_ASSERT(mActor);
|
|
mActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mFactory);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
RefPtr<IDBFactory> factory;
|
|
mFactory.swap(factory);
|
|
|
|
mActor->SendPermissionRetry();
|
|
mActor = nullptr;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundRequestChildBase
|
|
******************************************************************************/
|
|
|
|
BackgroundRequestChildBase::BackgroundRequestChildBase(IDBRequest* aRequest)
|
|
: mRequest(aRequest)
|
|
{
|
|
MOZ_ASSERT(aRequest);
|
|
aRequest->AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundRequestChildBase);
|
|
}
|
|
|
|
BackgroundRequestChildBase::~BackgroundRequestChildBase()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChildBase);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
BackgroundRequestChildBase::AssertIsOnOwningThread() const
|
|
{
|
|
MOZ_ASSERT(mRequest);
|
|
mRequest->AssertIsOnOwningThread();
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
/*******************************************************************************
|
|
* BackgroundFactoryChild
|
|
******************************************************************************/
|
|
|
|
BackgroundFactoryChild::BackgroundFactoryChild(IDBFactory* aFactory)
|
|
: mFactory(aFactory)
|
|
#ifdef DEBUG
|
|
, mOwningThread(NS_GetCurrentThread())
|
|
#endif
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aFactory);
|
|
aFactory->AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundFactoryChild);
|
|
}
|
|
|
|
BackgroundFactoryChild::~BackgroundFactoryChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryChild);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
BackgroundFactoryChild::AssertIsOnOwningThread() const
|
|
{
|
|
MOZ_ASSERT(mOwningThread);
|
|
|
|
bool current;
|
|
MOZ_ASSERT(NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(¤t)));
|
|
MOZ_ASSERT(current);
|
|
}
|
|
|
|
nsIEventTarget*
|
|
BackgroundFactoryChild::OwningThread() const
|
|
{
|
|
MOZ_ASSERT(mOwningThread);
|
|
return mOwningThread;
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
void
|
|
BackgroundFactoryChild::SendDeleteMeInternal()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (mFactory) {
|
|
mFactory->ClearBackgroundActor();
|
|
mFactory = nullptr;
|
|
|
|
MOZ_ALWAYS_TRUE(PBackgroundIDBFactoryChild::SendDeleteMe());
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundFactoryChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (mFactory) {
|
|
mFactory->ClearBackgroundActor();
|
|
#ifdef DEBUG
|
|
mFactory = nullptr;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
PBackgroundIDBFactoryRequestChild*
|
|
BackgroundFactoryChild::AllocPBackgroundIDBFactoryRequestChild(
|
|
const FactoryRequestParams& aParams)
|
|
{
|
|
MOZ_CRASH("PBackgroundIDBFactoryRequestChild actors should be manually "
|
|
"constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryChild::DeallocPBackgroundIDBFactoryRequestChild(
|
|
PBackgroundIDBFactoryRequestChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundFactoryRequestChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBDatabaseChild*
|
|
BackgroundFactoryChild::AllocPBackgroundIDBDatabaseChild(
|
|
const DatabaseSpec& aSpec,
|
|
PBackgroundIDBFactoryRequestChild* aRequest)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
auto request = static_cast<BackgroundFactoryRequestChild*>(aRequest);
|
|
MOZ_ASSERT(request);
|
|
|
|
return new BackgroundDatabaseChild(aSpec, request);
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryChild::DeallocPBackgroundIDBDatabaseChild(
|
|
PBackgroundIDBDatabaseChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundDatabaseChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundFactoryRequestChild
|
|
******************************************************************************/
|
|
|
|
BackgroundFactoryRequestChild::BackgroundFactoryRequestChild(
|
|
IDBFactory* aFactory,
|
|
IDBOpenDBRequest* aOpenRequest,
|
|
bool aIsDeleteOp,
|
|
uint64_t aRequestedVersion)
|
|
: BackgroundRequestChildBase(aOpenRequest)
|
|
, mFactory(aFactory)
|
|
, mRequestedVersion(aRequestedVersion)
|
|
, mIsDeleteOp(aIsDeleteOp)
|
|
{
|
|
// Can't assert owning thread here because IPDL has not yet set our manager!
|
|
MOZ_ASSERT(aFactory);
|
|
aFactory->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aOpenRequest);
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundFactoryRequestChild);
|
|
}
|
|
|
|
BackgroundFactoryRequestChild::~BackgroundFactoryRequestChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryRequestChild);
|
|
}
|
|
|
|
IDBOpenDBRequest*
|
|
BackgroundFactoryRequestChild::GetOpenDBRequest() const
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
return static_cast<IDBOpenDBRequest*>(mRequest.get());
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(NS_FAILED(aResponse));
|
|
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
|
|
|
|
mRequest->Reset();
|
|
|
|
DispatchErrorEvent(mRequest, aResponse);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryRequestChild::HandleResponse(
|
|
const OpenDatabaseRequestResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
mRequest->Reset();
|
|
|
|
auto databaseActor =
|
|
static_cast<BackgroundDatabaseChild*>(aResponse.databaseChild());
|
|
MOZ_ASSERT(databaseActor);
|
|
|
|
IDBDatabase* database = databaseActor->GetDOMObject();
|
|
if (!database) {
|
|
databaseActor->EnsureDOMObject();
|
|
|
|
database = databaseActor->GetDOMObject();
|
|
MOZ_ASSERT(database);
|
|
|
|
MOZ_ASSERT(!database->IsClosed());
|
|
}
|
|
|
|
if (database->IsClosed()) {
|
|
// If the database was closed already, which is only possible if we fired an
|
|
// "upgradeneeded" event, then we shouldn't fire a "success" event here.
|
|
// Instead we fire an error event with AbortErr.
|
|
DispatchErrorEvent(mRequest, NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
|
} else {
|
|
ResultHelper helper(mRequest, nullptr, database);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
databaseActor->ReleaseDOMObject();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryRequestChild::HandleResponse(
|
|
const DeleteDatabaseRequestResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
ResultHelper helper(mRequest, nullptr, &JS::UndefinedHandleValue);
|
|
|
|
nsCOMPtr<nsIDOMEvent> successEvent =
|
|
IDBVersionChangeEvent::Create(mRequest,
|
|
nsDependentString(kSuccessEventType),
|
|
aResponse.previousVersion());
|
|
MOZ_ASSERT(successEvent);
|
|
|
|
DispatchSuccessEvent(&helper, successEvent);
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
BackgroundFactoryRequestChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (aWhy != Deletion) {
|
|
IDBOpenDBRequest* openRequest = GetOpenDBRequest();
|
|
if (openRequest) {
|
|
openRequest->NoteComplete();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryRequestChild::Recv__delete__(
|
|
const FactoryRequestResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
bool result;
|
|
|
|
switch (aResponse.type()) {
|
|
case FactoryRequestResponse::Tnsresult:
|
|
result = HandleResponse(aResponse.get_nsresult());
|
|
break;
|
|
|
|
case FactoryRequestResponse::TOpenDatabaseRequestResponse:
|
|
result = HandleResponse(aResponse.get_OpenDatabaseRequestResponse());
|
|
break;
|
|
|
|
case FactoryRequestResponse::TDeleteDatabaseRequestResponse:
|
|
result = HandleResponse(aResponse.get_DeleteDatabaseRequestResponse());
|
|
break;
|
|
|
|
default:
|
|
MOZ_CRASH("Unknown response type!");
|
|
}
|
|
|
|
IDBOpenDBRequest* request = GetOpenDBRequest();
|
|
MOZ_ASSERT(request);
|
|
|
|
request->NoteComplete();
|
|
|
|
if (NS_WARN_IF(!result)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryRequestChild::RecvPermissionChallenge(
|
|
const PrincipalInfo& aPrincipalInfo)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (!NS_IsMainThread()) {
|
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
|
MOZ_ASSERT(workerPrivate);
|
|
workerPrivate->AssertIsOnWorkerThread();
|
|
|
|
RefPtr<WorkerPermissionChallenge> challenge =
|
|
new WorkerPermissionChallenge(workerPrivate, this, mFactory,
|
|
aPrincipalInfo);
|
|
|
|
if (NS_WARN_IF(!workerPrivate->AddFeature(challenge))) {
|
|
return false;
|
|
}
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(challenge));
|
|
return true;
|
|
}
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIPrincipal> principal =
|
|
mozilla::ipc::PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return false;
|
|
}
|
|
|
|
if (XRE_IsParentProcess()) {
|
|
nsCOMPtr<nsPIDOMWindow> window = mFactory->GetParentObject();
|
|
MOZ_ASSERT(window);
|
|
|
|
nsCOMPtr<Element> ownerElement =
|
|
do_QueryInterface(window->GetChromeEventHandler());
|
|
if (NS_WARN_IF(!ownerElement)) {
|
|
// If this fails, the page was navigated. Fail the permission check by
|
|
// forcing an immediate retry.
|
|
return SendPermissionRetry();
|
|
}
|
|
|
|
RefPtr<PermissionRequestMainProcessHelper> helper =
|
|
new PermissionRequestMainProcessHelper(this, mFactory, ownerElement, principal);
|
|
|
|
PermissionRequestBase::PermissionValue permission;
|
|
if (NS_WARN_IF(NS_FAILED(helper->PromptIfNeeded(&permission)))) {
|
|
return false;
|
|
}
|
|
|
|
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
|
|
permission == PermissionRequestBase::kPermissionDenied ||
|
|
permission == PermissionRequestBase::kPermissionPrompt);
|
|
|
|
if (permission != PermissionRequestBase::kPermissionPrompt) {
|
|
SendPermissionRetry();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
RefPtr<TabChild> tabChild = mFactory->GetTabChild();
|
|
MOZ_ASSERT(tabChild);
|
|
|
|
IPC::Principal ipcPrincipal(principal);
|
|
|
|
auto* actor = new PermissionRequestChildProcessActor(this, mFactory);
|
|
|
|
tabChild->SendPIndexedDBPermissionRequestConstructor(actor, ipcPrincipal);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundFactoryRequestChild::RecvBlocked(const uint64_t& aCurrentVersion)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
const nsDependentString type(kBlockedEventType);
|
|
|
|
nsCOMPtr<nsIDOMEvent> blockedEvent;
|
|
if (mIsDeleteOp) {
|
|
blockedEvent =
|
|
IDBVersionChangeEvent::Create(mRequest, type, aCurrentVersion);
|
|
MOZ_ASSERT(blockedEvent);
|
|
} else {
|
|
blockedEvent =
|
|
IDBVersionChangeEvent::Create(mRequest,
|
|
type,
|
|
aCurrentVersion,
|
|
mRequestedVersion);
|
|
MOZ_ASSERT(blockedEvent);
|
|
}
|
|
|
|
RefPtr<IDBRequest> kungFuDeathGrip = mRequest;
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: Firing \"blocked\" event",
|
|
"IndexedDB %s: C R[%llu]: \"blocked\"",
|
|
IDB_LOG_ID_STRING(),
|
|
mRequest->LoggingSerialNumber());
|
|
|
|
bool dummy;
|
|
if (NS_FAILED(mRequest->DispatchEvent(blockedEvent, &dummy))) {
|
|
NS_WARNING("Failed to dispatch event!");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundDatabaseChild
|
|
******************************************************************************/
|
|
|
|
BackgroundDatabaseChild::BackgroundDatabaseChild(
|
|
const DatabaseSpec& aSpec,
|
|
BackgroundFactoryRequestChild* aOpenRequestActor)
|
|
: mSpec(new DatabaseSpec(aSpec))
|
|
, mOpenRequestActor(aOpenRequestActor)
|
|
, mDatabase(nullptr)
|
|
{
|
|
// Can't assert owning thread here because IPDL has not yet set our manager!
|
|
MOZ_ASSERT(aOpenRequestActor);
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundDatabaseChild);
|
|
}
|
|
|
|
BackgroundDatabaseChild::~BackgroundDatabaseChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundDatabaseChild);
|
|
}
|
|
|
|
void
|
|
BackgroundDatabaseChild::SendDeleteMeInternal()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(!mTemporaryStrongDatabase);
|
|
MOZ_ASSERT(!mOpenRequestActor);
|
|
|
|
if (mDatabase) {
|
|
mDatabase->ClearBackgroundActor();
|
|
mDatabase = nullptr;
|
|
|
|
MOZ_ALWAYS_TRUE(PBackgroundIDBDatabaseChild::SendDeleteMe());
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundDatabaseChild::EnsureDOMObject()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mOpenRequestActor);
|
|
|
|
if (mTemporaryStrongDatabase) {
|
|
MOZ_ASSERT(!mSpec);
|
|
return;
|
|
}
|
|
|
|
MOZ_ASSERT(mSpec);
|
|
|
|
auto request = mOpenRequestActor->GetOpenDBRequest();
|
|
MOZ_ASSERT(request);
|
|
|
|
auto factory =
|
|
static_cast<BackgroundFactoryChild*>(Manager())->GetDOMObject();
|
|
MOZ_ASSERT(factory);
|
|
|
|
mTemporaryStrongDatabase =
|
|
IDBDatabase::Create(request, factory, this, mSpec);
|
|
|
|
MOZ_ASSERT(mTemporaryStrongDatabase);
|
|
mTemporaryStrongDatabase->AssertIsOnOwningThread();
|
|
|
|
mDatabase = mTemporaryStrongDatabase;
|
|
mSpec.forget();
|
|
}
|
|
|
|
void
|
|
BackgroundDatabaseChild::ReleaseDOMObject()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTemporaryStrongDatabase);
|
|
mTemporaryStrongDatabase->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mOpenRequestActor);
|
|
MOZ_ASSERT(mDatabase == mTemporaryStrongDatabase);
|
|
|
|
mOpenRequestActor = nullptr;
|
|
|
|
// This may be the final reference to the IDBDatabase object so we may end up
|
|
// calling SendDeleteMeInternal() here. Make sure everything is cleaned up
|
|
// properly before proceeding.
|
|
mTemporaryStrongDatabase = nullptr;
|
|
}
|
|
|
|
void
|
|
BackgroundDatabaseChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (mDatabase) {
|
|
mDatabase->ClearBackgroundActor();
|
|
#ifdef DEBUG
|
|
mDatabase = nullptr;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
PBackgroundIDBDatabaseFileChild*
|
|
BackgroundDatabaseChild::AllocPBackgroundIDBDatabaseFileChild(
|
|
PBlobChild* aBlobChild)
|
|
{
|
|
MOZ_CRASH("PBackgroundIDBFileChild actors should be manually constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::DeallocPBackgroundIDBDatabaseFileChild(
|
|
PBackgroundIDBDatabaseFileChild* aActor)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete aActor;
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBDatabaseRequestChild*
|
|
BackgroundDatabaseChild::AllocPBackgroundIDBDatabaseRequestChild(
|
|
const DatabaseRequestParams& aParams)
|
|
{
|
|
MOZ_CRASH("PBackgroundIDBDatabaseRequestChild actors should be manually "
|
|
"constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::DeallocPBackgroundIDBDatabaseRequestChild(
|
|
PBackgroundIDBDatabaseRequestChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundDatabaseRequestChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBTransactionChild*
|
|
BackgroundDatabaseChild::AllocPBackgroundIDBTransactionChild(
|
|
const nsTArray<nsString>& aObjectStoreNames,
|
|
const Mode& aMode)
|
|
{
|
|
MOZ_CRASH("PBackgroundIDBTransactionChild actors should be manually "
|
|
"constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::DeallocPBackgroundIDBTransactionChild(
|
|
PBackgroundIDBTransactionChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundTransactionChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBVersionChangeTransactionChild*
|
|
BackgroundDatabaseChild::AllocPBackgroundIDBVersionChangeTransactionChild(
|
|
const uint64_t& aCurrentVersion,
|
|
const uint64_t& aRequestedVersion,
|
|
const int64_t& aNextObjectStoreId,
|
|
const int64_t& aNextIndexId)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
IDBOpenDBRequest* request = mOpenRequestActor->GetOpenDBRequest();
|
|
MOZ_ASSERT(request);
|
|
|
|
return new BackgroundVersionChangeTransactionChild(request);
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
|
|
PBackgroundIDBVersionChangeTransactionChild* aActor,
|
|
const uint64_t& aCurrentVersion,
|
|
const uint64_t& aRequestedVersion,
|
|
const int64_t& aNextObjectStoreId,
|
|
const int64_t& aNextIndexId)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aActor);
|
|
MOZ_ASSERT(mOpenRequestActor);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
EnsureDOMObject();
|
|
|
|
auto* actor = static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
|
|
|
|
RefPtr<IDBOpenDBRequest> request = mOpenRequestActor->GetOpenDBRequest();
|
|
MOZ_ASSERT(request);
|
|
|
|
RefPtr<IDBTransaction> transaction =
|
|
IDBTransaction::CreateVersionChange(mDatabase,
|
|
actor,
|
|
request,
|
|
aNextObjectStoreId,
|
|
aNextIndexId);
|
|
if (NS_WARN_IF(!transaction)) {
|
|
// 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();
|
|
|
|
actor->SetDOMTransaction(transaction);
|
|
|
|
mDatabase->EnterSetVersionTransaction(aRequestedVersion);
|
|
|
|
request->SetTransaction(transaction);
|
|
|
|
nsCOMPtr<nsIDOMEvent> upgradeNeededEvent =
|
|
IDBVersionChangeEvent::Create(request,
|
|
nsDependentString(kUpgradeNeededEventType),
|
|
aCurrentVersion,
|
|
aRequestedVersion);
|
|
MOZ_ASSERT(upgradeNeededEvent);
|
|
|
|
ResultHelper helper(request, transaction, mDatabase);
|
|
|
|
DispatchSuccessEvent(&helper, upgradeNeededEvent);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::DeallocPBackgroundIDBVersionChangeTransactionChild(
|
|
PBackgroundIDBVersionChangeTransactionChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
PBackgroundMutableFileChild*
|
|
BackgroundDatabaseChild::AllocPBackgroundMutableFileChild(const nsString& aName,
|
|
const nsString& aType)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
#ifdef DEBUG
|
|
nsCOMPtr<nsIThread> owningThread = do_QueryInterface(OwningThread());
|
|
|
|
PRThread* owningPRThread;
|
|
owningThread->GetPRThread(&owningPRThread);
|
|
#endif
|
|
|
|
return new BackgroundMutableFileChild(DEBUGONLY(owningPRThread,)
|
|
aName,
|
|
aType);
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::DeallocPBackgroundMutableFileChild(
|
|
PBackgroundMutableFileChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundMutableFileChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
|
|
const NullableVersion& aNewVersion)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (!mDatabase || mDatabase->IsClosed()) {
|
|
return true;
|
|
}
|
|
|
|
RefPtr<IDBDatabase> kungFuDeathGrip = mDatabase;
|
|
|
|
// Handle bfcache'd windows.
|
|
if (nsPIDOMWindow* owner = mDatabase->GetOwner()) {
|
|
// The database must be closed if the window is already frozen.
|
|
bool shouldAbortAndClose = owner->IsFrozen();
|
|
|
|
// Anything in the bfcache has to be evicted and then we have to close the
|
|
// database also.
|
|
if (nsCOMPtr<nsIDocument> doc = owner->GetExtantDoc()) {
|
|
if (nsCOMPtr<nsIBFCacheEntry> bfCacheEntry = doc->GetBFCacheEntry()) {
|
|
bfCacheEntry->RemoveFromBFCacheSync();
|
|
shouldAbortAndClose = true;
|
|
}
|
|
}
|
|
|
|
if (shouldAbortAndClose) {
|
|
// Invalidate() doesn't close the database in the parent, so we have
|
|
// to call Close() and AbortTransactions() manually.
|
|
mDatabase->AbortTransactions(/* aShouldWarn */ false);
|
|
mDatabase->Close();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Otherwise fire a versionchange event.
|
|
const nsDependentString type(kVersionChangeEventType);
|
|
|
|
nsCOMPtr<nsIDOMEvent> versionChangeEvent;
|
|
|
|
switch (aNewVersion.type()) {
|
|
case NullableVersion::Tnull_t:
|
|
versionChangeEvent =
|
|
IDBVersionChangeEvent::Create(mDatabase, type, aOldVersion);
|
|
MOZ_ASSERT(versionChangeEvent);
|
|
break;
|
|
|
|
case NullableVersion::Tuint64_t:
|
|
versionChangeEvent =
|
|
IDBVersionChangeEvent::Create(mDatabase,
|
|
type,
|
|
aOldVersion,
|
|
aNewVersion.get_uint64_t());
|
|
MOZ_ASSERT(versionChangeEvent);
|
|
break;
|
|
|
|
default:
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child : Firing \"versionchange\" event",
|
|
"IndexedDB %s: C: IDBDatabase \"versionchange\" event",
|
|
IDB_LOG_ID_STRING());
|
|
|
|
bool dummy;
|
|
if (NS_FAILED(mDatabase->DispatchEvent(versionChangeEvent, &dummy))) {
|
|
NS_WARNING("Failed to dispatch event!");
|
|
}
|
|
|
|
if (!mDatabase->IsClosed()) {
|
|
SendBlocked();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseChild::RecvInvalidate()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (mDatabase) {
|
|
mDatabase->Invalidate();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundDatabaseRequestChild
|
|
******************************************************************************/
|
|
|
|
BackgroundDatabaseRequestChild::BackgroundDatabaseRequestChild(
|
|
IDBDatabase* aDatabase,
|
|
IDBRequest* aRequest)
|
|
: BackgroundRequestChildBase(aRequest)
|
|
, mDatabase(aDatabase)
|
|
{
|
|
// Can't assert owning thread here because IPDL has not yet set our manager!
|
|
MOZ_ASSERT(aDatabase);
|
|
aDatabase->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aRequest);
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundDatabaseRequestChild);
|
|
}
|
|
|
|
BackgroundDatabaseRequestChild::~BackgroundDatabaseRequestChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundDatabaseRequestChild);
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseRequestChild::HandleResponse(nsresult aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(NS_FAILED(aResponse));
|
|
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
|
|
|
|
mRequest->Reset();
|
|
|
|
DispatchErrorEvent(mRequest, aResponse);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseRequestChild::HandleResponse(
|
|
const CreateFileRequestResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
mRequest->Reset();
|
|
|
|
auto mutableFileActor =
|
|
static_cast<BackgroundMutableFileChild*>(aResponse.mutableFileChild());
|
|
MOZ_ASSERT(mutableFileActor);
|
|
|
|
mutableFileActor->EnsureDOMObject();
|
|
|
|
auto mutableFile =
|
|
static_cast<IDBMutableFile*>(mutableFileActor->GetDOMObject());
|
|
MOZ_ASSERT(mutableFile);
|
|
|
|
ResultHelper helper(mRequest, nullptr, mutableFile);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
|
|
mutableFileActor->ReleaseDOMObject();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
BackgroundDatabaseRequestChild::Recv__delete__(
|
|
const DatabaseRequestResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
|
|
switch (aResponse.type()) {
|
|
case DatabaseRequestResponse::Tnsresult:
|
|
return HandleResponse(aResponse.get_nsresult());
|
|
|
|
case DatabaseRequestResponse::TCreateFileRequestResponse:
|
|
return HandleResponse(aResponse.get_CreateFileRequestResponse());
|
|
|
|
default:
|
|
MOZ_CRASH("Unknown response type!");
|
|
}
|
|
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundTransactionBase
|
|
******************************************************************************/
|
|
|
|
BackgroundTransactionBase::BackgroundTransactionBase()
|
|
: mTransaction(nullptr)
|
|
{
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundTransactionBase);
|
|
}
|
|
|
|
BackgroundTransactionBase::BackgroundTransactionBase(
|
|
IDBTransaction* aTransaction)
|
|
: mTemporaryStrongTransaction(aTransaction)
|
|
, mTransaction(aTransaction)
|
|
{
|
|
MOZ_ASSERT(aTransaction);
|
|
aTransaction->AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundTransactionBase);
|
|
}
|
|
|
|
BackgroundTransactionBase::~BackgroundTransactionBase()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundTransactionBase);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
BackgroundTransactionBase::AssertIsOnOwningThread() const
|
|
{
|
|
MOZ_ASSERT(mTransaction);
|
|
mTransaction->AssertIsOnOwningThread();
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
void
|
|
BackgroundTransactionBase::NoteActorDestroyed()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT_IF(mTemporaryStrongTransaction, mTransaction);
|
|
|
|
if (mTransaction) {
|
|
mTransaction->ClearBackgroundActor();
|
|
|
|
// Normally this would be DEBUG-only but NoteActorDestroyed is also called
|
|
// from SendDeleteMeInternal. In that case we're going to receive an actual
|
|
// ActorDestroy call later and we don't want to touch a dead object.
|
|
mTemporaryStrongTransaction = nullptr;
|
|
mTransaction = nullptr;
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundTransactionBase::SetDOMTransaction(IDBTransaction* aTransaction)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aTransaction);
|
|
aTransaction->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(!mTemporaryStrongTransaction);
|
|
MOZ_ASSERT(!mTransaction);
|
|
|
|
mTemporaryStrongTransaction = aTransaction;
|
|
mTransaction = aTransaction;
|
|
}
|
|
|
|
void
|
|
BackgroundTransactionBase::NoteComplete()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT_IF(mTransaction, mTemporaryStrongTransaction);
|
|
|
|
mTemporaryStrongTransaction = nullptr;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundTransactionChild
|
|
******************************************************************************/
|
|
|
|
BackgroundTransactionChild::BackgroundTransactionChild(
|
|
IDBTransaction* aTransaction)
|
|
: BackgroundTransactionBase(aTransaction)
|
|
{
|
|
MOZ_ASSERT(aTransaction);
|
|
aTransaction->AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundTransactionChild);
|
|
}
|
|
|
|
BackgroundTransactionChild::~BackgroundTransactionChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundTransactionChild);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
BackgroundTransactionChild::AssertIsOnOwningThread() const
|
|
{
|
|
static_cast<BackgroundDatabaseChild*>(Manager())->AssertIsOnOwningThread();
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
void
|
|
BackgroundTransactionChild::SendDeleteMeInternal()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (mTransaction) {
|
|
NoteActorDestroyed();
|
|
|
|
MOZ_ALWAYS_TRUE(PBackgroundIDBTransactionChild::SendDeleteMe());
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundTransactionChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
NoteActorDestroyed();
|
|
}
|
|
|
|
bool
|
|
BackgroundTransactionChild::RecvComplete(const nsresult& aResult)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
mTransaction->FireCompleteOrAbortEvents(aResult);
|
|
|
|
NoteComplete();
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBRequestChild*
|
|
BackgroundTransactionChild::AllocPBackgroundIDBRequestChild(
|
|
const RequestParams& aParams)
|
|
{
|
|
MOZ_CRASH("PBackgroundIDBRequestChild actors should be manually "
|
|
"constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundTransactionChild::DeallocPBackgroundIDBRequestChild(
|
|
PBackgroundIDBRequestChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundRequestChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBCursorChild*
|
|
BackgroundTransactionChild::AllocPBackgroundIDBCursorChild(
|
|
const OpenCursorParams& aParams)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_CRASH("PBackgroundIDBCursorChild actors should be manually constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundTransactionChild::DeallocPBackgroundIDBCursorChild(
|
|
PBackgroundIDBCursorChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundCursorChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundVersionChangeTransactionChild
|
|
******************************************************************************/
|
|
|
|
BackgroundVersionChangeTransactionChild::
|
|
BackgroundVersionChangeTransactionChild(IDBOpenDBRequest* aOpenDBRequest)
|
|
: mOpenDBRequest(aOpenDBRequest)
|
|
{
|
|
MOZ_ASSERT(aOpenDBRequest);
|
|
aOpenDBRequest->AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundVersionChangeTransactionChild);
|
|
}
|
|
|
|
BackgroundVersionChangeTransactionChild::
|
|
~BackgroundVersionChangeTransactionChild()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundVersionChangeTransactionChild);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
BackgroundVersionChangeTransactionChild::AssertIsOnOwningThread() const
|
|
{
|
|
static_cast<BackgroundDatabaseChild*>(Manager())->AssertIsOnOwningThread();
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
void
|
|
BackgroundVersionChangeTransactionChild::SendDeleteMeInternal(
|
|
bool aFailedConstructor)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
if (mTransaction || aFailedConstructor) {
|
|
NoteActorDestroyed();
|
|
|
|
MOZ_ALWAYS_TRUE(PBackgroundIDBVersionChangeTransactionChild::
|
|
SendDeleteMe());
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundVersionChangeTransactionChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
mOpenDBRequest = nullptr;
|
|
|
|
NoteActorDestroyed();
|
|
}
|
|
|
|
bool
|
|
BackgroundVersionChangeTransactionChild::RecvComplete(const nsresult& aResult)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (!mTransaction) {
|
|
return true;
|
|
}
|
|
|
|
MOZ_ASSERT(mOpenDBRequest);
|
|
|
|
IDBDatabase* database = mTransaction->Database();
|
|
MOZ_ASSERT(database);
|
|
|
|
database->ExitSetVersionTransaction();
|
|
|
|
if (NS_FAILED(aResult)) {
|
|
database->Close();
|
|
}
|
|
|
|
mTransaction->FireCompleteOrAbortEvents(aResult);
|
|
|
|
mOpenDBRequest->SetTransaction(nullptr);
|
|
mOpenDBRequest = nullptr;
|
|
|
|
NoteComplete();
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBRequestChild*
|
|
BackgroundVersionChangeTransactionChild::AllocPBackgroundIDBRequestChild(
|
|
const RequestParams& aParams)
|
|
{
|
|
MOZ_CRASH("PBackgroundIDBRequestChild actors should be manually "
|
|
"constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBRequestChild(
|
|
PBackgroundIDBRequestChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundRequestChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
PBackgroundIDBCursorChild*
|
|
BackgroundVersionChangeTransactionChild::AllocPBackgroundIDBCursorChild(
|
|
const OpenCursorParams& aParams)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_CRASH("PBackgroundIDBCursorChild actors should be manually constructed!");
|
|
}
|
|
|
|
bool
|
|
BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBCursorChild(
|
|
PBackgroundIDBCursorChild* aActor)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
|
|
delete static_cast<BackgroundCursorChild*>(aActor);
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundMutableFileChild
|
|
******************************************************************************/
|
|
|
|
BackgroundMutableFileChild::BackgroundMutableFileChild(
|
|
DEBUGONLY(PRThread* aOwningThread,)
|
|
const nsAString& aName,
|
|
const nsAString& aType)
|
|
: BackgroundMutableFileChildBase(DEBUGONLY(aOwningThread))
|
|
, mName(aName)
|
|
, mType(aType)
|
|
{
|
|
// Can't assert owning thread here because IPDL has not yet set our manager!
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundMutableFileChild);
|
|
}
|
|
|
|
BackgroundMutableFileChild::~BackgroundMutableFileChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundMutableFileChild);
|
|
}
|
|
|
|
already_AddRefed<MutableFileBase>
|
|
BackgroundMutableFileChild::CreateMutableFile()
|
|
{
|
|
auto database =
|
|
static_cast<BackgroundDatabaseChild*>(Manager())->GetDOMObject();
|
|
MOZ_ASSERT(database);
|
|
|
|
RefPtr<IDBMutableFile> mutableFile =
|
|
new IDBMutableFile(database, this, mName, mType);
|
|
|
|
return mutableFile.forget();
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundRequestChild
|
|
******************************************************************************/
|
|
|
|
BackgroundRequestChild::BackgroundRequestChild(IDBRequest* aRequest)
|
|
: BackgroundRequestChildBase(aRequest)
|
|
, mTransaction(aRequest->GetTransaction())
|
|
{
|
|
MOZ_ASSERT(mTransaction);
|
|
mTransaction->AssertIsOnOwningThread();
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundRequestChild);
|
|
}
|
|
|
|
BackgroundRequestChild::~BackgroundRequestChild()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(!mTransaction);
|
|
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChild);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(nsresult aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(NS_FAILED(aResponse));
|
|
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
DispatchErrorEvent(mRequest, aResponse, mTransaction);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(const Key& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &aResponse);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(const nsTArray<Key>& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &aResponse);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(
|
|
const SerializedStructuredCloneReadInfo& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
// XXX Fix this somehow...
|
|
auto& serializedCloneInfo =
|
|
const_cast<SerializedStructuredCloneReadInfo&>(aResponse);
|
|
|
|
StructuredCloneReadInfo cloneReadInfo(Move(serializedCloneInfo));
|
|
|
|
ConvertActorsToBlobs(mTransaction->Database(),
|
|
aResponse,
|
|
cloneReadInfo.mFiles);
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &cloneReadInfo);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(
|
|
const nsTArray<SerializedStructuredCloneReadInfo>& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
nsTArray<StructuredCloneReadInfo> cloneReadInfos;
|
|
|
|
if (!aResponse.IsEmpty()) {
|
|
const uint32_t count = aResponse.Length();
|
|
|
|
cloneReadInfos.SetCapacity(count);
|
|
|
|
IDBDatabase* database = mTransaction->Database();
|
|
|
|
for (uint32_t index = 0; index < count; index++) {
|
|
// XXX Fix this somehow...
|
|
auto& serializedCloneInfo =
|
|
const_cast<SerializedStructuredCloneReadInfo&>(aResponse[index]);
|
|
|
|
StructuredCloneReadInfo* cloneReadInfo = cloneReadInfos.AppendElement();
|
|
|
|
// Get the files
|
|
nsTArray<StructuredCloneFile> files;
|
|
ConvertActorsToBlobs(database, serializedCloneInfo, files);
|
|
|
|
// Move relevant data into the cloneReadInfo
|
|
*cloneReadInfo = Move(serializedCloneInfo);
|
|
cloneReadInfo->mFiles = Move(files);
|
|
}
|
|
}
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &cloneReadInfos);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(JS::Handle<JS::Value> aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &aResponse);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::HandleResponse(uint64_t aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
JS::Value response(JS::NumberValue(aResponse));
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &response);
|
|
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundRequestChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (mTransaction) {
|
|
mTransaction->AssertIsOnOwningThread();
|
|
|
|
mTransaction->OnRequestFinished(/* aActorDestroyedNormally */
|
|
aWhy == Deletion);
|
|
#ifdef DEBUG
|
|
mTransaction = nullptr;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool
|
|
BackgroundRequestChild::Recv__delete__(const RequestResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (mTransaction->IsAborted()) {
|
|
// Always fire an "error" event with ABORT_ERR if the transaction was
|
|
// aborted, even if the request succeeded or failed with another error.
|
|
HandleResponse(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
|
|
} else {
|
|
switch (aResponse.type()) {
|
|
case RequestResponse::Tnsresult:
|
|
HandleResponse(aResponse.get_nsresult());
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreAddResponse:
|
|
HandleResponse(aResponse.get_ObjectStoreAddResponse().key());
|
|
break;
|
|
|
|
case RequestResponse::TObjectStorePutResponse:
|
|
HandleResponse(aResponse.get_ObjectStorePutResponse().key());
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreGetResponse:
|
|
HandleResponse(aResponse.get_ObjectStoreGetResponse().cloneInfo());
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreGetAllResponse:
|
|
HandleResponse(aResponse.get_ObjectStoreGetAllResponse().cloneInfos());
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreGetAllKeysResponse:
|
|
HandleResponse(aResponse.get_ObjectStoreGetAllKeysResponse().keys());
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreDeleteResponse:
|
|
HandleResponse(JS::UndefinedHandleValue);
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreClearResponse:
|
|
HandleResponse(JS::UndefinedHandleValue);
|
|
break;
|
|
|
|
case RequestResponse::TObjectStoreCountResponse:
|
|
HandleResponse(aResponse.get_ObjectStoreCountResponse().count());
|
|
break;
|
|
|
|
case RequestResponse::TIndexGetResponse:
|
|
HandleResponse(aResponse.get_IndexGetResponse().cloneInfo());
|
|
break;
|
|
|
|
case RequestResponse::TIndexGetKeyResponse:
|
|
HandleResponse(aResponse.get_IndexGetKeyResponse().key());
|
|
break;
|
|
|
|
case RequestResponse::TIndexGetAllResponse:
|
|
HandleResponse(aResponse.get_IndexGetAllResponse().cloneInfos());
|
|
break;
|
|
|
|
case RequestResponse::TIndexGetAllKeysResponse:
|
|
HandleResponse(aResponse.get_IndexGetAllKeysResponse().keys());
|
|
break;
|
|
|
|
case RequestResponse::TIndexCountResponse:
|
|
HandleResponse(aResponse.get_IndexCountResponse().count());
|
|
break;
|
|
|
|
default:
|
|
MOZ_CRASH("Unknown response type!");
|
|
}
|
|
}
|
|
|
|
mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true);
|
|
|
|
// Null this out so that we don't try to call OnRequestFinished() again in
|
|
// ActorDestroy.
|
|
mTransaction = nullptr;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* BackgroundCursorChild
|
|
******************************************************************************/
|
|
|
|
// Does not need to be threadsafe since this only runs on one thread, but
|
|
// inheriting from CancelableRunnable is easy.
|
|
class BackgroundCursorChild::DelayedActionRunnable final
|
|
: public CancelableRunnable
|
|
{
|
|
using ActionFunc = void (BackgroundCursorChild::*)();
|
|
|
|
BackgroundCursorChild* mActor;
|
|
RefPtr<IDBRequest> mRequest;
|
|
ActionFunc mActionFunc;
|
|
|
|
public:
|
|
explicit
|
|
DelayedActionRunnable(BackgroundCursorChild* aActor, ActionFunc aActionFunc)
|
|
: mActor(aActor)
|
|
, mRequest(aActor->mRequest)
|
|
, mActionFunc(aActionFunc)
|
|
{
|
|
MOZ_ASSERT(aActor);
|
|
aActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mActionFunc);
|
|
}
|
|
|
|
private:
|
|
~DelayedActionRunnable()
|
|
{ }
|
|
|
|
NS_DECL_NSIRUNNABLE
|
|
nsresult Cancel() override;
|
|
};
|
|
|
|
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
|
|
IDBObjectStore* aObjectStore,
|
|
Direction aDirection)
|
|
: mRequest(aRequest)
|
|
, mTransaction(aRequest->GetTransaction())
|
|
, mObjectStore(aObjectStore)
|
|
, mIndex(nullptr)
|
|
, mCursor(nullptr)
|
|
, mStrongRequest(aRequest)
|
|
, mDirection(aDirection)
|
|
{
|
|
MOZ_ASSERT(aObjectStore);
|
|
aObjectStore->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild);
|
|
|
|
#ifdef DEBUG
|
|
mOwningThread = PR_GetCurrentThread();
|
|
MOZ_ASSERT(mOwningThread);
|
|
#endif
|
|
}
|
|
|
|
BackgroundCursorChild::BackgroundCursorChild(IDBRequest* aRequest,
|
|
IDBIndex* aIndex,
|
|
Direction aDirection)
|
|
: mRequest(aRequest)
|
|
, mTransaction(aRequest->GetTransaction())
|
|
, mObjectStore(nullptr)
|
|
, mIndex(aIndex)
|
|
, mCursor(nullptr)
|
|
, mStrongRequest(aRequest)
|
|
, mDirection(aDirection)
|
|
{
|
|
MOZ_ASSERT(aIndex);
|
|
aIndex->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild);
|
|
|
|
#ifdef DEBUG
|
|
mOwningThread = PR_GetCurrentThread();
|
|
MOZ_ASSERT(mOwningThread);
|
|
#endif
|
|
}
|
|
|
|
BackgroundCursorChild::~BackgroundCursorChild()
|
|
{
|
|
MOZ_COUNT_DTOR(indexedDB::BackgroundCursorChild);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
BackgroundCursorChild::AssertIsOnOwningThread() const
|
|
{
|
|
MOZ_ASSERT(mOwningThread == PR_GetCurrentThread());
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
void
|
|
BackgroundCursorChild::SendContinueInternal(const CursorRequestParams& aParams,
|
|
const Key& aKey)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mCursor);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
// Make sure all our DOM objects stay alive.
|
|
mStrongCursor = mCursor;
|
|
|
|
MOZ_ASSERT(mRequest->ReadyState() == IDBRequestReadyState::Done);
|
|
mRequest->Reset();
|
|
|
|
mTransaction->OnNewRequest();
|
|
|
|
CursorRequestParams params = aParams;
|
|
Key key = aKey;
|
|
|
|
switch (params.type()) {
|
|
case CursorRequestParams::TContinueParams: {
|
|
if (key.IsUnset()) {
|
|
break;
|
|
}
|
|
while (!mCachedResponses.IsEmpty()) {
|
|
if (mCachedResponses[0].mKey == key) {
|
|
break;
|
|
}
|
|
mCachedResponses.RemoveElementAt(0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CursorRequestParams::TAdvanceParams: {
|
|
uint32_t& advanceCount = params.get_AdvanceParams().count();
|
|
while (advanceCount > 1 && !mCachedResponses.IsEmpty()) {
|
|
key = mCachedResponses[0].mKey;
|
|
mCachedResponses.RemoveElementAt(0);
|
|
--advanceCount;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
|
|
if (!mCachedResponses.IsEmpty()) {
|
|
nsCOMPtr<nsIRunnable> continueRunnable = new DelayedActionRunnable(
|
|
this, &BackgroundCursorChild::SendDelayedContinueInternal);
|
|
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(continueRunnable));
|
|
} else {
|
|
MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(params, key));
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::SendDelayedContinueInternal()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mCursor);
|
|
MOZ_ASSERT(mStrongCursor);
|
|
MOZ_ASSERT(!mCachedResponses.IsEmpty());
|
|
|
|
RefPtr<IDBCursor> cursor;
|
|
mStrongCursor.swap(cursor);
|
|
|
|
auto& item = mCachedResponses[0];
|
|
mCursor->Reset(Move(item.mKey), Move(item.mCloneInfo));
|
|
mCachedResponses.RemoveElementAt(0);
|
|
|
|
ResultHelper helper(mRequest, mTransaction, mCursor);
|
|
DispatchSuccessEvent(&helper);
|
|
|
|
mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true);
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::SendDeleteMeInternal()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
mRequest = nullptr;
|
|
mTransaction = nullptr;
|
|
mObjectStore = nullptr;
|
|
mIndex = nullptr;
|
|
|
|
if (mCursor) {
|
|
mCursor->ClearBackgroundActor();
|
|
mCursor = nullptr;
|
|
|
|
MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendDeleteMe());
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::InvalidateCachedResponses()
|
|
{
|
|
AssertIsOnOwningThread();
|
|
|
|
mCachedResponses.Clear();
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::HandleResponse(nsresult aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(NS_FAILED(aResponse));
|
|
MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
DispatchErrorEvent(mRequest, aResponse, mTransaction);
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::HandleResponse(const void_t& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
if (mCursor) {
|
|
mCursor->Reset();
|
|
}
|
|
|
|
ResultHelper helper(mRequest, mTransaction, &JS::NullHandleValue);
|
|
DispatchSuccessEvent(&helper);
|
|
|
|
if (!mCursor) {
|
|
nsCOMPtr<nsIRunnable> deleteRunnable = new DelayedActionRunnable(
|
|
this, &BackgroundCursorChild::SendDeleteMeInternal);
|
|
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(deleteRunnable));
|
|
}
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::HandleResponse(
|
|
const nsTArray<ObjectStoreCursorResponse>& aResponses)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mObjectStore);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
MOZ_ASSERT(aResponses.Length() == 1);
|
|
|
|
// XXX Fix this somehow...
|
|
auto& responses =
|
|
const_cast<nsTArray<ObjectStoreCursorResponse>&>(aResponses);
|
|
|
|
for (ObjectStoreCursorResponse& response : responses) {
|
|
StructuredCloneReadInfo cloneReadInfo(Move(response.cloneInfo()));
|
|
cloneReadInfo.mDatabase = mTransaction->Database();
|
|
|
|
ConvertActorsToBlobs(mTransaction->Database(),
|
|
response.cloneInfo(),
|
|
cloneReadInfo.mFiles);
|
|
|
|
RefPtr<IDBCursor> newCursor;
|
|
|
|
if (mCursor) {
|
|
if (mCursor->IsContinueCalled()) {
|
|
mCursor->Reset(Move(response.key()), Move(cloneReadInfo));
|
|
} else {
|
|
CachedResponse cachedResponse;
|
|
cachedResponse.mKey = Move(response.key());
|
|
cachedResponse.mCloneInfo = Move(cloneReadInfo);
|
|
mCachedResponses.AppendElement(Move(cachedResponse));
|
|
}
|
|
} else {
|
|
newCursor = IDBCursor::Create(this,
|
|
Move(response.key()),
|
|
Move(cloneReadInfo));
|
|
mCursor = newCursor;
|
|
}
|
|
}
|
|
|
|
ResultHelper helper(mRequest, mTransaction, mCursor);
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::HandleResponse(
|
|
const ObjectStoreKeyCursorResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mObjectStore);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
// XXX Fix this somehow...
|
|
auto& response = const_cast<ObjectStoreKeyCursorResponse&>(aResponse);
|
|
|
|
RefPtr<IDBCursor> newCursor;
|
|
|
|
if (mCursor) {
|
|
mCursor->Reset(Move(response.key()));
|
|
} else {
|
|
newCursor = IDBCursor::Create(this, Move(response.key()));
|
|
mCursor = newCursor;
|
|
}
|
|
|
|
ResultHelper helper(mRequest, mTransaction, mCursor);
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::HandleResponse(const IndexCursorResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mIndex);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
// XXX Fix this somehow...
|
|
auto& response = const_cast<IndexCursorResponse&>(aResponse);
|
|
|
|
StructuredCloneReadInfo cloneReadInfo(Move(response.cloneInfo()));
|
|
cloneReadInfo.mDatabase = mTransaction->Database();
|
|
|
|
ConvertActorsToBlobs(mTransaction->Database(),
|
|
response.cloneInfo(),
|
|
cloneReadInfo.mFiles);
|
|
|
|
RefPtr<IDBCursor> newCursor;
|
|
|
|
if (mCursor) {
|
|
mCursor->Reset(Move(response.key()),
|
|
Move(response.sortKey()),
|
|
Move(response.objectKey()),
|
|
Move(cloneReadInfo));
|
|
} else {
|
|
newCursor = IDBCursor::Create(this,
|
|
Move(response.key()),
|
|
Move(response.sortKey()),
|
|
Move(response.objectKey()),
|
|
Move(cloneReadInfo));
|
|
mCursor = newCursor;
|
|
}
|
|
|
|
ResultHelper helper(mRequest, mTransaction, mCursor);
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::HandleResponse(const IndexKeyCursorResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT(mIndex);
|
|
MOZ_ASSERT(!mStrongRequest);
|
|
MOZ_ASSERT(!mStrongCursor);
|
|
|
|
// XXX Fix this somehow...
|
|
auto& response = const_cast<IndexKeyCursorResponse&>(aResponse);
|
|
|
|
RefPtr<IDBCursor> newCursor;
|
|
|
|
if (mCursor) {
|
|
mCursor->Reset(Move(response.key()),
|
|
Move(response.sortKey()),
|
|
Move(response.objectKey()));
|
|
} else {
|
|
newCursor = IDBCursor::Create(this,
|
|
Move(response.key()),
|
|
Move(response.sortKey()),
|
|
Move(response.objectKey()));
|
|
mCursor = newCursor;
|
|
}
|
|
|
|
ResultHelper helper(mRequest, mTransaction, mCursor);
|
|
DispatchSuccessEvent(&helper);
|
|
}
|
|
|
|
void
|
|
BackgroundCursorChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT_IF(aWhy == Deletion, !mStrongRequest);
|
|
MOZ_ASSERT_IF(aWhy == Deletion, !mStrongCursor);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
if (mStrongRequest && !mStrongCursor && mTransaction) {
|
|
mTransaction->OnRequestFinished(/* aActorDestroyedNormally */
|
|
aWhy == Deletion);
|
|
}
|
|
|
|
if (mCursor) {
|
|
mCursor->ClearBackgroundActor();
|
|
#ifdef DEBUG
|
|
mCursor = nullptr;
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
mRequest = nullptr;
|
|
mTransaction = nullptr;
|
|
mObjectStore = nullptr;
|
|
mIndex = nullptr;
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse)
|
|
{
|
|
AssertIsOnOwningThread();
|
|
MOZ_ASSERT(aResponse.type() != CursorResponse::T__None);
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mTransaction);
|
|
MOZ_ASSERT_IF(mCursor, mStrongCursor);
|
|
MOZ_ASSERT_IF(!mCursor, mStrongRequest);
|
|
|
|
MaybeCollectGarbageOnIPCMessage();
|
|
|
|
RefPtr<IDBRequest> request;
|
|
mStrongRequest.swap(request);
|
|
|
|
RefPtr<IDBCursor> cursor;
|
|
mStrongCursor.swap(cursor);
|
|
|
|
switch (aResponse.type()) {
|
|
case CursorResponse::Tnsresult:
|
|
HandleResponse(aResponse.get_nsresult());
|
|
break;
|
|
|
|
case CursorResponse::Tvoid_t:
|
|
HandleResponse(aResponse.get_void_t());
|
|
break;
|
|
|
|
case CursorResponse::TArrayOfObjectStoreCursorResponse:
|
|
HandleResponse(aResponse.get_ArrayOfObjectStoreCursorResponse());
|
|
break;
|
|
|
|
case CursorResponse::TObjectStoreKeyCursorResponse:
|
|
HandleResponse(aResponse.get_ObjectStoreKeyCursorResponse());
|
|
break;
|
|
|
|
case CursorResponse::TIndexCursorResponse:
|
|
HandleResponse(aResponse.get_IndexCursorResponse());
|
|
break;
|
|
|
|
case CursorResponse::TIndexKeyCursorResponse:
|
|
HandleResponse(aResponse.get_IndexKeyCursorResponse());
|
|
break;
|
|
|
|
default:
|
|
MOZ_CRASH("Should never get here!");
|
|
}
|
|
|
|
mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true);
|
|
|
|
return true;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
BackgroundCursorChild::
|
|
DelayedActionRunnable::Run()
|
|
{
|
|
MOZ_ASSERT(mActor);
|
|
mActor->AssertIsOnOwningThread();
|
|
MOZ_ASSERT(mRequest);
|
|
MOZ_ASSERT(mActionFunc);
|
|
|
|
(mActor->*mActionFunc)();
|
|
|
|
mActor = nullptr;
|
|
mRequest = nullptr;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
BackgroundCursorChild::
|
|
DelayedActionRunnable::Cancel()
|
|
{
|
|
if (NS_WARN_IF(!mActor)) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
// This must always run to clean up our state.
|
|
Run();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
BackgroundCursorChild::CachedResponse::CachedResponse()
|
|
{
|
|
}
|
|
|
|
BackgroundCursorChild::CachedResponse::CachedResponse(CachedResponse&& aOther)
|
|
: mKey(Move(aOther.mKey))
|
|
{
|
|
mCloneInfo = Move(aOther.mCloneInfo);
|
|
}
|
|
|
|
} // namespace indexedDB
|
|
} // namespace dom
|
|
} // namespace mozilla
|