2010-06-23 23:46:08 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2015-05-03 22:32:37 +03:00
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2010-06-28 22:51:06 +04:00
|
|
|
#include "IDBObjectStore.h"
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "FileInfo.h"
|
2010-06-28 22:51:06 +04:00
|
|
|
#include "IDBCursor.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "IDBDatabase.h"
|
2010-06-29 02:22:41 +04:00
|
|
|
#include "IDBEvents.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "IDBFactory.h"
|
2010-06-29 02:22:41 +04:00
|
|
|
#include "IDBIndex.h"
|
2010-06-23 23:46:08 +04:00
|
|
|
#include "IDBKeyRange.h"
|
2014-06-12 07:35:29 +04:00
|
|
|
#include "IDBMutableFile.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "IDBRequest.h"
|
2010-06-28 20:46:21 +04:00
|
|
|
#include "IDBTransaction.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "IndexedDatabase.h"
|
|
|
|
#include "IndexedDatabaseInlines.h"
|
|
|
|
#include "IndexedDatabaseManager.h"
|
|
|
|
#include "js/Class.h"
|
2015-05-02 05:12:52 +03:00
|
|
|
#include "js/Date.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "js/StructuredClone.h"
|
2012-06-22 02:27:13 +04:00
|
|
|
#include "KeyPath.h"
|
2018-01-18 15:19:06 +03:00
|
|
|
#include "NullPrincipal.h"
|
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2016-05-22 23:31:11 +03:00
|
|
|
#include "mozilla/EndianUtils.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "mozilla/ErrorResult.h"
|
2018-01-18 15:19:06 +03:00
|
|
|
#include "mozilla/JSObjectHolder.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "mozilla/Move.h"
|
|
|
|
#include "mozilla/dom/BindingUtils.h"
|
|
|
|
#include "mozilla/dom/ContentChild.h"
|
|
|
|
#include "mozilla/dom/ContentParent.h"
|
|
|
|
#include "mozilla/dom/DOMStringList.h"
|
2014-10-08 20:15:23 +04:00
|
|
|
#include "mozilla/dom/File.h"
|
2018-01-18 15:19:06 +03:00
|
|
|
#include "mozilla/dom/FileBlobImpl.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "mozilla/dom/IDBMutableFileBinding.h"
|
2014-10-08 20:15:22 +04:00
|
|
|
#include "mozilla/dom/BlobBinding.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "mozilla/dom/IDBObjectStoreBinding.h"
|
2017-02-16 20:26:38 +03:00
|
|
|
#include "mozilla/dom/MemoryBlobImpl.h"
|
2017-08-29 18:56:49 +03:00
|
|
|
#include "mozilla/dom/StreamBlobImpl.h"
|
2015-09-30 15:22:08 +03:00
|
|
|
#include "mozilla/dom/StructuredCloneHolder.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "mozilla/dom/StructuredCloneTags.h"
|
|
|
|
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
|
2018-01-31 10:25:30 +03:00
|
|
|
#include "mozilla/dom/WorkerPrivate.h"
|
|
|
|
#include "mozilla/dom/WorkerScope.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "mozilla/ipc/BackgroundChild.h"
|
|
|
|
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
2018-01-18 15:19:06 +03:00
|
|
|
#include "mozilla/SystemGroup.h"
|
2014-09-27 03:21:57 +04:00
|
|
|
#include "nsCOMPtr.h"
|
2015-04-15 19:47:03 +03:00
|
|
|
#include "nsQueryObject.h"
|
2017-08-29 18:56:49 +03:00
|
|
|
#include "nsStreamUtils.h"
|
|
|
|
#include "nsStringStream.h"
|
2013-03-16 10:58:50 +04:00
|
|
|
#include "ProfilerHelpers.h"
|
2014-01-28 04:37:05 +04:00
|
|
|
#include "ReportInternalError.h"
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Include this last to avoid path problems on Windows.
|
|
|
|
#include "ActorsChild.h"
|
2013-01-11 17:32:20 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2017-06-07 13:36:20 +03:00
|
|
|
using namespace mozilla::dom::indexedDB;
|
2014-09-27 03:21:57 +04:00
|
|
|
using namespace mozilla::dom::quota;
|
|
|
|
using namespace mozilla::ipc;
|
2012-06-22 02:27:13 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
struct IDBObjectStore::StructuredCloneWriteInfo
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
JSAutoStructuredCloneBuffer mCloneBuffer;
|
2016-10-25 22:18:44 +03:00
|
|
|
nsTArray<StructuredCloneFile> mFiles;
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBDatabase* mDatabase;
|
|
|
|
uint64_t mOffsetToKeyProp;
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
explicit StructuredCloneWriteInfo(IDBDatabase* aDatabase)
|
2018-04-25 01:21:47 +03:00
|
|
|
: mCloneBuffer(JS::StructuredCloneScope::DifferentProcessForIndexedDB, nullptr,
|
2016-07-21 16:29:42 +03:00
|
|
|
nullptr)
|
|
|
|
, mDatabase(aDatabase)
|
2014-09-27 03:21:57 +04:00
|
|
|
, mOffsetToKeyProp(0)
|
2012-06-01 21:21:12 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(aDatabase);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
StructuredCloneWriteInfo(StructuredCloneWriteInfo&& aCloneWriteInfo)
|
2018-05-30 22:15:35 +03:00
|
|
|
: mCloneBuffer(std::move(aCloneWriteInfo.mCloneBuffer))
|
2014-09-27 03:21:57 +04:00
|
|
|
, mDatabase(aCloneWriteInfo.mDatabase)
|
|
|
|
, mOffsetToKeyProp(aCloneWriteInfo.mOffsetToKeyProp)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mDatabase);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
mFiles.SwapElements(aCloneWriteInfo.mFiles);
|
2014-09-27 03:21:57 +04:00
|
|
|
aCloneWriteInfo.mOffsetToKeyProp = 0;
|
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
~StructuredCloneWriteInfo()
|
2010-06-23 23:46:08 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_DTOR(StructuredCloneWriteInfo);
|
2010-06-23 23:46:08 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
namespace {
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
struct MOZ_STACK_CLASS MutableFileData final
|
2010-06-23 23:46:08 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
nsString type;
|
|
|
|
nsString name;
|
|
|
|
|
|
|
|
MutableFileData()
|
2012-06-01 21:21:12 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_CTOR(MutableFileData);
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
~MutableFileData()
|
2011-01-27 04:53:02 +03:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_DTOR(MutableFileData);
|
2011-01-27 04:53:02 +03:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
};
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
struct MOZ_STACK_CLASS BlobOrFileData final
|
2010-06-23 23:46:08 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
uint32_t tag;
|
|
|
|
uint64_t size;
|
|
|
|
nsString type;
|
|
|
|
nsString name;
|
2015-04-27 14:17:19 +03:00
|
|
|
int64_t lastModifiedDate;
|
2014-09-27 03:21:57 +04:00
|
|
|
|
|
|
|
BlobOrFileData()
|
|
|
|
: tag(0)
|
|
|
|
, size(0)
|
2015-04-27 14:17:19 +03:00
|
|
|
, lastModifiedDate(INT64_MAX)
|
2014-09-13 20:12:19 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_CTOR(BlobOrFileData);
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
~BlobOrFileData()
|
2014-09-13 20:12:19 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_COUNT_DTOR(BlobOrFileData);
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
};
|
|
|
|
|
2016-10-25 22:18:58 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
~WasmModuleData()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(WasmModuleData);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
struct MOZ_STACK_CLASS GetAddInfoClosure final
|
2010-08-27 00:57:30 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBObjectStore::StructuredCloneWriteInfo& mCloneWriteInfo;
|
|
|
|
JS::Handle<JS::Value> mValue;
|
2010-08-27 00:57:30 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
GetAddInfoClosure(IDBObjectStore::StructuredCloneWriteInfo& aCloneWriteInfo,
|
|
|
|
JS::Handle<JS::Value> aValue)
|
|
|
|
: mCloneWriteInfo(aCloneWriteInfo)
|
|
|
|
, mValue(aValue)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(GetAddInfoClosure);
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
~GetAddInfoClosure()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(GetAddInfoClosure);
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
};
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
2016-03-23 18:02:57 +03:00
|
|
|
GenerateRequest(JSContext* aCx, IDBObjectStore* aObjectStore)
|
2010-06-23 23:46:08 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(aObjectStore);
|
|
|
|
aObjectStore->AssertIsOnOwningThread();
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBTransaction* transaction = aObjectStore->Transaction();
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBRequest> request =
|
2016-03-23 18:02:57 +03:00
|
|
|
IDBRequest::Create(aCx, aObjectStore, transaction->Database(), transaction);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2017-08-29 18:56:49 +03:00
|
|
|
// Blob internal code clones this stream before it's passed to IPC, so we
|
|
|
|
// serialize module's optimized code only when AsyncWait() is called.
|
|
|
|
class WasmCompiledModuleStream final
|
|
|
|
: public nsIAsyncInputStream
|
|
|
|
, public nsICloneableInputStream
|
|
|
|
, private JS::WasmModuleListener
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISerialEventTarget> mOwningThread;
|
|
|
|
|
|
|
|
// Initially and while waiting for compilation to complete, the mModule field
|
|
|
|
// is non-null, keeping alive the module whose code needs to be serialized.
|
|
|
|
RefPtr<JS::WasmModule> mModule;
|
|
|
|
|
|
|
|
// A module stream can have up to one input stream callback.
|
|
|
|
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
|
|
|
|
|
|
|
// When a module's optimized code is ready to be serialized, it will be
|
|
|
|
// serialized into mStream and the mModule will be released. At this point,
|
|
|
|
// stream reads will succeed.
|
|
|
|
nsCOMPtr<nsIInputStream> mStream;
|
|
|
|
|
|
|
|
// When the stream is finished reading or closed, mStatus will be changed from
|
|
|
|
// NS_OK to NS_BASE_STREAM_CLOSED or whatever status was passed to
|
|
|
|
// CloseWithStatus.
|
|
|
|
nsresult mStatus;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit WasmCompiledModuleStream(JS::WasmModule* aModule)
|
|
|
|
: mOwningThread(GetCurrentThreadSerialEventTarget())
|
|
|
|
, mModule(aModule)
|
|
|
|
, mStatus(NS_OK)
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(aModule);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
IsOnOwningThread() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mOwningThread);
|
|
|
|
|
|
|
|
bool current;
|
|
|
|
return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(¤t)) && current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
AssertIsOnOwningThread() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(IsOnOwningThread());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Copy constructor for cloning.
|
|
|
|
explicit WasmCompiledModuleStream(const WasmCompiledModuleStream& aOther)
|
|
|
|
: mOwningThread(aOther.mOwningThread)
|
|
|
|
, mModule(aOther.mModule)
|
|
|
|
, mStatus(aOther.mStatus)
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (aOther.mStream) {
|
|
|
|
nsCOMPtr<nsICloneableInputStream> cloneableStream =
|
|
|
|
do_QueryInterface(aOther.mStream);
|
|
|
|
MOZ_ASSERT(cloneableStream);
|
|
|
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(cloneableStream->Clone(getter_AddRefs(mStream)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~WasmCompiledModuleStream() override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(Close());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CallCallback()
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mCallback);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStreamCallback> callback;
|
|
|
|
callback.swap(mCallback);
|
|
|
|
|
|
|
|
callback->OnInputStreamReady(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
|
|
|
|
// nsIInputStream:
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
Close() override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
return CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
Available(uint64_t* _retval) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (NS_FAILED(mStatus)) {
|
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mStream) {
|
|
|
|
*_retval = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mStream->Available(_retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
ReadSegments(nsWriteSegmentFun aWriter,
|
|
|
|
void* aClosure,
|
|
|
|
uint32_t aCount,
|
|
|
|
uint32_t* _retval) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (NS_FAILED(mStatus)) {
|
|
|
|
*_retval = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mStream) {
|
|
|
|
return NS_BASE_STREAM_WOULD_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mStream->ReadSegments(aWriter, aClosure, aCount, _retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
IsNonBlocking(bool* _retval) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
*_retval = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsIAsyncInputStream:
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
CloseWithStatus(nsresult aStatus) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (NS_FAILED(mStatus)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
mModule = nullptr;
|
|
|
|
|
|
|
|
if (mStream) {
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(mStream->Close());
|
|
|
|
mStream = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED;
|
|
|
|
|
|
|
|
if (mCallback) {
|
|
|
|
CallCallback();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
AsyncWait(nsIInputStreamCallback* aCallback,
|
|
|
|
uint32_t aFlags,
|
|
|
|
uint32_t aRequestedCount,
|
|
|
|
nsIEventTarget* aEventTarget) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT_IF(mCallback, !aCallback);
|
|
|
|
|
|
|
|
if (aFlags) {
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aCallback) {
|
|
|
|
mCallback = nullptr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aEventTarget) {
|
|
|
|
mCallback =
|
|
|
|
NS_NewInputStreamReadyEvent("WasmCompiledModuleStream::AsyncWait",
|
|
|
|
aCallback,
|
|
|
|
aEventTarget);
|
|
|
|
} else {
|
|
|
|
mCallback = aCallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(mStatus) || mStream) {
|
|
|
|
CallCallback();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(mModule);
|
|
|
|
mModule->notifyWhenCompilationComplete(this);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsICloneableInputStream:
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
GetCloneable(bool* aCloneable) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
*aCloneable = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
Clone(nsIInputStream** _retval) override
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> clone = new WasmCompiledModuleStream(*this);
|
|
|
|
|
|
|
|
clone.forget(_retval);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// JS::WasmModuleListener:
|
|
|
|
|
|
|
|
void
|
|
|
|
onCompilationComplete() override
|
|
|
|
{
|
|
|
|
if (!IsOnOwningThread()) {
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(NewCancelableRunnableMethod(
|
|
|
|
"WasmCompiledModuleStream::onCompilationComplete",
|
|
|
|
this,
|
|
|
|
&WasmCompiledModuleStream::onCompilationComplete)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(mStatus) || !mCallback) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(mModule);
|
|
|
|
|
|
|
|
size_t compiledSize = mModule->compiledSerializedSize();
|
|
|
|
|
|
|
|
nsCString compiled;
|
|
|
|
compiled.SetLength(compiledSize);
|
|
|
|
|
|
|
|
mModule->compiledSerialize(
|
|
|
|
reinterpret_cast<uint8_t*>(compiled.BeginWriting()), compiledSize);
|
|
|
|
|
|
|
|
MOZ_ALWAYS_SUCCEEDS(NS_NewCStringInputStream(getter_AddRefs(mStream),
|
2018-05-30 22:15:35 +03:00
|
|
|
std::move(compiled)));
|
2017-08-29 18:56:49 +03:00
|
|
|
|
|
|
|
mModule = nullptr;
|
|
|
|
|
|
|
|
CallCallback();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(WasmCompiledModuleStream,
|
|
|
|
nsIInputStream,
|
|
|
|
nsIAsyncInputStream,
|
|
|
|
nsICloneableInputStream)
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool
|
|
|
|
StructuredCloneWriteCallback(JSContext* aCx,
|
|
|
|
JSStructuredCloneWriter* aWriter,
|
|
|
|
JS::Handle<JSObject*> aObj,
|
|
|
|
void* aClosure)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(aCx);
|
|
|
|
MOZ_ASSERT(aWriter);
|
|
|
|
MOZ_ASSERT(aClosure);
|
2010-09-10 08:54:25 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
auto* cloneWriteInfo =
|
|
|
|
static_cast<IDBObjectStore::StructuredCloneWriteInfo*>(aClosure);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (JS_GetClass(aObj) == IDBObjectStore::DummyPropClass()) {
|
|
|
|
MOZ_ASSERT(!cloneWriteInfo->mOffsetToKeyProp);
|
2015-02-27 18:08:15 +03:00
|
|
|
cloneWriteInfo->mOffsetToKeyProp = js::GetSCOffset(aWriter);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
uint64_t value = 0;
|
|
|
|
// Omit endian swap
|
|
|
|
return JS_WriteBytes(aWriter, &value, sizeof(value));
|
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2017-07-10 23:05:24 +03:00
|
|
|
// UNWRAP_OBJECT calls might mutate this.
|
|
|
|
JS::Rooted<JSObject*> obj(aCx, aObj);
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBMutableFile* mutableFile;
|
2017-07-10 23:05:24 +03:00
|
|
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, &obj, mutableFile))) {
|
2015-09-09 14:15:05 +03:00
|
|
|
if (cloneWriteInfo->mDatabase->IsFileHandleDisabled()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBDatabase* database = mutableFile->Database();
|
|
|
|
MOZ_ASSERT(database);
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Throw when trying to store IDBMutableFile objects that live in a
|
|
|
|
// different database.
|
|
|
|
if (database != cloneWriteInfo->mDatabase) {
|
|
|
|
MOZ_ASSERT(!SameCOMIdentity(database, cloneWriteInfo->mDatabase));
|
2011-01-07 09:21:36 +03:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (database->Name() != cloneWriteInfo->mDatabase->Name()) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-07-26 02:41:50 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
nsCString fileOrigin, databaseOrigin;
|
|
|
|
PersistenceType filePersistenceType, databasePersistenceType;
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED(database->GetQuotaInfo(fileOrigin,
|
|
|
|
&filePersistenceType)))) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED(cloneWriteInfo->mDatabase->GetQuotaInfo(
|
|
|
|
databaseOrigin,
|
|
|
|
&databasePersistenceType)))) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (filePersistenceType != databasePersistenceType ||
|
|
|
|
fileOrigin != databaseOrigin) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2011-07-26 02:41:50 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
if (cloneWriteInfo->mFiles.Length() > size_t(UINT32_MAX)) {
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
const uint32_t index = cloneWriteInfo->mFiles.Length();
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_ConvertUTF16toUTF8 convType(mutableFile->Type());
|
|
|
|
uint32_t convTypeLength =
|
|
|
|
NativeEndian::swapToLittleEndian(convType.Length());
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_ConvertUTF16toUTF8 convName(mutableFile->Name());
|
|
|
|
uint32_t convNameLength =
|
|
|
|
NativeEndian::swapToLittleEndian(convName.Length());
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_MUTABLEFILE, uint32_t(index)) ||
|
|
|
|
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(uint32_t)) ||
|
|
|
|
!JS_WriteBytes(aWriter, convType.get(), convType.Length()) ||
|
|
|
|
!JS_WriteBytes(aWriter, &convNameLength, sizeof(uint32_t)) ||
|
|
|
|
!JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
|
|
|
|
return false;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
|
|
|
|
newFile->mMutableFile = mutableFile;
|
|
|
|
newFile->mType = StructuredCloneFile::eMutableFile;
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return true;
|
|
|
|
}
|
2010-10-19 21:58:52 +04:00
|
|
|
|
2014-10-08 20:15:22 +04:00
|
|
|
{
|
2015-05-12 15:09:51 +03:00
|
|
|
Blob* blob = nullptr;
|
2017-07-10 23:05:24 +03:00
|
|
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
|
2015-05-19 17:36:37 +03:00
|
|
|
ErrorResult rv;
|
|
|
|
uint64_t size = blob->GetSize(rv);
|
|
|
|
MOZ_ASSERT(!rv.Failed());
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
size = NativeEndian::swapToLittleEndian(size);
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
nsString type;
|
2015-05-19 17:36:37 +03:00
|
|
|
blob->GetType(type);
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_ConvertUTF16toUTF8 convType(type);
|
|
|
|
uint32_t convTypeLength =
|
|
|
|
NativeEndian::swapToLittleEndian(convType.Length());
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
if (cloneWriteInfo->mFiles.Length() > size_t(UINT32_MAX)) {
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"Fix the structured clone data to use a bigger type!");
|
|
|
|
return false;
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
const uint32_t index = cloneWriteInfo->mFiles.Length();
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!JS_WriteUint32Pair(aWriter,
|
2014-10-08 20:15:22 +04:00
|
|
|
blob->IsFile() ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
|
2014-09-27 03:21:57 +04:00
|
|
|
index) ||
|
|
|
|
!JS_WriteBytes(aWriter, &size, sizeof(size)) ||
|
|
|
|
!JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
|
|
|
|
!JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<File> file = blob->ToFile();
|
2015-05-12 15:09:51 +03:00
|
|
|
if (file) {
|
2015-05-18 16:51:54 +03:00
|
|
|
ErrorResult rv;
|
|
|
|
int64_t lastModifiedDate = file->GetLastModified(rv);
|
|
|
|
MOZ_ALWAYS_TRUE(!rv.Failed());
|
2010-10-19 21:58:52 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
nsString name;
|
2015-05-18 16:51:54 +03:00
|
|
|
file->GetName(name);
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_ConvertUTF16toUTF8 convName(name);
|
|
|
|
uint32_t convNameLength =
|
|
|
|
NativeEndian::swapToLittleEndian(convName.Length());
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) ||
|
2014-09-27 03:21:57 +04:00
|
|
|
!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
|
|
|
|
!JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
|
|
|
|
return false;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
|
|
|
|
newFile->mBlob = blob;
|
|
|
|
newFile->mType = StructuredCloneFile::eBlob;
|
2014-09-27 03:21:57 +04:00
|
|
|
|
|
|
|
return true;
|
2010-10-19 21:58:52 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-25 22:18:48 +03:00
|
|
|
if (JS::IsWasmModuleObject(aObj)) {
|
|
|
|
RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
|
|
|
|
MOZ_ASSERT(module);
|
|
|
|
|
2017-07-26 19:00:39 +03:00
|
|
|
size_t bytecodeSize = module->bytecodeSerializedSize();
|
2018-05-09 12:02:12 +03:00
|
|
|
UniquePtr<uint8_t[], JS::FreePolicy> bytecode(js_pod_malloc<uint8_t>(bytecodeSize));
|
2017-07-26 19:00:39 +03:00
|
|
|
module->bytecodeSerialize(bytecode.get(), bytecodeSize);
|
2016-10-25 22:18:48 +03:00
|
|
|
|
|
|
|
RefPtr<BlobImpl> blobImpl =
|
2017-02-16 20:26:38 +03:00
|
|
|
new MemoryBlobImpl(bytecode.release(), bytecodeSize, EmptyString());
|
2017-08-29 18:56:49 +03:00
|
|
|
|
2016-10-25 22:18:48 +03:00
|
|
|
RefPtr<Blob> bytecodeBlob = Blob::Create(nullptr, blobImpl);
|
|
|
|
|
2017-08-29 18:56:49 +03:00
|
|
|
if (module->compilationComplete()) {
|
|
|
|
size_t compiledSize = module->compiledSerializedSize();
|
|
|
|
UniquePtr<uint8_t[]> compiled(new uint8_t[compiledSize]);
|
|
|
|
module->compiledSerialize(compiled.get(), compiledSize);
|
|
|
|
|
|
|
|
blobImpl =
|
|
|
|
new MemoryBlobImpl(compiled.release(), compiledSize, EmptyString());
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIInputStream> stream(new WasmCompiledModuleStream(module));
|
|
|
|
|
2018-06-13 18:37:26 +03:00
|
|
|
blobImpl = StreamBlobImpl::Create(stream.forget(), EmptyString(),
|
|
|
|
UINT64_MAX);
|
2017-08-29 18:56:49 +03:00
|
|
|
}
|
2017-07-26 19:00:39 +03:00
|
|
|
|
2016-10-25 22:18:48 +03:00
|
|
|
RefPtr<Blob> compiledBlob = Blob::Create(nullptr, blobImpl);
|
|
|
|
|
|
|
|
if (cloneWriteInfo->mFiles.Length() + 1 > size_t(UINT32_MAX)) {
|
|
|
|
MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint32_t index = cloneWriteInfo->mFiles.Length();
|
|
|
|
|
2016-10-25 22:19:06 +03:00
|
|
|
// The ordering of the bytecode and compiled file is significant and must
|
|
|
|
// never be changed. These two files must always form a pair
|
|
|
|
// [eWasmBytecode, eWasmCompiled]. Everything else depends on it!
|
2016-10-25 22:18:48 +03:00
|
|
|
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, /* flags */ 0) ||
|
|
|
|
!JS_WriteUint32Pair(aWriter, index, index + 1)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
|
|
|
|
newFile->mBlob = bytecodeBlob;
|
|
|
|
newFile->mType = StructuredCloneFile::eWasmBytecode;
|
|
|
|
|
|
|
|
newFile = cloneWriteInfo->mFiles.AppendElement();
|
|
|
|
newFile->mBlob = compiledBlob;
|
|
|
|
newFile->mType = StructuredCloneFile::eWasmCompiled;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-30 15:22:08 +03:00
|
|
|
return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2010-10-19 21:58:52 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
nsresult
|
|
|
|
GetAddInfoCallback(JSContext* aCx, void* aClosure)
|
2012-06-01 21:21:12 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
|
|
|
|
nullptr /* read */,
|
|
|
|
StructuredCloneWriteCallback /* write */,
|
|
|
|
nullptr /* reportError */,
|
|
|
|
nullptr /* readTransfer */,
|
|
|
|
nullptr /* writeTransfer */,
|
2018-03-28 10:23:17 +03:00
|
|
|
nullptr /* freeTransfer */,
|
|
|
|
nullptr /* canTransfer */
|
2014-09-27 03:21:57 +04:00
|
|
|
};
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(aCx);
|
2013-06-01 00:29:54 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
auto* data = static_cast<GetAddInfoClosure*>(aClosure);
|
|
|
|
MOZ_ASSERT(data);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
data->mCloneWriteInfo.mOffsetToKeyProp = 0;
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!data->mCloneWriteInfo.mCloneBuffer.write(aCx,
|
|
|
|
data->mValue,
|
|
|
|
&kStructuredCloneCallbacks,
|
|
|
|
&data->mCloneWriteInfo)) {
|
|
|
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
bool
|
|
|
|
ResolveMysteryMutableFile(IDBMutableFile* aMutableFile,
|
|
|
|
const nsString& aName,
|
|
|
|
const nsString& aType)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aMutableFile);
|
|
|
|
aMutableFile->SetLazyData(aName, aType);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool
|
|
|
|
StructuredCloneReadString(JSStructuredCloneReader* aReader,
|
|
|
|
nsCString& aString)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
uint32_t length;
|
|
|
|
if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) {
|
|
|
|
NS_WARNING("Failed to read length!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
length = NativeEndian::swapFromLittleEndian(length);
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2015-01-28 12:00:40 +03:00
|
|
|
if (!aString.SetLength(length, fallible)) {
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_WARNING("Out of memory?");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char* buffer = aString.BeginWriting();
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!JS_ReadBytes(aReader, buffer, length)) {
|
|
|
|
NS_WARNING("Failed to read type!");
|
|
|
|
return false;
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return true;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool
|
|
|
|
ReadFileHandle(JSStructuredCloneReader* aReader,
|
|
|
|
MutableFileData* aRetval)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
static_assert(SCTAG_DOM_MUTABLEFILE == 0xFFFF8004, "Update me!");
|
|
|
|
MOZ_ASSERT(aReader && aRetval);
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
nsCString type;
|
|
|
|
if (!StructuredCloneReadString(aReader, type)) {
|
|
|
|
return false;
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
CopyUTF8toUTF16(type, aRetval->type);
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
nsCString name;
|
|
|
|
if (!StructuredCloneReadString(aReader, name)) {
|
|
|
|
return false;
|
2012-08-03 10:25:30 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
CopyUTF8toUTF16(name, aRetval->name);
|
|
|
|
|
2014-09-18 03:36:01 +04:00
|
|
|
return true;
|
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-18 03:36:01 +04:00
|
|
|
bool
|
2014-09-27 03:21:57 +04:00
|
|
|
ReadBlobOrFile(JSStructuredCloneReader* aReader,
|
|
|
|
uint32_t aTag,
|
|
|
|
BlobOrFileData* aRetval)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
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);
|
|
|
|
|
2015-04-27 14:17:19 +03:00
|
|
|
int64_t lastModifiedDate;
|
2014-09-27 03:21:57 +04:00
|
|
|
if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
|
2015-04-27 14:17:19 +03:00
|
|
|
lastModifiedDate = INT64_MAX;
|
2014-09-27 03:21:57 +04:00
|
|
|
} else {
|
|
|
|
if (NS_WARN_IF(!JS_ReadBytes(aReader, &lastModifiedDate,
|
|
|
|
sizeof(lastModifiedDate)))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate);
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
|
|
|
aRetval->lastModifiedDate = lastModifiedDate;
|
|
|
|
|
|
|
|
nsCString name;
|
|
|
|
if (NS_WARN_IF(!StructuredCloneReadString(aReader, name))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyUTF8toUTF16(name, aRetval->name);
|
|
|
|
|
2012-08-03 10:25:30 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-25 22:18:58 +03:00
|
|
|
bool
|
|
|
|
ReadWasmModule(JSStructuredCloneReader* aReader,
|
|
|
|
WasmModuleData* aRetval)
|
|
|
|
{
|
|
|
|
static_assert(SCTAG_DOM_WASM == 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;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
class ValueDeserializationHelper
|
2013-01-11 17:32:20 +04:00
|
|
|
{
|
|
|
|
public:
|
2014-09-27 03:21:57 +04:00
|
|
|
static bool
|
|
|
|
CreateAndWrapMutableFile(JSContext* aCx,
|
|
|
|
StructuredCloneFile& aFile,
|
|
|
|
const MutableFileData& aData,
|
|
|
|
JS::MutableHandle<JSObject*> aResult)
|
2013-01-11 17:32:20 +04:00
|
|
|
{
|
2015-09-09 14:15:05 +03:00
|
|
|
MOZ_ASSERT(aCx);
|
2018-01-18 15:19:07 +03:00
|
|
|
|
|
|
|
// If we have 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 propert
|
|
|
|
// |mType| flag.
|
|
|
|
if (aFile.mType == StructuredCloneFile::eBlob) {
|
|
|
|
aFile.mType = StructuredCloneFile::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;
|
|
|
|
}
|
|
|
|
|
2016-10-25 22:18:03 +03:00
|
|
|
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eMutableFile);
|
2013-01-11 17:32:20 +04:00
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
if (!aFile.mMutableFile || !NS_IsMainThread()) {
|
2015-06-11 23:34:30 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
if (NS_WARN_IF(!ResolveMysteryMutableFile(aFile.mMutableFile,
|
|
|
|
aData.name,
|
|
|
|
aData.type))) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-01-11 17:32:20 +04:00
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
JS::Rooted<JS::Value> wrappedMutableFile(aCx);
|
|
|
|
if (!ToJSValue(aCx, aFile.mMutableFile, &wrappedMutableFile)) {
|
2014-07-17 20:41:08 +04:00
|
|
|
return false;
|
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
aResult.set(&wrappedMutableFile.toObject());
|
2014-07-17 20:41:08 +04:00
|
|
|
return true;
|
2013-01-11 17:32:20 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
static bool
|
|
|
|
CreateAndWrapBlobOrFile(JSContext* aCx,
|
2014-10-08 20:15:22 +04:00
|
|
|
IDBDatabase* aDatabase,
|
2014-09-27 03:21:57 +04:00
|
|
|
StructuredCloneFile& aFile,
|
|
|
|
const BlobOrFileData& aData,
|
|
|
|
JS::MutableHandle<JSObject*> aResult)
|
2013-01-11 17:32:20 +04:00
|
|
|
{
|
2015-09-09 14:15:05 +03:00
|
|
|
MOZ_ASSERT(aCx);
|
2013-01-11 17:32:20 +04:00
|
|
|
MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
|
|
|
|
aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
|
|
|
|
aData.tag == SCTAG_DOM_BLOB);
|
2016-10-25 22:18:03 +03:00
|
|
|
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
|
2018-01-18 15:19:06 +03:00
|
|
|
|
|
|
|
RefPtr<Blob> blob = aFile.mBlob;
|
|
|
|
|
|
|
|
/* If we are creating an index, we do not have an mBlob but do have an
|
|
|
|
* mInfo. Unlike other index or upgrade cases, 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 (!blob) {
|
|
|
|
MOZ_ASSERT(aFile.mFileInfo);
|
|
|
|
nsCOMPtr<nsIFile> file = FileInfo::GetFileForFileInfo(aFile.mFileInfo);
|
|
|
|
if (!file) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RefPtr<FileBlobImpl> impl = new FileBlobImpl(file);
|
|
|
|
impl->SetFileId(aFile.mFileInfo->Id());
|
|
|
|
blob = File::Create(nullptr, impl);
|
|
|
|
}
|
2013-01-11 17:32:20 +04:00
|
|
|
|
2014-10-08 20:15:22 +04:00
|
|
|
// It can happen that this IDB is chrome code, so there is no parent, but
|
2014-10-08 20:15:23 +04:00
|
|
|
// still we want to set a correct parent for the new File object.
|
2014-10-08 20:15:22 +04:00
|
|
|
nsCOMPtr<nsISupports> parent;
|
2014-12-17 09:26:15 +03:00
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
if (aDatabase && aDatabase->GetParentObject()) {
|
|
|
|
parent = aDatabase->GetParentObject();
|
|
|
|
} else {
|
|
|
|
parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
|
|
|
}
|
2014-10-08 20:15:22 +04:00
|
|
|
} else {
|
2014-12-17 09:26:15 +03:00
|
|
|
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
|
|
|
MOZ_ASSERT(workerPrivate);
|
|
|
|
|
|
|
|
WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
|
|
|
|
MOZ_ASSERT(globalScope);
|
|
|
|
|
|
|
|
parent = do_QueryObject(globalScope);
|
2014-10-08 20:15:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(parent);
|
|
|
|
|
2013-01-11 17:32:20 +04:00
|
|
|
if (aData.tag == SCTAG_DOM_BLOB) {
|
2018-01-18 15:19:06 +03:00
|
|
|
blob->Impl()->SetLazyData(
|
2017-09-22 07:35:46 +03:00
|
|
|
VoidString(), aData.type, aData.size, INT64_MAX);
|
2018-01-18 15:19:06 +03:00
|
|
|
MOZ_ASSERT(!blob->IsFile());
|
2015-05-12 15:09:51 +03:00
|
|
|
|
2017-05-23 08:51:13 +03:00
|
|
|
// 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
|
2018-01-18 15:19:06 +03:00
|
|
|
// Blob (see the previous assert), but 'blob' still has the WebIDL DOM
|
|
|
|
// File wrapping.
|
2017-05-23 08:51:13 +03:00
|
|
|
// Before exposing it to content, we must recreate a DOM Blob object.
|
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
RefPtr<Blob> exposedBlob =
|
|
|
|
Blob::Create(blob->GetParentObject(), blob->Impl());
|
|
|
|
MOZ_ASSERT(exposedBlob);
|
2013-05-02 13:12:47 +04:00
|
|
|
JS::Rooted<JS::Value> wrappedBlob(aCx);
|
2018-01-18 15:19:06 +03:00
|
|
|
if (!ToJSValue(aCx, exposedBlob, &wrappedBlob)) {
|
2014-09-27 03:21:57 +04:00
|
|
|
return false;
|
2013-01-11 17:32:20 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
aResult.set(&wrappedBlob.toObject());
|
|
|
|
return true;
|
2013-01-11 17:32:20 +04:00
|
|
|
}
|
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
blob->Impl()->SetLazyData(
|
2017-05-23 08:50:54 +03:00
|
|
|
aData.name, aData.type, aData.size,
|
|
|
|
aData.lastModifiedDate * PR_USEC_PER_MSEC);
|
2013-01-11 17:32:20 +04:00
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
MOZ_ASSERT(blob->IsFile());
|
|
|
|
RefPtr<File> file = blob->ToFile();
|
2015-05-12 15:09:51 +03:00
|
|
|
MOZ_ASSERT(file);
|
|
|
|
|
2013-05-02 13:12:47 +04:00
|
|
|
JS::Rooted<JS::Value> wrappedFile(aCx);
|
2015-05-12 15:09:51 +03:00
|
|
|
if (!ToJSValue(aCx, file, &wrappedFile)) {
|
2014-09-27 03:21:57 +04:00
|
|
|
return false;
|
2013-01-11 17:32:20 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
aResult.set(&wrappedFile.toObject());
|
|
|
|
return true;
|
2013-01-11 17:32:20 +04:00
|
|
|
}
|
2016-10-25 22:18:58 +03:00
|
|
|
|
|
|
|
static bool
|
|
|
|
CreateAndWrapWasmModule(JSContext* aCx,
|
2016-10-25 22:19:06 +03:00
|
|
|
StructuredCloneFile& aFile,
|
2016-10-25 22:18:58 +03:00
|
|
|
const WasmModuleData& aData,
|
|
|
|
JS::MutableHandle<JSObject*> aResult)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aCx);
|
2016-10-25 22:19:06 +03:00
|
|
|
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmCompiled);
|
|
|
|
MOZ_ASSERT(!aFile.mBlob);
|
2018-01-18 15:19:07 +03:00
|
|
|
|
|
|
|
// If we don't have a WasmModule, we are probably using it for an index
|
|
|
|
// creation, but Wasm module can't be used in index creation, so just make a
|
|
|
|
// dummy object.
|
|
|
|
if (!aFile.mWasmModule) {
|
|
|
|
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
|
|
|
|
|
|
|
|
if (NS_WARN_IF(!obj)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
aResult.set(obj);
|
|
|
|
return true;
|
|
|
|
}
|
2016-10-25 22:18:58 +03:00
|
|
|
|
2016-10-25 22:19:06 +03:00
|
|
|
JS::Rooted<JSObject*> moduleObj(aCx, aFile.mWasmModule->createObject(aCx));
|
2016-10-25 22:18:58 +03:00
|
|
|
if (NS_WARN_IF(!moduleObj)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
aResult.set(moduleObj);
|
|
|
|
return true;
|
|
|
|
}
|
2013-01-11 17:32:20 +04:00
|
|
|
};
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
JSObject*
|
|
|
|
CommonStructuredCloneReadCallback(JSContext* aCx,
|
|
|
|
JSStructuredCloneReader* aReader,
|
|
|
|
uint32_t aTag,
|
|
|
|
uint32_t aData,
|
|
|
|
void* aClosure)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
// 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 &&
|
2016-10-25 22:18:48 +03:00
|
|
|
SCTAG_DOM_FILE == 0xffff8005 &&
|
|
|
|
SCTAG_DOM_WASM == 0xffff8006,
|
2014-09-27 03:21:57 +04:00
|
|
|
"You changed our structured clone tag values and just ate "
|
|
|
|
"everyone's IndexedDB data. I hope you are happy.");
|
|
|
|
|
|
|
|
if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
|
|
|
|
aTag == SCTAG_DOM_BLOB ||
|
|
|
|
aTag == SCTAG_DOM_FILE ||
|
2016-10-25 22:18:58 +03:00
|
|
|
aTag == SCTAG_DOM_MUTABLEFILE ||
|
|
|
|
aTag == SCTAG_DOM_WASM) {
|
2014-09-27 03:21:57 +04:00
|
|
|
auto* cloneReadInfo = static_cast<StructuredCloneReadInfo*>(aClosure);
|
|
|
|
|
2016-10-25 22:18:58 +03:00
|
|
|
JS::Rooted<JSObject*> result(aCx);
|
|
|
|
|
|
|
|
if (aTag == SCTAG_DOM_WASM) {
|
|
|
|
WasmModuleData data(aData);
|
|
|
|
if (NS_WARN_IF(!ReadWasmModule(aReader, &data))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(data.compiledIndex == data.bytecodeIndex + 1);
|
|
|
|
MOZ_ASSERT(!data.flags);
|
|
|
|
|
|
|
|
if (data.bytecodeIndex >= cloneReadInfo->mFiles.Length() ||
|
|
|
|
data.compiledIndex >= cloneReadInfo->mFiles.Length()) {
|
|
|
|
MOZ_ASSERT(false, "Bad index value!");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-10-25 22:19:06 +03:00
|
|
|
StructuredCloneFile& file = cloneReadInfo->mFiles[data.compiledIndex];
|
2016-10-25 22:18:58 +03:00
|
|
|
|
2018-01-18 15:19:07 +03:00
|
|
|
if (NS_WARN_IF(!ValueDeserializationHelper::CreateAndWrapWasmModule(aCx,
|
|
|
|
file,
|
|
|
|
data,
|
|
|
|
&result))) {
|
2016-10-25 22:18:58 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (aData >= cloneReadInfo->mFiles.Length()) {
|
|
|
|
MOZ_ASSERT(false, "Bad index value!");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (aTag == SCTAG_DOM_MUTABLEFILE) {
|
|
|
|
MutableFileData data;
|
|
|
|
if (NS_WARN_IF(!ReadFileHandle(aReader, &data))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2018-01-18 15:19:07 +03:00
|
|
|
if (NS_WARN_IF(!ValueDeserializationHelper::CreateAndWrapMutableFile(aCx,
|
|
|
|
file,
|
|
|
|
data,
|
|
|
|
&result))) {
|
2014-09-27 03:21:57 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return result;
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
BlobOrFileData data;
|
|
|
|
if (NS_WARN_IF(!ReadBlobOrFile(aReader, aTag, &data))) {
|
|
|
|
return nullptr;
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2018-01-18 15:19:07 +03:00
|
|
|
if (NS_WARN_IF(!ValueDeserializationHelper::CreateAndWrapBlobOrFile(aCx,
|
|
|
|
cloneReadInfo->mDatabase,
|
|
|
|
file,
|
|
|
|
data,
|
|
|
|
&result))) {
|
2014-09-27 03:21:57 +04:00
|
|
|
return nullptr;
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-09-30 15:22:08 +03:00
|
|
|
return StructuredCloneHolder::ReadFullySerializableObjects(aCx, aReader,
|
2015-10-07 22:32:14 +03:00
|
|
|
aTag);
|
2010-06-23 23:46:08 +04:00
|
|
|
}
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace
|
2012-06-22 02:27:13 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const JSClass IDBObjectStore::sDummyPropJSClass = {
|
|
|
|
"IDBObjectStore Dummy",
|
2014-11-22 21:23:39 +03:00
|
|
|
0 /* flags */
|
2014-09-27 03:21:57 +04:00
|
|
|
};
|
2012-06-22 02:27:13 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBObjectStore::IDBObjectStore(IDBTransaction* aTransaction,
|
|
|
|
const ObjectStoreSpec* aSpec)
|
|
|
|
: mTransaction(aTransaction)
|
2015-01-14 10:59:06 +03:00
|
|
|
, mCachedKeyPath(JS::UndefinedValue())
|
2014-09-27 03:21:57 +04:00
|
|
|
, mSpec(aSpec)
|
|
|
|
, mId(aSpec->metadata().id())
|
|
|
|
, mRooted(false)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aTransaction);
|
|
|
|
aTransaction->AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(aSpec);
|
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBObjectStore::~IDBObjectStore()
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (mRooted) {
|
2015-01-14 10:59:06 +03:00
|
|
|
mCachedKeyPath.setUndefined();
|
2014-09-27 03:21:57 +04:00
|
|
|
mozilla::DropJSObjects(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
already_AddRefed<IDBObjectStore>
|
|
|
|
IDBObjectStore::Create(IDBTransaction* aTransaction,
|
|
|
|
const ObjectStoreSpec& aSpec)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aTransaction);
|
|
|
|
aTransaction->AssertIsOnOwningThread();
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBObjectStore> objectStore =
|
2014-09-27 03:21:57 +04:00
|
|
|
new IDBObjectStore(aTransaction, &aSpec);
|
|
|
|
|
|
|
|
return objectStore.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
IDBObjectStore::AppendIndexUpdateInfo(
|
|
|
|
int64_t aIndexID,
|
|
|
|
const KeyPath& aKeyPath,
|
|
|
|
bool aUnique,
|
|
|
|
bool aMultiEntry,
|
2015-09-04 22:12:44 +03:00
|
|
|
const nsCString& aLocale,
|
2014-09-27 03:21:57 +04:00
|
|
|
JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aVal,
|
|
|
|
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2015-09-04 22:12:44 +03:00
|
|
|
const bool localeAware = !aLocale.IsEmpty();
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!aMultiEntry) {
|
|
|
|
Key key;
|
|
|
|
rv = aKeyPath.ExtractKey(aCx, aVal, key);
|
|
|
|
|
|
|
|
// If an index's keyPath doesn't match an object, we ignore that object.
|
|
|
|
if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
|
|
|
|
updateInfo->indexId() = aIndexID;
|
|
|
|
updateInfo->value() = key;
|
2015-09-04 22:12:44 +03:00
|
|
|
if (localeAware) {
|
|
|
|
rv = key.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
}
|
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-12-20 14:59:07 +04:00
|
|
|
|
2013-05-04 11:52:57 +04:00
|
|
|
JS::Rooted<JS::Value> val(aCx);
|
|
|
|
if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) {
|
2012-06-22 02:27:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2015-08-29 07:55:40 +03:00
|
|
|
bool isArray;
|
|
|
|
if (!JS_IsArrayObject(aCx, val, &isArray)) {
|
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
}
|
|
|
|
if (isArray) {
|
2014-01-29 14:00:40 +04:00
|
|
|
JS::Rooted<JSObject*> array(aCx, &val.toObject());
|
2012-03-07 03:52:55 +04:00
|
|
|
uint32_t arrayLength;
|
2014-09-27 03:21:57 +04:00
|
|
|
if (NS_WARN_IF(!JS_GetArrayLength(aCx, array, &arrayLength))) {
|
2014-01-28 04:37:05 +04:00
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
2011-12-04 21:39:01 +04:00
|
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
2010-06-23 23:46:08 +04:00
|
|
|
}
|
|
|
|
|
2012-03-07 03:52:55 +04:00
|
|
|
for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
|
2013-05-02 13:12:47 +04:00
|
|
|
JS::Rooted<JS::Value> arrayItem(aCx);
|
2014-09-27 03:21:57 +04:00
|
|
|
if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) {
|
2014-01-28 04:37:05 +04:00
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
2011-12-04 21:39:01 +04:00
|
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
}
|
2011-12-03 07:46:25 +04:00
|
|
|
|
2010-06-23 23:46:08 +04:00
|
|
|
Key value;
|
2011-12-04 21:39:01 +04:00
|
|
|
if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
|
|
|
|
value.IsUnset()) {
|
2010-06-23 23:46:08 +04:00
|
|
|
// Not a value we can do anything with, ignore it.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
|
2014-09-27 03:21:57 +04:00
|
|
|
updateInfo->indexId() = aIndexID;
|
|
|
|
updateInfo->value() = value;
|
2015-09-04 22:12:44 +03:00
|
|
|
if (localeAware) {
|
|
|
|
rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
}
|
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2011-12-04 21:39:01 +04:00
|
|
|
Key value;
|
2012-06-22 02:27:13 +04:00
|
|
|
if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
|
2011-12-04 21:39:01 +04:00
|
|
|
value.IsUnset()) {
|
|
|
|
// Not a value we can do anything with, ignore it.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
|
2014-09-27 03:21:57 +04:00
|
|
|
updateInfo->indexId() = aIndexID;
|
|
|
|
updateInfo->value() = value;
|
2015-09-04 22:12:44 +03:00
|
|
|
if (localeAware) {
|
|
|
|
rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
}
|
|
|
|
}
|
2011-12-16 11:34:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-12-21 19:02:04 +03:00
|
|
|
}
|
|
|
|
|
2012-10-03 23:05:20 +04:00
|
|
|
// static
|
|
|
|
void
|
|
|
|
IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
|
|
|
|
{
|
|
|
|
// This is kind of tricky, we only want to release stuff on the main thread,
|
|
|
|
// but we can end up being called on other threads if we have already been
|
|
|
|
// cleared on the main thread.
|
2016-06-07 11:49:43 +03:00
|
|
|
if (!aReadInfo.mFiles.Length()) {
|
2012-10-03 23:05:20 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aReadInfo.mFiles.Clear();
|
|
|
|
}
|
|
|
|
|
2011-06-09 06:21:53 +04:00
|
|
|
// static
|
|
|
|
bool
|
|
|
|
IDBObjectStore::DeserializeValue(JSContext* aCx,
|
2011-12-16 11:34:24 +04:00
|
|
|
StructuredCloneReadInfo& aCloneReadInfo,
|
2013-06-21 17:12:46 +04:00
|
|
|
JS::MutableHandle<JS::Value> aValue)
|
2011-06-09 06:21:53 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(aCx);
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2016-06-07 11:49:43 +03:00
|
|
|
if (!aCloneReadInfo.mData.Size()) {
|
2013-06-21 17:12:46 +04:00
|
|
|
aValue.setUndefined();
|
2011-06-09 06:21:53 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-07 11:49:43 +03:00
|
|
|
MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2011-06-09 06:21:53 +04:00
|
|
|
JSAutoRequest ar(aCx);
|
|
|
|
|
2014-12-17 03:30:39 +03:00
|
|
|
static const JSStructuredCloneCallbacks callbacks = {
|
2018-01-18 15:19:07 +03:00
|
|
|
CommonStructuredCloneReadCallback,
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr,
|
2013-11-15 08:42:34 +04:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
2018-03-28 10:23:17 +03:00
|
|
|
nullptr,
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr
|
2011-12-16 11:34:24 +04:00
|
|
|
};
|
|
|
|
|
2015-09-30 15:22:08 +03:00
|
|
|
// FIXME: Consider to use StructuredCloneHolder here and in other
|
2015-09-09 14:15:05 +03:00
|
|
|
// deserializing methods.
|
2016-06-07 11:49:43 +03:00
|
|
|
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
|
2018-04-25 01:21:47 +03:00
|
|
|
JS::StructuredCloneScope::DifferentProcessForIndexedDB,
|
2014-09-27 03:21:57 +04:00
|
|
|
aValue, &callbacks, &aCloneReadInfo)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2011-06-09 06:21:53 +04:00
|
|
|
}
|
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// This class helps to create only 1 sandbox.
|
|
|
|
class SandboxHolder final
|
2011-06-09 06:21:53 +04:00
|
|
|
{
|
2018-01-18 15:19:06 +03:00
|
|
|
public:
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(SandboxHolder)
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
static JSObject*
|
|
|
|
GetSandbox(JSContext* aCx)
|
|
|
|
{
|
|
|
|
SandboxHolder* holder = GetOrCreate();
|
|
|
|
return holder->GetSandboxInternal(aCx);
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
private:
|
|
|
|
~SandboxHolder() = default;
|
2011-06-09 06:21:53 +04:00
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
static SandboxHolder*
|
|
|
|
GetOrCreate()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2011-06-09 06:21:53 +04:00
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
static StaticRefPtr<SandboxHolder> sHolder;
|
|
|
|
if (!sHolder) {
|
|
|
|
sHolder = new SandboxHolder();
|
|
|
|
ClearOnShutdown(&sHolder);
|
|
|
|
}
|
|
|
|
return sHolder;
|
|
|
|
}
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
JSObject*
|
|
|
|
GetSandboxInternal(JSContext* aCx)
|
|
|
|
{
|
|
|
|
if (!mSandbox) {
|
|
|
|
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
|
|
|
MOZ_ASSERT(xpc, "This should never be null!");
|
|
|
|
|
|
|
|
// Let's use a null principal.
|
2018-03-22 21:36:20 +03:00
|
|
|
nsCOMPtr<nsIPrincipal> principal = NullPrincipal::CreateWithoutOriginAttributes();
|
2018-01-18 15:19:06 +03:00
|
|
|
|
|
|
|
JS::Rooted<JSObject*> sandbox(aCx);
|
|
|
|
nsresult rv = xpc->CreateSandbox(aCx, principal, sandbox.address());
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mSandbox = new JSObjectHolder(aCx, sandbox);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mSandbox->GetJSObject();
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
RefPtr<JSObjectHolder> mSandbox;
|
|
|
|
};
|
|
|
|
|
|
|
|
class DeserializeIndexValueHelper final : public Runnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DeserializeIndexValueHelper(int64_t aIndexID,
|
|
|
|
const KeyPath& aKeyPath,
|
|
|
|
bool aUnique,
|
|
|
|
bool aMultiEntry,
|
|
|
|
const nsCString& aLocale,
|
|
|
|
StructuredCloneReadInfo& aCloneReadInfo,
|
|
|
|
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
|
|
|
: Runnable("DeserializeIndexValueHelper")
|
|
|
|
, mMonitor("DeserializeIndexValueHelper::mMonitor")
|
|
|
|
, mIndexID(aIndexID)
|
|
|
|
, mKeyPath(aKeyPath)
|
|
|
|
, mUnique(aUnique)
|
|
|
|
, mMultiEntry(aMultiEntry)
|
|
|
|
, mLocale(aLocale)
|
|
|
|
, mCloneReadInfo(aCloneReadInfo)
|
|
|
|
, mUpdateInfoArray(aUpdateInfoArray)
|
|
|
|
, mStatus(NS_ERROR_FAILURE)
|
|
|
|
{}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
DispatchAndWait()
|
|
|
|
{
|
|
|
|
// We don't need to go to the main-thread and use the sandbox. Let's create
|
|
|
|
// the updateInfo data here.
|
|
|
|
if (!mCloneReadInfo.mData.Size()) {
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
jsapi.Init();
|
|
|
|
|
|
|
|
JS::Rooted<JS::Value> value(jsapi.cx());
|
|
|
|
value.setUndefined();
|
|
|
|
|
|
|
|
return IDBObjectStore::AppendIndexUpdateInfo(mIndexID, mKeyPath, mUnique,
|
|
|
|
mMultiEntry, mLocale,
|
|
|
|
jsapi.cx(), value,
|
|
|
|
mUpdateInfoArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The operation will continue on the main-thread.
|
|
|
|
|
|
|
|
MOZ_ASSERT(!(mCloneReadInfo.mData.Size() % sizeof(uint64_t)));
|
|
|
|
|
|
|
|
MonitorAutoLock lock(mMonitor);
|
|
|
|
|
|
|
|
RefPtr<Runnable> self = this;
|
|
|
|
nsresult rv = SystemGroup::Dispatch(TaskCategory::Other, self.forget());
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
lock.Wait();
|
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
Run() override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
jsapi.Init();
|
|
|
|
JSContext* cx = jsapi.cx();
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> global(cx, SandboxHolder::GetSandbox(cx));
|
|
|
|
if (NS_WARN_IF(!global)) {
|
|
|
|
OperationCompleted(NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(cx, global);
|
2018-01-18 15:19:06 +03:00
|
|
|
|
|
|
|
JS::Rooted<JS::Value> value(cx);
|
|
|
|
nsresult rv = DeserializeIndexValue(cx, &value);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
OperationCompleted(rv);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = IDBObjectStore::AppendIndexUpdateInfo(mIndexID, mKeyPath, mUnique,
|
|
|
|
mMultiEntry, mLocale, cx,
|
|
|
|
value, mUpdateInfoArray);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
OperationCompleted(rv);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
OperationCompleted(NS_OK);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsresult
|
|
|
|
DeserializeIndexValue(JSContext* aCx, JS::MutableHandle<JS::Value> aValue)
|
|
|
|
{
|
|
|
|
static const JSStructuredCloneCallbacks callbacks = {
|
2018-01-18 15:19:07 +03:00
|
|
|
CommonStructuredCloneReadCallback,
|
2018-01-18 15:19:06 +03:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
2018-03-28 10:23:17 +03:00
|
|
|
nullptr,
|
2018-01-18 15:19:06 +03:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
|
|
|
|
JS_STRUCTURED_CLONE_VERSION,
|
2018-04-25 01:21:47 +03:00
|
|
|
JS::StructuredCloneScope::DifferentProcessForIndexedDB,
|
2018-01-18 15:19:06 +03:00
|
|
|
aValue, &callbacks, &mCloneReadInfo)) {
|
|
|
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
OperationCompleted(nsresult aStatus)
|
|
|
|
{
|
|
|
|
mStatus = aStatus;
|
|
|
|
|
|
|
|
MonitorAutoLock lock(mMonitor);
|
|
|
|
lock.Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
Monitor mMonitor;
|
|
|
|
|
|
|
|
int64_t mIndexID;
|
|
|
|
const KeyPath& mKeyPath;
|
|
|
|
bool mUnique;
|
|
|
|
bool mMultiEntry;
|
|
|
|
const nsCString mLocale;
|
|
|
|
StructuredCloneReadInfo& mCloneReadInfo;
|
|
|
|
nsTArray<IndexUpdateInfo>& mUpdateInfoArray;
|
|
|
|
nsresult mStatus;
|
|
|
|
};
|
|
|
|
|
2018-01-18 15:19:07 +03:00
|
|
|
class DeserializeUpgradeValueHelper final : public Runnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit DeserializeUpgradeValueHelper(StructuredCloneReadInfo& aCloneReadInfo)
|
|
|
|
: Runnable("DeserializeUpgradeValueHelper")
|
|
|
|
, mMonitor("DeserializeUpgradeValueHelper::mMonitor")
|
|
|
|
, mCloneReadInfo(aCloneReadInfo)
|
|
|
|
, mStatus(NS_ERROR_FAILURE)
|
|
|
|
{}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
DispatchAndWait(nsAString& aFileIds)
|
|
|
|
{
|
|
|
|
// We don't need to go to the main-thread and use the sandbox.
|
|
|
|
if (!mCloneReadInfo.mData.Size()) {
|
|
|
|
PopulateFileIds(aFileIds);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The operation will continue on the main-thread.
|
|
|
|
|
|
|
|
MOZ_ASSERT(!(mCloneReadInfo.mData.Size() % sizeof(uint64_t)));
|
|
|
|
|
|
|
|
MonitorAutoLock lock(mMonitor);
|
|
|
|
|
|
|
|
RefPtr<Runnable> self = this;
|
|
|
|
nsresult rv = SystemGroup::Dispatch(TaskCategory::Other, self.forget());
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
lock.Wait();
|
|
|
|
|
|
|
|
if (NS_FAILED(mStatus)) {
|
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
PopulateFileIds(aFileIds);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
|
|
|
Run() override
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
AutoJSAPI jsapi;
|
|
|
|
jsapi.Init();
|
|
|
|
JSContext* cx = jsapi.cx();
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> global(cx, SandboxHolder::GetSandbox(cx));
|
|
|
|
if (NS_WARN_IF(!global)) {
|
|
|
|
OperationCompleted(NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-05-16 11:53:16 +03:00
|
|
|
JSAutoRealm ar(cx, global);
|
2018-01-18 15:19:07 +03:00
|
|
|
|
|
|
|
JS::Rooted<JS::Value> value(cx);
|
|
|
|
nsresult rv = DeserializeUpgradeValue(cx, &value);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
OperationCompleted(rv);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
OperationCompleted(NS_OK);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsresult
|
|
|
|
DeserializeUpgradeValue(JSContext* aCx, JS::MutableHandle<JS::Value> aValue)
|
|
|
|
{
|
|
|
|
static const JSStructuredCloneCallbacks callbacks = {
|
2018-01-18 15:19:07 +03:00
|
|
|
CommonStructuredCloneReadCallback,
|
2018-01-18 15:19:07 +03:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
2018-03-28 10:23:17 +03:00
|
|
|
nullptr,
|
2018-01-18 15:19:07 +03:00
|
|
|
nullptr
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
|
|
|
|
JS_STRUCTURED_CLONE_VERSION,
|
2018-04-25 01:21:47 +03:00
|
|
|
JS::StructuredCloneScope::DifferentProcessForIndexedDB,
|
2018-01-18 15:19:07 +03:00
|
|
|
aValue, &callbacks, &mCloneReadInfo)) {
|
|
|
|
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PopulateFileIds(nsAString& aFileIds)
|
|
|
|
{
|
|
|
|
for (uint32_t count = mCloneReadInfo.mFiles.Length(), index = 0;
|
|
|
|
index < count;
|
|
|
|
index++) {
|
|
|
|
StructuredCloneFile& file = mCloneReadInfo.mFiles[index];
|
|
|
|
MOZ_ASSERT(file.mFileInfo);
|
|
|
|
|
|
|
|
const int64_t id = file.mFileInfo->Id();
|
|
|
|
|
|
|
|
if (index) {
|
|
|
|
aFileIds.Append(' ');
|
|
|
|
}
|
|
|
|
aFileIds.AppendInt(file.mType == StructuredCloneFile::eBlob ? id : -id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
OperationCompleted(nsresult aStatus)
|
|
|
|
{
|
|
|
|
mStatus = aStatus;
|
|
|
|
|
|
|
|
MonitorAutoLock lock(mMonitor);
|
|
|
|
lock.Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
Monitor mMonitor;
|
|
|
|
StructuredCloneReadInfo& mCloneReadInfo;
|
|
|
|
nsresult mStatus;
|
|
|
|
};
|
|
|
|
|
2018-01-18 15:19:06 +03:00
|
|
|
} // anonymous
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
IDBObjectStore::DeserializeIndexValueToUpdateInfos(int64_t aIndexID,
|
|
|
|
const KeyPath& aKeyPath,
|
|
|
|
bool aUnique,
|
|
|
|
bool aMultiEntry,
|
|
|
|
const nsCString& aLocale,
|
|
|
|
StructuredCloneReadInfo& aCloneReadInfo,
|
|
|
|
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
|
|
|
RefPtr<DeserializeIndexValueHelper> helper =
|
|
|
|
new DeserializeIndexValueHelper(aIndexID, aKeyPath, aUnique, aMultiEntry,
|
|
|
|
aLocale, aCloneReadInfo, aUpdateInfoArray);
|
|
|
|
return helper->DispatchAndWait();
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
// static
|
2018-01-18 15:19:07 +03:00
|
|
|
nsresult
|
|
|
|
IDBObjectStore::DeserializeUpgradeValueToFileIds(StructuredCloneReadInfo& aCloneReadInfo,
|
|
|
|
nsAString& aFileIds)
|
2015-09-09 14:15:05 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
|
2018-01-18 15:19:07 +03:00
|
|
|
RefPtr<DeserializeUpgradeValueHelper> helper =
|
|
|
|
new DeserializeUpgradeValueHelper(aCloneReadInfo);
|
|
|
|
return helper->DispatchAndWait(aFileIds);
|
2015-09-09 14:15:05 +03:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
void
|
|
|
|
IDBObjectStore::AssertIsOnOwningThread() const
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(mTransaction);
|
|
|
|
mTransaction->AssertIsOnOwningThread();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
IDBObjectStore::GetAddInfo(JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aValue,
|
|
|
|
JS::Handle<JS::Value> aKeyVal,
|
|
|
|
StructuredCloneWriteInfo& aCloneWriteInfo,
|
|
|
|
Key& aKey,
|
|
|
|
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
|
|
|
|
{
|
|
|
|
// Return DATA_ERR if a key was passed in and this objectStore uses inline
|
|
|
|
// keys.
|
|
|
|
if (!aKeyVal.isUndefined() && HasValidKeyPath()) {
|
|
|
|
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool isAutoIncrement = AutoIncrement();
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (!HasValidKeyPath()) {
|
|
|
|
// Out-of-line keys must be passed in.
|
|
|
|
rv = aKey.SetFromJSVal(aCx, aKeyVal);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
} else if (!isAutoIncrement) {
|
|
|
|
rv = GetKeyPath().ExtractKey(aCx, aValue, aKey);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Return DATA_ERR if no key was specified this isn't an autoIncrement
|
|
|
|
// objectStore.
|
|
|
|
if (aKey.IsUnset() && !isAutoIncrement) {
|
|
|
|
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Figure out indexes and the index values to update here.
|
|
|
|
const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const uint32_t idxCount = indexes.Length();
|
|
|
|
aUpdateInfoArray.SetCapacity(idxCount); // Pretty good estimate
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t idxIndex = 0; idxIndex < idxCount; idxIndex++) {
|
|
|
|
const IndexMetadata& metadata = indexes[idxIndex];
|
|
|
|
|
|
|
|
rv = AppendIndexUpdateInfo(metadata.id(), metadata.keyPath(),
|
2015-09-04 22:12:44 +03:00
|
|
|
metadata.unique(), metadata.multiEntry(),
|
|
|
|
metadata.locale(), aCx, aValue,
|
|
|
|
aUpdateInfoArray);
|
2014-09-27 03:21:57 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
GetAddInfoClosure data(aCloneWriteInfo, aValue);
|
|
|
|
|
|
|
|
if (isAutoIncrement && HasValidKeyPath()) {
|
|
|
|
MOZ_ASSERT(aKey.IsUnset());
|
|
|
|
|
|
|
|
rv = GetKeyPath().ExtractOrCreateKey(aCx,
|
|
|
|
aValue,
|
|
|
|
aKey,
|
|
|
|
&GetAddInfoCallback,
|
|
|
|
&data);
|
|
|
|
} else {
|
|
|
|
rv = GetAddInfoCallback(aCx, &data);
|
2011-12-16 11:34:24 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return rv;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
|
|
|
IDBObjectStore::AddOrPut(JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aValue,
|
|
|
|
JS::Handle<JS::Value> aKey,
|
|
|
|
bool aOverwrite,
|
2014-10-16 08:56:52 +04:00
|
|
|
bool aFromCursor,
|
2014-09-27 03:21:57 +04:00
|
|
|
ErrorResult& aRv)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(aCx);
|
2014-10-16 08:56:52 +04:00
|
|
|
MOZ_ASSERT_IF(aFromCursor, aOverwrite);
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2016-03-15 09:00:37 +03:00
|
|
|
if (mTransaction->GetMode() == IDBTransaction::CLEANUP ||
|
|
|
|
mDeletedSpec) {
|
2015-06-20 19:08:23 +03:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
2011-12-16 11:34:24 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsWriteAllowed()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
|
|
|
|
return nullptr;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
JS::Rooted<JS::Value> value(aCx, aValue);
|
|
|
|
Key key;
|
|
|
|
StructuredCloneWriteInfo cloneWriteInfo(mTransaction->Database());
|
|
|
|
nsTArray<IndexUpdateInfo> updateInfo;
|
2013-01-11 17:32:20 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return nullptr;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
|
2016-10-17 06:45:03 +03:00
|
|
|
// Check the size limit of the serialized message which mainly consists of
|
|
|
|
// a StructuredCloneBuffer, an encoded object key, and the encoded index keys.
|
|
|
|
// kMaxIDBMsgOverhead covers the minor stuff not included in this calculation
|
|
|
|
// because the precise calculation would slow down this AddOrPut operation.
|
|
|
|
static const size_t kMaxIDBMsgOverhead = 1024 * 1024; // 1MB
|
|
|
|
const uint32_t maximalSizeFromPref =
|
|
|
|
IndexedDatabaseManager::MaxSerializedMsgSize();
|
|
|
|
MOZ_ASSERT(maximalSizeFromPref > kMaxIDBMsgOverhead);
|
|
|
|
const size_t kMaxMessageSize = maximalSizeFromPref - kMaxIDBMsgOverhead;
|
|
|
|
|
|
|
|
size_t indexUpdateInfoSize = 0;
|
|
|
|
for (size_t i = 0; i < updateInfo.Length(); i++) {
|
|
|
|
indexUpdateInfoSize += updateInfo[i].value().GetBuffer().Length();
|
|
|
|
indexUpdateInfoSize += updateInfo[i].localizedValue().GetBuffer().Length();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t messageSize = cloneWriteInfo.mCloneBuffer.data().Size() +
|
|
|
|
key.GetBuffer().Length() + indexUpdateInfoSize;
|
|
|
|
|
|
|
|
if (messageSize > kMaxMessageSize) {
|
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
|
|
aRv.ThrowDOMException(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR,
|
|
|
|
nsPrintfCString("The serialized value is too large"
|
|
|
|
" (size=%zu bytes, max=%zu bytes).",
|
|
|
|
messageSize, kMaxMessageSize));
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
ObjectStoreAddPutParams commonParams;
|
|
|
|
commonParams.objectStoreId() = Id();
|
2018-05-30 22:15:35 +03:00
|
|
|
commonParams.cloneInfo().data().data = std::move(cloneWriteInfo.mCloneBuffer.data());
|
2014-09-27 03:21:57 +04:00
|
|
|
commonParams.cloneInfo().offsetToKeyProp() = cloneWriteInfo.mOffsetToKeyProp;
|
|
|
|
commonParams.key() = key;
|
|
|
|
commonParams.indexUpdateInfos().SwapElements(updateInfo);
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
// Convert any blobs or mutable files into FileAddInfo.
|
|
|
|
nsTArray<StructuredCloneFile>& files = cloneWriteInfo.mFiles;
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
if (!files.IsEmpty()) {
|
|
|
|
const uint32_t count = files.Length();
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
FallibleTArray<FileAddInfo> fileAddInfos;
|
|
|
|
if (NS_WARN_IF(!fileAddInfos.SetCapacity(count, fallible))) {
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBDatabase* database = mTransaction->Database();
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t index = 0; index < count; index++) {
|
2016-10-25 22:18:44 +03:00
|
|
|
StructuredCloneFile& file = files[index];
|
|
|
|
|
|
|
|
FileAddInfo* fileAddInfo = fileAddInfos.AppendElement(fallible);
|
|
|
|
MOZ_ASSERT(fileAddInfo);
|
|
|
|
|
|
|
|
switch (file.mType) {
|
|
|
|
case StructuredCloneFile::eBlob: {
|
|
|
|
MOZ_ASSERT(file.mBlob);
|
|
|
|
MOZ_ASSERT(!file.mMutableFile);
|
|
|
|
|
|
|
|
PBackgroundIDBDatabaseFileChild* fileActor =
|
|
|
|
database->GetOrCreateFileActorForBlob(file.mBlob);
|
|
|
|
if (NS_WARN_IF(!fileActor)) {
|
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
|
|
aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileAddInfo->file() = fileActor;
|
|
|
|
fileAddInfo->type() = StructuredCloneFile::eBlob;
|
|
|
|
|
|
|
|
break;
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
case StructuredCloneFile::eMutableFile: {
|
|
|
|
MOZ_ASSERT(file.mMutableFile);
|
|
|
|
MOZ_ASSERT(!file.mBlob);
|
|
|
|
|
|
|
|
PBackgroundMutableFileChild* mutableFileActor =
|
|
|
|
file.mMutableFile->GetBackgroundActor();
|
|
|
|
if (NS_WARN_IF(!mutableFileActor)) {
|
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
|
|
aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileAddInfo->file() = mutableFileActor;
|
|
|
|
fileAddInfo->type() = StructuredCloneFile::eMutableFile;
|
|
|
|
|
|
|
|
break;
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2016-10-25 22:18:48 +03:00
|
|
|
case StructuredCloneFile::eWasmBytecode:
|
|
|
|
case StructuredCloneFile::eWasmCompiled: {
|
|
|
|
MOZ_ASSERT(file.mBlob);
|
|
|
|
MOZ_ASSERT(!file.mMutableFile);
|
|
|
|
|
|
|
|
PBackgroundIDBDatabaseFileChild* fileActor =
|
|
|
|
database->GetOrCreateFileActorForBlob(file.mBlob);
|
|
|
|
if (NS_WARN_IF(!fileActor)) {
|
|
|
|
IDB_REPORT_INTERNAL_ERR();
|
|
|
|
aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileAddInfo->file() = fileActor;
|
|
|
|
fileAddInfo->type() = file.mType;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
default:
|
|
|
|
MOZ_CRASH("Should never get here!");
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2016-10-25 22:18:44 +03:00
|
|
|
commonParams.fileAddInfos().SwapElements(fileAddInfos);
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
RequestParams params;
|
|
|
|
if (aOverwrite) {
|
|
|
|
params = ObjectStorePutParams(commonParams);
|
|
|
|
} else {
|
|
|
|
params = ObjectStoreAddParams(commonParams);
|
2013-09-26 03:11:47 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
if (!aFromCursor) {
|
|
|
|
if (aOverwrite) {
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).put(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.put()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(key));
|
|
|
|
} else {
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).add(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.add()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-09 14:15:05 +03:00
|
|
|
mTransaction->StartRequest(request, params);
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
|
|
|
IDBObjectStore::GetAllInternal(bool aKeysOnly,
|
|
|
|
JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aKey,
|
|
|
|
const Optional<uint32_t>& aLimit,
|
|
|
|
ErrorResult& aRv)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2015-06-20 19:08:23 +03:00
|
|
|
if (mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBKeyRange> keyRange;
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
2013-09-26 03:11:47 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const int64_t id = Id();
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
OptionalKeyRange optionalKeyRange;
|
|
|
|
if (keyRange) {
|
|
|
|
SerializedKeyRange serializedKeyRange;
|
|
|
|
keyRange->ToSerialized(serializedKeyRange);
|
|
|
|
optionalKeyRange = serializedKeyRange;
|
|
|
|
} else {
|
|
|
|
optionalKeyRange = void_t();
|
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0;
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
RequestParams params;
|
|
|
|
if (aKeysOnly) {
|
|
|
|
params = ObjectStoreGetAllKeysParams(id, optionalKeyRange, limit);
|
|
|
|
} else {
|
|
|
|
params = ObjectStoreGetAllParams(id, optionalKeyRange, limit);
|
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-12-11 08:12:40 +03:00
|
|
|
if (aKeysOnly) {
|
2014-10-16 08:56:52 +04:00
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
|
|
"getAllKeys(%s, %s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAllKeys()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange),
|
|
|
|
IDB_LOG_STRINGIFY(aLimit));
|
2014-12-11 08:12:40 +03:00
|
|
|
} else {
|
2014-10-16 08:56:52 +04:00
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
|
|
"getAll(%s, %s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAll()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange),
|
|
|
|
IDB_LOG_STRINGIFY(aLimit));
|
2014-12-11 08:12:40 +03:00
|
|
|
}
|
2014-10-16 08:56:52 +04:00
|
|
|
|
2015-03-19 00:20:59 +03:00
|
|
|
mTransaction->StartRequest(request, params);
|
2014-12-11 08:12:40 +03:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
2013-09-26 03:11:47 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
2016-03-23 18:02:57 +03:00
|
|
|
IDBObjectStore::Clear(JSContext* aCx, ErrorResult& aRv)
|
2013-09-26 03:11:47 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2015-06-20 19:08:23 +03:00
|
|
|
if (mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsWriteAllowed()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
|
|
|
|
return nullptr;
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
ObjectStoreClearParams params;
|
|
|
|
params.objectStoreId() = Id();
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2013-09-26 03:11:47 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).clear()",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.clear()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this));
|
|
|
|
|
2015-03-19 00:20:59 +03:00
|
|
|
mTransaction->StartRequest(request, params);
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBIndex>
|
|
|
|
IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2015-06-26 01:22:59 +03:00
|
|
|
if (mTransaction->IsCommittingOrDone() || mDeletedSpec) {
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return nullptr;
|
2010-12-16 00:21:11 +03:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
|
2011-01-23 21:16:00 +03:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const IndexMetadata* metadata = nullptr;
|
2011-12-03 07:46:25 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t idxCount = indexes.Length(), idxIndex = 0;
|
|
|
|
idxIndex < idxCount;
|
|
|
|
idxIndex++) {
|
|
|
|
const IndexMetadata& index = indexes[idxIndex];
|
|
|
|
if (index.name() == aName) {
|
|
|
|
metadata = &index;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-11-03 05:57:48 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!metadata) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2011-12-03 07:46:25 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const int64_t desiredId = metadata->id();
|
2011-12-03 07:46:25 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBIndex> index;
|
2011-12-03 07:46:25 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
|
|
|
|
idxIndex < idxCount;
|
|
|
|
idxIndex++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBIndex>& existingIndex = mIndexes[idxIndex];
|
2011-12-04 21:39:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (existingIndex->Id() == desiredId) {
|
|
|
|
index = existingIndex;
|
|
|
|
break;
|
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!index) {
|
|
|
|
index = IDBIndex::Create(this, *metadata);
|
|
|
|
MOZ_ASSERT(index);
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
mIndexes.AppendElement(index);
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return index.forget();
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
2016-02-22 21:11:02 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
|
2016-09-13 01:38:43 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes)
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Don't unlink mTransaction!
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2016-09-13 01:38:43 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedIndexes)
|
2013-03-16 10:58:50 +04:00
|
|
|
|
2015-01-14 10:59:06 +03:00
|
|
|
tmp->mCachedKeyPath.setUndefined();
|
2013-03-16 10:58:50 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (tmp->mRooted) {
|
|
|
|
mozilla::DropJSObjects(tmp);
|
|
|
|
tmp->mRooted = false;
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore)
|
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
|
|
NS_INTERFACE_MAP_END
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore)
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
JSObject*
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
IDBObjectStore::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
2014-09-27 03:21:57 +04:00
|
|
|
{
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
return IDBObjectStoreBinding::Wrap(aCx, this, aGivenProto);
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
nsPIDOMWindowInner*
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBObjectStore::GetParentObject() const
|
2014-09-13 20:12:19 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
return mTransaction->GetParentObject();
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
void
|
|
|
|
IDBObjectStore::GetKeyPath(JSContext* aCx,
|
|
|
|
JS::MutableHandle<JS::Value> aResult,
|
|
|
|
ErrorResult& aRv)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mCachedKeyPath.isUndefined()) {
|
|
|
|
aResult.set(mCachedKeyPath);
|
|
|
|
return;
|
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return;
|
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (mCachedKeyPath.isGCThing()) {
|
|
|
|
mozilla::HoldJSObjects(this);
|
|
|
|
mRooted = true;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
aResult.set(mCachedKeyPath);
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<DOMStringList>
|
|
|
|
IDBObjectStore::IndexNames()
|
2014-09-13 20:12:19 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<DOMStringList> list = new DOMStringList();
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!indexes.IsEmpty()) {
|
|
|
|
nsTArray<nsString>& listNames = list->StringArray();
|
|
|
|
listNames.SetCapacity(indexes.Length());
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t index = 0; index < indexes.Length(); index++) {
|
|
|
|
listNames.InsertElementSorted(indexes[index].name());
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return list.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<IDBRequest>
|
2016-07-21 11:31:59 +03:00
|
|
|
IDBObjectStore::GetInternal(bool aKeyOnly,
|
|
|
|
JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aKey,
|
|
|
|
ErrorResult& aRv)
|
2014-09-27 03:21:57 +04:00
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
2015-06-20 19:08:23 +03:00
|
|
|
if (mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBKeyRange> keyRange;
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!keyRange) {
|
|
|
|
// Must specify a key or keyRange for get().
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
|
|
|
|
return nullptr;
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2016-07-21 11:31:59 +03:00
|
|
|
const int64_t id = Id();
|
|
|
|
|
|
|
|
SerializedKeyRange serializedKeyRange;
|
|
|
|
keyRange->ToSerialized(serializedKeyRange);
|
|
|
|
|
|
|
|
RequestParams params;
|
|
|
|
if (aKeyOnly) {
|
|
|
|
params = ObjectStoreGetKeyParams(id, serializedKeyRange);
|
|
|
|
} else {
|
|
|
|
params = ObjectStoreGetParams(id, serializedKeyRange);
|
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).get(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.get()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange));
|
|
|
|
|
2015-03-19 00:20:59 +03:00
|
|
|
mTransaction->StartRequest(request, params);
|
2010-06-23 23:46:08 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
|
|
|
}
|
2011-01-27 04:53:02 +03:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
2014-10-16 08:56:52 +04:00
|
|
|
IDBObjectStore::DeleteInternal(JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aKey,
|
|
|
|
bool aFromCursor,
|
|
|
|
ErrorResult& aRv)
|
2014-09-27 03:21:57 +04:00
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
2013-02-01 23:41:11 +04:00
|
|
|
|
2015-06-20 19:08:23 +03:00
|
|
|
if (mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsWriteAllowed()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBKeyRange> keyRange;
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
|
|
|
|
if (NS_WARN_IF((aRv.Failed()))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!keyRange) {
|
|
|
|
// Must specify a key or keyRange for delete().
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
|
|
|
|
return nullptr;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
ObjectStoreDeleteParams params;
|
|
|
|
params.objectStoreId() = Id();
|
|
|
|
keyRange->ToSerialized(params.keyRange());
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
if (!aFromCursor) {
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).delete(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.delete()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange));
|
|
|
|
}
|
|
|
|
|
2015-03-19 00:20:59 +03:00
|
|
|
mTransaction->StartRequest(request, params);
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBIndex>
|
2014-12-11 21:07:44 +03:00
|
|
|
IDBObjectStore::CreateIndex(const nsAString& aName,
|
2016-04-29 05:56:02 +03:00
|
|
|
const StringOrStringSequence& aKeyPath,
|
2014-09-27 03:21:57 +04:00
|
|
|
const IDBIndexParameters& aOptionalParameters,
|
|
|
|
ErrorResult& aRv)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2015-06-20 19:09:27 +03:00
|
|
|
if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
|
2015-06-20 19:08:23 +03:00
|
|
|
mDeletedSpec) {
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2015-06-20 19:09:27 +03:00
|
|
|
IDBTransaction* transaction = IDBTransaction::GetCurrent();
|
2016-09-13 01:38:43 +03:00
|
|
|
if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
|
2015-06-20 19:09:27 +03:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
auto& indexes = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
|
|
|
|
for (uint32_t count = indexes.Length(), index = 0;
|
|
|
|
index < count;
|
|
|
|
index++) {
|
|
|
|
if (aName == indexes[index].name()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
|
|
|
|
return nullptr;
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
2012-08-02 10:02:29 +04:00
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2016-04-29 05:56:02 +03:00
|
|
|
KeyPath keyPath(0);
|
|
|
|
if (aKeyPath.IsString()) {
|
|
|
|
if (NS_FAILED(KeyPath::Parse(aKeyPath.GetAsString(), &keyPath)) ||
|
|
|
|
!keyPath.IsValid()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(aKeyPath.IsStringSequence());
|
|
|
|
if (aKeyPath.GetAsStringSequence().IsEmpty() ||
|
|
|
|
NS_FAILED(KeyPath::Parse(aKeyPath.GetAsStringSequence(), &keyPath)) ||
|
|
|
|
!keyPath.IsValid()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aOptionalParameters.mMultiEntry && keyPath.IsArray()) {
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
|
|
|
return nullptr;
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
for (uint32_t count = mIndexes.Length(), index = 0;
|
|
|
|
index < count;
|
|
|
|
index++) {
|
|
|
|
MOZ_ASSERT(mIndexes[index]->Name() != aName);
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
#endif
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const IndexMetadata* oldMetadataElements =
|
|
|
|
indexes.IsEmpty() ? nullptr : indexes.Elements();
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2015-09-04 22:12:44 +03:00
|
|
|
// With this setup we only validate the passed in locale name by the time we
|
|
|
|
// get to encoding Keys. Maybe we should do it here right away and error out.
|
|
|
|
|
|
|
|
// Valid locale names are always ASCII as per BCP-47.
|
|
|
|
nsCString locale = NS_LossyConvertUTF16toASCII(aOptionalParameters.mLocale);
|
|
|
|
bool autoLocale = locale.EqualsASCII("auto");
|
|
|
|
if (autoLocale) {
|
|
|
|
locale = IndexedDatabaseManager::GetLocale();
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IndexMetadata* metadata = indexes.AppendElement(
|
2016-04-29 05:56:02 +03:00
|
|
|
IndexMetadata(transaction->NextIndexId(), nsString(aName), keyPath,
|
2015-09-04 22:12:44 +03:00
|
|
|
locale,
|
2014-09-27 03:21:57 +04:00
|
|
|
aOptionalParameters.mUnique,
|
2015-09-04 22:12:44 +03:00
|
|
|
aOptionalParameters.mMultiEntry,
|
|
|
|
autoLocale));
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (oldMetadataElements &&
|
|
|
|
oldMetadataElements != indexes.Elements()) {
|
|
|
|
MOZ_ASSERT(indexes.Length() > 1);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Array got moved, update the spec pointers for all live indexes.
|
|
|
|
RefreshSpec(/* aMayDelete */ false);
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
transaction->CreateIndex(this, *metadata);
|
2012-08-02 10:02:29 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBIndex> index = IDBIndex::Create(this, *metadata);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(index);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
mIndexes.AppendElement(index);
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
// Don't do this in the macro because we always need to increment the serial
|
|
|
|
// number to keep in sync with the parent.
|
|
|
|
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
|
|
|
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).createIndex(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.createIndex()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
requestSerialNumber,
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(index));
|
2014-09-27 03:21:57 +04:00
|
|
|
|
|
|
|
return index.forget();
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
void
|
|
|
|
IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv)
|
2013-09-24 21:14:16 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2015-06-20 19:09:27 +03:00
|
|
|
if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
|
2015-06-20 19:08:23 +03:00
|
|
|
mDeletedSpec) {
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return;
|
2013-09-24 21:14:16 +04:00
|
|
|
}
|
|
|
|
|
2015-06-20 19:09:27 +03:00
|
|
|
IDBTransaction* transaction = IDBTransaction::GetCurrent();
|
2016-09-13 01:38:43 +03:00
|
|
|
if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
|
2015-06-20 19:09:27 +03:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
auto& metadataArray = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
int64_t foundId = 0;
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t metadataCount = metadataArray.Length(), metadataIndex = 0;
|
|
|
|
metadataIndex < metadataCount;
|
|
|
|
metadataIndex++) {
|
|
|
|
const IndexMetadata& metadata = metadataArray[metadataIndex];
|
|
|
|
MOZ_ASSERT(metadata.id());
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (aName == metadata.name()) {
|
|
|
|
foundId = metadata.id();
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Must do this before altering the metadata array!
|
|
|
|
for (uint32_t indexCount = mIndexes.Length(), indexIndex = 0;
|
|
|
|
indexIndex < indexCount;
|
|
|
|
indexIndex++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBIndex>& index = mIndexes[indexIndex];
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (index->Id() == foundId) {
|
|
|
|
index->NoteDeletion();
|
2016-09-13 01:38:43 +03:00
|
|
|
|
|
|
|
RefPtr<IDBIndex>* deletedIndex =
|
|
|
|
mDeletedIndexes.AppendElement();
|
|
|
|
deletedIndex->swap(mIndexes[indexIndex]);
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
mIndexes.RemoveElementAt(indexIndex);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
metadataArray.RemoveElementAt(metadataIndex);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
RefreshSpec(/* aMayDelete */ false);
|
|
|
|
break;
|
2013-09-24 21:14:16 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!foundId) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
|
|
|
|
return;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
// Don't do this in the macro because we always need to increment the serial
|
|
|
|
// number to keep in sync with the parent.
|
|
|
|
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
2014-12-11 08:12:40 +03:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
|
|
"deleteIndex(\"%s\")",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.deleteIndex()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
requestSerialNumber,
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
NS_ConvertUTF16toUTF8(aName).get());
|
|
|
|
|
|
|
|
transaction->DeleteIndex(this, foundId);
|
2013-09-24 21:14:16 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
|
|
|
IDBObjectStore::Count(JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aKey,
|
|
|
|
ErrorResult& aRv)
|
2013-09-24 21:14:16 +04:00
|
|
|
{
|
2015-06-20 19:08:23 +03:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBKeyRange> keyRange;
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
ObjectStoreCountParams params;
|
|
|
|
params.objectStoreId() = Id();
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (keyRange) {
|
|
|
|
SerializedKeyRange serializedKeyRange;
|
|
|
|
keyRange->ToSerialized(serializedKeyRange);
|
|
|
|
params.optionalKeyRange() = serializedKeyRange;
|
|
|
|
} else {
|
|
|
|
params.optionalKeyRange() = void_t();
|
2013-09-24 21:14:16 +04:00
|
|
|
}
|
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).count(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange));
|
|
|
|
|
2015-03-19 00:20:59 +03:00
|
|
|
mTransaction->StartRequest(request, params);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
2013-09-24 21:14:16 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
already_AddRefed<IDBRequest>
|
|
|
|
IDBObjectStore::OpenCursorInternal(bool aKeysOnly,
|
|
|
|
JSContext* aCx,
|
|
|
|
JS::Handle<JS::Value> aRange,
|
|
|
|
IDBCursorDirection aDirection,
|
|
|
|
ErrorResult& aRv)
|
2013-09-24 21:14:16 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
2016-03-30 14:03:03 +03:00
|
|
|
MOZ_ASSERT(aCx);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2015-06-20 19:08:23 +03:00
|
|
|
if (mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mTransaction->IsOpen()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDBKeyRange> keyRange;
|
2014-09-27 03:21:57 +04:00
|
|
|
aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
int64_t objectStoreId = Id();
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
OptionalKeyRange optionalKeyRange;
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (keyRange) {
|
|
|
|
SerializedKeyRange serializedKeyRange;
|
|
|
|
keyRange->ToSerialized(serializedKeyRange);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
optionalKeyRange = std::move(serializedKeyRange);
|
2013-09-24 21:14:16 +04:00
|
|
|
} else {
|
2014-09-27 03:21:57 +04:00
|
|
|
optionalKeyRange = void_t();
|
2013-09-24 21:14:16 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
OpenCursorParams params;
|
|
|
|
if (aKeysOnly) {
|
|
|
|
ObjectStoreOpenKeyCursorParams openParams;
|
|
|
|
openParams.objectStoreId() = objectStoreId;
|
2018-05-30 22:15:35 +03:00
|
|
|
openParams.optionalKeyRange() = std::move(optionalKeyRange);
|
2014-09-27 03:21:57 +04:00
|
|
|
openParams.direction() = direction;
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
params = std::move(openParams);
|
2014-09-27 03:21:57 +04:00
|
|
|
} else {
|
|
|
|
ObjectStoreOpenCursorParams openParams;
|
|
|
|
openParams.objectStoreId() = objectStoreId;
|
2018-05-30 22:15:35 +03:00
|
|
|
openParams.optionalKeyRange() = std::move(optionalKeyRange);
|
2014-09-27 03:21:57 +04:00
|
|
|
openParams.direction() = direction;
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
params = std::move(openParams);
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2016-03-23 18:02:57 +03:00
|
|
|
RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT(request);
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-10-16 08:56:52 +04:00
|
|
|
if (aKeysOnly) {
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
|
|
"openKeyCursor(%s, %s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: "
|
|
|
|
"IDBObjectStore.openKeyCursor()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange),
|
|
|
|
IDB_LOG_STRINGIFY(direction));
|
|
|
|
} else {
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s)."
|
|
|
|
"openCursor(%s, %s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.openCursor()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
request->LoggingSerialNumber(),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
IDB_LOG_STRINGIFY(this),
|
|
|
|
IDB_LOG_STRINGIFY(keyRange),
|
|
|
|
IDB_LOG_STRINGIFY(direction));
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
BackgroundCursorChild* actor =
|
|
|
|
new BackgroundCursorChild(request, this, direction);
|
2013-09-24 21:14:16 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
mTransaction->OpenCursor(actor, params);
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return request.forget();
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
void
|
|
|
|
IDBObjectStore::RefreshSpec(bool aMayDelete)
|
2014-09-18 03:36:01 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT_IF(mDeletedSpec, mSpec == mDeletedSpec);
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const DatabaseSpec* dbSpec = mTransaction->Database()->Spec();
|
|
|
|
MOZ_ASSERT(dbSpec);
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const nsTArray<ObjectStoreSpec>& objectStores = dbSpec->objectStores();
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool found = false;
|
2011-11-03 19:57:42 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t objCount = objectStores.Length(), objIndex = 0;
|
|
|
|
objIndex < objCount;
|
|
|
|
objIndex++) {
|
|
|
|
const ObjectStoreSpec& objSpec = objectStores[objIndex];
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (objSpec.metadata().id() == Id()) {
|
|
|
|
mSpec = &objSpec;
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
|
|
|
|
idxIndex < idxCount;
|
|
|
|
idxIndex++) {
|
|
|
|
mIndexes[idxIndex]->RefreshMetadata(aMayDelete);
|
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2016-09-13 01:38:43 +03:00
|
|
|
for (uint32_t idxCount = mDeletedIndexes.Length(), idxIndex = 0;
|
|
|
|
idxIndex < idxCount;
|
|
|
|
idxIndex++) {
|
|
|
|
mDeletedIndexes[idxIndex]->RefreshMetadata(false);
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
found = true;
|
|
|
|
break;
|
2014-09-18 03:36:01 +04:00
|
|
|
}
|
2014-09-13 20:12:19 +04:00
|
|
|
}
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
MOZ_ASSERT_IF(!aMayDelete && !mDeletedSpec, found);
|
2014-09-18 03:36:01 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (found) {
|
|
|
|
MOZ_ASSERT(mSpec != mDeletedSpec);
|
|
|
|
mDeletedSpec = nullptr;
|
|
|
|
} else {
|
|
|
|
NoteDeletion();
|
|
|
|
}
|
2011-11-03 19:57:42 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const ObjectStoreSpec&
|
|
|
|
IDBObjectStore::Spec() const
|
2011-11-03 19:57:42 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mSpec);
|
|
|
|
|
|
|
|
return *mSpec;
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBObjectStore::NoteDeletion()
|
2012-06-01 21:21:12 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mSpec);
|
|
|
|
MOZ_ASSERT(Id() == mSpec->metadata().id());
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (mDeletedSpec) {
|
|
|
|
MOZ_ASSERT(mDeletedSpec == mSpec);
|
|
|
|
return;
|
|
|
|
}
|
2013-03-16 10:58:50 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
// Copy the spec here.
|
|
|
|
mDeletedSpec = new ObjectStoreSpec(*mSpec);
|
|
|
|
mDeletedSpec->indexes().Clear();
|
2013-03-16 10:58:50 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
mSpec = mDeletedSpec;
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
if (!mIndexes.IsEmpty()) {
|
|
|
|
for (uint32_t count = mIndexes.Length(), index = 0;
|
|
|
|
index < count;
|
|
|
|
index++) {
|
|
|
|
mIndexes[index]->NoteDeletion();
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
const nsString&
|
|
|
|
IDBObjectStore::Name() const
|
2012-06-01 21:21:12 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mSpec);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return mSpec->metadata().name();
|
|
|
|
}
|
2013-03-16 10:58:50 +04:00
|
|
|
|
2016-03-30 06:04:56 +03:00
|
|
|
void
|
|
|
|
IDBObjectStore::SetName(const nsAString& aName, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
|
|
|
|
if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
|
|
|
|
mDeletedSpec) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
IDBTransaction* transaction = IDBTransaction::GetCurrent();
|
2016-09-13 01:38:43 +03:00
|
|
|
if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
|
2016-03-30 06:04:56 +03:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aName == mSpec->metadata().name()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache logging string of this object store before renaming.
|
|
|
|
const LoggingString loggingOldObjectStore(this);
|
|
|
|
|
|
|
|
nsresult rv =
|
|
|
|
transaction->Database()->RenameObjectStore(mSpec->metadata().id(),
|
|
|
|
aName);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't do this in the macro because we always need to increment the serial
|
|
|
|
// number to keep in sync with the parent.
|
|
|
|
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
|
|
|
|
|
|
|
|
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
|
|
|
|
"database(%s).transaction(%s).objectStore(%s).rename(%s)",
|
|
|
|
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.rename()",
|
|
|
|
IDB_LOG_ID_STRING(),
|
|
|
|
mTransaction->LoggingSerialNumber(),
|
|
|
|
requestSerialNumber,
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction->Database()),
|
|
|
|
IDB_LOG_STRINGIFY(mTransaction),
|
|
|
|
loggingOldObjectStore.get(),
|
|
|
|
IDB_LOG_STRINGIFY(this));
|
|
|
|
|
|
|
|
transaction->RenameObjectStore(mSpec->metadata().id(), aName);
|
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool
|
|
|
|
IDBObjectStore::AutoIncrement() const
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mSpec);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return mSpec->metadata().autoIncrement();
|
|
|
|
}
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2016-02-17 00:46:08 +03:00
|
|
|
const indexedDB::KeyPath&
|
2014-09-27 03:21:57 +04:00
|
|
|
IDBObjectStore::GetKeyPath() const
|
|
|
|
{
|
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mSpec);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return mSpec->metadata().keyPath();
|
2012-06-01 21:21:12 +04:00
|
|
|
}
|
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
bool
|
|
|
|
IDBObjectStore::HasValidKeyPath() const
|
2012-06-01 21:21:12 +04:00
|
|
|
{
|
2014-09-27 03:21:57 +04:00
|
|
|
AssertIsOnOwningThread();
|
|
|
|
MOZ_ASSERT(mSpec);
|
2012-06-01 21:21:12 +04:00
|
|
|
|
2014-09-27 03:21:57 +04:00
|
|
|
return GetKeyPath().IsValid();
|
2011-11-03 19:57:42 +04:00
|
|
|
}
|
2014-09-27 03:21:57 +04:00
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|