Line data Source code
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 : #include "IDBDatabase.h"
8 :
9 : #include "FileInfo.h"
10 : #include "IDBEvents.h"
11 : #include "IDBFactory.h"
12 : #include "IDBIndex.h"
13 : #include "IDBMutableFile.h"
14 : #include "IDBObjectStore.h"
15 : #include "IDBRequest.h"
16 : #include "IDBTransaction.h"
17 : #include "IDBFactory.h"
18 : #include "IndexedDatabaseManager.h"
19 : #include "mozilla/ErrorResult.h"
20 : #include "mozilla/EventDispatcher.h"
21 : #include "MainThreadUtils.h"
22 : #include "mozilla/Services.h"
23 : #include "mozilla/storage.h"
24 : #include "mozilla/dom/BindingDeclarations.h"
25 : #include "mozilla/dom/DOMStringList.h"
26 : #include "mozilla/dom/DOMStringListBinding.h"
27 : #include "mozilla/dom/Exceptions.h"
28 : #include "mozilla/dom/File.h"
29 : #include "mozilla/dom/IDBDatabaseBinding.h"
30 : #include "mozilla/dom/IDBObjectStoreBinding.h"
31 : #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
32 : #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
33 : #include "mozilla/dom/IPCBlobUtils.h"
34 : #include "mozilla/dom/quota/QuotaManager.h"
35 : #include "mozilla/ipc/BackgroundChild.h"
36 : #include "mozilla/ipc/BackgroundUtils.h"
37 : #include "mozilla/ipc/FileDescriptor.h"
38 : #include "mozilla/ipc/InputStreamParams.h"
39 : #include "mozilla/ipc/InputStreamUtils.h"
40 : #include "nsAutoPtr.h"
41 : #include "nsCOMPtr.h"
42 : #include "nsIDocument.h"
43 : #include "nsIObserver.h"
44 : #include "nsIObserverService.h"
45 : #include "nsIScriptError.h"
46 : #include "nsISupportsPrimitives.h"
47 : #include "nsThreadUtils.h"
48 : #include "ProfilerHelpers.h"
49 : #include "ReportInternalError.h"
50 : #include "ScriptErrorHelper.h"
51 : #include "nsQueryObject.h"
52 :
53 : // Include this last to avoid path problems on Windows.
54 : #include "ActorsChild.h"
55 :
56 : namespace mozilla {
57 : namespace dom {
58 :
59 : using namespace mozilla::dom::indexedDB;
60 : using namespace mozilla::dom::quota;
61 : using namespace mozilla::ipc;
62 : using namespace mozilla::services;
63 :
64 : namespace {
65 :
66 : const char kCycleCollectionObserverTopic[] = "cycle-collector-end";
67 : const char kMemoryPressureObserverTopic[] = "memory-pressure";
68 : const char kWindowObserverTopic[] = "inner-window-destroyed";
69 :
70 : class CancelableRunnableWrapper final
71 : : public CancelableRunnable
72 : {
73 : nsCOMPtr<nsIRunnable> mRunnable;
74 :
75 : public:
76 0 : explicit CancelableRunnableWrapper(nsIRunnable* aRunnable)
77 0 : : CancelableRunnable("dom::CancelableRunnableWrapper")
78 0 : , mRunnable(aRunnable)
79 : {
80 0 : MOZ_ASSERT(aRunnable);
81 0 : }
82 :
83 : private:
84 0 : ~CancelableRunnableWrapper()
85 0 : { }
86 :
87 : NS_DECL_NSIRUNNABLE
88 : nsresult Cancel() override;
89 : };
90 :
91 : class DatabaseFile final
92 : : public PBackgroundIDBDatabaseFileChild
93 : {
94 : IDBDatabase* mDatabase;
95 :
96 : public:
97 0 : explicit DatabaseFile(IDBDatabase* aDatabase)
98 0 : : mDatabase(aDatabase)
99 : {
100 0 : MOZ_ASSERT(aDatabase);
101 0 : aDatabase->AssertIsOnOwningThread();
102 :
103 0 : MOZ_COUNT_CTOR(DatabaseFile);
104 0 : }
105 :
106 : private:
107 0 : ~DatabaseFile()
108 0 : {
109 0 : MOZ_ASSERT(!mDatabase);
110 :
111 0 : MOZ_COUNT_DTOR(DatabaseFile);
112 0 : }
113 :
114 : virtual void
115 0 : ActorDestroy(ActorDestroyReason aWhy) override
116 : {
117 0 : MOZ_ASSERT(mDatabase);
118 0 : mDatabase->AssertIsOnOwningThread();
119 :
120 0 : if (aWhy != Deletion) {
121 0 : RefPtr<IDBDatabase> database = mDatabase;
122 0 : database->NoteFinishedFileActor(this);
123 : }
124 :
125 : #ifdef DEBUG
126 0 : mDatabase = nullptr;
127 : #endif
128 0 : }
129 : };
130 :
131 : } // namespace
132 :
133 : class IDBDatabase::Observer final
134 : : public nsIObserver
135 : {
136 : IDBDatabase* mWeakDatabase;
137 : const uint64_t mWindowId;
138 :
139 : public:
140 0 : Observer(IDBDatabase* aDatabase, uint64_t aWindowId)
141 0 : : mWeakDatabase(aDatabase)
142 0 : , mWindowId(aWindowId)
143 : {
144 0 : MOZ_ASSERT(NS_IsMainThread());
145 0 : MOZ_ASSERT(aDatabase);
146 0 : }
147 :
148 : void
149 0 : Revoke()
150 : {
151 0 : MOZ_ASSERT(NS_IsMainThread());
152 :
153 0 : mWeakDatabase = nullptr;
154 0 : }
155 :
156 : NS_DECL_ISUPPORTS
157 :
158 : private:
159 0 : ~Observer()
160 0 : {
161 0 : MOZ_ASSERT(NS_IsMainThread());
162 0 : MOZ_ASSERT(!mWeakDatabase);
163 0 : }
164 :
165 : NS_DECL_NSIOBSERVER
166 : };
167 :
168 0 : IDBDatabase::IDBDatabase(IDBOpenDBRequest* aRequest,
169 : IDBFactory* aFactory,
170 : BackgroundDatabaseChild* aActor,
171 0 : DatabaseSpec* aSpec)
172 : : IDBWrapperCache(aRequest)
173 : , mFactory(aFactory)
174 : , mSpec(aSpec)
175 : , mBackgroundActor(aActor)
176 0 : , mFileHandleDisabled(aRequest->IsFileHandleDisabled())
177 : , mClosed(false)
178 : , mInvalidated(false)
179 : , mQuotaExceeded(false)
180 0 : , mIncreasedActiveDatabaseCount(false)
181 : {
182 0 : MOZ_ASSERT(aRequest);
183 0 : MOZ_ASSERT(aFactory);
184 0 : aFactory->AssertIsOnOwningThread();
185 0 : MOZ_ASSERT(aActor);
186 0 : MOZ_ASSERT(aSpec);
187 0 : }
188 :
189 0 : IDBDatabase::~IDBDatabase()
190 : {
191 0 : AssertIsOnOwningThread();
192 0 : MOZ_ASSERT(!mBackgroundActor);
193 0 : MOZ_ASSERT(!mIncreasedActiveDatabaseCount);
194 0 : }
195 :
196 : // static
197 : already_AddRefed<IDBDatabase>
198 0 : IDBDatabase::Create(IDBOpenDBRequest* aRequest,
199 : IDBFactory* aFactory,
200 : BackgroundDatabaseChild* aActor,
201 : DatabaseSpec* aSpec)
202 : {
203 0 : MOZ_ASSERT(aRequest);
204 0 : MOZ_ASSERT(aFactory);
205 0 : aFactory->AssertIsOnOwningThread();
206 0 : MOZ_ASSERT(aActor);
207 0 : MOZ_ASSERT(aSpec);
208 :
209 : RefPtr<IDBDatabase> db =
210 0 : new IDBDatabase(aRequest, aFactory, aActor, aSpec);
211 :
212 0 : db->SetScriptOwner(aRequest->GetScriptOwner());
213 :
214 0 : if (NS_IsMainThread()) {
215 0 : if (nsPIDOMWindowInner* window = aFactory->GetParentObject()) {
216 0 : uint64_t windowId = window->WindowID();
217 :
218 0 : RefPtr<Observer> observer = new Observer(db, windowId);
219 :
220 0 : nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
221 0 : MOZ_ASSERT(obsSvc);
222 :
223 : // This topic must be successfully registered.
224 0 : MOZ_ALWAYS_SUCCEEDS(
225 : obsSvc->AddObserver(observer, kWindowObserverTopic, false));
226 :
227 : // These topics are not crucial.
228 0 : if (NS_FAILED(obsSvc->AddObserver(observer,
229 : kCycleCollectionObserverTopic,
230 0 : false)) ||
231 0 : NS_FAILED(obsSvc->AddObserver(observer,
232 : kMemoryPressureObserverTopic,
233 : false))) {
234 0 : NS_WARNING("Failed to add additional memory observers!");
235 : }
236 :
237 0 : db->mObserver.swap(observer);
238 : }
239 : }
240 :
241 0 : db->IncreaseActiveDatabaseCount();
242 :
243 0 : return db.forget();
244 : }
245 :
246 : #ifdef DEBUG
247 :
248 : void
249 0 : IDBDatabase::AssertIsOnOwningThread() const
250 : {
251 0 : MOZ_ASSERT(mFactory);
252 0 : mFactory->AssertIsOnOwningThread();
253 0 : }
254 :
255 : #endif // DEBUG
256 :
257 : nsIEventTarget*
258 0 : IDBDatabase::EventTarget() const
259 : {
260 0 : AssertIsOnOwningThread();
261 0 : return Factory()->EventTarget();
262 : }
263 :
264 : void
265 0 : IDBDatabase::CloseInternal()
266 : {
267 0 : AssertIsOnOwningThread();
268 :
269 0 : if (!mClosed) {
270 0 : mClosed = true;
271 :
272 0 : ExpireFileActors(/* aExpireAll */ true);
273 :
274 0 : if (mObserver) {
275 0 : mObserver->Revoke();
276 :
277 0 : nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
278 0 : if (obsSvc) {
279 : // These might not have been registered.
280 0 : obsSvc->RemoveObserver(mObserver, kCycleCollectionObserverTopic);
281 0 : obsSvc->RemoveObserver(mObserver, kMemoryPressureObserverTopic);
282 :
283 0 : MOZ_ALWAYS_SUCCEEDS(
284 : obsSvc->RemoveObserver(mObserver, kWindowObserverTopic));
285 : }
286 :
287 0 : mObserver = nullptr;
288 : }
289 :
290 0 : if (mBackgroundActor && !mInvalidated) {
291 0 : mBackgroundActor->SendClose();
292 : }
293 :
294 : // Decrease the number of active databases right after the database is
295 : // closed.
296 0 : MaybeDecreaseActiveDatabaseCount();
297 : }
298 0 : }
299 :
300 : void
301 0 : IDBDatabase::InvalidateInternal()
302 : {
303 0 : AssertIsOnOwningThread();
304 :
305 0 : InvalidateMutableFiles();
306 0 : AbortTransactions(/* aShouldWarn */ true);
307 :
308 0 : CloseInternal();
309 0 : }
310 :
311 : void
312 0 : IDBDatabase::EnterSetVersionTransaction(uint64_t aNewVersion)
313 : {
314 0 : AssertIsOnOwningThread();
315 0 : MOZ_ASSERT(aNewVersion);
316 0 : MOZ_ASSERT(!RunningVersionChangeTransaction());
317 0 : MOZ_ASSERT(mSpec);
318 0 : MOZ_ASSERT(!mPreviousSpec);
319 :
320 0 : mPreviousSpec = new DatabaseSpec(*mSpec);
321 :
322 0 : mSpec->metadata().version() = aNewVersion;
323 0 : }
324 :
325 : void
326 0 : IDBDatabase::ExitSetVersionTransaction()
327 : {
328 0 : AssertIsOnOwningThread();
329 :
330 0 : if (mPreviousSpec) {
331 0 : mPreviousSpec = nullptr;
332 : }
333 0 : }
334 :
335 : void
336 0 : IDBDatabase::RevertToPreviousState()
337 : {
338 0 : AssertIsOnOwningThread();
339 0 : MOZ_ASSERT(RunningVersionChangeTransaction());
340 0 : MOZ_ASSERT(mPreviousSpec);
341 :
342 : // Hold the current spec alive until RefreshTransactionsSpecEnumerator has
343 : // finished!
344 0 : nsAutoPtr<DatabaseSpec> currentSpec(mSpec.forget());
345 :
346 0 : mSpec = mPreviousSpec.forget();
347 :
348 0 : RefreshSpec(/* aMayDelete */ true);
349 0 : }
350 :
351 : void
352 0 : IDBDatabase::RefreshSpec(bool aMayDelete)
353 : {
354 0 : AssertIsOnOwningThread();
355 :
356 0 : for (auto iter = mTransactions.Iter(); !iter.Done(); iter.Next()) {
357 0 : RefPtr<IDBTransaction> transaction = iter.Get()->GetKey();
358 0 : MOZ_ASSERT(transaction);
359 0 : transaction->AssertIsOnOwningThread();
360 0 : transaction->RefreshSpec(aMayDelete);
361 : }
362 0 : }
363 :
364 : nsPIDOMWindowInner*
365 0 : IDBDatabase::GetParentObject() const
366 : {
367 0 : return mFactory->GetParentObject();
368 : }
369 :
370 : const nsString&
371 0 : IDBDatabase::Name() const
372 : {
373 0 : AssertIsOnOwningThread();
374 0 : MOZ_ASSERT(mSpec);
375 :
376 0 : return mSpec->metadata().name();
377 : }
378 :
379 : uint64_t
380 0 : IDBDatabase::Version() const
381 : {
382 0 : AssertIsOnOwningThread();
383 0 : MOZ_ASSERT(mSpec);
384 :
385 0 : return mSpec->metadata().version();
386 : }
387 :
388 : already_AddRefed<DOMStringList>
389 0 : IDBDatabase::ObjectStoreNames() const
390 : {
391 0 : AssertIsOnOwningThread();
392 0 : MOZ_ASSERT(mSpec);
393 :
394 0 : const nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
395 :
396 0 : RefPtr<DOMStringList> list = new DOMStringList();
397 :
398 0 : if (!objectStores.IsEmpty()) {
399 0 : nsTArray<nsString>& listNames = list->StringArray();
400 0 : listNames.SetCapacity(objectStores.Length());
401 :
402 0 : for (uint32_t index = 0; index < objectStores.Length(); index++) {
403 0 : listNames.InsertElementSorted(objectStores[index].metadata().name());
404 : }
405 : }
406 :
407 0 : return list.forget();
408 : }
409 :
410 : already_AddRefed<nsIDocument>
411 0 : IDBDatabase::GetOwnerDocument() const
412 : {
413 0 : if (nsPIDOMWindowInner* window = GetOwner()) {
414 0 : nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
415 0 : return doc.forget();
416 : }
417 0 : return nullptr;
418 : }
419 :
420 : already_AddRefed<IDBObjectStore>
421 0 : IDBDatabase::CreateObjectStore(
422 : const nsAString& aName,
423 : const IDBObjectStoreParameters& aOptionalParameters,
424 : ErrorResult& aRv)
425 : {
426 0 : AssertIsOnOwningThread();
427 :
428 0 : IDBTransaction* transaction = IDBTransaction::GetCurrent();
429 0 : if (!transaction ||
430 0 : transaction->Database() != this ||
431 0 : transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
432 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
433 0 : return nullptr;
434 : }
435 :
436 0 : if (!transaction->IsOpen()) {
437 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
438 0 : return nullptr;
439 : }
440 :
441 0 : KeyPath keyPath(0);
442 0 : if (NS_FAILED(KeyPath::Parse(aOptionalParameters.mKeyPath, &keyPath))) {
443 0 : aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
444 0 : return nullptr;
445 : }
446 :
447 0 : nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
448 0 : for (uint32_t count = objectStores.Length(), index = 0;
449 0 : index < count;
450 : index++) {
451 0 : if (aName == objectStores[index].metadata().name()) {
452 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
453 0 : return nullptr;
454 : }
455 : }
456 :
457 0 : if (!keyPath.IsAllowedForObjectStore(aOptionalParameters.mAutoIncrement)) {
458 0 : aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
459 0 : return nullptr;
460 : }
461 :
462 : const ObjectStoreSpec* oldSpecElements =
463 0 : objectStores.IsEmpty() ? nullptr : objectStores.Elements();
464 :
465 0 : ObjectStoreSpec* newSpec = objectStores.AppendElement();
466 0 : newSpec->metadata() =
467 0 : ObjectStoreMetadata(transaction->NextObjectStoreId(), nsString(aName),
468 0 : keyPath, aOptionalParameters.mAutoIncrement);
469 :
470 0 : if (oldSpecElements &&
471 0 : oldSpecElements != objectStores.Elements()) {
472 0 : MOZ_ASSERT(objectStores.Length() > 1);
473 :
474 : // Array got moved, update the spec pointers for all live objectStores and
475 : // indexes.
476 0 : RefreshSpec(/* aMayDelete */ false);
477 : }
478 :
479 : RefPtr<IDBObjectStore> objectStore =
480 0 : transaction->CreateObjectStore(*newSpec);
481 0 : MOZ_ASSERT(objectStore);
482 :
483 : // Don't do this in the macro because we always need to increment the serial
484 : // number to keep in sync with the parent.
485 0 : const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
486 :
487 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
488 : "database(%s).transaction(%s).createObjectStore(%s)",
489 : "IndexedDB %s: C T[%lld] R[%llu]: "
490 : "IDBDatabase.createObjectStore()",
491 : IDB_LOG_ID_STRING(),
492 : transaction->LoggingSerialNumber(),
493 : requestSerialNumber,
494 : IDB_LOG_STRINGIFY(this),
495 : IDB_LOG_STRINGIFY(transaction),
496 : IDB_LOG_STRINGIFY(objectStore));
497 :
498 0 : return objectStore.forget();
499 : }
500 :
501 : void
502 0 : IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv)
503 : {
504 0 : AssertIsOnOwningThread();
505 :
506 0 : IDBTransaction* transaction = IDBTransaction::GetCurrent();
507 0 : if (!transaction ||
508 0 : transaction->Database() != this ||
509 0 : transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
510 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
511 0 : return;
512 : }
513 :
514 0 : if (!transaction->IsOpen()) {
515 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
516 0 : return;
517 : }
518 :
519 0 : nsTArray<ObjectStoreSpec>& specArray = mSpec->objectStores();
520 :
521 0 : int64_t objectStoreId = 0;
522 :
523 0 : for (uint32_t specCount = specArray.Length(), specIndex = 0;
524 0 : specIndex < specCount;
525 : specIndex++) {
526 0 : const ObjectStoreMetadata& metadata = specArray[specIndex].metadata();
527 0 : MOZ_ASSERT(metadata.id());
528 :
529 0 : if (aName == metadata.name()) {
530 0 : objectStoreId = metadata.id();
531 :
532 : // Must do this before altering the metadata array!
533 0 : transaction->DeleteObjectStore(objectStoreId);
534 :
535 0 : specArray.RemoveElementAt(specIndex);
536 :
537 0 : RefreshSpec(/* aMayDelete */ false);
538 0 : break;
539 : }
540 : }
541 :
542 0 : if (!objectStoreId) {
543 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
544 0 : return;
545 : }
546 :
547 : // Don't do this in the macro because we always need to increment the serial
548 : // number to keep in sync with the parent.
549 0 : const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
550 :
551 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
552 : "database(%s).transaction(%s).deleteObjectStore(\"%s\")",
553 : "IndexedDB %s: C T[%lld] R[%llu]: "
554 : "IDBDatabase.deleteObjectStore()",
555 : IDB_LOG_ID_STRING(),
556 : transaction->LoggingSerialNumber(),
557 : requestSerialNumber,
558 : IDB_LOG_STRINGIFY(this),
559 : IDB_LOG_STRINGIFY(transaction),
560 : NS_ConvertUTF16toUTF8(aName).get());
561 : }
562 :
563 : already_AddRefed<IDBTransaction>
564 0 : IDBDatabase::Transaction(JSContext* aCx,
565 : const StringOrStringSequence& aStoreNames,
566 : IDBTransactionMode aMode,
567 : ErrorResult& aRv)
568 : {
569 0 : AssertIsOnOwningThread();
570 :
571 0 : if ((aMode == IDBTransactionMode::Readwriteflush ||
572 0 : aMode == IDBTransactionMode::Cleanup) &&
573 0 : !IndexedDatabaseManager::ExperimentalFeaturesEnabled()) {
574 : // Pretend that this mode doesn't exist. We don't have a way to annotate
575 : // certain enum values as depending on preferences so we just duplicate the
576 : // normal exception generation here.
577 0 : aRv.ThrowTypeError<MSG_INVALID_ENUM_VALUE>(
578 0 : NS_LITERAL_STRING("Argument 2 of IDBDatabase.transaction"),
579 0 : NS_LITERAL_STRING("readwriteflush"),
580 0 : NS_LITERAL_STRING("IDBTransactionMode"));
581 0 : return nullptr;
582 : }
583 :
584 0 : RefPtr<IDBTransaction> transaction;
585 0 : aRv = Transaction(aCx, aStoreNames, aMode, getter_AddRefs(transaction));
586 0 : if (NS_WARN_IF(aRv.Failed())) {
587 0 : return nullptr;
588 : }
589 :
590 0 : return transaction.forget();
591 : }
592 :
593 : nsresult
594 0 : IDBDatabase::Transaction(JSContext* aCx,
595 : const StringOrStringSequence& aStoreNames,
596 : IDBTransactionMode aMode,
597 : IDBTransaction** aTransaction)
598 : {
599 0 : AssertIsOnOwningThread();
600 :
601 0 : if (NS_WARN_IF((aMode == IDBTransactionMode::Readwriteflush ||
602 : aMode == IDBTransactionMode::Cleanup) &&
603 : !IndexedDatabaseManager::ExperimentalFeaturesEnabled())) {
604 0 : IDB_REPORT_INTERNAL_ERR();
605 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
606 : }
607 :
608 0 : if (QuotaManager::IsShuttingDown()) {
609 0 : IDB_REPORT_INTERNAL_ERR();
610 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
611 : }
612 :
613 0 : if (mClosed || RunningVersionChangeTransaction()) {
614 0 : return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
615 : }
616 :
617 0 : AutoTArray<nsString, 1> stackSequence;
618 :
619 0 : if (aStoreNames.IsString()) {
620 0 : stackSequence.AppendElement(aStoreNames.GetAsString());
621 : } else {
622 0 : MOZ_ASSERT(aStoreNames.IsStringSequence());
623 0 : if (aStoreNames.GetAsStringSequence().IsEmpty()) {
624 0 : return NS_ERROR_DOM_INVALID_ACCESS_ERR;
625 : }
626 : }
627 :
628 : const nsTArray<nsString>& storeNames =
629 0 : aStoreNames.IsString() ?
630 : stackSequence :
631 0 : static_cast<const nsTArray<nsString>&>(aStoreNames.GetAsStringSequence());
632 0 : MOZ_ASSERT(!storeNames.IsEmpty());
633 :
634 0 : const nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
635 0 : const uint32_t nameCount = storeNames.Length();
636 :
637 0 : nsTArray<nsString> sortedStoreNames;
638 0 : sortedStoreNames.SetCapacity(nameCount);
639 :
640 : // Check to make sure the object store names we collected actually exist.
641 0 : for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) {
642 0 : const nsString& name = storeNames[nameIndex];
643 :
644 0 : bool found = false;
645 :
646 0 : for (uint32_t objCount = objectStores.Length(), objIndex = 0;
647 0 : objIndex < objCount;
648 : objIndex++) {
649 0 : if (objectStores[objIndex].metadata().name() == name) {
650 0 : found = true;
651 0 : break;
652 : }
653 : }
654 :
655 0 : if (!found) {
656 0 : return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
657 : }
658 :
659 0 : sortedStoreNames.InsertElementSorted(name);
660 : }
661 :
662 : // Remove any duplicates.
663 0 : for (uint32_t nameIndex = nameCount - 1; nameIndex > 0; nameIndex--) {
664 0 : if (sortedStoreNames[nameIndex] == sortedStoreNames[nameIndex - 1]) {
665 0 : sortedStoreNames.RemoveElementAt(nameIndex);
666 : }
667 : }
668 :
669 : IDBTransaction::Mode mode;
670 0 : switch (aMode) {
671 : case IDBTransactionMode::Readonly:
672 0 : mode = IDBTransaction::READ_ONLY;
673 0 : break;
674 : case IDBTransactionMode::Readwrite:
675 0 : if (mQuotaExceeded) {
676 0 : mode = IDBTransaction::CLEANUP;
677 0 : mQuotaExceeded = false;
678 : } else {
679 0 : mode = IDBTransaction::READ_WRITE;
680 : }
681 0 : break;
682 : case IDBTransactionMode::Readwriteflush:
683 0 : mode = IDBTransaction::READ_WRITE_FLUSH;
684 0 : break;
685 : case IDBTransactionMode::Cleanup:
686 0 : mode = IDBTransaction::CLEANUP;
687 0 : mQuotaExceeded = false;
688 0 : break;
689 : case IDBTransactionMode::Versionchange:
690 0 : return NS_ERROR_DOM_TYPE_ERR;
691 :
692 : default:
693 0 : MOZ_CRASH("Unknown mode!");
694 : }
695 :
696 : RefPtr<IDBTransaction> transaction =
697 0 : IDBTransaction::Create(aCx, this, sortedStoreNames, mode);
698 0 : MOZ_ASSERT(transaction);
699 :
700 : BackgroundTransactionChild* actor =
701 0 : new BackgroundTransactionChild(transaction);
702 :
703 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: "
704 : "database(%s).transaction(%s)",
705 : "IndexedDB %s: C T[%lld]: IDBDatabase.transaction()",
706 : IDB_LOG_ID_STRING(),
707 : transaction->LoggingSerialNumber(),
708 : IDB_LOG_STRINGIFY(this),
709 : IDB_LOG_STRINGIFY(transaction));
710 :
711 0 : MOZ_ALWAYS_TRUE(
712 : mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor,
713 : sortedStoreNames,
714 : mode));
715 0 : MOZ_ASSERT(actor->GetActorEventTarget(),
716 : "The event target shall be inherited from it manager actor.");
717 :
718 0 : transaction->SetBackgroundActor(actor);
719 :
720 0 : if (mode == IDBTransaction::CLEANUP) {
721 0 : ExpireFileActors(/* aExpireAll */ true);
722 : }
723 :
724 0 : transaction.forget(aTransaction);
725 0 : return NS_OK;
726 : }
727 :
728 : StorageType
729 0 : IDBDatabase::Storage() const
730 : {
731 0 : AssertIsOnOwningThread();
732 0 : MOZ_ASSERT(mSpec);
733 :
734 0 : return PersistenceTypeToStorage(mSpec->metadata().persistenceType());
735 : }
736 :
737 : already_AddRefed<IDBRequest>
738 0 : IDBDatabase::CreateMutableFile(JSContext* aCx,
739 : const nsAString& aName,
740 : const Optional<nsAString>& aType,
741 : ErrorResult& aRv)
742 : {
743 0 : AssertIsOnOwningThread();
744 :
745 0 : if (QuotaManager::IsShuttingDown()) {
746 0 : IDB_REPORT_INTERNAL_ERR();
747 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
748 0 : return nullptr;
749 : }
750 :
751 0 : if (mClosed || mFileHandleDisabled) {
752 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
753 0 : return nullptr;
754 : }
755 :
756 0 : nsString type;
757 0 : if (aType.WasPassed()) {
758 0 : type = aType.Value();
759 : }
760 :
761 0 : CreateFileParams params(nsString(aName), type);
762 :
763 0 : RefPtr<IDBRequest> request = IDBRequest::Create(aCx, this, nullptr);
764 0 : MOZ_ASSERT(request);
765 :
766 : BackgroundDatabaseRequestChild* actor =
767 0 : new BackgroundDatabaseRequestChild(this, request);
768 :
769 0 : IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
770 : "database(%s).createMutableFile(%s)",
771 : "IndexedDB %s: C R[%llu]: IDBDatabase.createMutableFile()",
772 : IDB_LOG_ID_STRING(),
773 : request->LoggingSerialNumber(),
774 : IDB_LOG_STRINGIFY(this),
775 : NS_ConvertUTF16toUTF8(aName).get());
776 :
777 0 : mBackgroundActor->SendPBackgroundIDBDatabaseRequestConstructor(actor, params);
778 :
779 0 : MOZ_ASSERT(actor->GetActorEventTarget(),
780 : "The event target shall be inherited from its manager actor.");
781 :
782 0 : return request.forget();
783 : }
784 :
785 : void
786 0 : IDBDatabase::RegisterTransaction(IDBTransaction* aTransaction)
787 : {
788 0 : AssertIsOnOwningThread();
789 0 : MOZ_ASSERT(aTransaction);
790 0 : aTransaction->AssertIsOnOwningThread();
791 0 : MOZ_ASSERT(!mTransactions.Contains(aTransaction));
792 :
793 0 : mTransactions.PutEntry(aTransaction);
794 0 : }
795 :
796 : void
797 0 : IDBDatabase::UnregisterTransaction(IDBTransaction* aTransaction)
798 : {
799 0 : AssertIsOnOwningThread();
800 0 : MOZ_ASSERT(aTransaction);
801 0 : aTransaction->AssertIsOnOwningThread();
802 0 : MOZ_ASSERT(mTransactions.Contains(aTransaction));
803 :
804 0 : mTransactions.RemoveEntry(aTransaction);
805 0 : }
806 :
807 : void
808 0 : IDBDatabase::AbortTransactions(bool aShouldWarn)
809 : {
810 0 : AssertIsOnOwningThread();
811 :
812 : class MOZ_STACK_CLASS Helper final
813 : {
814 : typedef AutoTArray<RefPtr<IDBTransaction>, 20> StrongTransactionArray;
815 : typedef AutoTArray<IDBTransaction*, 20> WeakTransactionArray;
816 :
817 : public:
818 : static void
819 0 : AbortTransactions(IDBDatabase* aDatabase, const bool aShouldWarn)
820 : {
821 0 : MOZ_ASSERT(aDatabase);
822 0 : aDatabase->AssertIsOnOwningThread();
823 :
824 : nsTHashtable<nsPtrHashKey<IDBTransaction>>& transactionTable =
825 0 : aDatabase->mTransactions;
826 :
827 0 : if (!transactionTable.Count()) {
828 0 : return;
829 : }
830 :
831 0 : StrongTransactionArray transactionsToAbort;
832 0 : transactionsToAbort.SetCapacity(transactionTable.Count());
833 :
834 0 : for (auto iter = transactionTable.Iter(); !iter.Done(); iter.Next()) {
835 0 : IDBTransaction* transaction = iter.Get()->GetKey();
836 0 : MOZ_ASSERT(transaction);
837 :
838 0 : transaction->AssertIsOnOwningThread();
839 :
840 : // Transactions that are already done can simply be ignored. Otherwise
841 : // there is a race here and it's possible that the transaction has not
842 : // been successfully committed yet so we will warn the user.
843 0 : if (!transaction->IsDone()) {
844 0 : transactionsToAbort.AppendElement(transaction);
845 : }
846 : }
847 0 : MOZ_ASSERT(transactionsToAbort.Length() <= transactionTable.Count());
848 :
849 0 : if (transactionsToAbort.IsEmpty()) {
850 0 : return;
851 : }
852 :
853 : // We want to abort transactions as soon as possible so we iterate the
854 : // transactions once and abort them all first, collecting the transactions
855 : // that need to have a warning issued along the way. Those that need a
856 : // warning will be a subset of those that are aborted, so we don't need
857 : // additional strong references here.
858 0 : WeakTransactionArray transactionsThatNeedWarning;
859 :
860 0 : for (RefPtr<IDBTransaction>& transaction : transactionsToAbort) {
861 0 : MOZ_ASSERT(transaction);
862 0 : MOZ_ASSERT(!transaction->IsDone());
863 :
864 0 : if (aShouldWarn) {
865 0 : switch (transaction->GetMode()) {
866 : // We ignore transactions that could not have written any data.
867 : case IDBTransaction::READ_ONLY:
868 0 : break;
869 :
870 : // We warn for any transactions that could have written data.
871 : case IDBTransaction::READ_WRITE:
872 : case IDBTransaction::READ_WRITE_FLUSH:
873 : case IDBTransaction::CLEANUP:
874 : case IDBTransaction::VERSION_CHANGE:
875 0 : transactionsThatNeedWarning.AppendElement(transaction);
876 0 : break;
877 :
878 : default:
879 0 : MOZ_CRASH("Unknown mode!");
880 : }
881 : }
882 :
883 0 : transaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
884 : }
885 :
886 : static const char kWarningMessage[] =
887 : "IndexedDBTransactionAbortNavigation";
888 :
889 0 : for (IDBTransaction* transaction : transactionsThatNeedWarning) {
890 0 : MOZ_ASSERT(transaction);
891 :
892 0 : nsString filename;
893 : uint32_t lineNo, column;
894 0 : transaction->GetCallerLocation(filename, &lineNo, &column);
895 :
896 0 : aDatabase->LogWarning(kWarningMessage, filename, lineNo, column);
897 : }
898 : }
899 : };
900 :
901 0 : Helper::AbortTransactions(this, aShouldWarn);
902 0 : }
903 :
904 : PBackgroundIDBDatabaseFileChild*
905 0 : IDBDatabase::GetOrCreateFileActorForBlob(Blob* aBlob)
906 : {
907 0 : AssertIsOnOwningThread();
908 0 : MOZ_ASSERT(aBlob);
909 0 : MOZ_ASSERT(mBackgroundActor);
910 :
911 : // We use the File's nsIWeakReference as the key to the table because
912 : // a) it is unique per blob, b) it is reference-counted so that we can
913 : // guarantee that it stays alive, and c) it doesn't hold the actual File
914 : // alive.
915 0 : nsCOMPtr<nsIDOMBlob> blob = aBlob;
916 0 : nsCOMPtr<nsIWeakReference> weakRef = do_GetWeakReference(blob);
917 0 : MOZ_ASSERT(weakRef);
918 :
919 0 : PBackgroundIDBDatabaseFileChild* actor = nullptr;
920 :
921 0 : if (!mFileActors.Get(weakRef, &actor)) {
922 0 : BlobImpl* blobImpl = aBlob->Impl();
923 0 : MOZ_ASSERT(blobImpl);
924 :
925 : PBackgroundChild* backgroundManager =
926 0 : mBackgroundActor->Manager()->Manager();
927 0 : MOZ_ASSERT(backgroundManager);
928 :
929 0 : IPCBlob ipcBlob;
930 0 : nsresult rv = IPCBlobUtils::Serialize(blobImpl, backgroundManager, ipcBlob);
931 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
932 0 : return nullptr;
933 : }
934 :
935 0 : auto* dbFile = new DatabaseFile(this);
936 :
937 0 : actor =
938 0 : mBackgroundActor->SendPBackgroundIDBDatabaseFileConstructor(dbFile,
939 : ipcBlob);
940 0 : if (NS_WARN_IF(!actor)) {
941 0 : return nullptr;
942 : }
943 :
944 0 : MOZ_ASSERT(actor->GetActorEventTarget(),
945 : "The event target shall be inherited from its manager actor.");
946 0 : mFileActors.Put(weakRef, actor);
947 : }
948 :
949 0 : MOZ_ASSERT(actor);
950 :
951 0 : return actor;
952 : }
953 :
954 : void
955 0 : IDBDatabase::NoteFinishedFileActor(PBackgroundIDBDatabaseFileChild* aFileActor)
956 : {
957 0 : AssertIsOnOwningThread();
958 0 : MOZ_ASSERT(aFileActor);
959 :
960 0 : for (auto iter = mFileActors.Iter(); !iter.Done(); iter.Next()) {
961 0 : MOZ_ASSERT(iter.Key());
962 0 : PBackgroundIDBDatabaseFileChild* actor = iter.Data();
963 0 : MOZ_ASSERT(actor);
964 :
965 0 : if (actor == aFileActor) {
966 0 : iter.Remove();
967 : }
968 : }
969 0 : }
970 :
971 : void
972 0 : IDBDatabase::NoteActiveTransaction()
973 : {
974 0 : AssertIsOnOwningThread();
975 0 : MOZ_ASSERT(mFactory);
976 :
977 : // Increase the number of active transactions.
978 0 : mFactory->UpdateActiveTransactionCount(1);
979 0 : }
980 :
981 : void
982 0 : IDBDatabase::NoteInactiveTransaction()
983 : {
984 0 : AssertIsOnOwningThread();
985 :
986 0 : if (!mBackgroundActor || !mFileActors.Count()) {
987 0 : MOZ_ASSERT(mFactory);
988 0 : mFactory->UpdateActiveTransactionCount(-1);
989 0 : return;
990 : }
991 :
992 : RefPtr<Runnable> runnable =
993 0 : NewRunnableMethod("IDBDatabase::NoteInactiveTransactionDelayed",
994 : this,
995 0 : &IDBDatabase::NoteInactiveTransactionDelayed);
996 0 : MOZ_ASSERT(runnable);
997 :
998 0 : if (!NS_IsMainThread()) {
999 : // Wrap as a nsICancelableRunnable to make workers happy.
1000 0 : RefPtr<Runnable> cancelable = new CancelableRunnableWrapper(runnable);
1001 0 : cancelable.swap(runnable);
1002 : }
1003 :
1004 0 : MOZ_ALWAYS_SUCCEEDS(
1005 : EventTarget()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
1006 : }
1007 :
1008 : nsresult
1009 0 : IDBDatabase::GetQuotaInfo(nsACString& aOrigin,
1010 : PersistenceType* aPersistenceType)
1011 : {
1012 : using mozilla::dom::quota::QuotaManager;
1013 :
1014 0 : MOZ_ASSERT(NS_IsMainThread(), "This can't work off the main thread!");
1015 :
1016 0 : if (aPersistenceType) {
1017 0 : *aPersistenceType = mSpec->metadata().persistenceType();
1018 0 : MOZ_ASSERT(*aPersistenceType != PERSISTENCE_TYPE_INVALID);
1019 : }
1020 :
1021 0 : PrincipalInfo* principalInfo = mFactory->GetPrincipalInfo();
1022 0 : MOZ_ASSERT(principalInfo);
1023 :
1024 0 : switch (principalInfo->type()) {
1025 : case PrincipalInfo::TNullPrincipalInfo:
1026 0 : MOZ_CRASH("Is this needed?!");
1027 :
1028 : case PrincipalInfo::TSystemPrincipalInfo:
1029 0 : QuotaManager::GetInfoForChrome(nullptr, nullptr, &aOrigin);
1030 0 : return NS_OK;
1031 :
1032 : case PrincipalInfo::TContentPrincipalInfo: {
1033 : nsresult rv;
1034 : nsCOMPtr<nsIPrincipal> principal =
1035 0 : PrincipalInfoToPrincipal(*principalInfo, &rv);
1036 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1037 0 : return rv;
1038 : }
1039 :
1040 0 : rv = QuotaManager::GetInfoFromPrincipal(principal,
1041 : nullptr,
1042 : nullptr,
1043 : &aOrigin);
1044 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1045 0 : return rv;
1046 : }
1047 :
1048 0 : return NS_OK;
1049 : }
1050 :
1051 : default:
1052 0 : MOZ_CRASH("Unknown PrincipalInfo type!");
1053 : }
1054 :
1055 : MOZ_CRASH("Should never get here!");
1056 : }
1057 :
1058 : void
1059 0 : IDBDatabase::ExpireFileActors(bool aExpireAll)
1060 : {
1061 0 : AssertIsOnOwningThread();
1062 :
1063 0 : if (mBackgroundActor && mFileActors.Count()) {
1064 0 : for (auto iter = mFileActors.Iter(); !iter.Done(); iter.Next()) {
1065 0 : nsISupports* key = iter.Key();
1066 0 : PBackgroundIDBDatabaseFileChild* actor = iter.Data();
1067 0 : MOZ_ASSERT(key);
1068 0 : MOZ_ASSERT(actor);
1069 :
1070 0 : bool shouldExpire = aExpireAll;
1071 0 : if (!shouldExpire) {
1072 0 : nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(key);
1073 0 : MOZ_ASSERT(weakRef);
1074 :
1075 0 : nsCOMPtr<nsISupports> referent = do_QueryReferent(weakRef);
1076 0 : shouldExpire = !referent;
1077 : }
1078 :
1079 0 : if (shouldExpire) {
1080 0 : PBackgroundIDBDatabaseFileChild::Send__delete__(actor);
1081 :
1082 0 : if (!aExpireAll) {
1083 0 : iter.Remove();
1084 : }
1085 : }
1086 : }
1087 0 : if (aExpireAll) {
1088 0 : mFileActors.Clear();
1089 : }
1090 : } else {
1091 0 : MOZ_ASSERT(!mFileActors.Count());
1092 : }
1093 0 : }
1094 :
1095 : void
1096 0 : IDBDatabase::NoteLiveMutableFile(IDBMutableFile* aMutableFile)
1097 : {
1098 0 : AssertIsOnOwningThread();
1099 0 : MOZ_ASSERT(aMutableFile);
1100 0 : aMutableFile->AssertIsOnOwningThread();
1101 0 : MOZ_ASSERT(!mLiveMutableFiles.Contains(aMutableFile));
1102 :
1103 0 : mLiveMutableFiles.AppendElement(aMutableFile);
1104 0 : }
1105 :
1106 : void
1107 0 : IDBDatabase::NoteFinishedMutableFile(IDBMutableFile* aMutableFile)
1108 : {
1109 0 : AssertIsOnOwningThread();
1110 0 : MOZ_ASSERT(aMutableFile);
1111 0 : aMutableFile->AssertIsOnOwningThread();
1112 :
1113 : // It's ok if this is called after we cleared the array, so don't assert that
1114 : // aMutableFile is in the list.
1115 :
1116 0 : mLiveMutableFiles.RemoveElement(aMutableFile);
1117 0 : }
1118 :
1119 : void
1120 0 : IDBDatabase::InvalidateMutableFiles()
1121 : {
1122 0 : AssertIsOnOwningThread();
1123 :
1124 0 : if (!mLiveMutableFiles.IsEmpty()) {
1125 0 : for (uint32_t count = mLiveMutableFiles.Length(), index = 0;
1126 0 : index < count;
1127 : index++) {
1128 0 : mLiveMutableFiles[index]->Invalidate();
1129 : }
1130 :
1131 0 : mLiveMutableFiles.Clear();
1132 : }
1133 0 : }
1134 :
1135 : void
1136 0 : IDBDatabase::Invalidate()
1137 : {
1138 0 : AssertIsOnOwningThread();
1139 :
1140 0 : if (!mInvalidated) {
1141 0 : mInvalidated = true;
1142 :
1143 0 : InvalidateInternal();
1144 : }
1145 0 : }
1146 :
1147 : void
1148 0 : IDBDatabase::NoteInactiveTransactionDelayed()
1149 : {
1150 0 : ExpireFileActors(/* aExpireAll */ false);
1151 :
1152 0 : MOZ_ASSERT(mFactory);
1153 0 : mFactory->UpdateActiveTransactionCount(-1);
1154 0 : }
1155 :
1156 : void
1157 0 : IDBDatabase::LogWarning(const char* aMessageName,
1158 : const nsAString& aFilename,
1159 : uint32_t aLineNumber,
1160 : uint32_t aColumnNumber)
1161 : {
1162 0 : AssertIsOnOwningThread();
1163 0 : MOZ_ASSERT(aMessageName);
1164 :
1165 0 : ScriptErrorHelper::DumpLocalizedMessage(nsDependentCString(aMessageName),
1166 : aFilename,
1167 : aLineNumber,
1168 : aColumnNumber,
1169 : nsIScriptError::warningFlag,
1170 0 : mFactory->IsChrome(),
1171 0 : mFactory->InnerWindowID());
1172 0 : }
1173 :
1174 0 : NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
1175 0 : NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
1176 :
1177 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
1178 0 : NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
1179 :
1180 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
1181 :
1182 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
1183 0 : tmp->AssertIsOnOwningThread();
1184 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
1185 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1186 :
1187 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
1188 0 : tmp->AssertIsOnOwningThread();
1189 :
1190 : // Don't unlink mFactory!
1191 :
1192 : // We've been unlinked, at the very least we should be able to prevent further
1193 : // transactions from starting and unblock any other SetVersion callers.
1194 0 : tmp->CloseInternal();
1195 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1196 :
1197 : void
1198 0 : IDBDatabase::LastRelease()
1199 : {
1200 0 : AssertIsOnOwningThread();
1201 :
1202 0 : CloseInternal();
1203 :
1204 0 : if (mBackgroundActor) {
1205 0 : mBackgroundActor->SendDeleteMeInternal();
1206 0 : MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
1207 : }
1208 0 : }
1209 :
1210 : nsresult
1211 0 : IDBDatabase::PostHandleEvent(EventChainPostVisitor& aVisitor)
1212 : {
1213 : nsresult rv =
1214 0 : IndexedDatabaseManager::CommonPostHandleEvent(aVisitor, mFactory);
1215 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1216 0 : return rv;
1217 : }
1218 :
1219 0 : return NS_OK;
1220 : }
1221 :
1222 : JSObject*
1223 0 : IDBDatabase::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
1224 : {
1225 0 : return IDBDatabaseBinding::Wrap(aCx, this, aGivenProto);
1226 : }
1227 :
1228 : NS_IMETHODIMP
1229 0 : CancelableRunnableWrapper::Run()
1230 : {
1231 0 : nsCOMPtr<nsIRunnable> runnable;
1232 0 : mRunnable.swap(runnable);
1233 :
1234 0 : if (runnable) {
1235 0 : return runnable->Run();
1236 : }
1237 :
1238 0 : return NS_OK;
1239 : }
1240 :
1241 : nsresult
1242 0 : CancelableRunnableWrapper::Cancel()
1243 : {
1244 0 : if (mRunnable) {
1245 0 : mRunnable = nullptr;
1246 0 : return NS_OK;
1247 : }
1248 :
1249 0 : return NS_ERROR_UNEXPECTED;
1250 : }
1251 :
1252 0 : NS_IMPL_ISUPPORTS(IDBDatabase::Observer, nsIObserver)
1253 :
1254 : NS_IMETHODIMP
1255 0 : IDBDatabase::
1256 : Observer::Observe(nsISupports* aSubject,
1257 : const char* aTopic,
1258 : const char16_t* aData)
1259 : {
1260 0 : MOZ_ASSERT(NS_IsMainThread());
1261 0 : MOZ_ASSERT(aTopic);
1262 :
1263 0 : if (!strcmp(aTopic, kWindowObserverTopic)) {
1264 0 : if (mWeakDatabase) {
1265 0 : nsCOMPtr<nsISupportsPRUint64> supportsInt = do_QueryInterface(aSubject);
1266 0 : MOZ_ASSERT(supportsInt);
1267 :
1268 : uint64_t windowId;
1269 0 : MOZ_ALWAYS_SUCCEEDS(supportsInt->GetData(&windowId));
1270 :
1271 0 : if (windowId == mWindowId) {
1272 0 : RefPtr<IDBDatabase> database = mWeakDatabase;
1273 0 : mWeakDatabase = nullptr;
1274 :
1275 0 : database->InvalidateInternal();
1276 : }
1277 : }
1278 :
1279 0 : return NS_OK;
1280 : }
1281 :
1282 0 : if (!strcmp(aTopic, kCycleCollectionObserverTopic) ||
1283 0 : !strcmp(aTopic, kMemoryPressureObserverTopic)) {
1284 0 : if (mWeakDatabase) {
1285 0 : RefPtr<IDBDatabase> database = mWeakDatabase;
1286 :
1287 0 : database->ExpireFileActors(/* aExpireAll */ false);
1288 : }
1289 :
1290 0 : return NS_OK;
1291 : }
1292 :
1293 0 : NS_WARNING("Unknown observer topic!");
1294 0 : return NS_OK;
1295 : }
1296 :
1297 : nsresult
1298 0 : IDBDatabase::RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName)
1299 : {
1300 0 : MOZ_ASSERT(mSpec);
1301 :
1302 0 : nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
1303 :
1304 0 : ObjectStoreSpec* foundObjectStoreSpec = nullptr;
1305 : // Find the matched object store spec and check if 'aName' is already used by
1306 : // another object store.
1307 0 : for (uint32_t objCount = objectStores.Length(), objIndex = 0;
1308 0 : objIndex < objCount;
1309 : objIndex++) {
1310 0 : const ObjectStoreSpec& objSpec = objectStores[objIndex];
1311 0 : if (objSpec.metadata().id() == aObjectStoreId) {
1312 0 : MOZ_ASSERT(!foundObjectStoreSpec);
1313 0 : foundObjectStoreSpec = &objectStores[objIndex];
1314 0 : continue;
1315 : }
1316 0 : if (aName == objSpec.metadata().name()) {
1317 0 : return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
1318 : }
1319 : }
1320 :
1321 0 : MOZ_ASSERT(foundObjectStoreSpec);
1322 :
1323 : // Update the name of the matched object store.
1324 0 : foundObjectStoreSpec->metadata().name() = nsString(aName);
1325 :
1326 0 : return NS_OK;
1327 : }
1328 :
1329 : nsresult
1330 0 : IDBDatabase::RenameIndex(int64_t aObjectStoreId,
1331 : int64_t aIndexId,
1332 : const nsAString& aName)
1333 : {
1334 0 : MOZ_ASSERT(mSpec);
1335 :
1336 0 : nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
1337 :
1338 0 : ObjectStoreSpec* foundObjectStoreSpec = nullptr;
1339 : // Find the matched index metadata and check if 'aName' is already used by
1340 : // another index.
1341 0 : for (uint32_t objCount = objectStores.Length(), objIndex = 0;
1342 0 : objIndex < objCount;
1343 : objIndex++) {
1344 0 : const ObjectStoreSpec& objSpec = objectStores[objIndex];
1345 0 : if (objSpec.metadata().id() == aObjectStoreId) {
1346 0 : foundObjectStoreSpec = &objectStores[objIndex];
1347 0 : break;
1348 : }
1349 : }
1350 :
1351 0 : MOZ_ASSERT(foundObjectStoreSpec);
1352 :
1353 0 : nsTArray<IndexMetadata>& indexes = foundObjectStoreSpec->indexes();
1354 0 : IndexMetadata* foundIndexMetadata = nullptr;
1355 0 : for (uint32_t idxCount = indexes.Length(), idxIndex = 0;
1356 0 : idxIndex < idxCount;
1357 : idxIndex++) {
1358 0 : const IndexMetadata& metadata = indexes[idxIndex];
1359 0 : if (metadata.id() == aIndexId) {
1360 0 : MOZ_ASSERT(!foundIndexMetadata);
1361 0 : foundIndexMetadata = &indexes[idxIndex];
1362 0 : continue;
1363 : }
1364 0 : if (aName == metadata.name()) {
1365 0 : return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
1366 : }
1367 : }
1368 :
1369 0 : MOZ_ASSERT(foundIndexMetadata);
1370 :
1371 : // Update the name of the matched object store.
1372 0 : foundIndexMetadata->name() = nsString(aName);
1373 :
1374 0 : return NS_OK;
1375 : }
1376 :
1377 : void
1378 0 : IDBDatabase::IncreaseActiveDatabaseCount()
1379 : {
1380 0 : AssertIsOnOwningThread();
1381 0 : MOZ_ASSERT(mFactory);
1382 0 : MOZ_ASSERT(!mIncreasedActiveDatabaseCount);
1383 :
1384 0 : mFactory->UpdateActiveDatabaseCount(1);
1385 0 : mIncreasedActiveDatabaseCount = true;
1386 0 : }
1387 :
1388 : void
1389 0 : IDBDatabase::MaybeDecreaseActiveDatabaseCount()
1390 : {
1391 0 : AssertIsOnOwningThread();
1392 :
1393 0 : if (mIncreasedActiveDatabaseCount) {
1394 : // Decrease the number of active databases.
1395 0 : MOZ_ASSERT(mFactory);
1396 0 : mFactory->UpdateActiveDatabaseCount(-1);
1397 0 : mIncreasedActiveDatabaseCount = false;
1398 : }
1399 0 : }
1400 :
1401 : } // namespace dom
1402 : } // namespace mozilla
|