dom/indexedDB/IDBRequest.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=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/. */
     7 #include "IDBRequest.h"
     9 #include "nsIScriptContext.h"
    11 #include "mozilla/ContentEvents.h"
    12 #include "mozilla/EventDispatcher.h"
    13 #include "mozilla/dom/ErrorEventBinding.h"
    14 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
    15 #include "mozilla/dom/UnionTypes.h"
    16 #include "nsComponentManagerUtils.h"
    17 #include "nsDOMClassInfoID.h"
    18 #include "nsDOMJSUtils.h"
    19 #include "nsContentUtils.h"
    20 #include "nsCxPusher.h"
    21 #include "nsJSUtils.h"
    22 #include "nsPIDOMWindow.h"
    23 #include "nsString.h"
    24 #include "nsThreadUtils.h"
    25 #include "nsWrapperCacheInlines.h"
    27 #include "AsyncConnectionHelper.h"
    28 #include "IDBCursor.h"
    29 #include "IDBEvents.h"
    30 #include "IDBFactory.h"
    31 #include "IDBIndex.h"
    32 #include "IDBObjectStore.h"
    33 #include "IDBTransaction.h"
    34 #include "ReportInternalError.h"
    36 namespace {
    38 #ifdef MOZ_ENABLE_PROFILER_SPS
    39 uint64_t gNextRequestSerialNumber = 1;
    40 #endif
    42 } // anonymous namespace
    44 USING_INDEXEDDB_NAMESPACE
    45 using mozilla::dom::OwningIDBObjectStoreOrIDBIndexOrIDBCursor;
    46 using mozilla::dom::ErrorEventInit;
    47 using namespace mozilla;
    49 IDBRequest::IDBRequest(IDBDatabase* aDatabase)
    50 : IDBWrapperCache(aDatabase),
    51   mResultVal(JSVAL_VOID),
    52   mActorParent(nullptr),
    53 #ifdef MOZ_ENABLE_PROFILER_SPS
    54   mSerialNumber(gNextRequestSerialNumber++),
    55 #endif
    56   mErrorCode(NS_OK),
    57   mLineNo(0),
    58   mHaveResultOrErrorCode(false)
    59 {
    60   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    61 }
    63 IDBRequest::IDBRequest(nsPIDOMWindow* aOwner)
    64 : IDBWrapperCache(aOwner),
    65   mResultVal(JSVAL_VOID),
    66   mActorParent(nullptr),
    67 #ifdef MOZ_ENABLE_PROFILER_SPS
    68   mSerialNumber(gNextRequestSerialNumber++),
    69 #endif
    70   mErrorCode(NS_OK),
    71   mLineNo(0),
    72   mHaveResultOrErrorCode(false)
    73 {
    74   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    75 }
    77 IDBRequest::~IDBRequest()
    78 {
    79   mResultVal = JSVAL_VOID;
    80   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    81 }
    83 // static
    84 already_AddRefed<IDBRequest>
    85 IDBRequest::Create(IDBDatabase* aDatabase,
    86                    IDBTransaction* aTransaction)
    87 {
    88   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    89   nsRefPtr<IDBRequest> request(new IDBRequest(aDatabase));
    91   request->mTransaction = aTransaction;
    92   request->SetScriptOwner(aDatabase->GetScriptOwner());
    94   if (!aDatabase->Factory()->FromIPC()) {
    95     request->CaptureCaller();
    96   }
    99   return request.forget();
   100 }
   102 // static
   103 already_AddRefed<IDBRequest>
   104 IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore,
   105                    IDBDatabase* aDatabase,
   106                    IDBTransaction* aTransaction)
   107 {
   108   nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
   110   request->mSourceAsObjectStore = aSourceAsObjectStore;
   112   return request.forget();
   113 }
   115 // static
   116 already_AddRefed<IDBRequest>
   117 IDBRequest::Create(IDBIndex* aSourceAsIndex,
   118                    IDBDatabase* aDatabase,
   119                    IDBTransaction* aTransaction)
   120 {
   121   nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction);
   123   request->mSourceAsIndex = aSourceAsIndex;
   125   return request.forget();
   126 }
   128 #ifdef DEBUG
   129 void
   130 IDBRequest::AssertSourceIsCorrect() const
   131 {
   132   // At most one of mSourceAs* is allowed to be non-null.  Check that by
   133   // summing the double negation of each one and asserting the sum is at most
   134   // 1.
   136   MOZ_ASSERT(!!mSourceAsObjectStore + !!mSourceAsIndex + !!mSourceAsCursor <= 1);
   137 }
   138 #endif
   140 void
   141 IDBRequest::GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
   142 {
   143   MOZ_ASSERT(NS_IsMainThread());
   145   AssertSourceIsCorrect();
   147   if (mSourceAsObjectStore) {
   148     aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore;
   149   } else if (mSourceAsIndex) {
   150     aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex;
   151   } else if (mSourceAsCursor) {
   152     aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor;
   153   } else {
   154     aSource.SetNull();
   155   }
   156 }
   158 void
   159 IDBRequest::Reset()
   160 {
   161   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   162   mResultVal = JSVAL_VOID;
   163   mHaveResultOrErrorCode = false;
   164   mError = nullptr;
   165 }
   167 nsresult
   168 IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
   169 {
   170   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   171   NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
   172   NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
   174   mHaveResultOrErrorCode = true;
   176   nsresult rv = aHelper->GetResultCode();
   178   // If the request failed then set the error code and return.
   179   if (NS_FAILED(rv)) {
   180     SetError(rv);
   181     return NS_OK;
   182   }
   184   // See if our window is still valid. If not then we're going to pretend that
   185   // we never completed.
   186   if (NS_FAILED(CheckInnerWindowCorrectness())) {
   187     return NS_OK;
   188   }
   190   // Otherwise we need to get the result from the helper.
   191   AutoPushJSContext cx(GetJSContext());
   192   if (!cx) {
   193     IDB_WARNING("Failed to get safe JSContext!");
   194     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   195     SetError(rv);
   196     return rv;
   197   }
   199   JS::Rooted<JSObject*> global(cx, IDBWrapperCache::GetParentObject());
   200   NS_ASSERTION(global, "This should never be null!");
   202   JSAutoCompartment ac(cx, global);
   203   AssertIsRooted();
   205   JS::Rooted<JS::Value> value(cx);
   206   rv = aHelper->GetSuccessResult(cx, &value);
   207   if (NS_FAILED(rv)) {
   208     NS_WARNING("GetSuccessResult failed!");
   209   }
   211   if (NS_SUCCEEDED(rv)) {
   212     mError = nullptr;
   213     mResultVal = value;
   214   }
   215   else {
   216     SetError(rv);
   217     mResultVal = JSVAL_VOID;
   218   }
   220   return rv;
   221 }
   223 void
   224 IDBRequest::NotifyHelperSentResultsToChildProcess(nsresult aRv)
   225 {
   226   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   227   NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
   228   NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
   230   // See if our window is still valid. If not then we're going to pretend that
   231   // we never completed.
   232   if (NS_FAILED(CheckInnerWindowCorrectness())) {
   233     return;
   234   }
   236   mHaveResultOrErrorCode = true;
   238   if (NS_FAILED(aRv)) {
   239     SetError(aRv);
   240   }
   241 }
   243 void
   244 IDBRequest::SetError(nsresult aRv)
   245 {
   246   NS_ASSERTION(NS_FAILED(aRv), "Er, what?");
   247   NS_ASSERTION(!mError, "Already have an error?");
   249   mHaveResultOrErrorCode = true;
   250   mError = new mozilla::dom::DOMError(GetOwner(), aRv);
   251   mErrorCode = aRv;
   253   mResultVal = JSVAL_VOID;
   254 }
   256 #ifdef DEBUG
   257 nsresult
   258 IDBRequest::GetErrorCode() const
   259 {
   260   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   261   NS_ASSERTION(mHaveResultOrErrorCode, "Don't call me yet!");
   262   return mErrorCode;
   263 }
   264 #endif
   266 JSContext*
   267 IDBRequest::GetJSContext()
   268 {
   269   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   271   JSContext* cx;
   273   if (GetScriptOwner()) {
   274     return nsContentUtils::GetSafeJSContext();
   275   }
   277   nsresult rv;
   278   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   279   NS_ENSURE_SUCCESS(rv, nullptr);
   280   NS_ENSURE_TRUE(sc, nullptr);
   282   cx = sc->GetNativeContext();
   283   NS_ASSERTION(cx, "Failed to get a context!");
   285   return cx;
   286 }
   288 void
   289 IDBRequest::CaptureCaller()
   290 {
   291   AutoJSContext cx;
   293   const char* filename = nullptr;
   294   uint32_t lineNo = 0;
   295   if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
   296     NS_WARNING("Failed to get caller.");
   297     return;
   298   }
   300   mFilename.Assign(NS_ConvertUTF8toUTF16(filename));
   301   mLineNo = lineNo;
   302 }
   304 void
   305 IDBRequest::FillScriptErrorEvent(ErrorEventInit& aEventInit) const
   306 {
   307   aEventInit.mLineno = mLineNo;
   308   aEventInit.mFilename = mFilename;
   309 }
   311 mozilla::dom::IDBRequestReadyState
   312 IDBRequest::ReadyState() const
   313 {
   314   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   316   if (IsPending()) {
   317     return IDBRequestReadyState::Pending;
   318   }
   320   return IDBRequestReadyState::Done;
   321 }
   323 JSObject*
   324 IDBRequest::WrapObject(JSContext* aCx)
   325 {
   326   return IDBRequestBinding::Wrap(aCx, this);
   327 }
   329 void
   330 IDBRequest::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   331                       ErrorResult& aRv) const
   332 {
   333   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   335   if (!mHaveResultOrErrorCode) {
   336     // XXX Need a real error code here.
   337     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   338   }
   340   JS::ExposeValueToActiveJS(mResultVal);
   341   aResult.set(mResultVal);
   342 }
   344 mozilla::dom::DOMError*
   345 IDBRequest::GetError(mozilla::ErrorResult& aRv)
   346 {
   347   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   349   if (!mHaveResultOrErrorCode) {
   350     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   351     return nullptr;
   352   }
   354   return mError;
   355 }
   357 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
   359 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   360   // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because
   361   // DOMEventTargetHelper does it for us.
   362   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore)
   363   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex)
   364   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor)
   365   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
   366   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
   367 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   369 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   370   tmp->mResultVal = JSVAL_VOID;
   371   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore)
   372   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex)
   373   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor)
   374   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
   375   NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
   376 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   378 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache)
   379   // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
   380   // DOMEventTargetHelper does it for us.
   381   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal)
   382 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   384 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest)
   385 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
   387 NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache)
   388 NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache)
   390 nsresult
   391 IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
   392 {
   393   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   395   aVisitor.mCanHandle = true;
   396   aVisitor.mParentTarget = mTransaction;
   397   return NS_OK;
   398 }
   400 IDBOpenDBRequest::IDBOpenDBRequest(nsPIDOMWindow* aOwner)
   401   : IDBRequest(aOwner)
   402 {
   403   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   404 }
   406 IDBOpenDBRequest::~IDBOpenDBRequest()
   407 {
   408   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   409 }
   411 // static
   412 already_AddRefed<IDBOpenDBRequest>
   413 IDBOpenDBRequest::Create(IDBFactory* aFactory,
   414                          nsPIDOMWindow* aOwner,
   415                          JS::Handle<JSObject*> aScriptOwner)
   416 {
   417   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   418   NS_ASSERTION(aFactory, "Null pointer!");
   420   nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aOwner);
   422   request->SetScriptOwner(aScriptOwner);
   423   request->mFactory = aFactory;
   425   if (!aFactory->FromIPC()) {
   426     request->CaptureCaller();
   427   }
   429   return request.forget();
   430 }
   432 void
   433 IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
   434 {
   435   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   437   NS_ASSERTION(!aTransaction || !mTransaction,
   438                "Shouldn't have a transaction here!");
   440   mTransaction = aTransaction;
   441 }
   443 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
   445 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
   446                                                   IDBRequest)
   447   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
   448 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   450 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
   451                                                 IDBRequest)
   452   // Don't unlink mFactory!
   453 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   455 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
   456 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
   458 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
   459 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
   461 nsresult
   462 IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor)
   463 {
   464   return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
   465 }
   467 JSObject*
   468 IDBOpenDBRequest::WrapObject(JSContext* aCx)
   469 {
   470   return IDBOpenDBRequestBinding::Wrap(aCx, this);
   471 }

mercurial