dom/indexedDB/IDBRequest.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial