1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_H_ 30 #define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_H_ 31 32 #include <memory> 33 34 #include "base/macros.h" 35 #include "base/memory/scoped_refptr.h" 36 #include "third_party/blink/public/common/indexeddb/web_idb_types.h" 37 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink-forward.h" 38 #include "third_party/blink/public/platform/web_blob_info.h" 39 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h" 40 #include "third_party/blink/renderer/bindings/core/v8/script_value.h" 41 #include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index.h" 42 #include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h" 43 #include "third_party/blink/renderer/core/dom/dom_string_list.h" 44 #include "third_party/blink/renderer/core/dom/events/event_listener.h" 45 #include "third_party/blink/renderer/core/dom/events/event_queue.h" 46 #include "third_party/blink/renderer/core/dom/events/event_target.h" 47 #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" 48 #include "third_party/blink/renderer/modules/event_modules.h" 49 #include "third_party/blink/renderer/modules/indexeddb/idb_any.h" 50 #include "third_party/blink/renderer/modules/indexeddb/idb_transaction.h" 51 #include "third_party/blink/renderer/modules/indexeddb/indexed_db.h" 52 #include "third_party/blink/renderer/modules/indexeddb/web_idb_cursor.h" 53 #include "third_party/blink/renderer/modules/modules_export.h" 54 #include "third_party/blink/renderer/platform/bindings/script_state.h" 55 #include "third_party/blink/renderer/platform/blob/blob_data.h" 56 #include "third_party/blink/renderer/platform/heap/handle.h" 57 #include "third_party/blink/renderer/platform/wtf/hash_map.h" 58 59 namespace blink { 60 61 class DOMException; 62 class ExceptionState; 63 class IDBCursor; 64 struct IDBDatabaseMetadata; 65 class IDBValue; 66 67 class MODULES_EXPORT IDBRequest : public EventTargetWithInlineData, 68 public ActiveScriptWrappable<IDBRequest>, 69 public ExecutionContextLifecycleObserver { 70 DEFINE_WRAPPERTYPEINFO(); 71 72 public: 73 using Source = IDBObjectStoreOrIDBIndexOrIDBCursor; 74 // Container for async tracing state. 75 // 76 // The documentation for TRACE_EVENT_NESTABLE_ASYNC_{BEGIN,END} suggests 77 // identifying trace events by using pointers or a counter that is always 78 // incremented on the same thread. This is not viable for IndexedDB, because 79 // the same object can result in multiple trace events (requests associated 80 // with cursors), and IndexedDB can be used from multiple threads in the same 81 // renderer (workers). Furthermore, we want to record the beginning event of 82 // an async trace right when we start serving an IDB API call, before the 83 // IDBRequest object is created, so we can't rely on information in an 84 // IDBRequest. 85 // 86 // This class solves the ID uniqueness problem by relying on an atomic counter 87 // to generating unique IDs in a threadsafe manner. The atomic machinery is 88 // used when tracing is enabled. The recording problem is solved by having 89 // instances of this class store the information needed to record async trace 90 // end events (via TRACE_EVENT_NESTABLE_ASYNC_END). 91 // 92 // From a mechanical perspective, creating an AsyncTraceState instance records 93 // the beginning event of an async trace. The instance is then moved into an 94 // IDBRequest, which records the async trace's end event at the right time. 95 class MODULES_EXPORT AsyncTraceState { 96 public: 97 // Creates an empty instance, which does not produce any tracing events. 98 // 99 // This is used for internal requests that should not show up in an 100 // application's trace. Examples of internal requests are the requests 101 // issued by DevTools, and the requests used to populate indexes. 102 explicit AsyncTraceState() = default; 103 104 // Creates an instance that produces begin/end events with the given name. 105 // 106 // The string pointed to by tracing_name argument must live for the entire 107 // application. The easiest way to meet this requirement is to have it be a 108 // string literal. 109 explicit AsyncTraceState(const char* trace_event_name); 110 ~AsyncTraceState(); 111 112 // Used to transfer the trace end event state to an IDBRequest. AsyncTraceState(AsyncTraceState && other)113 AsyncTraceState(AsyncTraceState&& other) { 114 DCHECK(IsEmpty()); 115 this->trace_event_name_ = other.trace_event_name_; 116 this->id_ = other.id_; 117 other.trace_event_name_ = nullptr; 118 } 119 AsyncTraceState& operator=(AsyncTraceState&& rhs) { 120 DCHECK(IsEmpty()); 121 this->trace_event_name_ = rhs.trace_event_name_; 122 this->id_ = rhs.id_; 123 rhs.trace_event_name_ = nullptr; 124 return *this; 125 } 126 127 // True if this instance does not store information for a tracing end event. 128 // 129 // An instance is cleared when RecordAndReset() is called on it, or when its 130 // state is moved into a different instance. Empty instances are also 131 // produced by the AsyncStateTrace() constructor. IsEmpty()132 bool IsEmpty() const { return !trace_event_name_; } 133 134 // Records the trace end event whose information is stored in this instance. 135 // 136 // The method results in the completion of the async trace tracked by this 137 // instance, so the instance is cleared. 138 void RecordAndReset(); 139 140 protected: // For testing trace_event_name()141 const char* trace_event_name() const { return trace_event_name_; } id()142 size_t id() const { return id_; } 143 144 // Populates the instance with state for a new async trace. 145 // 146 // The method uses the given even name and generates a new unique ID. The 147 // newly generated unique ID is returned. 148 size_t PopulateForNewEvent(const char* trace_event_name); 149 150 private: 151 friend class IDBRequest; 152 153 // The name of the async trace events tracked by this instance. 154 // 155 // Null is used to signal that the instance is empty, so the event name 156 // cannot be null. 157 const char* trace_event_name_ = nullptr; 158 // Uniquely generated ID that ties an async trace's begin and end events. 159 size_t id_ = 0; 160 161 DISALLOW_COPY_AND_ASSIGN(AsyncTraceState); 162 }; 163 164 static IDBRequest* Create(ScriptState*, 165 IDBIndex* source, 166 IDBTransaction*, 167 AsyncTraceState); 168 static IDBRequest* Create(ScriptState*, 169 IDBObjectStore* source, 170 IDBTransaction*, 171 AsyncTraceState); 172 static IDBRequest* Create(ScriptState*, 173 IDBCursor*, 174 IDBTransaction* source, 175 AsyncTraceState); 176 static IDBRequest* Create(ScriptState*, 177 const Source&, 178 IDBTransaction*, 179 AsyncTraceState); 180 181 IDBRequest(ScriptState*, const Source&, IDBTransaction*, AsyncTraceState); 182 ~IDBRequest() override; 183 184 void Trace(Visitor*) const override; 185 GetIsolate()186 v8::Isolate* GetIsolate() const { return isolate_; } 187 ScriptValue result(ScriptState*, ExceptionState&); 188 DOMException* error(ExceptionState&) const; 189 void source(ScriptState*, Source&) const; transaction()190 IDBTransaction* transaction() const { return transaction_.Get(); } 191 isResultDirty()192 bool isResultDirty() const { return result_dirty_; } ResultAsAny()193 IDBAny* ResultAsAny() const { return result_; } 194 195 // Requests made during index population are implementation details and so 196 // events should not be visible to script. PreventPropagation()197 void PreventPropagation() { prevent_propagation_ = true; } 198 199 // Defined in the IDL 200 enum ReadyState { PENDING = 1, DONE = 2, kEarlyDeath = 3 }; 201 202 const String& readyState() const; 203 204 // Returns a new WebIDBCallbacks for this request. 205 // 206 // Each call must be paired with a WebCallbacksDestroyed() call. Most requests 207 // have a single WebIDBCallbacks instance created for them. 208 // 209 // Requests used to open and iterate cursors are special, because they are 210 // reused between openCursor() and continue() / advance() calls. These 211 // requests have a new WebIDBCallbacks instance created for each of the 212 // above-mentioned calls that they are involved in. 213 std::unique_ptr<WebIDBCallbacks> CreateWebCallbacks(); WebCallbacksDestroyed()214 void WebCallbacksDestroyed() { 215 DCHECK(web_callbacks_); 216 web_callbacks_ = nullptr; 217 } 218 #if DCHECK_IS_ON() WebCallbacks()219 WebIDBCallbacks* WebCallbacks() const { return web_callbacks_; } 220 #endif // DCHECK_IS_ON() 221 222 DEFINE_ATTRIBUTE_EVENT_LISTENER(success, kSuccess) 223 DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError) 224 225 void SetCursorDetails(indexed_db::CursorType, mojom::IDBCursorDirection); 226 void SetPendingCursor(IDBCursor*); 227 void Abort(); 228 229 // Blink's delivery of results from IndexedDB's backing store to script is 230 // more complicated than prescribed in the IndexedDB specification. 231 // 232 // IDBValue, which holds responses from the backing store, is either the 233 // serialized V8 value, or a reference to a Blob that holds the serialized 234 // value. IDBValueWrapping.h has the motivation and details. This introduces 235 // the following complexities. 236 // 237 // 1) De-serialization is expensive, so it is done lazily in 238 // IDBRequest::result(), which is called synchronously from script. On the 239 // other hand, Blob data can only be fetched asynchronously. So, IDBValues 240 // that reference serialized data stored in Blobs must be processed before 241 // IDBRequest event handlers are invoked, because the event handler script may 242 // call IDBRequest::result(). 243 // 244 // 2) The IDBRequest events must be dispatched (enqueued in DOMWindow's event 245 // queue) in the order in which the requests were issued. If an IDBValue 246 // references a Blob, the Blob processing must block event dispatch for all 247 // following IDBRequests in the same transaction. 248 // 249 // The Blob de-referencing and IDBRequest blocking is performed in the 250 // HandleResponse() overloads below. Each HandleResponse() overload is paired 251 // with a matching EnqueueResponse() overload, which is called when an 252 // IDBRequest's result event can be delivered to the application. All the 253 // HandleResponse() variants include a fast path that calls directly into 254 // EnqueueResponse() if no queueing is required. 255 // 256 // Some types of requests, such as indexedDB.openDatabase(), cannot be issued 257 // after a request that needs Blob processing, so their results are handled by 258 // having WebIDBCallbacksImpl call directly into EnqueueResponse(), 259 // EnqueueBlocked(), or EnqueueUpgradeNeeded(). 260 261 void HandleResponse(DOMException*); 262 void HandleResponse(std::unique_ptr<IDBKey>); 263 void HandleResponse(std::unique_ptr<WebIDBCursor>, 264 std::unique_ptr<IDBKey>, 265 std::unique_ptr<IDBKey> primary_key, 266 std::unique_ptr<IDBValue>); 267 void HandleResponse(std::unique_ptr<IDBKey>, 268 std::unique_ptr<IDBKey> primary_key, 269 std::unique_ptr<IDBValue>); 270 void HandleResponse(std::unique_ptr<IDBValue>); 271 void HandleResponse(Vector<std::unique_ptr<IDBValue>>); 272 void HandleResponse(int64_t); 273 void HandleResponse(); 274 void HandleResponse( 275 bool key_only, 276 mojo::PendingReceiver<mojom::blink::IDBDatabaseGetAllResultSink> 277 receiver); 278 279 // Only used in webkitGetDatabaseNames(), which is deprecated and hopefully 280 // going away soon. 281 void EnqueueResponse(const Vector<String>&); 282 283 // Only IDBOpenDBRequest instances should receive these: EnqueueBlocked(int64_t old_version)284 virtual void EnqueueBlocked(int64_t old_version) { NOTREACHED(); } EnqueueUpgradeNeeded(int64_t old_version,std::unique_ptr<WebIDBDatabase>,const IDBDatabaseMetadata &,mojom::IDBDataLoss,String data_loss_message)285 virtual void EnqueueUpgradeNeeded(int64_t old_version, 286 std::unique_ptr<WebIDBDatabase>, 287 const IDBDatabaseMetadata&, 288 mojom::IDBDataLoss, 289 String data_loss_message) { 290 NOTREACHED(); 291 } EnqueueResponse(std::unique_ptr<WebIDBDatabase>,const IDBDatabaseMetadata &)292 virtual void EnqueueResponse(std::unique_ptr<WebIDBDatabase>, 293 const IDBDatabaseMetadata&) { 294 NOTREACHED(); 295 } 296 297 // ScriptWrappable 298 bool HasPendingActivity() const final; 299 300 // ExecutionContextLifecycleObserver 301 void ContextDestroyed() override; 302 303 // EventTarget 304 const AtomicString& InterfaceName() const override; 305 ExecutionContext* GetExecutionContext() const final; 306 307 // Called by a version change transaction that has finished to set this 308 // request back from DONE (following "upgradeneeded") back to PENDING (for 309 // the upcoming "success" or "error"). 310 void TransactionDidFinishAndDispatch(); 311 312 IDBCursor* GetResultCursor() const; 313 314 // Used to hang onto Blobs until the browser process handles the request. 315 // 316 // Blobs are ref-counted on the browser side, and BlobDataHandles manage 317 // references from renderers. When a BlobDataHandle gets destroyed, the 318 // browser-side Blob gets derefenced, which might cause it to be destroyed as 319 // well. 320 // 321 // After script uses a Blob in a put() request, the Blink-side Blob object 322 // (which hangs onto the BlobDataHandle) may get garbage-collected. IDBRequest 323 // needs to hang onto the BlobDataHandle as well, to avoid having the 324 // browser-side Blob get destroyed before the IndexedDB request is processed. transit_blob_handles()325 inline Vector<scoped_refptr<BlobDataHandle>>& transit_blob_handles() { 326 return transit_blob_handles_; 327 } 328 329 #if DCHECK_IS_ON() TransactionHasQueuedResults()330 inline bool TransactionHasQueuedResults() const { 331 return transaction_ && transaction_->HasQueuedResults(); 332 } 333 #endif // DCHECK_IS_ON() 334 335 #if DCHECK_IS_ON() QueueItem()336 inline IDBRequestQueueItem* QueueItem() const { return queue_item_; } 337 #endif // DCHECK_IS_ON() 338 AssignNewMetrics(AsyncTraceState metrics)339 void AssignNewMetrics(AsyncTraceState metrics) { 340 DCHECK(metrics_.IsEmpty()); 341 metrics_ = std::move(metrics); 342 } 343 344 protected: 345 void EnqueueEvent(Event*); 346 virtual bool ShouldEnqueueEvent() const; 347 void EnqueueResultInternal(IDBAny*); 348 void SetResult(IDBAny*); 349 350 // Overridden by IDBOpenDBRequest. 351 virtual void EnqueueResponse(int64_t); 352 353 // EventTarget 354 DispatchEventResult DispatchEventInternal(Event&) override; 355 356 // Can be nullptr for requests that are not associated with a transaction, 357 // i.e. delete requests and completed or unsuccessful open requests. 358 Member<IDBTransaction> transaction_; 359 360 ReadyState ready_state_ = PENDING; 361 bool request_aborted_ = false; // May be aborted by transaction then receive 362 // async onsuccess; ignore vs. assert. 363 // Maintain the isolate so that all externally allocated memory can be 364 // registered against it. 365 v8::Isolate* isolate_; 366 367 AsyncTraceState metrics_; 368 369 private: 370 // Calls EnqueueResponse(). 371 friend class IDBRequestQueueItem; 372 373 void SetResultCursor(IDBCursor*, 374 std::unique_ptr<IDBKey>, 375 std::unique_ptr<IDBKey> primary_key, 376 std::unique_ptr<IDBValue>); 377 378 void EnqueueResponse(DOMException*); 379 void EnqueueResponse(std::unique_ptr<IDBKey>); 380 void EnqueueResponse(std::unique_ptr<WebIDBCursor>, 381 std::unique_ptr<IDBKey>, 382 std::unique_ptr<IDBKey> primary_key, 383 std::unique_ptr<IDBValue>); 384 void EnqueueResponse(std::unique_ptr<IDBKey>, 385 std::unique_ptr<IDBKey> primary_key, 386 std::unique_ptr<IDBValue>); 387 void EnqueueResponse(std::unique_ptr<IDBValue>); 388 void EnqueueResponse(Vector<std::unique_ptr<IDBValue>>); 389 void EnqueueResponse(); 390 ClearPutOperationBlobs()391 void ClearPutOperationBlobs() { transit_blob_handles_.clear(); } 392 393 Source source_; 394 Member<IDBAny> result_; 395 Member<DOMException> error_; 396 397 bool has_pending_activity_ = true; 398 Member<EventQueue> event_queue_; 399 400 // Only used if the result type will be a cursor. 401 indexed_db::CursorType cursor_type_ = indexed_db::kCursorKeyAndValue; 402 mojom::IDBCursorDirection cursor_direction_ = mojom::IDBCursorDirection::Next; 403 // When a cursor is continued/advanced, |result_| is cleared and 404 // |pendingCursor_| holds it. 405 Member<IDBCursor> pending_cursor_; 406 // New state is not applied to the cursor object until the event is 407 // dispatched. 408 std::unique_ptr<IDBKey> cursor_key_; 409 std::unique_ptr<IDBKey> cursor_primary_key_; 410 std::unique_ptr<IDBValue> cursor_value_; 411 412 Vector<scoped_refptr<BlobDataHandle>> transit_blob_handles_; 413 414 bool did_fire_upgrade_needed_event_ = false; 415 bool prevent_propagation_ = false; 416 bool result_dirty_ = true; 417 418 // Pointer back to the WebIDBCallbacks that holds a persistent reference to 419 // this object. 420 WebIDBCallbacks* web_callbacks_ = nullptr; 421 422 // Non-null while this request is queued behind other requests that are still 423 // getting post-processed. 424 // 425 // The IDBRequestQueueItem is owned by the result queue in IDBTransaction. 426 IDBRequestQueueItem* queue_item_ = nullptr; 427 }; 428 429 } // namespace blink 430 431 #endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_H_ 432