Skip to content

Commit 15fb854

Browse files
committed
LibWeb/IndexedDB: Throw an InvalidState when handling removed items
This fixes a bunch of FIXME's, and passes a previously crashing subtest on WPT. https://wpt.fyi/results/IndexedDB/idbindex-rename-errors.any.html
1 parent a125bc9 commit 15fb854

File tree

5 files changed

+78
-26
lines changed

5 files changed

+78
-26
lines changed

Libraries/LibWeb/IndexedDB/IDBDatabase.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ WebIDL::ExceptionOr<void> IDBDatabase::delete_object_store(String const& name)
186186
// 7. Destroy store.
187187
database->remove_object_store(*store);
188188

189+
store->mark_deleted();
190+
189191
return {};
190192
}
191193

Libraries/LibWeb/IndexedDB/IDBIndex.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ WebIDL::ExceptionOr<void> IDBIndex::set_name(String const& value)
6666
if (!transaction->is_active())
6767
return WebIDL::TransactionInactiveError::create(realm, "Transaction is not active while updating index name"_utf16);
6868

69-
// FIXME: 6. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
69+
// 6. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
70+
if (index->is_deleted() || index->object_store()->is_deleted())
71+
return WebIDL::InvalidStateError::create(realm, "Index or index’s object store has been deleted"_utf16);
7072

7173
// 7. If index’s name is equal to name, terminate these steps.
7274
if (index->name() == name)
@@ -112,9 +114,11 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBIndex::open_cursor(JS::Value query,
112114
auto transaction = this->transaction();
113115

114116
// 2. Let index be this’s index.
115-
[[maybe_unused]] auto index = this->index();
117+
auto index = this->index();
116118

117-
// FIXME: 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
119+
// 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
120+
if (index->is_deleted() || index->object_store()->is_deleted())
121+
return WebIDL::InvalidStateError::create(realm, "Index or index’s object store has been deleted"_utf16);
118122

119123
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
120124
if (!transaction->is_active())
@@ -152,7 +156,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBIndex::get(JS::Value query)
152156
// 2. Let index be this’s index.
153157
auto index = this->index();
154158

155-
// FIXME: 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
159+
// 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
160+
if (index->is_deleted() || index->object_store()->is_deleted())
161+
return WebIDL::InvalidStateError::create(realm, "Index or index’s object store has been deleted"_utf16);
156162

157163
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
158164
if (!transaction->is_active())
@@ -183,7 +189,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBIndex::get_key(JS::Value query)
183189
// 2. Let index be this’s index.
184190
auto index = this->index();
185191

186-
// FIXME: 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
192+
// 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
193+
if (index->is_deleted() || index->object_store()->is_deleted())
194+
return WebIDL::InvalidStateError::create(realm, "Index or index’s object store has been deleted"_utf16);
187195

188196
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
189197
if (!transaction->is_active())
@@ -230,7 +238,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBIndex::count(JS::Value query)
230238
// 2. Let index be this’s index.
231239
auto index = this->index();
232240

233-
// FIXME: 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
241+
// 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
242+
if (index->is_deleted() || index->object_store()->is_deleted())
243+
return WebIDL::InvalidStateError::create(realm, "Index or index’s object store has been deleted"_utf16);
234244

235245
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
236246
if (!transaction->is_active())
@@ -259,9 +269,11 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBIndex::open_key_cursor(JS::Value que
259269
auto transaction = this->transaction();
260270

261271
// 2. Let index be this’s index.
262-
[[maybe_unused]] auto index = this->index();
272+
auto index = this->index();
263273

264-
// FIXME: 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
274+
// 3. If index or index’s object store has been deleted, throw an "InvalidStateError" DOMException.
275+
if (index->is_deleted() || index->object_store()->is_deleted())
276+
return WebIDL::InvalidStateError::create(realm, "Index or index’s object store has been deleted"_utf16);
265277

266278
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
267279
if (!transaction->is_active())

Libraries/LibWeb/IndexedDB/IDBObjectStore.cpp

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ WebIDL::ExceptionOr<void> IDBObjectStore::set_name(String const& value)
7272
// 3. Let store be this’s object store.
7373
auto& store = m_store;
7474

75-
// FIXME: 4. If store has been deleted, throw an "InvalidStateError" DOMException.
75+
// 4. If store has been deleted, throw an "InvalidStateError" DOMException.
76+
if (store->is_deleted())
77+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
7678

7779
// 5. If transaction is not an upgrade transaction, throw an "InvalidStateError" DOMException.
7880
if (!transaction->is_upgrade_transaction())
@@ -157,7 +159,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBIndex>> IDBObjectStore::create_index(String const
157159
if (!transaction->is_upgrade_transaction())
158160
return WebIDL::InvalidStateError::create(realm, "Transaction is not an upgrade transaction"_utf16);
159161

160-
// FIXME: 4. If store has been deleted, throw an "InvalidStateError" DOMException.
162+
// 4. If store has been deleted, throw an "InvalidStateError" DOMException.
163+
if (store->is_deleted())
164+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
161165

162166
// 5. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
163167
if (!transaction->is_active())
@@ -195,25 +199,29 @@ WebIDL::ExceptionOr<GC::Ref<IDBIndex>> IDBObjectStore::create_index(String const
195199
// https://w3c.github.io/IndexedDB/#dom-idbobjectstore-index
196200
WebIDL::ExceptionOr<GC::Ref<IDBIndex>> IDBObjectStore::index(String const& name)
197201
{
202+
auto& realm = this->realm();
203+
198204
// 1. Let transaction be this’s transaction.
199205
auto transaction = this->transaction();
200206

201207
// 2. Let store be this’s object store.
202-
[[maybe_unused]] auto store = this->store();
208+
auto store = this->store();
203209

204-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
210+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
211+
if (store->is_deleted())
212+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
205213

206214
// 4. If transaction’s state is finished, then throw an "InvalidStateError" DOMException.
207215
if (transaction->state() == IDBTransaction::TransactionState::Finished)
208-
return WebIDL::InvalidStateError::create(realm(), "Transaction is finished"_utf16);
216+
return WebIDL::InvalidStateError::create(realm, "Transaction is finished"_utf16);
209217

210218
// 5. Let index be the index named name in this’s index set if one exists, or throw a "NotFoundError" DOMException otherwise.
211219
auto index = m_indexes.get(name);
212220
if (!index.has_value())
213-
return WebIDL::NotFoundError::create(realm(), "Index not found in object store"_utf16);
221+
return WebIDL::NotFoundError::create(realm, "Index not found in object store"_utf16);
214222

215223
// 6. Return an index handle associated with index and this.
216-
return IDBIndex::create(realm(), *index, *this);
224+
return IDBIndex::create(realm, *index, *this);
217225
}
218226

219227
// https://w3c.github.io/IndexedDB/#dom-idbobjectstore-deleteindex
@@ -231,7 +239,9 @@ WebIDL::ExceptionOr<void> IDBObjectStore::delete_index(String const& name)
231239
if (!transaction->is_upgrade_transaction())
232240
return WebIDL::InvalidStateError::create(realm, "Transaction is not an upgrade transaction"_utf16);
233241

234-
// FIXME: 4. If store has been deleted, throw an "InvalidStateError" DOMException.
242+
// 4. If store has been deleted, throw an "InvalidStateError" DOMException.
243+
if (store->is_deleted())
244+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
235245

236246
// 5. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
237247
if (!transaction->is_active())
@@ -248,6 +258,8 @@ WebIDL::ExceptionOr<void> IDBObjectStore::delete_index(String const& name)
248258
// 8. Destroy index.
249259
store->index_set().remove(name);
250260

261+
index.release_value()->mark_deleted();
262+
251263
return {};
252264
}
253265

@@ -262,7 +274,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::add_or_put(GC::Ref<IDBO
262274
// 2. Let store be handle’s object store.
263275
auto& store = *handle->store();
264276

265-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
277+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
278+
if (store.is_deleted())
279+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
266280

267281
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
268282
if (!transaction->is_active())
@@ -370,7 +384,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::count(Optional<JS::Valu
370384
// 2. Let store be this's object store.
371385
auto store = this->store();
372386

373-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
387+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
388+
if (store->is_deleted())
389+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
374390

375391
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
376392
if (!transaction->is_active())
@@ -401,7 +417,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::get(JS::Value query)
401417
// 2. Let store be this's object store.
402418
auto store = this->store();
403419

404-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
420+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
421+
if (store->is_deleted())
422+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
405423

406424
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
407425
if (!transaction->is_active())
@@ -430,9 +448,11 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::open_cursor(JS::Value q
430448
auto transaction = this->transaction();
431449

432450
// 2. Let store be this's object store.
433-
[[maybe_unused]] auto store = this->store();
451+
auto store = this->store();
434452

435-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
453+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
454+
if (store->is_deleted())
455+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
436456

437457
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
438458
if (!transaction->is_active())
@@ -472,7 +492,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::delete_(JS::Value query
472492
// 2. Let store be this’s object store.
473493
auto store = this->store();
474494

475-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
495+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
496+
if (store->is_deleted())
497+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
476498

477499
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
478500
if (!transaction->is_active())
@@ -507,7 +529,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::clear()
507529
// 2. Let store be this’s object store.
508530
auto store = this->store();
509531

510-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
532+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
533+
if (store->is_deleted())
534+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
511535

512536
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
513537
if (!transaction->is_active())
@@ -539,7 +563,9 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::get_key(JS::Value query
539563
// 2. Let store be this’s object store.
540564
auto store = this->store();
541565

542-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
566+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
567+
if (store->is_deleted())
568+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
543569

544570
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
545571
if (!transaction->is_active())
@@ -576,9 +602,11 @@ WebIDL::ExceptionOr<GC::Ref<IDBRequest>> IDBObjectStore::open_key_cursor(JS::Val
576602
auto transaction = this->transaction();
577603

578604
// 2. Let store be this’s object store.
579-
[[maybe_unused]] auto store = this->store();
605+
auto store = this->store();
580606

581-
// FIXME: 3. If store has been deleted, throw an "InvalidStateError" DOMException.
607+
// 3. If store has been deleted, throw an "InvalidStateError" DOMException.
608+
if (store->is_deleted())
609+
return WebIDL::InvalidStateError::create(realm, "Object store has been deleted"_utf16);
582610

583611
// 4. If transaction’s state is not active, then throw a "TransactionInactiveError" DOMException.
584612
if (!transaction->is_active())

Libraries/LibWeb/IndexedDB/Internal/Index.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class Index : public JS::Cell {
4545

4646
HTML::SerializationRecord referenced_value(IndexRecord const& index_record) const;
4747

48+
[[nodiscard]] bool is_deleted() const { return m_deleted; }
49+
void mark_deleted() { m_deleted = true; }
50+
4851
protected:
4952
virtual void visit_edges(Visitor&) override;
5053

@@ -68,6 +71,8 @@ class Index : public JS::Cell {
6871

6972
// The keys are derived from the referenced object store’s values using a key path.
7073
KeyPath m_key_path;
74+
75+
bool m_deleted { false };
7176
};
7277

7378
}

Libraries/LibWeb/IndexedDB/Internal/ObjectStore.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ class ObjectStore : public JS::Cell {
5454
GC::ConservativeVector<ObjectStoreRecord> first_n_in_range(GC::Ref<IDBKeyRange> range, Optional<WebIDL::UnsignedLong> count);
5555
GC::ConservativeVector<ObjectStoreRecord> last_n_in_range(GC::Ref<IDBKeyRange> range, Optional<WebIDL::UnsignedLong> count);
5656

57+
[[nodiscard]] bool is_deleted() const { return m_deleted; }
58+
void mark_deleted() { m_deleted = true; }
59+
5760
protected:
5861
virtual void visit_edges(Visitor&) override;
5962

@@ -77,6 +80,8 @@ class ObjectStore : public JS::Cell {
7780

7881
// An object store has a list of records
7982
Vector<ObjectStoreRecord> m_records;
83+
84+
bool m_deleted { false };
8085
};
8186

8287
}

0 commit comments

Comments
 (0)