1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/indexedDB/IDBRequest.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,471 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "IDBRequest.h" 1.11 + 1.12 +#include "nsIScriptContext.h" 1.13 + 1.14 +#include "mozilla/ContentEvents.h" 1.15 +#include "mozilla/EventDispatcher.h" 1.16 +#include "mozilla/dom/ErrorEventBinding.h" 1.17 +#include "mozilla/dom/IDBOpenDBRequestBinding.h" 1.18 +#include "mozilla/dom/UnionTypes.h" 1.19 +#include "nsComponentManagerUtils.h" 1.20 +#include "nsDOMClassInfoID.h" 1.21 +#include "nsDOMJSUtils.h" 1.22 +#include "nsContentUtils.h" 1.23 +#include "nsCxPusher.h" 1.24 +#include "nsJSUtils.h" 1.25 +#include "nsPIDOMWindow.h" 1.26 +#include "nsString.h" 1.27 +#include "nsThreadUtils.h" 1.28 +#include "nsWrapperCacheInlines.h" 1.29 + 1.30 +#include "AsyncConnectionHelper.h" 1.31 +#include "IDBCursor.h" 1.32 +#include "IDBEvents.h" 1.33 +#include "IDBFactory.h" 1.34 +#include "IDBIndex.h" 1.35 +#include "IDBObjectStore.h" 1.36 +#include "IDBTransaction.h" 1.37 +#include "ReportInternalError.h" 1.38 + 1.39 +namespace { 1.40 + 1.41 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.42 +uint64_t gNextRequestSerialNumber = 1; 1.43 +#endif 1.44 + 1.45 +} // anonymous namespace 1.46 + 1.47 +USING_INDEXEDDB_NAMESPACE 1.48 +using mozilla::dom::OwningIDBObjectStoreOrIDBIndexOrIDBCursor; 1.49 +using mozilla::dom::ErrorEventInit; 1.50 +using namespace mozilla; 1.51 + 1.52 +IDBRequest::IDBRequest(IDBDatabase* aDatabase) 1.53 +: IDBWrapperCache(aDatabase), 1.54 + mResultVal(JSVAL_VOID), 1.55 + mActorParent(nullptr), 1.56 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.57 + mSerialNumber(gNextRequestSerialNumber++), 1.58 +#endif 1.59 + mErrorCode(NS_OK), 1.60 + mLineNo(0), 1.61 + mHaveResultOrErrorCode(false) 1.62 +{ 1.63 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.64 +} 1.65 + 1.66 +IDBRequest::IDBRequest(nsPIDOMWindow* aOwner) 1.67 +: IDBWrapperCache(aOwner), 1.68 + mResultVal(JSVAL_VOID), 1.69 + mActorParent(nullptr), 1.70 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.71 + mSerialNumber(gNextRequestSerialNumber++), 1.72 +#endif 1.73 + mErrorCode(NS_OK), 1.74 + mLineNo(0), 1.75 + mHaveResultOrErrorCode(false) 1.76 +{ 1.77 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.78 +} 1.79 + 1.80 +IDBRequest::~IDBRequest() 1.81 +{ 1.82 + mResultVal = JSVAL_VOID; 1.83 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.84 +} 1.85 + 1.86 +// static 1.87 +already_AddRefed<IDBRequest> 1.88 +IDBRequest::Create(IDBDatabase* aDatabase, 1.89 + IDBTransaction* aTransaction) 1.90 +{ 1.91 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.92 + nsRefPtr<IDBRequest> request(new IDBRequest(aDatabase)); 1.93 + 1.94 + request->mTransaction = aTransaction; 1.95 + request->SetScriptOwner(aDatabase->GetScriptOwner()); 1.96 + 1.97 + if (!aDatabase->Factory()->FromIPC()) { 1.98 + request->CaptureCaller(); 1.99 + } 1.100 + 1.101 + 1.102 + return request.forget(); 1.103 +} 1.104 + 1.105 +// static 1.106 +already_AddRefed<IDBRequest> 1.107 +IDBRequest::Create(IDBObjectStore* aSourceAsObjectStore, 1.108 + IDBDatabase* aDatabase, 1.109 + IDBTransaction* aTransaction) 1.110 +{ 1.111 + nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction); 1.112 + 1.113 + request->mSourceAsObjectStore = aSourceAsObjectStore; 1.114 + 1.115 + return request.forget(); 1.116 +} 1.117 + 1.118 +// static 1.119 +already_AddRefed<IDBRequest> 1.120 +IDBRequest::Create(IDBIndex* aSourceAsIndex, 1.121 + IDBDatabase* aDatabase, 1.122 + IDBTransaction* aTransaction) 1.123 +{ 1.124 + nsRefPtr<IDBRequest> request = Create(aDatabase, aTransaction); 1.125 + 1.126 + request->mSourceAsIndex = aSourceAsIndex; 1.127 + 1.128 + return request.forget(); 1.129 +} 1.130 + 1.131 +#ifdef DEBUG 1.132 +void 1.133 +IDBRequest::AssertSourceIsCorrect() const 1.134 +{ 1.135 + // At most one of mSourceAs* is allowed to be non-null. Check that by 1.136 + // summing the double negation of each one and asserting the sum is at most 1.137 + // 1. 1.138 + 1.139 + MOZ_ASSERT(!!mSourceAsObjectStore + !!mSourceAsIndex + !!mSourceAsCursor <= 1); 1.140 +} 1.141 +#endif 1.142 + 1.143 +void 1.144 +IDBRequest::GetSource(Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const 1.145 +{ 1.146 + MOZ_ASSERT(NS_IsMainThread()); 1.147 + 1.148 + AssertSourceIsCorrect(); 1.149 + 1.150 + if (mSourceAsObjectStore) { 1.151 + aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore; 1.152 + } else if (mSourceAsIndex) { 1.153 + aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex; 1.154 + } else if (mSourceAsCursor) { 1.155 + aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor; 1.156 + } else { 1.157 + aSource.SetNull(); 1.158 + } 1.159 +} 1.160 + 1.161 +void 1.162 +IDBRequest::Reset() 1.163 +{ 1.164 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.165 + mResultVal = JSVAL_VOID; 1.166 + mHaveResultOrErrorCode = false; 1.167 + mError = nullptr; 1.168 +} 1.169 + 1.170 +nsresult 1.171 +IDBRequest::NotifyHelperCompleted(HelperBase* aHelper) 1.172 +{ 1.173 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.174 + NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!"); 1.175 + NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!"); 1.176 + 1.177 + mHaveResultOrErrorCode = true; 1.178 + 1.179 + nsresult rv = aHelper->GetResultCode(); 1.180 + 1.181 + // If the request failed then set the error code and return. 1.182 + if (NS_FAILED(rv)) { 1.183 + SetError(rv); 1.184 + return NS_OK; 1.185 + } 1.186 + 1.187 + // See if our window is still valid. If not then we're going to pretend that 1.188 + // we never completed. 1.189 + if (NS_FAILED(CheckInnerWindowCorrectness())) { 1.190 + return NS_OK; 1.191 + } 1.192 + 1.193 + // Otherwise we need to get the result from the helper. 1.194 + AutoPushJSContext cx(GetJSContext()); 1.195 + if (!cx) { 1.196 + IDB_WARNING("Failed to get safe JSContext!"); 1.197 + rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.198 + SetError(rv); 1.199 + return rv; 1.200 + } 1.201 + 1.202 + JS::Rooted<JSObject*> global(cx, IDBWrapperCache::GetParentObject()); 1.203 + NS_ASSERTION(global, "This should never be null!"); 1.204 + 1.205 + JSAutoCompartment ac(cx, global); 1.206 + AssertIsRooted(); 1.207 + 1.208 + JS::Rooted<JS::Value> value(cx); 1.209 + rv = aHelper->GetSuccessResult(cx, &value); 1.210 + if (NS_FAILED(rv)) { 1.211 + NS_WARNING("GetSuccessResult failed!"); 1.212 + } 1.213 + 1.214 + if (NS_SUCCEEDED(rv)) { 1.215 + mError = nullptr; 1.216 + mResultVal = value; 1.217 + } 1.218 + else { 1.219 + SetError(rv); 1.220 + mResultVal = JSVAL_VOID; 1.221 + } 1.222 + 1.223 + return rv; 1.224 +} 1.225 + 1.226 +void 1.227 +IDBRequest::NotifyHelperSentResultsToChildProcess(nsresult aRv) 1.228 +{ 1.229 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.230 + NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!"); 1.231 + NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!"); 1.232 + 1.233 + // See if our window is still valid. If not then we're going to pretend that 1.234 + // we never completed. 1.235 + if (NS_FAILED(CheckInnerWindowCorrectness())) { 1.236 + return; 1.237 + } 1.238 + 1.239 + mHaveResultOrErrorCode = true; 1.240 + 1.241 + if (NS_FAILED(aRv)) { 1.242 + SetError(aRv); 1.243 + } 1.244 +} 1.245 + 1.246 +void 1.247 +IDBRequest::SetError(nsresult aRv) 1.248 +{ 1.249 + NS_ASSERTION(NS_FAILED(aRv), "Er, what?"); 1.250 + NS_ASSERTION(!mError, "Already have an error?"); 1.251 + 1.252 + mHaveResultOrErrorCode = true; 1.253 + mError = new mozilla::dom::DOMError(GetOwner(), aRv); 1.254 + mErrorCode = aRv; 1.255 + 1.256 + mResultVal = JSVAL_VOID; 1.257 +} 1.258 + 1.259 +#ifdef DEBUG 1.260 +nsresult 1.261 +IDBRequest::GetErrorCode() const 1.262 +{ 1.263 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.264 + NS_ASSERTION(mHaveResultOrErrorCode, "Don't call me yet!"); 1.265 + return mErrorCode; 1.266 +} 1.267 +#endif 1.268 + 1.269 +JSContext* 1.270 +IDBRequest::GetJSContext() 1.271 +{ 1.272 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.273 + 1.274 + JSContext* cx; 1.275 + 1.276 + if (GetScriptOwner()) { 1.277 + return nsContentUtils::GetSafeJSContext(); 1.278 + } 1.279 + 1.280 + nsresult rv; 1.281 + nsIScriptContext* sc = GetContextForEventHandlers(&rv); 1.282 + NS_ENSURE_SUCCESS(rv, nullptr); 1.283 + NS_ENSURE_TRUE(sc, nullptr); 1.284 + 1.285 + cx = sc->GetNativeContext(); 1.286 + NS_ASSERTION(cx, "Failed to get a context!"); 1.287 + 1.288 + return cx; 1.289 +} 1.290 + 1.291 +void 1.292 +IDBRequest::CaptureCaller() 1.293 +{ 1.294 + AutoJSContext cx; 1.295 + 1.296 + const char* filename = nullptr; 1.297 + uint32_t lineNo = 0; 1.298 + if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) { 1.299 + NS_WARNING("Failed to get caller."); 1.300 + return; 1.301 + } 1.302 + 1.303 + mFilename.Assign(NS_ConvertUTF8toUTF16(filename)); 1.304 + mLineNo = lineNo; 1.305 +} 1.306 + 1.307 +void 1.308 +IDBRequest::FillScriptErrorEvent(ErrorEventInit& aEventInit) const 1.309 +{ 1.310 + aEventInit.mLineno = mLineNo; 1.311 + aEventInit.mFilename = mFilename; 1.312 +} 1.313 + 1.314 +mozilla::dom::IDBRequestReadyState 1.315 +IDBRequest::ReadyState() const 1.316 +{ 1.317 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.318 + 1.319 + if (IsPending()) { 1.320 + return IDBRequestReadyState::Pending; 1.321 + } 1.322 + 1.323 + return IDBRequestReadyState::Done; 1.324 +} 1.325 + 1.326 +JSObject* 1.327 +IDBRequest::WrapObject(JSContext* aCx) 1.328 +{ 1.329 + return IDBRequestBinding::Wrap(aCx, this); 1.330 +} 1.331 + 1.332 +void 1.333 +IDBRequest::GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 1.334 + ErrorResult& aRv) const 1.335 +{ 1.336 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.337 + 1.338 + if (!mHaveResultOrErrorCode) { 1.339 + // XXX Need a real error code here. 1.340 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 1.341 + } 1.342 + 1.343 + JS::ExposeValueToActiveJS(mResultVal); 1.344 + aResult.set(mResultVal); 1.345 +} 1.346 + 1.347 +mozilla::dom::DOMError* 1.348 +IDBRequest::GetError(mozilla::ErrorResult& aRv) 1.349 +{ 1.350 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.351 + 1.352 + if (!mHaveResultOrErrorCode) { 1.353 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.354 + return nullptr; 1.355 + } 1.356 + 1.357 + return mError; 1.358 +} 1.359 + 1.360 +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest) 1.361 + 1.362 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache) 1.363 + // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because 1.364 + // DOMEventTargetHelper does it for us. 1.365 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore) 1.366 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex) 1.367 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor) 1.368 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) 1.369 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError) 1.370 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.371 + 1.372 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest, IDBWrapperCache) 1.373 + tmp->mResultVal = JSVAL_VOID; 1.374 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore) 1.375 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex) 1.376 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor) 1.377 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction) 1.378 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mError) 1.379 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.380 + 1.381 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache) 1.382 + // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because 1.383 + // DOMEventTargetHelper does it for us. 1.384 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResultVal) 1.385 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.386 + 1.387 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBRequest) 1.388 +NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache) 1.389 + 1.390 +NS_IMPL_ADDREF_INHERITED(IDBRequest, IDBWrapperCache) 1.391 +NS_IMPL_RELEASE_INHERITED(IDBRequest, IDBWrapperCache) 1.392 + 1.393 +nsresult 1.394 +IDBRequest::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.395 +{ 1.396 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.397 + 1.398 + aVisitor.mCanHandle = true; 1.399 + aVisitor.mParentTarget = mTransaction; 1.400 + return NS_OK; 1.401 +} 1.402 + 1.403 +IDBOpenDBRequest::IDBOpenDBRequest(nsPIDOMWindow* aOwner) 1.404 + : IDBRequest(aOwner) 1.405 +{ 1.406 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.407 +} 1.408 + 1.409 +IDBOpenDBRequest::~IDBOpenDBRequest() 1.410 +{ 1.411 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.412 +} 1.413 + 1.414 +// static 1.415 +already_AddRefed<IDBOpenDBRequest> 1.416 +IDBOpenDBRequest::Create(IDBFactory* aFactory, 1.417 + nsPIDOMWindow* aOwner, 1.418 + JS::Handle<JSObject*> aScriptOwner) 1.419 +{ 1.420 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.421 + NS_ASSERTION(aFactory, "Null pointer!"); 1.422 + 1.423 + nsRefPtr<IDBOpenDBRequest> request = new IDBOpenDBRequest(aOwner); 1.424 + 1.425 + request->SetScriptOwner(aScriptOwner); 1.426 + request->mFactory = aFactory; 1.427 + 1.428 + if (!aFactory->FromIPC()) { 1.429 + request->CaptureCaller(); 1.430 + } 1.431 + 1.432 + return request.forget(); 1.433 +} 1.434 + 1.435 +void 1.436 +IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction) 1.437 +{ 1.438 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.439 + 1.440 + NS_ASSERTION(!aTransaction || !mTransaction, 1.441 + "Shouldn't have a transaction here!"); 1.442 + 1.443 + mTransaction = aTransaction; 1.444 +} 1.445 + 1.446 +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest) 1.447 + 1.448 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest, 1.449 + IDBRequest) 1.450 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory) 1.451 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.452 + 1.453 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest, 1.454 + IDBRequest) 1.455 + // Don't unlink mFactory! 1.456 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.457 + 1.458 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest) 1.459 +NS_INTERFACE_MAP_END_INHERITING(IDBRequest) 1.460 + 1.461 +NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest) 1.462 +NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest) 1.463 + 1.464 +nsresult 1.465 +IDBOpenDBRequest::PostHandleEvent(EventChainPostVisitor& aVisitor) 1.466 +{ 1.467 + return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor); 1.468 +} 1.469 + 1.470 +JSObject* 1.471 +IDBOpenDBRequest::WrapObject(JSContext* aCx) 1.472 +{ 1.473 + return IDBOpenDBRequestBinding::Wrap(aCx, this); 1.474 +}