dom/indexedDB/IDBFactory.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/ContentParent.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 "nsCxPusher.h"
    30 #include "nsDOMClassInfoID.h"
    31 #include "nsGlobalWindow.h"
    32 #include "nsHashKeys.h"
    33 #include "nsPIDOMWindow.h"
    34 #include "nsServiceManagerUtils.h"
    35 #include "nsThreadUtils.h"
    36 #include "nsXPCOMCID.h"
    38 #include "AsyncConnectionHelper.h"
    39 #include "CheckPermissionsHelper.h"
    40 #include "DatabaseInfo.h"
    41 #include "IDBDatabase.h"
    42 #include "IDBEvents.h"
    43 #include "IDBKeyRange.h"
    44 #include "IndexedDatabaseManager.h"
    45 #include "Key.h"
    46 #include "ProfilerHelpers.h"
    47 #include "ReportInternalError.h"
    48 #include "nsNetUtil.h"
    50 #include "ipc/IndexedDBChild.h"
    52 #define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
    54 USING_INDEXEDDB_NAMESPACE
    55 USING_QUOTA_NAMESPACE
    57 using mozilla::dom::ContentChild;
    58 using mozilla::dom::ContentParent;
    59 using mozilla::dom::IDBOpenDBOptions;
    60 using mozilla::dom::NonNull;
    61 using mozilla::dom::Optional;
    62 using mozilla::dom::TabChild;
    63 using mozilla::ErrorResult;
    64 using mozilla::Preferences;
    66 namespace {
    68 struct ObjectStoreInfoMap
    69 {
    70   ObjectStoreInfoMap()
    71   : id(INT64_MIN), info(nullptr) { }
    73   int64_t id;
    74   ObjectStoreInfo* info;
    75 };
    77 } // anonymous namespace
    79 IDBFactory::IDBFactory()
    80 : mPrivilege(Content), mDefaultPersistenceType(PERSISTENCE_TYPE_TEMPORARY),
    81   mOwningObject(nullptr), mActorChild(nullptr), mActorParent(nullptr),
    82   mContentParent(nullptr), mRootedOwningObject(false)
    83 {
    84   SetIsDOMBinding();
    85 }
    87 IDBFactory::~IDBFactory()
    88 {
    89   NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
    90   if (mActorChild) {
    91     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
    92     mActorChild->Send__delete__(mActorChild);
    93     NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
    94   }
    95   if (mRootedOwningObject) {
    96     mOwningObject = nullptr;
    97     mozilla::DropJSObjects(this);
    98   }
    99 }
   101 // static
   102 nsresult
   103 IDBFactory::Create(nsPIDOMWindow* aWindow,
   104                    const nsACString& aGroup,
   105                    const nsACString& aASCIIOrigin,
   106                    ContentParent* aContentParent,
   107                    IDBFactory** aFactory)
   108 {
   109   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   110   NS_ASSERTION(aASCIIOrigin.IsEmpty() || nsContentUtils::IsCallerChrome(),
   111                "Non-chrome may not supply their own origin!");
   113   IDB_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   115   if (aWindow->IsOuterWindow()) {
   116     aWindow = aWindow->GetCurrentInnerWindow();
   117     IDB_ENSURE_TRUE(aWindow, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   118   }
   120   // Make sure that the manager is up before we do anything here since lots of
   121   // decisions depend on which process we're running in.
   122   indexedDB::IndexedDatabaseManager* mgr =
   123     indexedDB::IndexedDatabaseManager::GetOrCreate();
   124   IDB_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   126   nsresult rv;
   128   nsCString group(aGroup);
   129   nsCString origin(aASCIIOrigin);
   130   StoragePrivilege privilege;
   131   PersistenceType defaultPersistenceType;
   132   if (origin.IsEmpty()) {
   133     NS_ASSERTION(aGroup.IsEmpty(), "Should be empty too!");
   135     rv = QuotaManager::GetInfoFromWindow(aWindow, &group, &origin, &privilege,
   136                                          &defaultPersistenceType);
   137   }
   138   else {
   139     rv = QuotaManager::GetInfoFromWindow(aWindow, nullptr, nullptr, &privilege,
   140                                          &defaultPersistenceType);
   141   }
   142   if (NS_FAILED(rv)) {
   143     // Not allowed.
   144     *aFactory = nullptr;
   145     return NS_OK;
   146   }
   148   nsRefPtr<IDBFactory> factory = new IDBFactory();
   149   factory->mGroup = group;
   150   factory->mASCIIOrigin = origin;
   151   factory->mPrivilege = privilege;
   152   factory->mDefaultPersistenceType = defaultPersistenceType;
   153   factory->mWindow = aWindow;
   154   factory->mContentParent = aContentParent;
   156   if (!IndexedDatabaseManager::IsMainProcess()) {
   157     TabChild* tabChild = TabChild::GetFrom(aWindow);
   158     IDB_ENSURE_TRUE(tabChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   160     IndexedDBChild* actor = new IndexedDBChild(origin);
   162     bool allowed;
   163     tabChild->SendPIndexedDBConstructor(actor, group, origin, &allowed);
   165     if (!allowed) {
   166       actor->Send__delete__(actor);
   167       *aFactory = nullptr;
   168       return NS_OK;
   169     }
   171     actor->SetFactory(factory);
   172   }
   174   factory.forget(aFactory);
   175   return NS_OK;
   176 }
   178 // static
   179 nsresult
   180 IDBFactory::Create(JSContext* aCx,
   181                    JS::Handle<JSObject*> aOwningObject,
   182                    ContentParent* aContentParent,
   183                    IDBFactory** aFactory)
   184 {
   185   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   186   NS_ASSERTION(aCx, "Null context!");
   187   NS_ASSERTION(aOwningObject, "Null object!");
   188   NS_ASSERTION(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
   189                "Not a global object!");
   190   NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
   192   // Make sure that the manager is up before we do anything here since lots of
   193   // decisions depend on which process we're running in.
   194   IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
   195   IDB_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   197   nsCString group;
   198   nsCString origin;
   199   StoragePrivilege privilege;
   200   PersistenceType defaultPersistenceType;
   201   QuotaManager::GetInfoForChrome(&group, &origin, &privilege,
   202                                  &defaultPersistenceType);
   204   nsRefPtr<IDBFactory> factory = new IDBFactory();
   205   factory->mGroup = group;
   206   factory->mASCIIOrigin = origin;
   207   factory->mPrivilege = privilege;
   208   factory->mDefaultPersistenceType = defaultPersistenceType;
   209   factory->mOwningObject = aOwningObject;
   210   factory->mContentParent = aContentParent;
   212   mozilla::HoldJSObjects(factory.get());
   213   factory->mRootedOwningObject = true;
   215   if (!IndexedDatabaseManager::IsMainProcess()) {
   216     ContentChild* contentChild = ContentChild::GetSingleton();
   217     IDB_ENSURE_TRUE(contentChild, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   219     IndexedDBChild* actor = new IndexedDBChild(origin);
   221     contentChild->SendPIndexedDBConstructor(actor);
   223     actor->SetFactory(factory);
   224   }
   226   factory.forget(aFactory);
   227   return NS_OK;
   228 }
   230 // static
   231 nsresult
   232 IDBFactory::Create(ContentParent* aContentParent,
   233                    IDBFactory** aFactory)
   234 {
   235   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   236   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   237   NS_ASSERTION(nsContentUtils::IsCallerChrome(), "Only for chrome!");
   238   NS_ASSERTION(aContentParent, "Null ContentParent!");
   240   NS_ASSERTION(!nsContentUtils::GetCurrentJSContext(), "Should be called from C++");
   242   // We need to get this information before we push a null principal to avoid
   243   // IsCallerChrome() assertion in quota manager.
   244   nsCString group;
   245   nsCString origin;
   246   StoragePrivilege privilege;
   247   PersistenceType defaultPersistenceType;
   248   QuotaManager::GetInfoForChrome(&group, &origin, &privilege,
   249                                  &defaultPersistenceType);
   251   nsCOMPtr<nsIPrincipal> principal =
   252     do_CreateInstance("@mozilla.org/nullprincipal;1");
   253   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
   255   AutoSafeJSContext cx;
   257   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   258   NS_ASSERTION(xpc, "This should never be null!");
   260   nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
   261   nsresult rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
   262   NS_ENSURE_SUCCESS(rv, rv);
   264   JS::Rooted<JSObject*> global(cx, globalHolder->GetJSObject());
   265   NS_ENSURE_STATE(global);
   267   // The CreateSandbox call returns a proxy to the actual sandbox object. We
   268   // don't need a proxy here.
   269   global = js::UncheckedUnwrap(global);
   271   JSAutoCompartment ac(cx, global);
   273   nsRefPtr<IDBFactory> factory = new IDBFactory();
   274   factory->mGroup = group;
   275   factory->mASCIIOrigin = origin;
   276   factory->mPrivilege = privilege;
   277   factory->mDefaultPersistenceType = defaultPersistenceType;
   278   factory->mOwningObject = global;
   279   factory->mContentParent = aContentParent;
   281   mozilla::HoldJSObjects(factory.get());
   282   factory->mRootedOwningObject = true;
   284   factory.forget(aFactory);
   285   return NS_OK;
   286 }
   288 // static
   289 already_AddRefed<nsIFileURL>
   290 IDBFactory::GetDatabaseFileURL(nsIFile* aDatabaseFile,
   291                                PersistenceType aPersistenceType,
   292                                const nsACString& aGroup,
   293                                const nsACString& aOrigin)
   294 {
   295   nsCOMPtr<nsIURI> uri;
   296   nsresult rv = NS_NewFileURI(getter_AddRefs(uri), aDatabaseFile);
   297   NS_ENSURE_SUCCESS(rv, nullptr);
   299   nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
   300   NS_ASSERTION(fileUrl, "This should always succeed!");
   302   nsAutoCString type;
   303   PersistenceTypeToText(aPersistenceType, type);
   305   rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
   306                          NS_LITERAL_CSTRING("&group=") + aGroup +
   307                          NS_LITERAL_CSTRING("&origin=") + aOrigin);
   308   NS_ENSURE_SUCCESS(rv, nullptr);
   310   return fileUrl.forget();
   311 }
   313 // static
   314 already_AddRefed<mozIStorageConnection>
   315 IDBFactory::GetConnection(const nsAString& aDatabaseFilePath,
   316                           PersistenceType aPersistenceType,
   317                           const nsACString& aGroup,
   318                           const nsACString& aOrigin)
   319 {
   320   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   321   NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")),
   322                "Bad file path!");
   324   nsCOMPtr<nsIFile> dbFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
   325   NS_ENSURE_TRUE(dbFile, nullptr);
   327   nsresult rv = dbFile->InitWithPath(aDatabaseFilePath);
   328   NS_ENSURE_SUCCESS(rv, nullptr);
   330   bool exists;
   331   rv = dbFile->Exists(&exists);
   332   NS_ENSURE_SUCCESS(rv, nullptr);
   333   NS_ENSURE_TRUE(exists, nullptr);
   335   nsCOMPtr<nsIFileURL> dbFileUrl =
   336     GetDatabaseFileURL(dbFile, aPersistenceType, aGroup, aOrigin);
   337   NS_ENSURE_TRUE(dbFileUrl, nullptr);
   339   nsCOMPtr<mozIStorageService> ss =
   340     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   341   NS_ENSURE_TRUE(ss, nullptr);
   343   nsCOMPtr<mozIStorageConnection> connection;
   344   rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(connection));
   345   NS_ENSURE_SUCCESS(rv, nullptr);
   347   rv = SetDefaultPragmas(connection);
   348   NS_ENSURE_SUCCESS(rv, nullptr);
   350   return connection.forget();
   351 }
   353 // static
   354 nsresult
   355 IDBFactory::SetDefaultPragmas(mozIStorageConnection* aConnection)
   356 {
   357   NS_ASSERTION(aConnection, "Null connection!");
   359   static const char query[] =
   360 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   361     // Switch the journaling mode to TRUNCATE to avoid changing the directory
   362     // structure at the conclusion of every transaction for devices with slower
   363     // file systems.
   364     "PRAGMA journal_mode = TRUNCATE; "
   365 #endif
   366     // We use foreign keys in lots of places.
   367     "PRAGMA foreign_keys = ON; "
   368     // The "INSERT OR REPLACE" statement doesn't fire the update trigger,
   369     // instead it fires only the insert trigger. This confuses the update
   370     // refcount function. This behavior changes with enabled recursive triggers,
   371     // so the statement fires the delete trigger first and then the insert
   372     // trigger.
   373     "PRAGMA recursive_triggers = ON;";
   375   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(query));
   376   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   378   return NS_OK;
   379 }
   381 inline
   382 bool
   383 IgnoreWhitespace(char16_t c)
   384 {
   385   return false;
   386 }
   388 // static
   389 nsresult
   390 IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
   391                                     const nsACString& aDatabaseId,
   392                                     uint64_t* aVersion,
   393                                     ObjectStoreInfoArray& aObjectStores)
   394 {
   395   AssertIsOnIOThread();
   396   NS_ASSERTION(aConnection, "Null pointer!");
   398   aObjectStores.Clear();
   400    // Load object store names and ids.
   401   nsCOMPtr<mozIStorageStatement> stmt;
   402   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   403     "SELECT name, id, key_path, auto_increment "
   404     "FROM object_store"
   405   ), getter_AddRefs(stmt));
   406   NS_ENSURE_SUCCESS(rv, rv);
   408   nsAutoTArray<ObjectStoreInfoMap, 20> infoMap;
   410   bool hasResult;
   411   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   412     nsRefPtr<ObjectStoreInfo>* element =
   413       aObjectStores.AppendElement(new ObjectStoreInfo());
   415     ObjectStoreInfo* info = element->get();
   417     rv = stmt->GetString(0, info->name);
   418     NS_ENSURE_SUCCESS(rv, rv);
   420     info->id = stmt->AsInt64(1);
   422     int32_t columnType;
   423     nsresult rv = stmt->GetTypeOfIndex(2, &columnType);
   424     NS_ENSURE_SUCCESS(rv, rv);
   426     // NB: We don't have to handle the NULL case, since that is the default
   427     // for a new KeyPath.
   428     if (columnType != mozIStorageStatement::VALUE_TYPE_NULL) {
   429       NS_ASSERTION(columnType == mozIStorageStatement::VALUE_TYPE_TEXT,
   430                    "Should be a string");
   431       nsString keyPathSerialization;
   432       rv = stmt->GetString(2, keyPathSerialization);
   433       NS_ENSURE_SUCCESS(rv, rv);
   435       info->keyPath = KeyPath::DeserializeFromString(keyPathSerialization);
   436     }
   438     info->nextAutoIncrementId = stmt->AsInt64(3);
   439     info->comittedAutoIncrementId = info->nextAutoIncrementId;
   441     info->autoIncrement = !!info->nextAutoIncrementId;
   443     ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
   444     NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY);
   446     mapEntry->id = info->id;
   447     mapEntry->info = info;
   448   }
   449   NS_ENSURE_SUCCESS(rv, rv);
   451   // Load index information
   452   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   453     "SELECT object_store_id, id, name, key_path, unique_index, multientry "
   454     "FROM object_store_index"
   455   ), getter_AddRefs(stmt));
   456   NS_ENSURE_SUCCESS(rv, rv);
   458   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   459     int64_t objectStoreId = stmt->AsInt64(0);
   461     ObjectStoreInfo* objectStoreInfo = nullptr;
   462     for (uint32_t index = 0; index < infoMap.Length(); index++) {
   463       if (infoMap[index].id == objectStoreId) {
   464         objectStoreInfo = infoMap[index].info;
   465         break;
   466       }
   467     }
   469     if (!objectStoreInfo) {
   470       NS_ERROR("Index for nonexistant object store!");
   471       return NS_ERROR_UNEXPECTED;
   472     }
   474     IndexInfo* indexInfo = objectStoreInfo->indexes.AppendElement();
   475     NS_ENSURE_TRUE(indexInfo, NS_ERROR_OUT_OF_MEMORY);
   477     indexInfo->id = stmt->AsInt64(1);
   479     rv = stmt->GetString(2, indexInfo->name);
   480     NS_ENSURE_SUCCESS(rv, rv);
   482     nsString keyPathSerialization;
   483     rv = stmt->GetString(3, keyPathSerialization);
   484     NS_ENSURE_SUCCESS(rv, rv);
   486     // XXX bent wants to assert here
   487     indexInfo->keyPath = KeyPath::DeserializeFromString(keyPathSerialization);
   488     indexInfo->unique = !!stmt->AsInt32(4);
   489     indexInfo->multiEntry = !!stmt->AsInt32(5);
   490   }
   491   NS_ENSURE_SUCCESS(rv, rv);
   493   // Load version information.
   494   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   495     "SELECT version "
   496     "FROM database"
   497   ), getter_AddRefs(stmt));
   498   NS_ENSURE_SUCCESS(rv, rv);
   500   rv = stmt->ExecuteStep(&hasResult);
   501   NS_ENSURE_SUCCESS(rv, rv);
   503   if (!hasResult) {
   504     NS_ERROR("Database has no version!");
   505     return NS_ERROR_UNEXPECTED;
   506   }
   508   int64_t version = 0;
   509   rv = stmt->GetInt64(0, &version);
   511   *aVersion = std::max<int64_t>(version, 0);
   513   return rv;
   514 }
   516 // static
   517 nsresult
   518 IDBFactory::SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
   519                                 uint64_t aVersion,
   520                                 ObjectStoreInfoArray& aObjectStores)
   521 {
   522   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   523   NS_ASSERTION(aDatabaseInfo, "Null pointer!");
   525   ObjectStoreInfoArray objectStores;
   526   objectStores.SwapElements(aObjectStores);
   528 #ifdef DEBUG
   529   {
   530     nsTArray<nsString> existingNames;
   531     aDatabaseInfo->GetObjectStoreNames(existingNames);
   532     NS_ASSERTION(existingNames.IsEmpty(), "Should be an empty DatabaseInfo");
   533   }
   534 #endif
   536   aDatabaseInfo->version = aVersion;
   538   for (uint32_t index = 0; index < objectStores.Length(); index++) {
   539     nsRefPtr<ObjectStoreInfo>& info = objectStores[index];
   541     if (!aDatabaseInfo->PutObjectStore(info)) {
   542       NS_WARNING("Out of memory!");
   543       return NS_ERROR_OUT_OF_MEMORY;
   544     }
   545   }
   547   return NS_OK;
   548 }
   550 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory)
   551 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory)
   553 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory)
   554   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   555   NS_INTERFACE_MAP_ENTRY(nsISupports)
   556 NS_INTERFACE_MAP_END
   558 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory)
   560 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory)
   561   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   562   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   563 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   565 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
   566   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   567   if (tmp->mOwningObject) {
   568     tmp->mOwningObject = nullptr;
   569   }
   570   if (tmp->mRootedOwningObject) {
   571     mozilla::DropJSObjects(tmp);
   572     tmp->mRootedOwningObject = false;
   573   }
   574   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
   575 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   577 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
   578   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   579   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOwningObject)
   580 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   582 nsresult
   583 IDBFactory::OpenInternal(const nsAString& aName,
   584                          int64_t aVersion,
   585                          PersistenceType aPersistenceType,
   586                          const nsACString& aGroup,
   587                          const nsACString& aASCIIOrigin,
   588                          StoragePrivilege aPrivilege,
   589                          bool aDeleting,
   590                          IDBOpenDBRequest** _retval)
   591 {
   592   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   593   NS_ASSERTION(mWindow || mOwningObject, "Must have one of these!");
   595   AutoJSContext cx;
   596   nsCOMPtr<nsPIDOMWindow> window;
   597   JS::Rooted<JSObject*> scriptOwner(cx);
   599   if (mWindow) {
   600     window = mWindow;
   601     scriptOwner =
   602       static_cast<nsGlobalWindow*>(window.get())->FastGetGlobalJSObject();
   603   }
   604   else {
   605     scriptOwner = mOwningObject;
   606   }
   608   if (aPrivilege == Chrome) {
   609     // Chrome privilege, ignore the persistence type parameter.
   610     aPersistenceType = PERSISTENCE_TYPE_PERSISTENT;
   611   }
   613   nsRefPtr<IDBOpenDBRequest> request =
   614     IDBOpenDBRequest::Create(this, window, scriptOwner);
   615   IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   617   nsresult rv;
   619   if (IndexedDatabaseManager::IsMainProcess()) {
   620     nsRefPtr<OpenDatabaseHelper> openHelper =
   621       new OpenDatabaseHelper(request, aName, aGroup, aASCIIOrigin, aVersion,
   622                              aPersistenceType, aDeleting, mContentParent,
   623                              aPrivilege);
   625     rv = openHelper->Init();
   626     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   628     if (!Preferences::GetBool(PREF_INDEXEDDB_ENABLED)) {
   629       openHelper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   630       rv = openHelper->WaitForOpenAllowed();
   631     }
   632     else {
   633       if (mPrivilege != Chrome &&
   634           aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
   635         nsRefPtr<CheckPermissionsHelper> permissionHelper =
   636           new CheckPermissionsHelper(openHelper, window);
   638         QuotaManager* quotaManager = QuotaManager::Get();
   639         NS_ASSERTION(quotaManager, "This should never be null!");
   641         rv = quotaManager->
   642           WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
   643                              Nullable<PersistenceType>(aPersistenceType),
   644                              openHelper->Id(), permissionHelper);
   645       }
   646       else {
   647         // Chrome and temporary storage doesn't need to check the permission.
   648         rv = openHelper->WaitForOpenAllowed();
   649       }
   650     }
   651     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   652   }
   653   else if (aDeleting) {
   654     nsCString databaseId;
   655     QuotaManager::GetStorageId(aPersistenceType, aASCIIOrigin, Client::IDB,
   656                                aName, databaseId);
   657     MOZ_ASSERT(!databaseId.IsEmpty());
   659     IndexedDBDeleteDatabaseRequestChild* actor =
   660       new IndexedDBDeleteDatabaseRequestChild(this, request, databaseId);
   662     mActorChild->SendPIndexedDBDeleteDatabaseRequestConstructor(
   663                                                               actor,
   664                                                               nsString(aName),
   665                                                               aPersistenceType);
   666   }
   667   else {
   668     IndexedDBDatabaseChild* dbActor =
   669       static_cast<IndexedDBDatabaseChild*>(
   670         mActorChild->SendPIndexedDBDatabaseConstructor(nsString(aName),
   671                                                        aVersion,
   672                                                        aPersistenceType));
   674     dbActor->SetRequest(request);
   675   }
   677 #ifdef IDB_PROFILER_USE_MARKS
   678   {
   679     NS_ConvertUTF16toUTF8 profilerName(aName);
   680     if (aDeleting) {
   681       IDB_PROFILER_MARK("IndexedDB Request %llu: deleteDatabase(\"%s\")",
   682                         "MT IDBFactory.deleteDatabase()",
   683                         request->GetSerialNumber(), profilerName.get());
   684     }
   685     else {
   686       IDB_PROFILER_MARK("IndexedDB Request %llu: open(\"%s\", %lld)",
   687                         "MT IDBFactory.open()",
   688                         request->GetSerialNumber(), profilerName.get(),
   689                         aVersion);
   690     }
   691   }
   692 #endif
   694   request.forget(_retval);
   695   return NS_OK;
   696 }
   698 JSObject*
   699 IDBFactory::WrapObject(JSContext* aCx)
   700 {
   701   return IDBFactoryBinding::Wrap(aCx, this);
   702 }
   704 already_AddRefed<IDBOpenDBRequest>
   705 IDBFactory::Open(const nsAString& aName, const IDBOpenDBOptions& aOptions,
   706                  ErrorResult& aRv)
   707 {
   708   return Open(nullptr, aName, aOptions.mVersion, aOptions.mStorage, false, aRv);
   709 }
   711 already_AddRefed<IDBOpenDBRequest>
   712 IDBFactory::DeleteDatabase(const nsAString& aName,
   713                            const IDBOpenDBOptions& aOptions,
   714                            ErrorResult& aRv)
   715 {
   716   return Open(nullptr, aName, Optional<uint64_t>(), aOptions.mStorage, true,
   717               aRv);
   718 }
   720 int16_t
   721 IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
   722                 JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
   723 {
   724   Key first, second;
   725   nsresult rv = first.SetFromJSVal(aCx, aFirst);
   726   if (NS_FAILED(rv)) {
   727     aRv.Throw(rv);
   728     return 0;
   729   }
   731   rv = second.SetFromJSVal(aCx, aSecond);
   732   if (NS_FAILED(rv)) {
   733     aRv.Throw(rv);
   734     return 0;
   735   }
   737   if (first.IsUnset() || second.IsUnset()) {
   738     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
   739     return 0;
   740   }
   742   return Key::CompareKeys(first, second);
   743 }
   745 already_AddRefed<IDBOpenDBRequest>
   746 IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
   747                              uint64_t aVersion, ErrorResult& aRv)
   748 {
   749   // Just to be on the extra-safe side
   750   if (!nsContentUtils::IsCallerChrome()) {
   751     MOZ_CRASH();
   752   }
   754   return Open(aPrincipal, aName, Optional<uint64_t>(aVersion),
   755               Optional<mozilla::dom::StorageType>(), false, aRv);
   756 }
   758 already_AddRefed<IDBOpenDBRequest>
   759 IDBFactory::OpenForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
   760                              const IDBOpenDBOptions& aOptions, ErrorResult& aRv)
   761 {
   762   // Just to be on the extra-safe side
   763   if (!nsContentUtils::IsCallerChrome()) {
   764     MOZ_CRASH();
   765   }
   767   return Open(aPrincipal, aName, aOptions.mVersion, aOptions.mStorage, false,
   768               aRv);
   769 }
   771 already_AddRefed<IDBOpenDBRequest>
   772 IDBFactory::DeleteForPrincipal(nsIPrincipal* aPrincipal, const nsAString& aName,
   773                                const IDBOpenDBOptions& aOptions,
   774                                ErrorResult& aRv)
   775 {
   776   // Just to be on the extra-safe side
   777   if (!nsContentUtils::IsCallerChrome()) {
   778     MOZ_CRASH();
   779   }
   781   return Open(aPrincipal, aName, Optional<uint64_t>(), aOptions.mStorage, true,
   782               aRv);
   783 }
   785 already_AddRefed<IDBOpenDBRequest>
   786 IDBFactory::Open(nsIPrincipal* aPrincipal, const nsAString& aName,
   787                  const Optional<uint64_t>& aVersion,
   788                  const Optional<mozilla::dom::StorageType>& aStorageType,
   789                  bool aDelete, ErrorResult& aRv)
   790 {
   791   nsresult rv;
   793   nsCString group;
   794   nsCString origin;
   795   StoragePrivilege privilege;
   796   PersistenceType defaultPersistenceType;
   797   if (aPrincipal) {
   798     rv = QuotaManager::GetInfoFromPrincipal(aPrincipal, &group, &origin,
   799                                             &privilege,
   800                                             &defaultPersistenceType);
   801     if (NS_FAILED(rv)) {
   802       IDB_REPORT_INTERNAL_ERR();
   803       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   804       return nullptr;
   805     }
   806   }
   807   else {
   808     group = mGroup;
   809     origin = mASCIIOrigin;
   810     privilege = mPrivilege;
   811     defaultPersistenceType = mDefaultPersistenceType;
   812   }
   814   uint64_t version = 0;
   815   if (!aDelete && aVersion.WasPassed()) {
   816     if (aVersion.Value() < 1) {
   817       aRv.ThrowTypeError(MSG_INVALID_VERSION);
   818       return nullptr;
   819     }
   820     version = aVersion.Value();
   821   }
   823   PersistenceType persistenceType =
   824     PersistenceTypeFromStorage(aStorageType, defaultPersistenceType);
   826   nsRefPtr<IDBOpenDBRequest> request;
   827   rv = OpenInternal(aName, version, persistenceType, group, origin, privilege,
   828                     aDelete, getter_AddRefs(request));
   829   if (NS_FAILED(rv)) {
   830     aRv.Throw(rv);
   831     return nullptr;
   832   }
   834   return request.forget();
   835 }

mercurial