Exemplo n.º 1
0
already_AddRefed<IDBOpenDBRequest>
IDBFactory::OpenInternal(JSContext* aCx,
                         nsIPrincipal* aPrincipal,
                         const nsAString& aName,
                         const Optional<uint64_t>& aVersion,
                         const Optional<StorageType>& aStorageType,
                         bool aDeleting,
                         ErrorResult& aRv)
{
    MOZ_ASSERT(mWindow || mOwningObject);
    MOZ_ASSERT_IF(!mWindow, !mPrivateBrowsingMode);

    CommonFactoryRequestParams commonParams;
    commonParams.privateBrowsingMode() = mPrivateBrowsingMode;

    PrincipalInfo& principalInfo = commonParams.principalInfo();

    if (aPrincipal) {
        if (!NS_IsMainThread()) {
            MOZ_CRASH("Figure out security checks for workers!");
        }
        MOZ_ASSERT(nsContentUtils::IsCallerChrome());

        if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
                                 &principalInfo)))) {
            IDB_REPORT_INTERNAL_ERR();
            aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
            return nullptr;
        }

        if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
                principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
            IDB_REPORT_INTERNAL_ERR();
            aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
            return nullptr;
        }
    } else {
        principalInfo = *mPrincipalInfo;
    }

    uint64_t version = 0;
    if (!aDeleting && aVersion.WasPassed()) {
        if (aVersion.Value() < 1) {
            aRv.ThrowTypeError<MSG_INVALID_VERSION>();
            return nullptr;
        }
        version = aVersion.Value();
    }

    // Nothing can be done here if we have previously failed to create a
    // background actor.
    if (mBackgroundActorFailed) {
        IDB_REPORT_INTERNAL_ERR();
        aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
        return nullptr;
    }

    PersistenceType persistenceType;

    if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
        // Chrome privilege always gets persistent storage.
        persistenceType = PERSISTENCE_TYPE_PERSISTENT;
    } else {
        persistenceType = PersistenceTypeFromStorage(aStorageType);
    }

    DatabaseMetadata& metadata = commonParams.metadata();
    metadata.name() = aName;
    metadata.persistenceType() = persistenceType;

    FactoryRequestParams params;
    if (aDeleting) {
        metadata.version() = 0;
        params = DeleteDatabaseRequestParams(commonParams);
    } else {
        metadata.version() = version;
        params = OpenDatabaseRequestParams(commonParams);
    }

    if (!mBackgroundActor && mPendingRequests.IsEmpty()) {
        BackgroundChildImpl::ThreadLocal* threadLocal =
            BackgroundChildImpl::GetThreadLocalForCurrentThread();

        nsAutoPtr<ThreadLocal> newIDBThreadLocal;
        ThreadLocal* idbThreadLocal;

        if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
            idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
        } else {
            nsCOMPtr<nsIUUIDGenerator> uuidGen =
                do_GetService("@mozilla.org/uuid-generator;1");
            MOZ_ASSERT(uuidGen);

            nsID id;
            MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id));

            newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id);
        }

        if (PBackgroundChild* actor = BackgroundChild::GetForCurrentThread()) {
            BackgroundActorCreated(actor, idbThreadLocal->GetLoggingInfo());
        } else {
            // We need to start the sequence to create a background actor for this
            // thread.
            RefPtr<BackgroundCreateCallback> cb =
                new BackgroundCreateCallback(this, idbThreadLocal->GetLoggingInfo());
            if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(cb))) {
                IDB_REPORT_INTERNAL_ERR();
                aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
                return nullptr;
            }
        }

        if (newIDBThreadLocal) {
            if (!threadLocal) {
                threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
            }
            MOZ_ASSERT(threadLocal);
            MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);

            threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
        }
    }

    RefPtr<IDBOpenDBRequest> request;

    if (mWindow) {
        JS::Rooted<JSObject*> scriptOwner(aCx,
                                          nsGlobalWindow::Cast(mWindow.get())->FastGetGlobalJSObject());
        MOZ_ASSERT(scriptOwner);

        request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner);
    } else {
        JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject);

        request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner);
        if (!request) {
            MOZ_ASSERT(!NS_IsMainThread());
            aRv.ThrowUncatchableException();
            return nullptr;
        }
    }

    MOZ_ASSERT(request);

    if (aDeleting) {
        IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                     "indexedDB.deleteDatabase(\"%s\")",
                     "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()",
                     IDB_LOG_ID_STRING(),
                     request->LoggingSerialNumber(),
                     NS_ConvertUTF16toUTF8(aName).get());
    } else {
        IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                     "indexedDB.open(\"%s\", %s)",
                     "IndexedDB %s: C R[%llu]: IDBFactory.open()",
                     IDB_LOG_ID_STRING(),
                     request->LoggingSerialNumber(),
                     NS_ConvertUTF16toUTF8(aName).get(),
                     IDB_LOG_STRINGIFY(aVersion));
    }

    // If we already have a background actor then we can start this request now.
    if (mBackgroundActor) {
        nsresult rv = InitiateRequest(request, params);
        if (NS_WARN_IF(NS_FAILED(rv))) {
            IDB_REPORT_INTERNAL_ERR();
            aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
            return nullptr;
        }
    } else {
        mPendingRequests.AppendElement(new PendingRequestInfo(request, params));
    }

    return request.forget();
}
Exemplo n.º 2
0
already_AddRefed<IDBOpenDBRequest>
IDBFactory::OpenInternal(JSContext* aCx,
                         nsIPrincipal* aPrincipal,
                         const nsAString& aName,
                         const Optional<uint64_t>& aVersion,
                         const Optional<StorageType>& aStorageType,
                         bool aDeleting,
                         CallerType aCallerType,
                         ErrorResult& aRv)
{
  MOZ_ASSERT(mWindow || mOwningObject);
  MOZ_ASSERT_IF(!mWindow, !mPrivateBrowsingMode);

  CommonFactoryRequestParams commonParams;

  PrincipalInfo& principalInfo = commonParams.principalInfo();

  if (aPrincipal) {
    if (!NS_IsMainThread()) {
      MOZ_CRASH("Figure out security checks for workers!  What's this "
                "aPrincipal we have on a worker thread?");
    }
    MOZ_ASSERT(aCallerType == CallerType::System);
    MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode == (aPrincipal->GetPrivateBrowsingId() > 0));

    if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
                                                      &principalInfo)))) {
      IDB_REPORT_INTERNAL_ERR();
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      return nullptr;
    }

    if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
        principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
      IDB_REPORT_INTERNAL_ERR();
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      return nullptr;
    }
  } else {
    principalInfo = *mPrincipalInfo;
  }

  uint64_t version = 0;
  if (!aDeleting && aVersion.WasPassed()) {
    if (aVersion.Value() < 1) {
      aRv.ThrowTypeError<MSG_INVALID_VERSION>();
      return nullptr;
    }
    version = aVersion.Value();
  }

  // Nothing can be done here if we have previously failed to create a
  // background actor.
  if (mBackgroundActorFailed) {
    IDB_REPORT_INTERNAL_ERR();
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    return nullptr;
  }

  PersistenceType persistenceType;

  bool isInternal = principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo;
  if (!isInternal && principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
    nsCString origin = principalInfo.get_ContentPrincipalInfo().originNoSuffix();
    isInternal = QuotaManager::IsOriginInternal(origin);
  }

  // Allow storage attributes for add-ons independent of the pref.
  // This works in the main thread only, workers don't have the principal.
  bool isAddon = false;
  if (NS_IsMainThread()) {
    // aPrincipal is passed inconsistently, so even when we are already on
    // the main thread, we may have been passed a null aPrincipal.
    nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(principalInfo);
    if (principal) {
      nsAutoString addonId;
      Unused << NS_WARN_IF(NS_FAILED(principal->GetAddonId(addonId)));
      isAddon = !addonId.IsEmpty();
    }
  }

  if (isInternal) {
    // Chrome privilege and internal origins always get persistent storage.
    persistenceType = PERSISTENCE_TYPE_PERSISTENT;
  } else if (isAddon || DOMPrefs::IndexedDBStorageOptionsEnabled()) {
    persistenceType = PersistenceTypeFromStorage(aStorageType);
  } else {
    persistenceType = PERSISTENCE_TYPE_DEFAULT;
  }

  DatabaseMetadata& metadata = commonParams.metadata();
  metadata.name() = aName;
  metadata.persistenceType() = persistenceType;

  FactoryRequestParams params;
  if (aDeleting) {
    metadata.version() = 0;
    params = DeleteDatabaseRequestParams(commonParams);
  } else {
    metadata.version() = version;
    params = OpenDatabaseRequestParams(commonParams);
  }

  if (!mBackgroundActor) {
    BackgroundChildImpl::ThreadLocal* threadLocal =
      BackgroundChildImpl::GetThreadLocalForCurrentThread();

    nsAutoPtr<ThreadLocal> newIDBThreadLocal;
    ThreadLocal* idbThreadLocal;

    if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
      idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
    } else {
      nsCOMPtr<nsIUUIDGenerator> uuidGen =
        do_GetService("@mozilla.org/uuid-generator;1");
      MOZ_ASSERT(uuidGen);

      nsID id;
      MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id));

      newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id);
    }

    PBackgroundChild* backgroundActor =
      BackgroundChild::GetOrCreateForCurrentThread();
    if (NS_WARN_IF(!backgroundActor)) {
      IDB_REPORT_INTERNAL_ERR();
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      return nullptr;
    }

    {
      BackgroundFactoryChild* actor = new BackgroundFactoryChild(this);

      // Set EventTarget for the top-level actor.
      // All child actors created later inherit the same event target.
      backgroundActor->SetEventTargetForActor(actor, EventTarget());
      MOZ_ASSERT(actor->GetActorEventTarget());
      mBackgroundActor =
        static_cast<BackgroundFactoryChild*>(
          backgroundActor->SendPBackgroundIDBFactoryConstructor(actor,
                                                                idbThreadLocal->GetLoggingInfo()));

      if (NS_WARN_IF(!mBackgroundActor)) {
        mBackgroundActorFailed = true;
        IDB_REPORT_INTERNAL_ERR();
        aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
        return nullptr;
      }
    }

    if (newIDBThreadLocal) {
      if (!threadLocal) {
        threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
      }
      MOZ_ASSERT(threadLocal);
      MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);

      threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
    }
  }

  RefPtr<IDBOpenDBRequest> request;

  if (mWindow) {
    JS::Rooted<JSObject*> scriptOwner(aCx,
                                      nsGlobalWindowInner::Cast(mWindow.get())->FastGetGlobalJSObject());
    MOZ_ASSERT(scriptOwner);

    request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner);
  } else {
    JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject);

    request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner);
    if (!request) {
      MOZ_ASSERT(!NS_IsMainThread());
      aRv.ThrowUncatchableException();
      return nullptr;
    }
  }

  MOZ_ASSERT(request);

  if (aDeleting) {
    IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                   "indexedDB.deleteDatabase(\"%s\")",
                 "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()",
                 IDB_LOG_ID_STRING(),
                 request->LoggingSerialNumber(),
                 NS_ConvertUTF16toUTF8(aName).get());
  } else {
    IDB_LOG_MARK("IndexedDB %s: Child  Request[%llu]: "
                   "indexedDB.open(\"%s\", %s)",
                 "IndexedDB %s: C R[%llu]: IDBFactory.open()",
                 IDB_LOG_ID_STRING(),
                 request->LoggingSerialNumber(),
                 NS_ConvertUTF16toUTF8(aName).get(),
                 IDB_LOG_STRINGIFY(aVersion));
  }

  nsresult rv = InitiateRequest(request, params);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    IDB_REPORT_INTERNAL_ERR();
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
    return nullptr;
  }

  return request.forget();
}