Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/indexedDB/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  IndexedDatabase.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "mozilla/dom/IndexedDatabase.h"
#include "IndexedDatabaseInlines.h"

#include "IDBDatabase.h"

#include "mozilla/dom/FileBlobImpl.h"
#include "mozilla/dom/FileList.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "mozilla/dom/URLSearchParams.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "MainThreadUtils.h"
#include "jsapi.h"
#include "nsIFile.h"
#include "nsIGlobalObject.h"
#include "nsQueryObject.h"
#include "nsString.h"

namespace mozilla::dom::indexedDB {
namespace {
struct MOZ_STACK_CLASS MutableFileData final {
  nsString type;
  nsString name;

  MOZ_COUNTED_DEFAULT_CTOR(MutableFileData)

  MOZ_COUNTED_DTOR(MutableFileData)
};

struct MOZ_STACK_CLASS BlobOrFileData final {
  uint32_t tag = 0;
  uint64_t size = 0;
  nsString type;
  nsString name;
  int64_t lastModifiedDate = INT64_MAX;

  MOZ_COUNTED_DEFAULT_CTOR(BlobOrFileData)

  MOZ_COUNTED_DTOR(BlobOrFileData)
};

struct MOZ_STACK_CLASS WasmModuleData final {
  uint32_t bytecodeIndex;
  uint32_t compiledIndex;
  uint32_t flags;

  explicit WasmModuleData(uint32_t aFlags)
      : bytecodeIndex(0), compiledIndex(0), flags(aFlags) {
    MOZ_COUNT_CTOR(WasmModuleData);
  }

  MOZ_COUNTED_DTOR(WasmModuleData)
};

bool StructuredCloneReadString(JSStructuredCloneReader* aReader,
                               nsCString& aString) {
  uint32_t length;
  if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) {
    NS_WARNING("Failed to read length!");
    return false;
  }
  length = NativeEndian::swapFromLittleEndian(length);

  if (!aString.SetLength(length, fallible)) {
    NS_WARNING("Out of memory?");
    return false;
  }
  charconst buffer = aString.BeginWriting();

  if (!JS_ReadBytes(aReader, buffer, length)) {
    NS_WARNING("Failed to read type!");
    return false;
  }

  return true;
}

bool ReadFileHandle(JSStructuredCloneReader* aReader,
                    MutableFileData* aRetval) {
  static_assert(SCTAG_DOM_MUTABLEFILE == 0xFFFF8004, "Update me!");
  MOZ_ASSERT(aReader && aRetval);

  nsCString type;
  if (!StructuredCloneReadString(aReader, type)) {
    return false;
  }
  CopyUTF8toUTF16(type, aRetval->type);

  nsCString name;
  if (!StructuredCloneReadString(aReader, name)) {
    return false;
  }
  CopyUTF8toUTF16(name, aRetval->name);

  return true;
}

bool ReadBlobOrFile(JSStructuredCloneReader* aReader, uint32_t aTag,
                    BlobOrFileData* aRetval) {
  static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
                    SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
                    SCTAG_DOM_FILE == 0xffff8005,
                "Update me!");

  MOZ_ASSERT(aReader);
  MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
             aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
             aTag == SCTAG_DOM_BLOB);
  MOZ_ASSERT(aRetval);

  aRetval->tag = aTag;

  uint64_t size;
  if (NS_WARN_IF(!JS_ReadBytes(aReader, &size, sizeof(uint64_t)))) {
    return false;
  }

  aRetval->size = NativeEndian::swapFromLittleEndian(size);

  nsCString type;
  if (NS_WARN_IF(!StructuredCloneReadString(aReader, type))) {
    return false;
  }

  CopyUTF8toUTF16(type, aRetval->type);

  // Blobs are done.
  if (aTag == SCTAG_DOM_BLOB) {
    return true;
  }

  MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
             aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE);

  int64_t lastModifiedDate;
  if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
    lastModifiedDate = INT64_MAX;
  } else {
    if (NS_WARN_IF(!JS_ReadBytes(aReader, &lastModifiedDate,
                                 sizeof(lastModifiedDate)))) {
      return false;
    }
    lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate);
  }

  aRetval->lastModifiedDate = lastModifiedDate;

  nsCString name;
  if (NS_WARN_IF(!StructuredCloneReadString(aReader, name))) {
    return false;
  }

  CopyUTF8toUTF16(name, aRetval->name);

  return true;
}

bool ReadWasmModule(JSStructuredCloneReader* aReader, WasmModuleData* aRetval) {
  static_assert(SCTAG_DOM_WASM_MODULE == 0xFFFF8006, "Update me!");
  MOZ_ASSERT(aReader && aRetval);

  uint32_t bytecodeIndex;
  uint32_t compiledIndex;
  if (NS_WARN_IF(!JS_ReadUint32Pair(aReader, &bytecodeIndex, &compiledIndex))) {
    return false;
  }

  aRetval->bytecodeIndex = bytecodeIndex;
  aRetval->compiledIndex = compiledIndex;

  return true;
}

template <typename StructuredCloneFile>
class ValueDeserializationHelper;

class ValueDeserializationHelperBase {
 public:
  static bool CreateAndWrapWasmModule(JSContext* aCx,
                                      const StructuredCloneFileBase& aFile,
                                      const WasmModuleData& aData,
                                      JS::MutableHandle<JSObject*> aResult) {
    MOZ_ASSERT(aCx);
    MOZ_ASSERT(aFile.Type() == StructuredCloneFileBase::eWasmBytecode);

    // Both on the parent and child side, just create a plain object here,
    // support for de-serialization of WebAssembly.Modules has been removed in
    // bug 1561876. Full removal is tracked in bug 1487479.

    JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
    if (NS_WARN_IF(!obj)) {
      return false;
    }

    aResult.set(obj);
    return true;
  }

  template <typename StructuredCloneFile>
  static already_AddRefed<File> CreateUnwrappedFile(
      JSContext* aCx, IDBDatabase* aDatabase, const StructuredCloneFile& aFile,
      const BlobOrFileData& aData) {
    MOZ_ASSERT(aCx);
    MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
               aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE);
    MOZ_ASSERT(aFile.Type() == StructuredCloneFileBase::eBlob);

    const auto blob = ValueDeserializationHelper<StructuredCloneFile>::GetBlob(
        aCx, aDatabase, aFile);
    if (NS_WARN_IF(!blob)) {
      return nullptr;
    }

    blob->Impl()->SetLazyData(aData.name, aData.type, aData.size,
                              aData.lastModifiedDate * PR_USEC_PER_MSEC);

    MOZ_ASSERT(blob->IsFile());
    RefPtr<File> file = blob->ToFile();
    MOZ_ASSERT(file);

    return file.forget();
  }

  template <typename StructuredCloneFile>
  static bool CreateAndWrapBlobOrFile(JSContext* aCx, IDBDatabase* aDatabase,
                                      const StructuredCloneFile& aFile,
                                      const BlobOrFileData& aData,
                                      JS::MutableHandle<JSObject*> aResult) {
    MOZ_ASSERT(aCx);
    MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
               aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
               aData.tag == SCTAG_DOM_BLOB);
    MOZ_ASSERT(aFile.Type() == StructuredCloneFileBase::eBlob);

    if (aData.tag == SCTAG_DOM_FILE ||
        aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
      RefPtr<File> file =
          ValueDeserializationHelper<StructuredCloneFile>::CreateUnwrappedFile(
              aCx, aDatabase, aFile, aData);
      return WrapAsJSObject(aCx, file, aResult);
    }

    const auto blob = ValueDeserializationHelper<StructuredCloneFile>::GetBlob(
        aCx, aDatabase, aFile);
    if (NS_WARN_IF(!blob)) {
      return false;
    }

    MOZ_ASSERT(aData.tag == SCTAG_DOM_BLOB);
    blob->Impl()->SetLazyData(VoidString(), aData.type, aData.size, INT64_MAX);
    MOZ_ASSERT(!blob->IsFile());

    // XXX The comment below is somewhat confusing, since it seems to imply
    // that this branch is only executed when called from ActorsParent, but
    // it's executed from both the parent and the child side code.

    // ActorsParent sends here a kind of half blob and half file wrapped into
    // a DOM File object. DOM File and DOM Blob are a WebIDL wrapper around a
    // BlobImpl object. SetLazyData() has just changed the BlobImpl to be a
    // Blob (see the previous assert), but 'blob' still has the WebIDL DOM
    // File wrapping.
    // Before exposing it to content, we must recreate a DOM Blob object.

    const RefPtr<Blob> exposedBlob =
        Blob::Create(blob->GetParentObject(), blob->Impl());
    if (NS_WARN_IF(!exposedBlob)) {
      return false;
    }

    return WrapAsJSObject(aCx, exposedBlob, aResult);
  }
};

template <>
class ValueDeserializationHelper<StructuredCloneFileParent>
    : public ValueDeserializationHelperBase {
 public:
  static bool CreateAndWrapMutableFile(JSContext* aCx,
                                       StructuredCloneFileParent& aFile,
                                       const MutableFileData& aData,
                                       JS::MutableHandle<JSObject*> aResult) {
    MOZ_ASSERT(aCx);
    MOZ_ASSERT(aFile.Type() == StructuredCloneFileBase::eBlob);

    // We are in an IDB SQLite schema upgrade where we don't care about a real
    // 'MutableFile', but we just care of having a proper |mType| flag.

    aFile.MutateType(StructuredCloneFileBase::eMutableFile);

    // Just make a dummy object.
    JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));

    if (NS_WARN_IF(!obj)) {
      return false;
    }

    aResult.set(obj);
    return true;
  }

  static RefPtr<Blob> GetBlob(JSContext* aCx, IDBDatabase* aDatabase,
                              const StructuredCloneFileParent& aFile) {
    // This is chrome code, so there is no parent, but still we want to set a
    // correct parent for the new File object.
    const auto global = [aDatabase, aCx]() -> nsCOMPtr<nsIGlobalObject> {
      if (NS_IsMainThread()) {
        if (aDatabase && aDatabase->GetParentObject()) {
          return aDatabase->GetParentObject();
        }
        return xpc::CurrentNativeGlobal(aCx);
      }
      const WorkerPrivate* const workerPrivate =
          GetCurrentThreadWorkerPrivate();
      MOZ_ASSERT(workerPrivate);

      WorkerGlobalScope* const globalScope = workerPrivate->GlobalScope();
      MOZ_ASSERT(globalScope);

      return do_QueryObject(globalScope);
    }();

    MOZ_ASSERT(global);

    // We do not have an mBlob but do have a DatabaseFileInfo.
    //
    // If we are creating an index, we do need a real-looking Blob/File instance
    // because the index's key path can reference their properties.  Rather than
    // create a fake-looking object, create a real Blob.
    //
    // If we are in a schema upgrade, we don't strictly need that, but we do not
    // need to optimize for that, and create it anyway.
    const nsCOMPtr<nsIFile> file = aFile.FileInfo().GetFileForFileInfo();
    if (!file) {
      return nullptr;
    }

    const auto impl = MakeRefPtr<FileBlobImpl>(file);
    impl->SetFileId(aFile.FileInfo().Id());
    return File::Create(global, impl);
  }
};

template <>
class ValueDeserializationHelper<StructuredCloneFileChild>
    : public ValueDeserializationHelperBase {
 public:
  static bool CreateAndWrapMutableFile(JSContext* aCx,
                                       StructuredCloneFileChild& aFile,
                                       const MutableFileData& aData,
                                       JS::MutableHandle<JSObject*> aResult) {
    MOZ_ASSERT(aCx);
    MOZ_ASSERT(aFile.Type() == StructuredCloneFileBase::eMutableFile);

    return false;
  }

  static RefPtr<Blob> GetBlob(JSContext* aCx, IDBDatabase* aDatabase,
                              const StructuredCloneFileChild& aFile) {
    if (aFile.HasBlob()) {
      return aFile.BlobPtr();
    }

    MOZ_CRASH("Expected a StructuredCloneFile with a Blob");
  }
};

}  // namespace

template <typename StructuredCloneReadInfo>
JSObject* CommonStructuredCloneReadCallback(
    JSContext* aCx, JSStructuredCloneReader* aReader,
    const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aData,
    StructuredCloneReadInfo* aCloneReadInfo, IDBDatabase* aDatabase) {
  // We need to statically assert that our tag values are what we expect
  // so that if people accidentally change them they notice.
  static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
                    SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
                    SCTAG_DOM_MUTABLEFILE == 0xffff8004 &&
                    SCTAG_DOM_FILE == 0xffff8005 &&
                    SCTAG_DOM_WASM_MODULE == 0xffff8006 &&
                    SCTAG_DOM_URLSEARCHPARAMS == 0xffff8014 &&
                    SCTAG_DOM_FILELIST == 0xffff8003,
                "You changed our structured clone tag values and just ate "
                "everyone's IndexedDB data. I hope you are happy.");

  if (aTag == SCTAG_DOM_URLSEARCHPARAMS) {
    // Protect the result from a moving GC in ~RefPtr.
    JS::Rooted<JSObject*> result(aCx);

    {
      // Scope for the RefPtr below.

      nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
      if (!global) {
        return nullptr;
      }

      RefPtr<URLSearchParams> params = new URLSearchParams(global);

      uint32_t paramCount;
      uint32_t zero;
      if (!JS_ReadUint32Pair(aReader, ¶mCount, &zero)) {
        return nullptr;
      }

      nsAutoString key;
      nsAutoString value;
      for (uint32_t index = 0; index < paramCount; index++) {
        if (!StructuredCloneHolder::ReadString(aReader, key) ||
            !StructuredCloneHolder::ReadString(aReader, value)) {
          return nullptr;
        }
        params->Append(NS_ConvertUTF16toUTF8(key),
                       NS_ConvertUTF16toUTF8(value));
      }

      if (!WrapAsJSObject(aCx, params, &result)) {
        return nullptr;
      }
    }

    return result;
  }

  using StructuredCloneFile =
      typename StructuredCloneReadInfo::StructuredCloneFile;

  if (aTag == SCTAG_DOM_FILELIST) {
    const auto& files = aCloneReadInfo->Files();

    uint32_t fileListLength = aData;

    if (fileListLength > files.Length()) {
      MOZ_ASSERT(false"Bad file list length value!");

      return nullptr;
    }

    // We need to ensure that all RAII smart pointers which may trigger GC are
    // destroyed on return prior to this JS::Rooted being destroyed and
    // unrooting the pointer. This scope helps make this intent more explicit.
    JS::Rooted<JSObject*> obj(aCx);
    {
      nsCOMPtr<nsIGlobalObject> global = xpc::CurrentNativeGlobal(aCx);
      if (!global) {
        MOZ_ASSERT(false"Could not access global!");

        return nullptr;
      }

      RefPtr<FileList> fileList = new FileList(global);

      for (uint32_t i = 0u; i < fileListLength; ++i) {
        uint32_t tag = UINT32_MAX;
        uint32_t index = UINT32_MAX;
        if (!JS_ReadUint32Pair(aReader, &tag, &index)) {
          return nullptr;
        }

        if (tag != SCTAG_DOM_FILE) {
          MOZ_ASSERT(false"Unexpected tag!");

          return nullptr;
        }

        if (uint64_t(index) >= files.Length()) {
          MOZ_ASSERT(false"Bad index!");

          return nullptr;
        }

        BlobOrFileData data;
        if (NS_WARN_IF(!ReadBlobOrFile(aReader, tag, &data))) {
          return nullptr;
        }

        auto& fileObj = aCloneReadInfo->MutableFile(index);

        RefPtr<File> file = ValueDeserializationHelper<
            StructuredCloneFile>::CreateUnwrappedFile(aCx, aDatabase, fileObj,
                                                      data);
        if (!file) {
          MOZ_ASSERT(false"Could not deserialize file!");

          return nullptr;
        }

        if (!fileList->Append(file)) {
          MOZ_ASSERT(false"Could not extend filelist!");

          return nullptr;
        }
      }

      if (!WrapAsJSObject(aCx, fileList, &obj)) {
        return nullptr;
      }
    }

    return obj;
  }

  if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
      aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE ||
      aTag == SCTAG_DOM_MUTABLEFILE || aTag == SCTAG_DOM_WASM_MODULE) {
    JS::Rooted<JSObject*> result(aCx);

    if (aTag == SCTAG_DOM_WASM_MODULE) {
      WasmModuleData data(aData);
      if (NS_WARN_IF(!ReadWasmModule(aReader, &data))) {
        return nullptr;
      }

      MOZ_ASSERT(data.compiledIndex == data.bytecodeIndex + 1);
      MOZ_ASSERT(!data.flags);

      const auto& files = aCloneReadInfo->Files();
      if (data.bytecodeIndex >= files.Length() ||
          data.compiledIndex >= files.Length()) {
        MOZ_ASSERT(false"Bad index value!");
        return nullptr;
      }

      const auto& file = files[data.bytecodeIndex];

      if (NS_WARN_IF(!ValueDeserializationHelper<StructuredCloneFile>::
                         CreateAndWrapWasmModule(aCx, file, data, &result))) {
        return nullptr;
      }

      return result;
    }

    if (aData >= aCloneReadInfo->Files().Length()) {
      MOZ_ASSERT(false"Bad index value!");
      return nullptr;
    }

    auto& file = aCloneReadInfo->MutableFile(aData);

    if (aTag == SCTAG_DOM_MUTABLEFILE) {
      MutableFileData data;
      if (NS_WARN_IF(!ReadFileHandle(aReader, &data))) {
        return nullptr;
      }

      if (NS_WARN_IF(!ValueDeserializationHelper<StructuredCloneFile>::
                         CreateAndWrapMutableFile(aCx, file, data, &result))) {
        return nullptr;
      }

      return result;
    }

    BlobOrFileData data;
    if (NS_WARN_IF(!ReadBlobOrFile(aReader, aTag, &data))) {
      return nullptr;
    }

    if (NS_WARN_IF(!ValueDeserializationHelper<
                   StructuredCloneFile>::CreateAndWrapBlobOrFile(aCx, aDatabase,
                                                                 file, data,
                                                                 &result))) {
      return nullptr;
    }

    return result;
  }

  return StructuredCloneHolder::ReadFullySerializableObjects(aCx, aReader, aTag,
                                                             true);
}

template JSObject* CommonStructuredCloneReadCallback(
    JSContext* aCx, JSStructuredCloneReader* aReader,
    const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aData,
    StructuredCloneReadInfoChild* aCloneReadInfo, IDBDatabase* aDatabase);

template JSObject* CommonStructuredCloneReadCallback(
    JSContext* aCx, JSStructuredCloneReader* aReader,
    const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aData,
    StructuredCloneReadInfoParent* aCloneReadInfo, IDBDatabase* aDatabase);
}  // namespace mozilla::dom::indexedDB

Messung V0.5
C=94 H=99 G=96

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.