IDBRequest.h (7510B)
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 #ifndef mozilla_dom_idbrequest_h__ 8 #define mozilla_dom_idbrequest_h__ 9 10 #include "ReportInternalError.h" 11 #include "SafeRefPtr.h" 12 #include "js/RootingAPI.h" 13 #include "mozilla/DOMEventTargetHelper.h" 14 #include "mozilla/EventForwards.h" 15 #include "mozilla/HoldDropJSObjects.h" 16 #include "mozilla/SourceLocation.h" 17 #include "mozilla/dom/DOMException.h" 18 #include "mozilla/dom/IDBRequestBinding.h" 19 #include "mozilla/dom/ScriptSettings.h" 20 #include "nsCycleCollectionParticipant.h" 21 22 #define PRIVATE_IDBREQUEST_IID \ 23 {0xe68901e5, 0x1d50, 0x4ee9, {0xaf, 0x49, 0x90, 0x99, 0x4a, 0xff, 0xc8, 0x39}} 24 25 class nsIGlobalObject; 26 27 namespace mozilla { 28 29 class ErrorResult; 30 31 namespace dom { 32 33 class IDBCursor; 34 class IDBDatabase; 35 class IDBFactory; 36 class IDBIndex; 37 class IDBObjectStore; 38 class IDBTransaction; 39 template <typename> 40 struct Nullable; 41 class OwningIDBObjectStoreOrIDBIndexOrIDBCursor; 42 class StrongWorkerRef; 43 44 namespace detail { 45 // This class holds the IID for use with NS_GET_IID. 46 class PrivateIDBRequest { 47 public: 48 NS_INLINE_DECL_STATIC_IID(PRIVATE_IDBREQUEST_IID) 49 }; 50 51 } // namespace detail 52 53 class IDBRequest : public DOMEventTargetHelper { 54 protected: 55 // mSourceAsObjectStore and mSourceAsIndex are exclusive and one must always 56 // be set. mSourceAsCursor is sometimes set also. 57 RefPtr<IDBObjectStore> mSourceAsObjectStore; 58 RefPtr<IDBIndex> mSourceAsIndex; 59 RefPtr<IDBCursor> mSourceAsCursor; 60 61 SafeRefPtr<IDBTransaction> mTransaction; 62 63 JS::Heap<JS::Value> mResultVal; 64 RefPtr<DOMException> mError; 65 66 JSCallingLocation mCallerLocation; 67 uint64_t mLoggingSerialNumber; 68 nsresult mErrorCode; 69 bool mHaveResultOrErrorCode; 70 71 public: 72 [[nodiscard]] static MovingNotNull<RefPtr<IDBRequest>> Create( 73 JSContext* aCx, IDBDatabase* aDatabase, 74 SafeRefPtr<IDBTransaction> aTransaction); 75 76 [[nodiscard]] static MovingNotNull<RefPtr<IDBRequest>> Create( 77 JSContext* aCx, IDBObjectStore* aSource, IDBDatabase* aDatabase, 78 SafeRefPtr<IDBTransaction> aTransaction); 79 80 [[nodiscard]] static MovingNotNull<RefPtr<IDBRequest>> Create( 81 JSContext* aCx, IDBIndex* aSource, IDBDatabase* aDatabase, 82 SafeRefPtr<IDBTransaction> aTransaction); 83 84 static uint64_t NextSerialNumber(); 85 86 // EventTarget 87 void GetEventTargetParent(EventChainPreVisitor& aVisitor) override; 88 89 void GetSource( 90 Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const; 91 92 void Reset(); 93 94 template <typename ResultCallback> 95 void SetResult(const ResultCallback& aCallback) { 96 AssertIsOnOwningThread(); 97 MOZ_ASSERT(!mHaveResultOrErrorCode); 98 MOZ_ASSERT(mResultVal.isUndefined()); 99 MOZ_ASSERT(!mError); 100 101 // Already disconnected from the owner. 102 if (!GetOwnerGlobal()) { 103 SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 104 return; 105 } 106 107 // See this global is still valid. 108 if (NS_WARN_IF(NS_FAILED(CheckCurrentGlobalCorrectness()))) { 109 SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 110 return; 111 } 112 113 AutoJSAPI autoJS; 114 if (!autoJS.Init(GetOwnerGlobal())) { 115 IDB_WARNING("Failed to initialize AutoJSAPI!"); 116 SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 117 return; 118 } 119 120 JSContext* cx = autoJS.cx(); 121 122 JS::Rooted<JS::Value> result(cx); 123 nsresult rv = aCallback(cx, &result); 124 if (NS_WARN_IF(NS_FAILED(rv))) { 125 // This can only fail if the structured clone contains a mutable file 126 // and the child is not in the main thread and main process. 127 // In that case CreateAndWrapMutableFile() returns false which shows up 128 // as NS_ERROR_DOM_DATA_CLONE_ERR here. 129 MOZ_ASSERT(rv == NS_ERROR_DOM_DATA_CLONE_ERR); 130 131 // We are not setting a result or an error object here since we want to 132 // throw an exception when the 'result' property is being touched. 133 return; 134 } 135 136 mError = nullptr; 137 138 mResultVal = result; 139 mozilla::HoldJSObjects(this); 140 141 mHaveResultOrErrorCode = true; 142 } 143 144 void SetError(nsresult aRv); 145 146 nsresult GetErrorCode() const 147 #ifdef DEBUG 148 ; 149 #else 150 { 151 return mErrorCode; 152 } 153 #endif 154 155 DOMException* GetErrorAfterResult() const 156 #ifdef DEBUG 157 ; 158 #else 159 { 160 return mError; 161 } 162 #endif 163 164 DOMException* GetError(ErrorResult& aRv); 165 166 const JSCallingLocation& GetCallerLocation() const { return mCallerLocation; } 167 168 bool IsPending() const { return !mHaveResultOrErrorCode; } 169 170 uint64_t LoggingSerialNumber() const { 171 AssertIsOnOwningThread(); 172 173 return mLoggingSerialNumber; 174 } 175 176 void SetLoggingSerialNumber(uint64_t aLoggingSerialNumber); 177 178 nsIGlobalObject* GetParentObject() const { return GetOwnerGlobal(); } 179 180 void GetResult(JS::MutableHandle<JS::Value> aResult, ErrorResult& aRv) const; 181 182 void GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 183 ErrorResult& aRv) const { 184 GetResult(aResult, aRv); 185 } 186 187 Maybe<IDBTransaction&> MaybeTransactionRef() const { 188 AssertIsOnOwningThread(); 189 190 return mTransaction.maybeDeref(); 191 } 192 193 IDBTransaction& MutableTransactionRef() const { 194 AssertIsOnOwningThread(); 195 196 return *mTransaction; 197 } 198 199 SafeRefPtr<IDBTransaction> AcquireTransaction() const { 200 AssertIsOnOwningThread(); 201 202 return mTransaction.clonePtr(); 203 } 204 205 // For WebIDL binding. 206 RefPtr<IDBTransaction> GetTransaction() const { 207 AssertIsOnOwningThread(); 208 209 return AsRefPtr(mTransaction.clonePtr()); 210 } 211 212 IDBRequestReadyState ReadyState() const; 213 214 void SetSource(IDBCursor* aSource); 215 216 IMPL_EVENT_HANDLER(success); 217 IMPL_EVENT_HANDLER(error); 218 219 void AssertIsOnOwningThread() const { NS_ASSERT_OWNINGTHREAD(IDBRequest); } 220 221 NS_DECL_ISUPPORTS_INHERITED 222 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IDBRequest, 223 DOMEventTargetHelper) 224 225 // nsWrapperCache 226 virtual JSObject* WrapObject(JSContext* aCx, 227 JS::Handle<JSObject*> aGivenProto) override; 228 229 protected: 230 explicit IDBRequest(IDBDatabase* aDatabase); 231 explicit IDBRequest(nsIGlobalObject* aGlobal); 232 ~IDBRequest(); 233 234 void InitMembers(); 235 236 void ConstructResult(); 237 }; 238 239 class IDBOpenDBRequest final : public IDBRequest { 240 // Only touched on the owning thread. 241 SafeRefPtr<IDBFactory> mFactory; 242 243 RefPtr<StrongWorkerRef> mWorkerRef; 244 245 bool mIncreasedActiveDatabaseCount; 246 247 public: 248 [[nodiscard]] static RefPtr<IDBOpenDBRequest> Create( 249 JSContext* aCx, SafeRefPtr<IDBFactory> aFactory, 250 nsIGlobalObject* aGlobal); 251 252 void SetTransaction(SafeRefPtr<IDBTransaction> aTransaction); 253 254 void DispatchNonTransactionError(nsresult aErrorCode); 255 256 void NoteComplete(); 257 258 // EventTarget 259 IMPL_EVENT_HANDLER(blocked); 260 IMPL_EVENT_HANDLER(upgradeneeded); 261 262 NS_DECL_ISUPPORTS_INHERITED 263 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest, IDBRequest) 264 265 // nsWrapperCache 266 virtual JSObject* WrapObject(JSContext* aCx, 267 JS::Handle<JSObject*> aGivenProto) override; 268 269 private: 270 IDBOpenDBRequest(SafeRefPtr<IDBFactory> aFactory, nsIGlobalObject* aGlobal); 271 272 ~IDBOpenDBRequest(); 273 274 void IncreaseActiveDatabaseCount(); 275 276 void MaybeDecreaseActiveDatabaseCount(); 277 }; 278 279 } // namespace dom 280 } // namespace mozilla 281 282 #endif // mozilla_dom_idbrequest_h__