Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / indexedDB / IDBFactory.cpp
bloba17ce5d1f86550a4bdb0df60a2273c3fbcafca85
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=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/. */
7 #include "IDBFactory.h"
9 #include "nsIFile.h"
10 #include "nsIPrincipal.h"
11 #include "nsIScriptContext.h"
12 #include "nsIScriptSecurityManager.h"
13 #include "nsIXPConnect.h"
14 #include "nsIXPCScriptable.h"
16 #include <algorithm>
17 #include "mozilla/dom/nsIContentParent.h"
18 #include "mozilla/dom/ContentChild.h"
19 #include "mozilla/dom/IDBFactoryBinding.h"
20 #include "mozilla/dom/PBrowserChild.h"
21 #include "mozilla/dom/quota/OriginOrPatternString.h"
22 #include "mozilla/dom/quota/QuotaManager.h"
23 #include "mozilla/dom/TabChild.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/storage.h"
26 #include "nsComponentManagerUtils.h"
27 #include "nsCharSeparatedTokenizer.h"
28 #include "nsContentUtils.h"
29 #include "nsDOMClassInfoID.h"
30 #include "nsGlobalWindow.h"
31 #include "nsHashKeys.h"
32 #include "nsPIDOMWindow.h"
33 #include "nsServiceManagerUtils.h"
34 #include "nsThreadUtils.h"
35 #include "nsXPCOMCID.h"
37 #include "AsyncConnectionHelper.h"
38 #include "CheckPermissionsHelper.h"
39 #include "DatabaseInfo.h"
40 #include "IDBDatabase.h"
41 #include "IDBEvents.h"
42 #include "IDBKeyRange.h"
43 #include "IndexedDatabaseManager.h"
44 #include "Key.h"
45 #include "ProfilerHelpers.h"
46 #include "ReportInternalError.h"
47 #include "nsNetUtil.h"
49 #include "ipc/IndexedDBChild.h"
51 #define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
53 USING_INDEXEDDB_NAMESPACE
54 USING_QUOTA_NAMESPACE
56 using mozilla::dom::ContentChild;
57 using mozilla::dom::nsIContentParent;
58 using mozilla::dom::IDBOpenDBOptions;
59 using mozilla::dom::NonNull;
60 using mozilla::dom::Optional;
61 using mozilla::dom::TabChild;
62 using mozilla::ErrorResult;
63 using mozilla::Preferences;
65 namespace {
67 struct ObjectStoreInfoMap
69 ObjectStoreInfoMap()
70 : id(INT64_MIN), info(nullptr) { }
72 int64_t id;
73 ObjectStoreInfo* info;
76 } // anonymous namespace
78 IDBFactory::IDBFactory()
79 : mPrivilege(Content), mDefaultPersistenceType(PERSISTENCE_TYPE_TEMPORARY),
80 mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
81 mContentParent(nullptr), mRootedOwningObject(false)
83 SetIsDOMBinding();
86 IDBFactory::~IDBFactory()
88 NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
89 if (mActorChild) {
90 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
91 mActorChild->Send__delete__(mActorChild);
92 NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
94 if (mRootedOwningObject) {
95 mOwningObject = nullptr;
96 mozilla::DropJSObjects(this);
100 // static
101 nsresult
102 IDBFactory::Create(nsPIDOMWindow* aWindow,
103 const nsACString& aGroup,
104 const nsACString& aASCIIOrigin,
105 nsIContentParent* aContentParent,
106 IDBFactory** aFactory)
108 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
109 NS_ASSERTION(aASCIIOrigin.IsEmpty() || nsContentUtils::IsCallerChrome(),
110 "Non-chrome may not supply their own origin!");
112 IDB_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
114 if (aWindow->IsOuterWindow()) {
115 aWindow = aWindow->GetCurrentInnerWindow();
116 IDB_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
119 // Make sure that the manager is up before we do anything here since lots of
120 // decisions depend on which process we're running in.
121 indexedDB::IndexedDatabaseManager* mgr =
122 indexedDB::IndexedDatabaseManager::GetOrCreate();
123 IDB_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
125 nsresult rv;
127 nsCString group(aGroup);
128 nsCString origin(aASCIIOrigin);
129 StoragePrivilege privilege;
130 PersistenceType defaultPersistenceType;
131 if (origin.IsEmpty()) {
132 NS_ASSERTION(aGroup.IsEmpty(), "Should be empty too!");
134 rv = QuotaManager::GetInfoFromWindow(aWindow, &group, &origin, &privilege,
135 &defaultPersistenceType);
137 else {
138 rv = QuotaManager::GetInfoFromWindow(aWindow, nullptr, nullptr, &privilege,
139 &defaultPersistenceType);
141 if (NS_FAILED(rv)) {
142 // Not allowed.
143 *aFactory = nullptr;
144 return NS_OK;
147 nsRefPtr<IDBFactory> factory = new IDBFactory();
148 factory->mGroup = group;
149 factory->mASCIIOrigin = origin;
150 factory->mPrivilege = privilege;
151 factory->mDefaultPersistenceType = defaultPersistenceType;
152 factory->mWindow = aWindow;
153 factory->mContentParent = aContentParent;
155 if (!IndexedDatabaseManager::IsMainProcess()) {
156 TabChild* tabChild = TabChild::GetFrom(aWindow);
157 IDB_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
159 IndexedDBChild* actor = new IndexedDBChild(tabChild, origin);
161 bool allowed;
162 tabChild->SendPIndexedDBConstructor(actor, group, origin, &allowed);
164 if (!allowed) {
165 actor->Send__delete__(actor);
166 *aFactory = nullptr;
167 return NS_OK;
170 actor->SetFactory(factory);
173 factory.forget(aFactory);
174 return NS_OK;
177 // static
178 nsresult
179 IDBFactory::Create(JSContext* aCx,
180 JS::Handle<JSObject*> aOwningObject,
181 nsIContentParent* aContentParent,
182 IDBFactory** aFactory)
184 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
185 NS_ASSERTION(aCx, "Null context!");
186 NS_ASSERTION(aOwningObject, "Null object!");
187 NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
188 "Not a global object!");
189 NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
191 // Make sure that the manager is up before we do anything here since lots of
192 // decisions depend on which process we're running in.
193 IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
194 IDB_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
196 nsCString group;
197 nsCString origin;
198 StoragePrivilege privilege;
199 PersistenceType defaultPersistenceType;
200 QuotaManager::GetInfoForChrome(&group, &origin, &privilege,
201 &defaultPersistenceType);
203 nsRefPtr<IDBFactory> factory = new IDBFactory();
204 factory->mGroup = group;
205 factory->mASCIIOrigin = origin;
206 factory->mPrivilege = privilege;
207 factory->mDefaultPersistenceType = defaultPersistenceType;
208 factory->mOwningObject = aOwningObject;
209 factory->mContentParent = aContentParent;
211 mozilla::HoldJSObjects(factory.get());
212 factory->mRootedOwningObject = true;
214 if (!IndexedDatabaseManager::IsMainProcess()) {
215 ContentChild* contentChild = ContentChild::GetSingleton();
216 IDB_ENSURE_TRUE(contentChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
218 IndexedDBChild* actor = new IndexedDBChild(contentChild, origin);
220 contentChild->SendPIndexedDBConstructor(actor);
222 actor->SetFactory(factory);
225 factory.forget(aFactory);
226 return NS_OK;
229 // static
230 nsresult
231 IDBFactory::Create(nsIContentParent* aContentParent,
232 IDBFactory** aFactory)
234 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
235 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
236 NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
238 // We need to get this information before we push a null principal to avoid
239 // IsCallerChrome() assertion in quota manager.
240 nsCString group;
241 nsCString origin;
242 StoragePrivilege privilege;
243 PersistenceType defaultPersistenceType;
244 QuotaManager::GetInfoForChrome(&group, &origin, &privilege,
245 &defaultPersistenceType);
247 nsCOMPtr<nsIPrincipal> principal =
248 do_CreateInstance("@mozilla.org/nullprincipal;1");
249 NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
251 AutoSafeJSContext cx;
253 nsIXPConnect* xpc = nsContentUtils::XPConnect();
254 NS_ASSERTION(xpc, "This should never be null!");
256 nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
257 nsresult rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
258 NS_ENSURE_SUCCESS(rv, rv);
260 JS::Rooted<JSObject*> global(cx, globalHolder->GetJSObject());
261 NS_ENSURE_STATE(global);
263 // The CreateSandbox call returns a proxy to the actual sandbox object. We
264 // don't need a proxy here.
265 global = js::UncheckedUnwrap(global);
267 JSAutoCompartment ac(cx, global);
269 nsRefPtr<IDBFactory> factory = new IDBFactory();
270 factory->mGroup = group;
271 factory->mASCIIOrigin = origin;
272 factory->mPrivilege = privilege;
273 factory->mDefaultPersistenceType = defaultPersistenceType;
274 factory->mOwningObject = global;
275 factory->mContentParent = aContentParent;
277 mozilla::HoldJSObjects(factory.get());
278 factory->mRootedOwningObject = true;
280 factory.forget(aFactory);
281 return NS_OK;
284 // static
285 already_AddRefed<nsIFileURL>
286 IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile,
287 PersistenceType aPersistenceType,
288 const nsACString& aGroup,
289 const nsACString& aOrigin)
291 nsCOMPtr<nsIURI> uri;
292 nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile);
293 NS_ENSURE_SUCCESS(rv, nullptr);
295 nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
296 NS_ASSERTION(fileUrl, "This should always succeed!");
298 nsAutoCString type;
299 PersistenceTypeToText(aPersistenceType, type);
301 rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
302 NS_LITERAL_CSTRING("&group=") + aGroup +
303 NS_LITERAL_CSTRING("&origin=") + aOrigin);
304 NS_ENSURE_SUCCESS(rv, nullptr);
306 return fileUrl.forget();
309 // static
310 already_AddRefed<mozIStorageConnection>
311 IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
312 PersistenceType aPersistenceType,
313 const nsACString& aGroup,
314 const nsACString& aOrigin)
316 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
317 NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")),
318 "Bad file path!");
320 nsCOMPtr<nsIFile> dbFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
321 NS_ENSURE_TRUE(dbFile, nullptr);
323 nsresult rv = dbFile->InitWithPath(aDatabaseFilePath);
324 NS_ENSURE_SUCCESS(rv, nullptr);
326 bool exists;
327 rv = dbFile->Exists(&exists);
328 NS_ENSURE_SUCCESS(rv, nullptr);
329 NS_ENSURE_TRUE(exists, nullptr);
331 nsCOMPtr<nsIFileURL> dbFileUrl =
332 GetDatabaseFileURL(dbFile, aPersistenceType, aGroup, aOrigin);
333 NS_ENSURE_TRUE(dbFileUrl, nullptr);
335 nsCOMPtr<mozIStorageService> ss =
336 do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
337 NS_ENSURE_TRUE(ss, nullptr);
339 nsCOMPtr<mozIStorageConnection> connection;
340 rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
341 NS_ENSURE_SUCCESS(rv, nullptr);
343 rv = SetDefaultPragmas(connection);
344 NS_ENSURE_SUCCESS(rv, nullptr);
346 return connection.forget();
349 // static
350 nsresult
351 IDBFactory::SetDefaultPragmas(mozIStorageConnection* aConnection)
353 NS_ASSERTION(aConnection, "Null connection!");
355 static const char query[] =
356 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
357 // Switch the journaling mode to TRUNCATE to avoid changing the directory
358 // structure at the conclusion of every transaction for devices with slower
359 // file systems.
360 "PRAGMA journal_mode = TRUNCATE; "
361 #endif
362 // We use foreign keys in lots of places.
363 "PRAGMA foreign_keys = ON; "
364 // The "INSERT OR REPLACE" statement doesn't fire the update trigger,
365 // instead it fires only the insert trigger. This confuses the update
366 // refcount function. This behavior changes with enabled recursive triggers,
367 // so the statement fires the delete trigger first and then the insert
368 // trigger.
369 "PRAGMA recursive_triggers = ON;";
371 nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(query));
372 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
374 return NS_OK;
377 inline
378 bool
379 IgnoreWhitespace(char16_t c)
381 return false;
384 // static
385 nsresult
386 IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
387 const nsACString& aDatabaseId,
388 uint64_t* aVersion,
389 ObjectStoreInfoArray& aObjectStores)
391 AssertIsOnIOThread();
392 NS_ASSERTION(aConnection, "Null pointer!");
394 aObjectStores.Clear();
396 // Load object store names and ids.
397 nsCOMPtr<mozIStorageStatement> stmt;
398 nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
399 "SELECT name, id, key_path, auto_increment "
400 "FROM object_store"
401 ), getter_AddRefs(stmt));
402 NS_ENSURE_SUCCESS(rv, rv);
404 nsAutoTArray<ObjectStoreInfoMap, 20> infoMap;
406 bool hasResult;
407 while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
408 nsRefPtr<ObjectStoreInfo>* element =
409 aObjectStores.AppendElement(new ObjectStoreInfo());
411 ObjectStoreInfo* info = element->get();
413 rv = stmt->GetString(0, info->name);
414 NS_ENSURE_SUCCESS(rv, rv);
416 info->id = stmt->AsInt64(1);
418 int32_t columnType;
419 nsresult rv = stmt->GetTypeOfIndex(2, &columnType);
420 NS_ENSURE_SUCCESS(rv, rv);
422 // NB: We don't have to handle the NULL case, since that is the default
423 // for a new KeyPath.
424 if (columnType != mozIStorageStatement::VALUE_TYPE_NULL) {
425 NS_ASSERTION(columnType == mozIStorageStatement::VALUE_TYPE_TEXT,
426 "Should be a string");
427 nsString keyPathSerialization;
428 rv = stmt->GetString(2, keyPathSerialization);
429 NS_ENSURE_SUCCESS(rv, rv);
431 info->keyPath = KeyPath::DeserializeFromString(keyPathSerialization);
434 info->nextAutoIncrementId = stmt->AsInt64(3);
435 info->comittedAutoIncrementId = info->nextAutoIncrementId;
437 info->autoIncrement = !!info->nextAutoIncrementId;
439 ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
440 NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY);
442 mapEntry->id = info->id;
443 mapEntry->info = info;
445 NS_ENSURE_SUCCESS(rv, rv);
447 // Load index information
448 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
449 "SELECT object_store_id, id, name, key_path, unique_index, multientry "
450 "FROM object_store_index"
451 ), getter_AddRefs(stmt));
452 NS_ENSURE_SUCCESS(rv, rv);
454 while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
455 int64_t objectStoreId = stmt->AsInt64(0);
457 ObjectStoreInfo* objectStoreInfo = nullptr;
458 for (uint32_t index = 0; index < infoMap.Length(); index++) {
459 if (infoMap[index].id == objectStoreId) {
460 objectStoreInfo = infoMap[index].info;
461 break;
465 if (!objectStoreInfo) {
466 NS_ERROR("Index for nonexistant object store!");
467 return NS_ERROR_UNEXPECTED;
470 IndexInfo* indexInfo = objectStoreInfo->indexes.AppendElement();
471 NS_ENSURE_TRUE(indexInfo, NS_ERROR_OUT_OF_MEMORY);
473 indexInfo->id = stmt->AsInt64(1);
475 rv = stmt->GetString(2, indexInfo->name);
476 NS_ENSURE_SUCCESS(rv, rv);
478 nsString keyPathSerialization;
479 rv = stmt->GetString(3, keyPathSerialization);
480 NS_ENSURE_SUCCESS(rv, rv);
482 // XXX bent wants to assert here
483 indexInfo->keyPath = KeyPath::DeserializeFromString(keyPathSerialization);
484 indexInfo->unique = !!stmt->AsInt32(4);
485 indexInfo->multiEntry = !!stmt->AsInt32(5);
487 NS_ENSURE_SUCCESS(rv, rv);
489 // Load version information.
490 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
491 "SELECT version "
492 "FROM database"
493 ), getter_AddRefs(stmt));
494 NS_ENSURE_SUCCESS(rv, rv);
496 rv = stmt->ExecuteStep(&hasResult);
497 NS_ENSURE_SUCCESS(rv, rv);
499 if (!hasResult) {
500 NS_ERROR("Database has no version!");
501 return NS_ERROR_UNEXPECTED;
504 int64_t version = 0;
505 rv = stmt->GetInt64(0, &version);
507 *aVersion = std::max<int64_t>(version, 0);
509 return rv;
512 // static
513 nsresult
514 IDBFactory::SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
515 uint64_t aVersion,
516 ObjectStoreInfoArray& aObjectStores)
518 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
519 NS_ASSERTION(aDatabaseInfo, "Null pointer!");
521 ObjectStoreInfoArray objectStores;
522 objectStores.SwapElements(aObjectStores);
524 #ifdef DEBUG
526 nsTArray<nsString> existingNames;
527 aDatabaseInfo->GetObjectStoreNames(existingNames);
528 NS_ASSERTION(existingNames.IsEmpty(), "Should be an empty DatabaseInfo");
530 #endif
532 aDatabaseInfo->version = aVersion;
534 for (uint32_t index = 0; index < objectStores.Length(); index++) {
535 nsRefPtr<ObjectStoreInfo>& info = objectStores[index];
537 if (!aDatabaseInfo->PutObjectStore(info)) {
538 NS_WARNING("Out of memory!");
539 return NS_ERROR_OUT_OF_MEMORY;
543 return NS_OK;
546 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory)
547 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory)
549 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory)
550 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
551 NS_INTERFACE_MAP_ENTRY(nsISupports)
552 NS_INTERFACE_MAP_END
554 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory)
556 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory)
557 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
558 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
559 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
561 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
562 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
563 if (tmp->mOwningObject) {
564 tmp->mOwningObject = nullptr;
566 if (tmp->mRootedOwningObject) {
567 mozilla::DropJSObjects(tmp);
568 tmp->mRootedOwningObject = false;
570 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
571 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
573 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
574 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
575 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOwningObject)
576 NS_IMPL_CYCLE_COLLECTION_TRACE_END
578 nsresult
579 IDBFactory::OpenInternal(const nsAString& aName,
580 int64_t aVersion,
581 PersistenceType aPersistenceType,
582 const nsACString& aGroup,
583 const nsACString& aASCIIOrigin,
584 StoragePrivilege aPrivilege,
585 bool aDeleting,
586 IDBOpenDBRequest** _retval)
588 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
589 NS_ASSERTION(mWindow || mOwningObject, "Must have one of these!");
591 AutoJSContext cx;
592 nsCOMPtr<nsPIDOMWindow> window;
593 JS::Rooted<JSObject*> scriptOwner(cx);
595 if (mWindow) {
596 window = mWindow;
597 scriptOwner =
598 static_cast<nsGlobalWindow*>(window.get())->FastGetGlobalJSObject();
600 else {
601 scriptOwner = mOwningObject;
604 if (aPrivilege == Chrome) {
605 // Chrome privilege, ignore the persistence type parameter.
606 aPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
609 nsRefPtr<IDBOpenDBRequest> request =
610 IDBOpenDBRequest::Create(this, window, scriptOwner);
611 IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
613 nsresult rv;
615 if (IndexedDatabaseManager::IsMainProcess()) {
616 nsRefPtr<OpenDatabaseHelper> openHelper =
617 new OpenDatabaseHelper(request, aName, aGroup, aASCIIOrigin, aVersion,
618 aPersistenceType, aDeleting, mContentParent,
619 aPrivilege);
621 rv = openHelper->Init();
622 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
624 if (!Preferences::GetBool(PREF_INDEXEDDB_ENABLED)) {
625 openHelper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
626 rv = openHelper->WaitForOpenAllowed();
628 else {
629 if (mPrivilege != Chrome &&
630 aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
631 nsRefPtr<CheckPermissionsHelper> permissionHelper =
632 new CheckPermissionsHelper(openHelper, window);
634 QuotaManager* quotaManager = QuotaManager::Get();
635 NS_ASSERTION(quotaManager, "This should never be null!");
637 rv = quotaManager->
638 WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
639 Nullable<PersistenceType>(aPersistenceType),
640 openHelper->Id(), permissionHelper);
642 else {
643 // Chrome and temporary storage doesn't need to check the permission.
644 rv = openHelper->WaitForOpenAllowed();
647 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
649 else if (aDeleting) {
650 nsCString databaseId;
651 QuotaManager::GetStorageId(aPersistenceType, aASCIIOrigin, Client::IDB,
652 aName, databaseId);
653 MOZ_ASSERT(!databaseId.IsEmpty());
655 IndexedDBDeleteDatabaseRequestChild* actor =
656 new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId);
658 mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor(
659 actor,
660 nsString(aName),
661 aPersistenceType);
663 else {
664 IndexedDBDatabaseChild* dbActor =
665 static_cast<IndexedDBDatabaseChild*>(
666 mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName),
667 aVersion,
668 aPersistenceType));
670 dbActor->SetRequest(request);
673 #ifdef IDB_PROFILER_USE_MARKS
675 NS_ConvertUTF16toUTF8 profilerName(aName);
676 if (aDeleting) {
677 IDB_PROFILER_MARK("IndexedDB Request %llu: deleteDatabase(\"%s\")",
678 "MT IDBFactory.deleteDatabase()",
679 request->GetSerialNumber(), profilerName.get());
681 else {
682 IDB_PROFILER_MARK("IndexedDB Request %llu: open(\"%s\", %lld)",
683 "MT IDBFactory.open()",
684 request->GetSerialNumber(), profilerName.get(),
685 aVersion);
688 #endif
690 request.forget(_retval);
691 return NS_OK;
694 JSObject*
695 IDBFactory::WrapObject(JSContext* aCx)
697 return IDBFactoryBinding::Wrap(aCx, this);
700 already_AddRefed<IDBOpenDBRequest>
701 IDBFactory::Open(const nsAString& aName, const IDBOpenDBOptions& aOptions,
702 ErrorResult& aRv)
704 return Open(nullptr, aName, aOptions.mVersion, aOptions.mStorage, false, aRv);
707 already_AddRefed<IDBOpenDBRequest>
708 IDBFactory::DeleteDatabase(const nsAString& aName,
709 const IDBOpenDBOptions& aOptions,
710 ErrorResult& aRv)
712 return Open(nullptr, aName, Optional<uint64_t>(), aOptions.mStorage, true,
713 aRv);
716 int16_t
717 IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
718 JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
720 Key first, second;
721 nsresult rv = first.SetFromJSVal(aCx, aFirst);
722 if (NS_FAILED(rv)) {
723 aRv.Throw(rv);
724 return 0;
727 rv = second.SetFromJSVal(aCx, aSecond);
728 if (NS_FAILED(rv)) {
729 aRv.Throw(rv);
730 return 0;
733 if (first.IsUnset() || second.IsUnset()) {
734 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
735 return 0;
738 return Key::CompareKeys(first, second);
741 already_AddRefed<IDBOpenDBRequest>
742 IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
743 uint64_t aVersion, ErrorResult& aRv)
745 // Just to be on the extra-safe side
746 if (!nsContentUtils::IsCallerChrome()) {
747 MOZ_CRASH();
750 return Open(aPrincipal, aName, Optional<uint64_t>(aVersion),
751 Optional<mozilla::dom::StorageType>(), false, aRv);
754 already_AddRefed<IDBOpenDBRequest>
755 IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
756 const IDBOpenDBOptions& aOptions, ErrorResult& aRv)
758 // Just to be on the extra-safe side
759 if (!nsContentUtils::IsCallerChrome()) {
760 MOZ_CRASH();
763 return Open(aPrincipal, aName, aOptions.mVersion, aOptions.mStorage, false,
764 aRv);
767 already_AddRefed<IDBOpenDBRequest>
768 IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
769 const IDBOpenDBOptions& aOptions,
770 ErrorResult& aRv)
772 // Just to be on the extra-safe side
773 if (!nsContentUtils::IsCallerChrome()) {
774 MOZ_CRASH();
777 return Open(aPrincipal, aName, Optional<uint64_t>(), aOptions.mStorage, true,
778 aRv);
781 already_AddRefed<IDBOpenDBRequest>
782 IDBFactory::Open(nsIPrincipal* aPrincipal, const nsAString& aName,
783 const Optional<uint64_t>& aVersion,
784 const Optional<mozilla::dom::StorageType>& aStorageType,
785 bool aDelete, ErrorResult& aRv)
787 nsresult rv;
789 nsCString group;
790 nsCString origin;
791 StoragePrivilege privilege;
792 PersistenceType defaultPersistenceType;
793 if (aPrincipal) {
794 rv = QuotaManager::GetInfoFromPrincipal(aPrincipal, &group, &origin,
795 &privilege,
796 &defaultPersistenceType);
797 if (NS_FAILED(rv)) {
798 IDB_REPORT_INTERNAL_ERR();
799 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
800 return nullptr;
803 else {
804 group = mGroup;
805 origin = mASCIIOrigin;
806 privilege = mPrivilege;
807 defaultPersistenceType = mDefaultPersistenceType;
810 uint64_t version = 0;
811 if (!aDelete && aVersion.WasPassed()) {
812 if (aVersion.Value() < 1) {
813 aRv.ThrowTypeError(MSG_INVALID_VERSION);
814 return nullptr;
816 version = aVersion.Value();
819 PersistenceType persistenceType =
820 PersistenceTypeFromStorage(aStorageType, defaultPersistenceType);
822 nsRefPtr<IDBOpenDBRequest> request;
823 rv = OpenInternal(aName, version, persistenceType, group, origin, privilege,
824 aDelete, getter_AddRefs(request));
825 if (NS_FAILED(rv)) {
826 aRv.Throw(rv);
827 return nullptr;
830 return request.forget();