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  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
27 
28 #include <limits>
29 #include <memory>
30 
31 #include "base/atomic_sequence_num.h"
32 #include "base/optional.h"
33 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
34 #include "third_party/blink/public/common/indexeddb/web_idb_types.h"
35 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink.h"
36 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
37 #include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
38 #include "third_party/blink/renderer/bindings/modules/v8/v8_idb_observer_callback.h"
39 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
40 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
41 #include "third_party/blink/renderer/modules/indexed_db_names.h"
42 #include "third_party/blink/renderer/modules/indexeddb/idb_any.h"
43 #include "third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.h"
44 #include "third_party/blink/renderer/modules/indexeddb/idb_index.h"
45 #include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
46 #include "third_party/blink/renderer/modules/indexeddb/idb_observer.h"
47 #include "third_party/blink/renderer/modules/indexeddb/idb_observer_changes.h"
48 #include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
49 #include "third_party/blink/renderer/modules/indexeddb/idb_version_change_event.h"
50 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks.h"
51 #include "third_party/blink/renderer/modules/indexeddb/web_idb_database_callbacks_impl.h"
52 #include "third_party/blink/renderer/modules/indexeddb/web_idb_transaction_impl.h"
53 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
54 #include "third_party/blink/renderer/platform/heap/heap.h"
55 #include "third_party/blink/renderer/platform/wtf/assertions.h"
56 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
57 
58 namespace blink {
59 
60 const char IDBDatabase::kCannotObserveVersionChangeTransaction[] =
61     "An observer cannot target a version change transaction.";
62 const char IDBDatabase::kIndexDeletedErrorMessage[] =
63     "The index or its object store has been deleted.";
64 const char IDBDatabase::kIndexNameTakenErrorMessage[] =
65     "An index with the specified name already exists.";
66 const char IDBDatabase::kIsKeyCursorErrorMessage[] =
67     "The cursor is a key cursor.";
68 const char IDBDatabase::kNoKeyOrKeyRangeErrorMessage[] =
69     "No key or key range specified.";
70 const char IDBDatabase::kNoSuchIndexErrorMessage[] =
71     "The specified index was not found.";
72 const char IDBDatabase::kNoSuchObjectStoreErrorMessage[] =
73     "The specified object store was not found.";
74 const char IDBDatabase::kNoValueErrorMessage[] =
75     "The cursor is being iterated or has iterated past its end.";
76 const char IDBDatabase::kNotValidKeyErrorMessage[] =
77     "The parameter is not a valid key.";
78 const char IDBDatabase::kNotVersionChangeTransactionErrorMessage[] =
79     "The database is not running a version change transaction.";
80 const char IDBDatabase::kObjectStoreDeletedErrorMessage[] =
81     "The object store has been deleted.";
82 const char IDBDatabase::kObjectStoreNameTakenErrorMessage[] =
83     "An object store with the specified name already exists.";
84 const char IDBDatabase::kRequestNotFinishedErrorMessage[] =
85     "The request has not finished.";
86 const char IDBDatabase::kSourceDeletedErrorMessage[] =
87     "The cursor's source or effective object store has been deleted.";
88 const char IDBDatabase::kTransactionInactiveErrorMessage[] =
89     "The transaction is not active.";
90 const char IDBDatabase::kTransactionFinishedErrorMessage[] =
91     "The transaction has finished.";
92 const char IDBDatabase::kTransactionReadOnlyErrorMessage[] =
93     "The transaction is read-only.";
94 const char IDBDatabase::kDatabaseClosedErrorMessage[] =
95     "The database connection is closed.";
96 
IDBDatabase(ExecutionContext * context,std::unique_ptr<WebIDBDatabase> backend,IDBDatabaseCallbacks * callbacks,v8::Isolate * isolate,mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime)97 IDBDatabase::IDBDatabase(
98     ExecutionContext* context,
99     std::unique_ptr<WebIDBDatabase> backend,
100     IDBDatabaseCallbacks* callbacks,
101     v8::Isolate* isolate,
102     mojo::PendingRemote<mojom::blink::ObservedFeature> connection_lifetime)
103     : ExecutionContextLifecycleObserver(context),
104       backend_(std::move(backend)),
105       connection_lifetime_(std::move(connection_lifetime)),
106       event_queue_(
107           MakeGarbageCollected<EventQueue>(context, TaskType::kDatabaseAccess)),
108       database_callbacks_(callbacks),
109       isolate_(isolate),
110       feature_handle_for_scheduler_(
111           context
112               ? context->GetScheduler()->RegisterFeature(
113                     SchedulingPolicy::Feature::kIndexedDBConnection,
114                     {SchedulingPolicy::RecordMetricsForBackForwardCache()})
115               : FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle()) {
116   database_callbacks_->Connect(this);
117 }
118 
~IDBDatabase()119 IDBDatabase::~IDBDatabase() {
120   if (!close_pending_ && backend_)
121     backend_->Close();
122 }
123 
Trace(Visitor * visitor) const124 void IDBDatabase::Trace(Visitor* visitor) const {
125   visitor->Trace(version_change_transaction_);
126   visitor->Trace(transactions_);
127   visitor->Trace(observers_);
128   visitor->Trace(event_queue_);
129   visitor->Trace(database_callbacks_);
130   EventTargetWithInlineData::Trace(visitor);
131   ExecutionContextLifecycleObserver::Trace(visitor);
132 }
133 
NextTransactionId()134 int64_t IDBDatabase::NextTransactionId() {
135   // Starts at 1, unlike AtomicSequenceNumber.
136   // Only keep a 32-bit counter to allow ports to use the other 32
137   // bits of the id.
138   static base::AtomicSequenceNumber current_transaction_id;
139   return current_transaction_id.GetNext() + 1;
140 }
141 
NextObserverId()142 int32_t IDBDatabase::NextObserverId() {
143   // Starts at 1, unlike AtomicSequenceNumber.
144   static base::AtomicSequenceNumber current_observer_id;
145   return current_observer_id.GetNext() + 1;
146 }
147 
SetMetadata(const IDBDatabaseMetadata & metadata)148 void IDBDatabase::SetMetadata(const IDBDatabaseMetadata& metadata) {
149   metadata_ = metadata;
150 }
151 
SetDatabaseMetadata(const IDBDatabaseMetadata & metadata)152 void IDBDatabase::SetDatabaseMetadata(const IDBDatabaseMetadata& metadata) {
153   metadata_.CopyFrom(metadata);
154 }
155 
TransactionCreated(IDBTransaction * transaction)156 void IDBDatabase::TransactionCreated(IDBTransaction* transaction) {
157   DCHECK(transaction);
158   DCHECK(!transactions_.Contains(transaction->Id()));
159   transactions_.insert(transaction->Id(), transaction);
160 
161   if (transaction->IsVersionChange()) {
162     DCHECK(!version_change_transaction_);
163     version_change_transaction_ = transaction;
164   }
165 }
166 
TransactionFinished(const IDBTransaction * transaction)167 void IDBDatabase::TransactionFinished(const IDBTransaction* transaction) {
168   DCHECK(transaction);
169   DCHECK(transactions_.Contains(transaction->Id()));
170   DCHECK_EQ(transactions_.at(transaction->Id()), transaction);
171   transactions_.erase(transaction->Id());
172 
173   if (transaction->IsVersionChange()) {
174     DCHECK_EQ(version_change_transaction_, transaction);
175     version_change_transaction_ = nullptr;
176   }
177 
178   if (close_pending_ && transactions_.IsEmpty())
179     CloseConnection();
180 }
181 
OnAbort(int64_t transaction_id,DOMException * error)182 void IDBDatabase::OnAbort(int64_t transaction_id, DOMException* error) {
183   DCHECK(transactions_.Contains(transaction_id));
184   transactions_.at(transaction_id)->OnAbort(error);
185 }
186 
OnComplete(int64_t transaction_id)187 void IDBDatabase::OnComplete(int64_t transaction_id) {
188   DCHECK(transactions_.Contains(transaction_id));
189   transactions_.at(transaction_id)->OnComplete();
190 }
191 
OnChanges(const WebIDBDatabaseCallbacks::ObservationIndexMap & observation_index_map,Vector<Persistent<IDBObservation>> observations,const WebIDBDatabaseCallbacks::TransactionMap & transactions)192 void IDBDatabase::OnChanges(
193     const WebIDBDatabaseCallbacks::ObservationIndexMap& observation_index_map,
194     Vector<Persistent<IDBObservation>> observations,
195     const WebIDBDatabaseCallbacks::TransactionMap& transactions) {
196   for (const auto& observation : observations) {
197     observation->SetIsolate(isolate_);
198   }
199 
200   for (const auto& map_entry : observation_index_map) {
201     auto observer_lookup_result = observers_.find(map_entry.key);
202     if (observer_lookup_result != observers_.end()) {
203       IDBObserver* observer = observer_lookup_result->value;
204 
205       auto transactions_lookup_result = transactions.find(map_entry.key);
206       if (transactions_lookup_result != transactions.end()) {
207         const std::pair<int64_t, Vector<int64_t>>& obs_txn =
208             transactions_lookup_result->value;
209         HashSet<String> stores;
210         for (int64_t store_id : obs_txn.second) {
211           stores.insert(metadata_.object_stores.at(store_id)->name);
212         }
213       }
214 
215       observer->Callback()->InvokeAndReportException(
216           observer, MakeGarbageCollected<IDBObserverChanges>(
217                         this, nullptr, observations, map_entry.value));
218     }
219   }
220 }
221 
objectStoreNames() const222 DOMStringList* IDBDatabase::objectStoreNames() const {
223   auto* object_store_names = MakeGarbageCollected<DOMStringList>();
224   for (const auto& it : metadata_.object_stores)
225     object_store_names->Append(it.value->name);
226   object_store_names->Sort();
227   return object_store_names;
228 }
229 
GetObjectStoreName(int64_t object_store_id) const230 const String& IDBDatabase::GetObjectStoreName(int64_t object_store_id) const {
231   const auto& it = metadata_.object_stores.find(object_store_id);
232   DCHECK(it != metadata_.object_stores.end());
233   return it->value->name;
234 }
235 
AddObserver(IDBObserver * observer,int64_t transaction_id,bool include_transaction,bool no_records,bool values,std::bitset<blink::kIDBOperationTypeCount> operation_types)236 int32_t IDBDatabase::AddObserver(
237     IDBObserver* observer,
238     int64_t transaction_id,
239     bool include_transaction,
240     bool no_records,
241     bool values,
242     std::bitset<blink::kIDBOperationTypeCount> operation_types) {
243   int32_t observer_id = NextObserverId();
244   observers_.Set(observer_id, observer);
245   Backend()->AddObserver(transaction_id, observer_id, include_transaction,
246                          no_records, values, operation_types);
247   return observer_id;
248 }
249 
RemoveObservers(const Vector<int32_t> & observer_ids)250 void IDBDatabase::RemoveObservers(const Vector<int32_t>& observer_ids) {
251   observers_.RemoveAll(observer_ids);
252   Backend()->RemoveObservers(observer_ids);
253 }
254 
createObjectStore(const String & name,const IDBKeyPath & key_path,bool auto_increment,ExceptionState & exception_state)255 IDBObjectStore* IDBDatabase::createObjectStore(
256     const String& name,
257     const IDBKeyPath& key_path,
258     bool auto_increment,
259     ExceptionState& exception_state) {
260   IDB_TRACE("IDBDatabase::createObjectStore");
261 
262   if (!version_change_transaction_) {
263     exception_state.ThrowDOMException(
264         DOMExceptionCode::kInvalidStateError,
265         IDBDatabase::kNotVersionChangeTransactionErrorMessage);
266     return nullptr;
267   }
268   if (!version_change_transaction_->IsActive()) {
269     exception_state.ThrowDOMException(
270         DOMExceptionCode::kTransactionInactiveError,
271         version_change_transaction_->InactiveErrorMessage());
272     return nullptr;
273   }
274 
275   if (!key_path.IsNull() && !key_path.IsValid()) {
276     exception_state.ThrowDOMException(
277         DOMExceptionCode::kSyntaxError,
278         "The keyPath option is not a valid key path.");
279     return nullptr;
280   }
281 
282   if (ContainsObjectStore(name)) {
283     exception_state.ThrowDOMException(
284         DOMExceptionCode::kConstraintError,
285         IDBDatabase::kObjectStoreNameTakenErrorMessage);
286     return nullptr;
287   }
288 
289   if (auto_increment && ((key_path.GetType() == mojom::IDBKeyPathType::String &&
290                           key_path.GetString().IsEmpty()) ||
291                          key_path.GetType() == mojom::IDBKeyPathType::Array)) {
292     exception_state.ThrowDOMException(
293         DOMExceptionCode::kInvalidAccessError,
294         "The autoIncrement option was set but the "
295         "keyPath option was empty or an array.");
296     return nullptr;
297   }
298 
299   if (!backend_) {
300     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
301                                       IDBDatabase::kDatabaseClosedErrorMessage);
302     return nullptr;
303   }
304 
305   int64_t object_store_id = metadata_.max_object_store_id + 1;
306   DCHECK_NE(object_store_id, IDBObjectStoreMetadata::kInvalidId);
307   version_change_transaction_->transaction_backend()->CreateObjectStore(
308       object_store_id, name, key_path, auto_increment);
309 
310   scoped_refptr<IDBObjectStoreMetadata> store_metadata =
311       base::AdoptRef(new IDBObjectStoreMetadata(
312           name, object_store_id, key_path, auto_increment,
313           WebIDBDatabase::kMinimumIndexId));
314   auto* object_store = MakeGarbageCollected<IDBObjectStore>(
315       store_metadata, version_change_transaction_.Get());
316   version_change_transaction_->ObjectStoreCreated(name, object_store);
317   metadata_.object_stores.Set(object_store_id, std::move(store_metadata));
318   ++metadata_.max_object_store_id;
319 
320   return object_store;
321 }
322 
deleteObjectStore(const String & name,ExceptionState & exception_state)323 void IDBDatabase::deleteObjectStore(const String& name,
324                                     ExceptionState& exception_state) {
325   IDB_TRACE("IDBDatabase::deleteObjectStore");
326   if (!version_change_transaction_) {
327     exception_state.ThrowDOMException(
328         DOMExceptionCode::kInvalidStateError,
329         IDBDatabase::kNotVersionChangeTransactionErrorMessage);
330     return;
331   }
332   if (!version_change_transaction_->IsActive()) {
333     exception_state.ThrowDOMException(
334         DOMExceptionCode::kTransactionInactiveError,
335         version_change_transaction_->InactiveErrorMessage());
336     return;
337   }
338 
339   int64_t object_store_id = FindObjectStoreId(name);
340   if (object_store_id == IDBObjectStoreMetadata::kInvalidId) {
341     exception_state.ThrowDOMException(
342         DOMExceptionCode::kNotFoundError,
343         "The specified object store was not found.");
344     return;
345   }
346 
347   if (!backend_) {
348     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
349                                       IDBDatabase::kDatabaseClosedErrorMessage);
350     return;
351   }
352 
353   version_change_transaction_->transaction_backend()->DeleteObjectStore(
354       object_store_id);
355   version_change_transaction_->ObjectStoreDeleted(object_store_id, name);
356   metadata_.object_stores.erase(object_store_id);
357 }
358 
transaction(ScriptState * script_state,const StringOrStringSequence & store_names,const String & mode,ExceptionState & exception_state)359 IDBTransaction* IDBDatabase::transaction(
360     ScriptState* script_state,
361     const StringOrStringSequence& store_names,
362     const String& mode,
363     ExceptionState& exception_state) {
364   return transaction(script_state, store_names, mode, nullptr, exception_state);
365 }
366 
transaction(ScriptState * script_state,const StringOrStringSequence & store_names,const String & mode_string,const IDBTransactionOptions * options,ExceptionState & exception_state)367 IDBTransaction* IDBDatabase::transaction(
368     ScriptState* script_state,
369     const StringOrStringSequence& store_names,
370     const String& mode_string,
371     const IDBTransactionOptions* options,
372     ExceptionState& exception_state) {
373   IDB_TRACE("IDBDatabase::transaction");
374 
375   HashSet<String> scope;
376   if (store_names.IsString()) {
377     scope.insert(store_names.GetAsString());
378   } else if (store_names.IsStringSequence()) {
379     for (const String& name : store_names.GetAsStringSequence())
380       scope.insert(name);
381   } else {
382     NOTREACHED();
383   }
384 
385   if (version_change_transaction_) {
386     exception_state.ThrowDOMException(
387         DOMExceptionCode::kInvalidStateError,
388         "A version change transaction is running.");
389     return nullptr;
390   }
391 
392   if (close_pending_) {
393     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
394                                       "The database connection is closing.");
395     return nullptr;
396   }
397 
398   if (!backend_) {
399     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
400                                       IDBDatabase::kDatabaseClosedErrorMessage);
401     return nullptr;
402   }
403 
404   if (scope.IsEmpty()) {
405     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
406                                       "The storeNames parameter was empty.");
407     return nullptr;
408   }
409 
410   Vector<int64_t> object_store_ids;
411   for (const String& name : scope) {
412     int64_t object_store_id = FindObjectStoreId(name);
413     if (object_store_id == IDBObjectStoreMetadata::kInvalidId) {
414       exception_state.ThrowDOMException(
415           DOMExceptionCode::kNotFoundError,
416           "One of the specified object stores was not found.");
417       return nullptr;
418     }
419     object_store_ids.push_back(object_store_id);
420   }
421 
422   mojom::IDBTransactionMode mode = IDBTransaction::StringToMode(mode_string);
423   if (mode != mojom::IDBTransactionMode::ReadOnly &&
424       mode != mojom::IDBTransactionMode::ReadWrite) {
425     exception_state.ThrowTypeError(
426         "The mode provided ('" + mode_string +
427         "') is not one of 'readonly' or 'readwrite'.");
428     return nullptr;
429   }
430 
431   // TODO(cmp): Delete |transaction_id| once all users are removed.
432   int64_t transaction_id = NextTransactionId();
433   auto transaction_backend = std::make_unique<WebIDBTransactionImpl>(
434       ExecutionContext::From(script_state)
435           ->GetTaskRunner(TaskType::kDatabaseAccess),
436       transaction_id);
437 
438   mojom::IDBTransactionDurability durability =
439       mojom::IDBTransactionDurability::Default;
440   if (options) {
441     DCHECK(RuntimeEnabledFeatures::IDBRelaxedDurabilityEnabled());
442     if (options->durability() == indexed_db_names::kRelaxed) {
443       durability = mojom::IDBTransactionDurability::Relaxed;
444     } else if (options->durability() == indexed_db_names::kStrict) {
445       durability = mojom::IDBTransactionDurability::Strict;
446     }
447   }
448 
449   backend_->CreateTransaction(transaction_backend->CreateReceiver(),
450                               transaction_id, object_store_ids, mode,
451                               durability);
452 
453   return IDBTransaction::CreateNonVersionChange(
454       script_state, std::move(transaction_backend), transaction_id, scope, mode,
455       durability, this);
456 }
457 
ForceClose()458 void IDBDatabase::ForceClose() {
459   for (const auto& it : transactions_)
460     it.value->abort(IGNORE_EXCEPTION_FOR_TESTING);
461   this->close();
462   EnqueueEvent(Event::Create(event_type_names::kClose));
463 }
464 
close()465 void IDBDatabase::close() {
466   IDB_TRACE("IDBDatabase::close");
467   if (close_pending_)
468     return;
469 
470   connection_lifetime_.reset();
471   close_pending_ = true;
472   feature_handle_for_scheduler_.reset();
473 
474   if (transactions_.IsEmpty())
475     CloseConnection();
476 }
477 
CloseConnection()478 void IDBDatabase::CloseConnection() {
479   DCHECK(close_pending_);
480   DCHECK(transactions_.IsEmpty());
481 
482   if (backend_) {
483     backend_->Close();
484     backend_.reset();
485   }
486 
487   if (database_callbacks_)
488     database_callbacks_->DetachWebCallbacks();
489 
490   if (!GetExecutionContext())
491     return;
492 
493   // Remove any pending versionchange events scheduled to fire on this
494   // connection. They would have been scheduled by the backend when another
495   // connection attempted an upgrade, but the frontend connection is being
496   // closed before they could fire.
497   event_queue_->CancelAllEvents();
498 }
499 
OnVersionChange(int64_t old_version,int64_t new_version)500 void IDBDatabase::OnVersionChange(int64_t old_version, int64_t new_version) {
501   IDB_TRACE("IDBDatabase::onVersionChange");
502   if (!GetExecutionContext())
503     return;
504 
505   if (close_pending_) {
506     // If we're pending, that means there's a busy transaction. We won't
507     // fire 'versionchange' but since we're not closing immediately the
508     // back-end should still send out 'blocked'.
509     backend_->VersionChangeIgnored();
510     return;
511   }
512 
513   base::Optional<uint64_t> new_version_nullable;
514   if (new_version != IDBDatabaseMetadata::kNoVersion) {
515     new_version_nullable = new_version;
516   }
517   EnqueueEvent(MakeGarbageCollected<IDBVersionChangeEvent>(
518       event_type_names::kVersionchange, old_version, new_version_nullable));
519 }
520 
EnqueueEvent(Event * event)521 void IDBDatabase::EnqueueEvent(Event* event) {
522   DCHECK(GetExecutionContext());
523   event->SetTarget(this);
524   event_queue_->EnqueueEvent(FROM_HERE, *event);
525 }
526 
DispatchEventInternal(Event & event)527 DispatchEventResult IDBDatabase::DispatchEventInternal(Event& event) {
528   IDB_TRACE("IDBDatabase::dispatchEvent");
529 
530   event.SetTarget(this);
531 
532   // If this event originated from script, it should have no side effects.
533   if (!event.isTrusted())
534     return EventTarget::DispatchEventInternal(event);
535   DCHECK(event.type() == event_type_names::kVersionchange ||
536          event.type() == event_type_names::kClose);
537 
538   if (!GetExecutionContext())
539     return DispatchEventResult::kCanceledBeforeDispatch;
540 
541   DispatchEventResult dispatch_result =
542       EventTarget::DispatchEventInternal(event);
543   if (event.type() == event_type_names::kVersionchange && !close_pending_ &&
544       backend_)
545     backend_->VersionChangeIgnored();
546   return dispatch_result;
547 }
548 
FindObjectStoreId(const String & name) const549 int64_t IDBDatabase::FindObjectStoreId(const String& name) const {
550   for (const auto& it : metadata_.object_stores) {
551     if (it.value->name == name) {
552       DCHECK_NE(it.key, IDBObjectStoreMetadata::kInvalidId);
553       return it.key;
554     }
555   }
556   return IDBObjectStoreMetadata::kInvalidId;
557 }
558 
RenameObjectStore(int64_t object_store_id,const String & new_name)559 void IDBDatabase::RenameObjectStore(int64_t object_store_id,
560                                     const String& new_name) {
561   DCHECK(version_change_transaction_)
562       << "Object store renamed on database without a versionchange transaction";
563   DCHECK(version_change_transaction_->IsActive())
564       << "Object store renamed when versionchange transaction is not active";
565   DCHECK(backend_) << "Object store renamed after database connection closed";
566   DCHECK(metadata_.object_stores.Contains(object_store_id));
567 
568   backend_->RenameObjectStore(version_change_transaction_->Id(),
569                               object_store_id, new_name);
570 
571   IDBObjectStoreMetadata* object_store_metadata =
572       metadata_.object_stores.at(object_store_id);
573   version_change_transaction_->ObjectStoreRenamed(object_store_metadata->name,
574                                                   new_name);
575   object_store_metadata->name = new_name;
576 }
577 
RevertObjectStoreCreation(int64_t object_store_id)578 void IDBDatabase::RevertObjectStoreCreation(int64_t object_store_id) {
579   DCHECK(version_change_transaction_) << "Object store metadata reverted on "
580                                          "database without a versionchange "
581                                          "transaction";
582   DCHECK(!version_change_transaction_->IsActive())
583       << "Object store metadata reverted when versionchange transaction is "
584          "still active";
585   DCHECK(metadata_.object_stores.Contains(object_store_id));
586   metadata_.object_stores.erase(object_store_id);
587 }
588 
RevertObjectStoreMetadata(scoped_refptr<IDBObjectStoreMetadata> old_metadata)589 void IDBDatabase::RevertObjectStoreMetadata(
590     scoped_refptr<IDBObjectStoreMetadata> old_metadata) {
591   DCHECK(version_change_transaction_) << "Object store metadata reverted on "
592                                          "database without a versionchange "
593                                          "transaction";
594   DCHECK(!version_change_transaction_->IsActive())
595       << "Object store metadata reverted when versionchange transaction is "
596          "still active";
597   DCHECK(old_metadata.get());
598   metadata_.object_stores.Set(old_metadata->id, std::move(old_metadata));
599 }
600 
HasPendingActivity() const601 bool IDBDatabase::HasPendingActivity() const {
602   // The script wrapper must not be collected before the object is closed or
603   // we can't fire a "versionchange" event to let script manually close the
604   // connection.
605   return !close_pending_ && GetExecutionContext() && HasEventListeners();
606 }
607 
ContextDestroyed()608 void IDBDatabase::ContextDestroyed() {
609   // Immediately close the connection to the back end. Don't attempt a
610   // normal close() since that may wait on transactions which require a
611   // round trip to the back-end to abort.
612   if (backend_) {
613     backend_->Close();
614     backend_.reset();
615   }
616 
617   connection_lifetime_.reset();
618 
619   if (database_callbacks_)
620     database_callbacks_->DetachWebCallbacks();
621 }
622 
InterfaceName() const623 const AtomicString& IDBDatabase::InterfaceName() const {
624   return event_target_names::kIDBDatabase;
625 }
626 
GetExecutionContext() const627 ExecutionContext* IDBDatabase::GetExecutionContext() const {
628   return ExecutionContextLifecycleObserver::GetExecutionContext();
629 }
630 
631 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kNoError,
632                    DOMExceptionCode::kNoError);
633 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kUnknownError,
634                    DOMExceptionCode::kUnknownError);
635 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kConstraintError,
636                    DOMExceptionCode::kConstraintError);
637 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kDataError,
638                    DOMExceptionCode::kDataError);
639 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kVersionError,
640                    DOMExceptionCode::kVersionError);
641 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kAbortError,
642                    DOMExceptionCode::kAbortError);
643 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kQuotaError,
644                    DOMExceptionCode::kQuotaExceededError);
645 STATIC_ASSERT_ENUM(mojom::blink::IDBException::kTimeoutError,
646                    DOMExceptionCode::kTimeoutError);
647 
648 }  // namespace blink
649