tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IDBRequest.cpp (12528B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "IDBRequest.h"
      8 
      9 #include <utility>
     10 
     11 #include "BackgroundChildImpl.h"
     12 #include "IDBCursor.h"
     13 #include "IDBDatabase.h"
     14 #include "IDBEvents.h"
     15 #include "IDBFactory.h"
     16 #include "IDBIndex.h"
     17 #include "IDBObjectStore.h"
     18 #include "IDBTransaction.h"
     19 #include "IndexedDatabaseManager.h"
     20 #include "ReportInternalError.h"
     21 #include "ThreadLocal.h"
     22 #include "mozilla/ContentEvents.h"
     23 #include "mozilla/ErrorResult.h"
     24 #include "mozilla/EventDispatcher.h"
     25 #include "mozilla/HoldDropJSObjects.h"
     26 #include "mozilla/dom/DOMException.h"
     27 #include "mozilla/dom/ErrorEventBinding.h"
     28 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
     29 #include "mozilla/dom/ScriptSettings.h"
     30 #include "mozilla/dom/WorkerPrivate.h"
     31 #include "mozilla/dom/WorkerRef.h"
     32 #include "nsCOMPtr.h"
     33 #include "nsContentUtils.h"
     34 #include "nsIGlobalObject.h"
     35 #include "nsIScriptContext.h"
     36 #include "nsJSUtils.h"
     37 #include "nsString.h"
     38 
     39 namespace mozilla::dom {
     40 
     41 using namespace mozilla::dom::indexedDB;
     42 using namespace mozilla::ipc;
     43 
     44 IDBRequest::IDBRequest(IDBDatabase* aDatabase)
     45    : DOMEventTargetHelper(aDatabase),
     46      mLoggingSerialNumber(0),
     47      mHaveResultOrErrorCode(false) {
     48  MOZ_ASSERT(aDatabase);
     49  aDatabase->AssertIsOnOwningThread();
     50 
     51  InitMembers();
     52 }
     53 
     54 IDBRequest::IDBRequest(nsIGlobalObject* aGlobal)
     55    : DOMEventTargetHelper(aGlobal),
     56      mLoggingSerialNumber(0),
     57      mHaveResultOrErrorCode(false) {
     58  InitMembers();
     59 }
     60 
     61 IDBRequest::~IDBRequest() {
     62  AssertIsOnOwningThread();
     63  mozilla::DropJSObjects(this);
     64 }
     65 
     66 void IDBRequest::InitMembers() {
     67  AssertIsOnOwningThread();
     68 
     69  mResultVal.setUndefined();
     70  mLoggingSerialNumber = NextSerialNumber();
     71  mErrorCode = NS_OK;
     72  mHaveResultOrErrorCode = false;
     73 }
     74 
     75 // static
     76 MovingNotNull<RefPtr<IDBRequest>> IDBRequest::Create(
     77    JSContext* aCx, IDBDatabase* aDatabase,
     78    SafeRefPtr<IDBTransaction> aTransaction) {
     79  MOZ_ASSERT(aCx);
     80  MOZ_ASSERT(aDatabase);
     81  aDatabase->AssertIsOnOwningThread();
     82 
     83  RefPtr<IDBRequest> request = new IDBRequest(aDatabase);
     84  request->mCallerLocation = JSCallingLocation::Get(aCx);
     85 
     86  request->mTransaction = std::move(aTransaction);
     87 
     88  return WrapMovingNotNullUnchecked(std::move(request));
     89 }
     90 
     91 // static
     92 MovingNotNull<RefPtr<IDBRequest>> IDBRequest::Create(
     93    JSContext* aCx, IDBObjectStore* aSourceAsObjectStore,
     94    IDBDatabase* aDatabase, SafeRefPtr<IDBTransaction> aTransaction) {
     95  MOZ_ASSERT(aSourceAsObjectStore);
     96  aSourceAsObjectStore->AssertIsOnOwningThread();
     97 
     98  auto request =
     99      Create(aCx, aDatabase, std::move(aTransaction)).unwrapBasePtr();
    100 
    101  request->mSourceAsObjectStore = aSourceAsObjectStore;
    102 
    103  return WrapMovingNotNullUnchecked(std::move(request));
    104 }
    105 
    106 // static
    107 MovingNotNull<RefPtr<IDBRequest>> IDBRequest::Create(
    108    JSContext* aCx, IDBIndex* aSourceAsIndex, IDBDatabase* aDatabase,
    109    SafeRefPtr<IDBTransaction> aTransaction) {
    110  MOZ_ASSERT(aSourceAsIndex);
    111  aSourceAsIndex->AssertIsOnOwningThread();
    112 
    113  auto request =
    114      Create(aCx, aDatabase, std::move(aTransaction)).unwrapBasePtr();
    115 
    116  request->mSourceAsIndex = aSourceAsIndex;
    117 
    118  return WrapMovingNotNullUnchecked(std::move(request));
    119 }
    120 
    121 // static
    122 uint64_t IDBRequest::NextSerialNumber() {
    123  BackgroundChildImpl::ThreadLocal* threadLocal =
    124      BackgroundChildImpl::GetThreadLocalForCurrentThread();
    125  MOZ_ASSERT(threadLocal);
    126 
    127  const auto& idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
    128  MOZ_ASSERT(idbThreadLocal);
    129 
    130  return idbThreadLocal->NextRequestSN();
    131 }
    132 
    133 void IDBRequest::SetLoggingSerialNumber(uint64_t aLoggingSerialNumber) {
    134  AssertIsOnOwningThread();
    135  MOZ_ASSERT(aLoggingSerialNumber > mLoggingSerialNumber);
    136 
    137  mLoggingSerialNumber = aLoggingSerialNumber;
    138 }
    139 
    140 void IDBRequest::GetSource(
    141    Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const {
    142  AssertIsOnOwningThread();
    143 
    144  MOZ_ASSERT_IF(mSourceAsObjectStore, !mSourceAsIndex);
    145  MOZ_ASSERT_IF(mSourceAsIndex, !mSourceAsObjectStore);
    146  MOZ_ASSERT_IF(mSourceAsCursor, mSourceAsObjectStore || mSourceAsIndex);
    147 
    148  // Always check cursor first since cursor requests hold both the cursor and
    149  // the objectStore or index the cursor came from.
    150  if (mSourceAsCursor) {
    151    aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor;
    152  } else if (mSourceAsObjectStore) {
    153    aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore;
    154  } else if (mSourceAsIndex) {
    155    aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex;
    156  } else {
    157    aSource.SetNull();
    158  }
    159 }
    160 
    161 void IDBRequest::Reset() {
    162  AssertIsOnOwningThread();
    163 
    164  mResultVal.setUndefined();
    165 
    166  mHaveResultOrErrorCode = false;
    167  mError = nullptr;
    168 }
    169 
    170 void IDBRequest::SetError(nsresult aRv) {
    171  AssertIsOnOwningThread();
    172  MOZ_ASSERT(NS_FAILED(aRv));
    173  MOZ_ASSERT(NS_ERROR_GET_MODULE(aRv) == NS_ERROR_MODULE_DOM_INDEXEDDB);
    174  MOZ_ASSERT(!mError);
    175 
    176  mHaveResultOrErrorCode = true;
    177  mError = DOMException::Create(aRv);
    178  mErrorCode = aRv;
    179 
    180  mResultVal.setUndefined();
    181 }
    182 
    183 #ifdef DEBUG
    184 
    185 nsresult IDBRequest::GetErrorCode() const {
    186  AssertIsOnOwningThread();
    187  MOZ_ASSERT(mHaveResultOrErrorCode);
    188 
    189  return mErrorCode;
    190 }
    191 
    192 DOMException* IDBRequest::GetErrorAfterResult() const {
    193  AssertIsOnOwningThread();
    194  MOZ_ASSERT(mHaveResultOrErrorCode);
    195 
    196  return mError;
    197 }
    198 
    199 #endif  // DEBUG
    200 
    201 IDBRequestReadyState IDBRequest::ReadyState() const {
    202  AssertIsOnOwningThread();
    203 
    204  return IsPending() ? IDBRequestReadyState::Pending
    205                     : IDBRequestReadyState::Done;
    206 }
    207 
    208 void IDBRequest::SetSource(IDBCursor* aSource) {
    209  AssertIsOnOwningThread();
    210  MOZ_ASSERT(aSource);
    211  MOZ_ASSERT(mSourceAsObjectStore || mSourceAsIndex);
    212  MOZ_ASSERT(!mSourceAsCursor);
    213 
    214  mSourceAsCursor = aSource;
    215 }
    216 
    217 JSObject* IDBRequest::WrapObject(JSContext* aCx,
    218                                 JS::Handle<JSObject*> aGivenProto) {
    219  return IDBRequest_Binding::Wrap(aCx, this, aGivenProto);
    220 }
    221 
    222 void IDBRequest::GetResult(JS::MutableHandle<JS::Value> aResult,
    223                           ErrorResult& aRv) const {
    224  AssertIsOnOwningThread();
    225 
    226  if (!mHaveResultOrErrorCode) {
    227    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    228    return;
    229  }
    230 
    231  aResult.set(mResultVal);
    232 }
    233 
    234 DOMException* IDBRequest::GetError(ErrorResult& aRv) {
    235  AssertIsOnOwningThread();
    236 
    237  if (!mHaveResultOrErrorCode) {
    238    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    239    return nullptr;
    240  }
    241 
    242  return mError;
    243 }
    244 
    245 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
    246 
    247 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
    248                                                  DOMEventTargetHelper)
    249  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore)
    250  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex)
    251  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor)
    252  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
    253  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
    254 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    255 
    256 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
    257                                                DOMEventTargetHelper)
    258  mozilla::DropJSObjects(tmp);
    259  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore)
    260  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex)
    261  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor)
    262  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
    263  NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
    264 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    265 
    266 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, DOMEventTargetHelper)
    267  // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
    268  // DOMEventTargetHelper does it for us.
    269  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultVal)
    270 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    271 
    272 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBRequest)
    273  if (aIID.Equals(NS_GET_IID(mozilla::dom::detail::PrivateIDBRequest))) {
    274    foundInterface = static_cast<EventTarget*>(this);
    275  } else
    276 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
    277 
    278 NS_IMPL_ADDREF_INHERITED(IDBRequest, DOMEventTargetHelper)
    279 NS_IMPL_RELEASE_INHERITED(IDBRequest, DOMEventTargetHelper)
    280 
    281 void IDBRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
    282  AssertIsOnOwningThread();
    283 
    284  aVisitor.mCanHandle = true;
    285  aVisitor.SetParentTarget(mTransaction.unsafeGetRawPtr(), false);
    286 }
    287 
    288 IDBOpenDBRequest::IDBOpenDBRequest(SafeRefPtr<IDBFactory> aFactory,
    289                                   nsIGlobalObject* aGlobal)
    290    : IDBRequest(aGlobal),
    291      mFactory(std::move(aFactory)),
    292      mIncreasedActiveDatabaseCount(false) {
    293  AssertIsOnOwningThread();
    294  MOZ_ASSERT(mFactory);
    295  MOZ_ASSERT(aGlobal);
    296 }
    297 
    298 IDBOpenDBRequest::~IDBOpenDBRequest() {
    299  AssertIsOnOwningThread();
    300  MOZ_ASSERT(!mIncreasedActiveDatabaseCount);
    301 }
    302 
    303 // static
    304 RefPtr<IDBOpenDBRequest> IDBOpenDBRequest::Create(
    305    JSContext* aCx, SafeRefPtr<IDBFactory> aFactory, nsIGlobalObject* aGlobal) {
    306  MOZ_ASSERT(aFactory);
    307  aFactory->AssertIsOnOwningThread();
    308  MOZ_ASSERT(aGlobal);
    309 
    310  RefPtr<IDBOpenDBRequest> request =
    311      new IDBOpenDBRequest(std::move(aFactory), aGlobal);
    312  request->mCallerLocation = JSCallingLocation::Get(aCx);
    313 
    314  if (!NS_IsMainThread()) {
    315    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    316    MOZ_ASSERT(workerPrivate);
    317 
    318    workerPrivate->AssertIsOnWorkerThread();
    319 
    320    request->mWorkerRef =
    321        StrongWorkerRef::Create(workerPrivate, "IDBOpenDBRequest");
    322    if (NS_WARN_IF(!request->mWorkerRef)) {
    323      return nullptr;
    324    }
    325  }
    326 
    327  request->IncreaseActiveDatabaseCount();
    328 
    329  return request;
    330 }
    331 
    332 void IDBOpenDBRequest::SetTransaction(SafeRefPtr<IDBTransaction> aTransaction) {
    333  AssertIsOnOwningThread();
    334 
    335  MOZ_ASSERT(!aTransaction || !mTransaction);
    336 
    337  mTransaction = std::move(aTransaction);
    338 }
    339 
    340 void IDBOpenDBRequest::DispatchNonTransactionError(nsresult aErrorCode) {
    341  AssertIsOnOwningThread();
    342  MOZ_ASSERT(NS_FAILED(aErrorCode));
    343  MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_INDEXEDDB);
    344 
    345  // The actor failed to initiate, decrease the number of active IDBOpenRequests
    346  // here since NoteComplete won't be called.
    347  MaybeDecreaseActiveDatabaseCount();
    348 
    349  SetError(aErrorCode);
    350 
    351  // Make an error event and fire it at the target.
    352  auto event = CreateGenericEvent(this, nsDependentString(kErrorEventType),
    353                                  eDoesBubble, eCancelable);
    354 
    355  IgnoredErrorResult rv;
    356  DispatchEvent(*event, rv);
    357  if (rv.Failed()) {
    358    NS_WARNING("Failed to dispatch event!");
    359  }
    360 }
    361 
    362 void IDBOpenDBRequest::NoteComplete() {
    363  AssertIsOnOwningThread();
    364  MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerRef);
    365 
    366  // Normally, we decrease the number of active IDBOpenRequests here.
    367  MaybeDecreaseActiveDatabaseCount();
    368 
    369  // If we have a WorkerRef, then nulling this out will release the worker.
    370  mWorkerRef = nullptr;
    371 }
    372 
    373 void IDBOpenDBRequest::IncreaseActiveDatabaseCount() {
    374  AssertIsOnOwningThread();
    375  MOZ_ASSERT(!mIncreasedActiveDatabaseCount);
    376 
    377  // Increase the number of active IDBOpenRequests.
    378  // Note: We count here instead of the actor's ctor because the preemption
    379  // could happen at next JS interrupt but its BackgroundFactoryRequestChild
    380  // could be created asynchronously from IDBFactory::BackgroundCreateCallback
    381  // ::ActorCreated() if its PBackgroundChild is not created yet on this thread.
    382  mFactory->UpdateActiveDatabaseCount(1);
    383  mIncreasedActiveDatabaseCount = true;
    384 }
    385 
    386 void IDBOpenDBRequest::MaybeDecreaseActiveDatabaseCount() {
    387  AssertIsOnOwningThread();
    388 
    389  if (mIncreasedActiveDatabaseCount) {
    390    // Decrease the number of active IDBOpenRequests.
    391    mFactory->UpdateActiveDatabaseCount(-1);
    392    mIncreasedActiveDatabaseCount = false;
    393  }
    394 }
    395 
    396 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
    397 
    398 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest, IDBRequest)
    399  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
    400 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    401 
    402 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest, IDBRequest)
    403  // Don't unlink mFactory!
    404 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    405 
    406 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBOpenDBRequest)
    407 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
    408 
    409 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
    410 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
    411 
    412 JSObject* IDBOpenDBRequest::WrapObject(JSContext* aCx,
    413                                       JS::Handle<JSObject*> aGivenProto) {
    414  AssertIsOnOwningThread();
    415 
    416  return IDBOpenDBRequest_Binding::Wrap(aCx, this, aGivenProto);
    417 }
    418 
    419 }  // namespace mozilla::dom