Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "IDBObjectStore.h"
8 :
9 : #include "FileInfo.h"
10 : #include "IDBCursor.h"
11 : #include "IDBDatabase.h"
12 : #include "IDBEvents.h"
13 : #include "IDBFactory.h"
14 : #include "IDBIndex.h"
15 : #include "IDBKeyRange.h"
16 : #include "IDBMutableFile.h"
17 : #include "IDBRequest.h"
18 : #include "IDBTransaction.h"
19 : #include "IndexedDatabase.h"
20 : #include "IndexedDatabaseInlines.h"
21 : #include "IndexedDatabaseManager.h"
22 : #include "js/Class.h"
23 : #include "js/Date.h"
24 : #include "js/StructuredClone.h"
25 : #include "KeyPath.h"
26 : #include "mozilla/EndianUtils.h"
27 : #include "mozilla/ErrorResult.h"
28 : #include "mozilla/Move.h"
29 : #include "mozilla/dom/BindingUtils.h"
30 : #include "mozilla/dom/ContentChild.h"
31 : #include "mozilla/dom/ContentParent.h"
32 : #include "mozilla/dom/DOMStringList.h"
33 : #include "mozilla/dom/File.h"
34 : #include "mozilla/dom/IDBMutableFileBinding.h"
35 : #include "mozilla/dom/BlobBinding.h"
36 : #include "mozilla/dom/IDBObjectStoreBinding.h"
37 : #include "mozilla/dom/MemoryBlobImpl.h"
38 : #include "mozilla/dom/StructuredCloneHolder.h"
39 : #include "mozilla/dom/StructuredCloneTags.h"
40 : #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
41 : #include "mozilla/ipc/BackgroundChild.h"
42 : #include "mozilla/ipc/PBackgroundSharedTypes.h"
43 : #include "nsCOMPtr.h"
44 : #include "nsQueryObject.h"
45 : #include "ProfilerHelpers.h"
46 : #include "ReportInternalError.h"
47 : #include "WorkerPrivate.h"
48 : #include "WorkerScope.h"
49 :
50 : // Include this last to avoid path problems on Windows.
51 : #include "ActorsChild.h"
52 :
53 : namespace mozilla {
54 : namespace dom {
55 :
56 : using namespace mozilla::dom::indexedDB;
57 : using namespace mozilla::dom::quota;
58 : using namespace mozilla::dom::workers;
59 : using namespace mozilla::ipc;
60 :
61 : struct IDBObjectStore::StructuredCloneWriteInfo
62 : {
63 : JSAutoStructuredCloneBuffer mCloneBuffer;
64 : nsTArray<StructuredCloneFile> mFiles;
65 : IDBDatabase* mDatabase;
66 : uint64_t mOffsetToKeyProp;
67 :
68 0 : explicit StructuredCloneWriteInfo(IDBDatabase* aDatabase)
69 0 : : mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
70 : nullptr)
71 : , mDatabase(aDatabase)
72 0 : , mOffsetToKeyProp(0)
73 : {
74 0 : MOZ_ASSERT(aDatabase);
75 :
76 0 : MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
77 0 : }
78 :
79 : StructuredCloneWriteInfo(StructuredCloneWriteInfo&& aCloneWriteInfo)
80 : : mCloneBuffer(Move(aCloneWriteInfo.mCloneBuffer))
81 : , mDatabase(aCloneWriteInfo.mDatabase)
82 : , mOffsetToKeyProp(aCloneWriteInfo.mOffsetToKeyProp)
83 : {
84 : MOZ_ASSERT(mDatabase);
85 :
86 : MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
87 :
88 : mFiles.SwapElements(aCloneWriteInfo.mFiles);
89 : aCloneWriteInfo.mOffsetToKeyProp = 0;
90 : }
91 :
92 0 : ~StructuredCloneWriteInfo()
93 0 : {
94 0 : MOZ_COUNT_DTOR(StructuredCloneWriteInfo);
95 0 : }
96 : };
97 :
98 : namespace {
99 :
100 : struct MOZ_STACK_CLASS MutableFileData final
101 : {
102 : nsString type;
103 : nsString name;
104 :
105 0 : MutableFileData()
106 0 : {
107 0 : MOZ_COUNT_CTOR(MutableFileData);
108 0 : }
109 :
110 0 : ~MutableFileData()
111 0 : {
112 0 : MOZ_COUNT_DTOR(MutableFileData);
113 0 : }
114 : };
115 :
116 : struct MOZ_STACK_CLASS BlobOrFileData final
117 : {
118 : uint32_t tag;
119 : uint64_t size;
120 : nsString type;
121 : nsString name;
122 : int64_t lastModifiedDate;
123 :
124 0 : BlobOrFileData()
125 0 : : tag(0)
126 : , size(0)
127 0 : , lastModifiedDate(INT64_MAX)
128 : {
129 0 : MOZ_COUNT_CTOR(BlobOrFileData);
130 0 : }
131 :
132 0 : ~BlobOrFileData()
133 0 : {
134 0 : MOZ_COUNT_DTOR(BlobOrFileData);
135 0 : }
136 : };
137 :
138 : struct MOZ_STACK_CLASS WasmModuleData final
139 : {
140 : uint32_t bytecodeIndex;
141 : uint32_t compiledIndex;
142 : uint32_t flags;
143 :
144 0 : explicit WasmModuleData(uint32_t aFlags)
145 0 : : bytecodeIndex(0)
146 : , compiledIndex(0)
147 0 : , flags(aFlags)
148 : {
149 0 : MOZ_COUNT_CTOR(WasmModuleData);
150 0 : }
151 :
152 0 : ~WasmModuleData()
153 0 : {
154 0 : MOZ_COUNT_DTOR(WasmModuleData);
155 0 : }
156 : };
157 :
158 : struct MOZ_STACK_CLASS GetAddInfoClosure final
159 : {
160 : IDBObjectStore::StructuredCloneWriteInfo& mCloneWriteInfo;
161 : JS::Handle<JS::Value> mValue;
162 :
163 0 : GetAddInfoClosure(IDBObjectStore::StructuredCloneWriteInfo& aCloneWriteInfo,
164 : JS::Handle<JS::Value> aValue)
165 0 : : mCloneWriteInfo(aCloneWriteInfo)
166 0 : , mValue(aValue)
167 : {
168 0 : MOZ_COUNT_CTOR(GetAddInfoClosure);
169 0 : }
170 :
171 0 : ~GetAddInfoClosure()
172 0 : {
173 0 : MOZ_COUNT_DTOR(GetAddInfoClosure);
174 0 : }
175 : };
176 :
177 : already_AddRefed<IDBRequest>
178 0 : GenerateRequest(JSContext* aCx, IDBObjectStore* aObjectStore)
179 : {
180 0 : MOZ_ASSERT(aObjectStore);
181 0 : aObjectStore->AssertIsOnOwningThread();
182 :
183 0 : IDBTransaction* transaction = aObjectStore->Transaction();
184 :
185 : RefPtr<IDBRequest> request =
186 0 : IDBRequest::Create(aCx, aObjectStore, transaction->Database(), transaction);
187 0 : MOZ_ASSERT(request);
188 :
189 0 : return request.forget();
190 : }
191 :
192 : bool
193 0 : StructuredCloneWriteCallback(JSContext* aCx,
194 : JSStructuredCloneWriter* aWriter,
195 : JS::Handle<JSObject*> aObj,
196 : void* aClosure)
197 : {
198 0 : MOZ_ASSERT(aCx);
199 0 : MOZ_ASSERT(aWriter);
200 0 : MOZ_ASSERT(aClosure);
201 :
202 : auto* cloneWriteInfo =
203 0 : static_cast<IDBObjectStore::StructuredCloneWriteInfo*>(aClosure);
204 :
205 0 : if (JS_GetClass(aObj) == IDBObjectStore::DummyPropClass()) {
206 0 : MOZ_ASSERT(!cloneWriteInfo->mOffsetToKeyProp);
207 0 : cloneWriteInfo->mOffsetToKeyProp = js::GetSCOffset(aWriter);
208 :
209 0 : uint64_t value = 0;
210 : // Omit endian swap
211 0 : return JS_WriteBytes(aWriter, &value, sizeof(value));
212 : }
213 :
214 : // UNWRAP_OBJECT calls might mutate this.
215 0 : JS::Rooted<JSObject*> obj(aCx, aObj);
216 :
217 : IDBMutableFile* mutableFile;
218 0 : if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, &obj, mutableFile))) {
219 0 : if (cloneWriteInfo->mDatabase->IsFileHandleDisabled()) {
220 0 : return false;
221 : }
222 :
223 0 : IDBDatabase* database = mutableFile->Database();
224 0 : MOZ_ASSERT(database);
225 :
226 : // Throw when trying to store IDBMutableFile objects that live in a
227 : // different database.
228 0 : if (database != cloneWriteInfo->mDatabase) {
229 0 : MOZ_ASSERT(!SameCOMIdentity(database, cloneWriteInfo->mDatabase));
230 :
231 0 : if (database->Name() != cloneWriteInfo->mDatabase->Name()) {
232 0 : return false;
233 : }
234 :
235 0 : nsCString fileOrigin, databaseOrigin;
236 : PersistenceType filePersistenceType, databasePersistenceType;
237 :
238 0 : if (NS_WARN_IF(NS_FAILED(database->GetQuotaInfo(fileOrigin,
239 : &filePersistenceType)))) {
240 0 : return false;
241 : }
242 :
243 0 : if (NS_WARN_IF(NS_FAILED(cloneWriteInfo->mDatabase->GetQuotaInfo(
244 : databaseOrigin,
245 : &databasePersistenceType)))) {
246 0 : return false;
247 : }
248 :
249 0 : if (filePersistenceType != databasePersistenceType ||
250 0 : fileOrigin != databaseOrigin) {
251 0 : return false;
252 : }
253 : }
254 :
255 0 : if (cloneWriteInfo->mFiles.Length() > size_t(UINT32_MAX)) {
256 0 : MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
257 : return false;
258 : }
259 :
260 0 : const uint32_t index = cloneWriteInfo->mFiles.Length();
261 :
262 0 : NS_ConvertUTF16toUTF8 convType(mutableFile->Type());
263 : uint32_t convTypeLength =
264 0 : NativeEndian::swapToLittleEndian(convType.Length());
265 :
266 0 : NS_ConvertUTF16toUTF8 convName(mutableFile->Name());
267 : uint32_t convNameLength =
268 0 : NativeEndian::swapToLittleEndian(convName.Length());
269 :
270 0 : if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_MUTABLEFILE, uint32_t(index)) ||
271 0 : !JS_WriteBytes(aWriter, &convTypeLength, sizeof(uint32_t)) ||
272 0 : !JS_WriteBytes(aWriter, convType.get(), convType.Length()) ||
273 0 : !JS_WriteBytes(aWriter, &convNameLength, sizeof(uint32_t)) ||
274 0 : !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
275 0 : return false;
276 : }
277 :
278 0 : StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
279 0 : newFile->mMutableFile = mutableFile;
280 0 : newFile->mType = StructuredCloneFile::eMutableFile;
281 :
282 0 : return true;
283 : }
284 :
285 : {
286 0 : Blob* blob = nullptr;
287 0 : if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
288 0 : ErrorResult rv;
289 0 : uint64_t size = blob->GetSize(rv);
290 0 : MOZ_ASSERT(!rv.Failed());
291 :
292 0 : size = NativeEndian::swapToLittleEndian(size);
293 :
294 0 : nsString type;
295 0 : blob->GetType(type);
296 :
297 0 : NS_ConvertUTF16toUTF8 convType(type);
298 : uint32_t convTypeLength =
299 0 : NativeEndian::swapToLittleEndian(convType.Length());
300 :
301 0 : if (cloneWriteInfo->mFiles.Length() > size_t(UINT32_MAX)) {
302 0 : MOZ_ASSERT(false,
303 : "Fix the structured clone data to use a bigger type!");
304 : return false;
305 : }
306 :
307 0 : const uint32_t index = cloneWriteInfo->mFiles.Length();
308 :
309 0 : if (!JS_WriteUint32Pair(aWriter,
310 0 : blob->IsFile() ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
311 0 : index) ||
312 0 : !JS_WriteBytes(aWriter, &size, sizeof(size)) ||
313 0 : !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
314 0 : !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
315 0 : return false;
316 : }
317 :
318 0 : RefPtr<File> file = blob->ToFile();
319 0 : if (file) {
320 0 : ErrorResult rv;
321 0 : int64_t lastModifiedDate = file->GetLastModified(rv);
322 0 : MOZ_ALWAYS_TRUE(!rv.Failed());
323 :
324 0 : lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
325 :
326 0 : nsString name;
327 0 : file->GetName(name);
328 :
329 0 : NS_ConvertUTF16toUTF8 convName(name);
330 : uint32_t convNameLength =
331 0 : NativeEndian::swapToLittleEndian(convName.Length());
332 :
333 0 : if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) ||
334 0 : !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
335 0 : !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
336 0 : return false;
337 : }
338 : }
339 :
340 0 : StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
341 0 : newFile->mBlob = blob;
342 0 : newFile->mType = StructuredCloneFile::eBlob;
343 :
344 0 : return true;
345 : }
346 : }
347 :
348 0 : if (JS::IsWasmModuleObject(aObj)) {
349 0 : RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
350 0 : MOZ_ASSERT(module);
351 :
352 : size_t bytecodeSize;
353 : size_t compiledSize;
354 0 : module->serializedSize(&bytecodeSize, &compiledSize);
355 :
356 0 : UniquePtr<uint8_t[]> bytecode(new uint8_t[bytecodeSize]);
357 0 : MOZ_ASSERT(bytecode);
358 :
359 0 : UniquePtr<uint8_t[]> compiled(new uint8_t[compiledSize]);
360 0 : MOZ_ASSERT(compiled);
361 :
362 0 : module->serialize(bytecode.get(),
363 : bytecodeSize,
364 : compiled.get(),
365 0 : compiledSize);
366 :
367 : RefPtr<BlobImpl> blobImpl =
368 0 : new MemoryBlobImpl(bytecode.release(), bytecodeSize, EmptyString());
369 0 : RefPtr<Blob> bytecodeBlob = Blob::Create(nullptr, blobImpl);
370 :
371 : blobImpl =
372 0 : new MemoryBlobImpl(compiled.release(), compiledSize, EmptyString());
373 0 : RefPtr<Blob> compiledBlob = Blob::Create(nullptr, blobImpl);
374 :
375 0 : if (cloneWriteInfo->mFiles.Length() + 1 > size_t(UINT32_MAX)) {
376 0 : MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
377 : return false;
378 : }
379 :
380 0 : const uint32_t index = cloneWriteInfo->mFiles.Length();
381 :
382 : // The ordering of the bytecode and compiled file is significant and must
383 : // never be changed. These two files must always form a pair
384 : // [eWasmBytecode, eWasmCompiled]. Everything else depends on it!
385 0 : if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, /* flags */ 0) ||
386 0 : !JS_WriteUint32Pair(aWriter, index, index + 1)) {
387 0 : return false;
388 : }
389 :
390 0 : StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
391 0 : newFile->mBlob = bytecodeBlob;
392 0 : newFile->mType = StructuredCloneFile::eWasmBytecode;
393 :
394 0 : newFile = cloneWriteInfo->mFiles.AppendElement();
395 0 : newFile->mBlob = compiledBlob;
396 0 : newFile->mType = StructuredCloneFile::eWasmCompiled;
397 :
398 0 : return true;
399 : }
400 :
401 0 : return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
402 : }
403 :
404 : nsresult
405 0 : GetAddInfoCallback(JSContext* aCx, void* aClosure)
406 : {
407 : static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
408 : nullptr /* read */,
409 : StructuredCloneWriteCallback /* write */,
410 : nullptr /* reportError */,
411 : nullptr /* readTransfer */,
412 : nullptr /* writeTransfer */,
413 : nullptr /* freeTransfer */
414 : };
415 :
416 0 : MOZ_ASSERT(aCx);
417 :
418 0 : auto* data = static_cast<GetAddInfoClosure*>(aClosure);
419 0 : MOZ_ASSERT(data);
420 :
421 0 : data->mCloneWriteInfo.mOffsetToKeyProp = 0;
422 :
423 0 : if (!data->mCloneWriteInfo.mCloneBuffer.write(aCx,
424 : data->mValue,
425 : &kStructuredCloneCallbacks,
426 0 : &data->mCloneWriteInfo)) {
427 0 : return NS_ERROR_DOM_DATA_CLONE_ERR;
428 : }
429 :
430 0 : return NS_OK;
431 : }
432 :
433 : bool
434 0 : ResolveMysteryMutableFile(IDBMutableFile* aMutableFile,
435 : const nsString& aName,
436 : const nsString& aType)
437 : {
438 0 : MOZ_ASSERT(aMutableFile);
439 0 : aMutableFile->SetLazyData(aName, aType);
440 0 : return true;
441 : }
442 :
443 : bool
444 0 : StructuredCloneReadString(JSStructuredCloneReader* aReader,
445 : nsCString& aString)
446 : {
447 : uint32_t length;
448 0 : if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) {
449 0 : NS_WARNING("Failed to read length!");
450 0 : return false;
451 : }
452 0 : length = NativeEndian::swapFromLittleEndian(length);
453 :
454 0 : if (!aString.SetLength(length, fallible)) {
455 0 : NS_WARNING("Out of memory?");
456 0 : return false;
457 : }
458 0 : char* buffer = aString.BeginWriting();
459 :
460 0 : if (!JS_ReadBytes(aReader, buffer, length)) {
461 0 : NS_WARNING("Failed to read type!");
462 0 : return false;
463 : }
464 :
465 0 : return true;
466 : }
467 :
468 : bool
469 0 : ReadFileHandle(JSStructuredCloneReader* aReader,
470 : MutableFileData* aRetval)
471 : {
472 : static_assert(SCTAG_DOM_MUTABLEFILE == 0xFFFF8004, "Update me!");
473 0 : MOZ_ASSERT(aReader && aRetval);
474 :
475 0 : nsCString type;
476 0 : if (!StructuredCloneReadString(aReader, type)) {
477 0 : return false;
478 : }
479 0 : CopyUTF8toUTF16(type, aRetval->type);
480 :
481 0 : nsCString name;
482 0 : if (!StructuredCloneReadString(aReader, name)) {
483 0 : return false;
484 : }
485 0 : CopyUTF8toUTF16(name, aRetval->name);
486 :
487 0 : return true;
488 : }
489 :
490 : bool
491 0 : ReadBlobOrFile(JSStructuredCloneReader* aReader,
492 : uint32_t aTag,
493 : BlobOrFileData* aRetval)
494 : {
495 : static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
496 : SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
497 : SCTAG_DOM_FILE == 0xffff8005,
498 : "Update me!");
499 :
500 0 : MOZ_ASSERT(aReader);
501 0 : MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
502 : aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
503 : aTag == SCTAG_DOM_BLOB);
504 0 : MOZ_ASSERT(aRetval);
505 :
506 0 : aRetval->tag = aTag;
507 :
508 : uint64_t size;
509 0 : if (NS_WARN_IF(!JS_ReadBytes(aReader, &size, sizeof(uint64_t)))) {
510 0 : return false;
511 : }
512 :
513 0 : aRetval->size = NativeEndian::swapFromLittleEndian(size);
514 :
515 0 : nsCString type;
516 0 : if (NS_WARN_IF(!StructuredCloneReadString(aReader, type))) {
517 0 : return false;
518 : }
519 :
520 0 : CopyUTF8toUTF16(type, aRetval->type);
521 :
522 : // Blobs are done.
523 0 : if (aTag == SCTAG_DOM_BLOB) {
524 0 : return true;
525 : }
526 :
527 0 : MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
528 : aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE);
529 :
530 : int64_t lastModifiedDate;
531 0 : if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
532 0 : lastModifiedDate = INT64_MAX;
533 : } else {
534 0 : if (NS_WARN_IF(!JS_ReadBytes(aReader, &lastModifiedDate,
535 : sizeof(lastModifiedDate)))) {
536 0 : return false;
537 : }
538 0 : lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate);
539 : }
540 :
541 0 : aRetval->lastModifiedDate = lastModifiedDate;
542 :
543 0 : nsCString name;
544 0 : if (NS_WARN_IF(!StructuredCloneReadString(aReader, name))) {
545 0 : return false;
546 : }
547 :
548 0 : CopyUTF8toUTF16(name, aRetval->name);
549 :
550 0 : return true;
551 : }
552 :
553 : bool
554 0 : ReadWasmModule(JSStructuredCloneReader* aReader,
555 : WasmModuleData* aRetval)
556 : {
557 : static_assert(SCTAG_DOM_WASM == 0xFFFF8006, "Update me!");
558 0 : MOZ_ASSERT(aReader && aRetval);
559 :
560 : uint32_t bytecodeIndex;
561 : uint32_t compiledIndex;
562 0 : if (NS_WARN_IF(!JS_ReadUint32Pair(aReader,
563 : &bytecodeIndex,
564 : &compiledIndex))) {
565 0 : return false;
566 : }
567 :
568 0 : aRetval->bytecodeIndex = bytecodeIndex;
569 0 : aRetval->compiledIndex = compiledIndex;
570 :
571 0 : return true;
572 : }
573 :
574 : class ValueDeserializationHelper
575 : {
576 : public:
577 : static bool
578 0 : CreateAndWrapMutableFile(JSContext* aCx,
579 : StructuredCloneFile& aFile,
580 : const MutableFileData& aData,
581 : JS::MutableHandle<JSObject*> aResult)
582 : {
583 0 : MOZ_ASSERT(aCx);
584 0 : MOZ_ASSERT(aFile.mType == StructuredCloneFile::eMutableFile);
585 :
586 0 : if (!aFile.mMutableFile || !NS_IsMainThread()) {
587 0 : return false;
588 : }
589 :
590 0 : if (NS_WARN_IF(!ResolveMysteryMutableFile(aFile.mMutableFile,
591 : aData.name,
592 : aData.type))) {
593 0 : return false;
594 : }
595 :
596 0 : JS::Rooted<JS::Value> wrappedMutableFile(aCx);
597 0 : if (!ToJSValue(aCx, aFile.mMutableFile, &wrappedMutableFile)) {
598 0 : return false;
599 : }
600 :
601 0 : aResult.set(&wrappedMutableFile.toObject());
602 0 : return true;
603 : }
604 :
605 : static bool
606 0 : CreateAndWrapBlobOrFile(JSContext* aCx,
607 : IDBDatabase* aDatabase,
608 : StructuredCloneFile& aFile,
609 : const BlobOrFileData& aData,
610 : JS::MutableHandle<JSObject*> aResult)
611 : {
612 0 : MOZ_ASSERT(aCx);
613 0 : MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
614 : aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
615 : aData.tag == SCTAG_DOM_BLOB);
616 0 : MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
617 0 : MOZ_ASSERT(aFile.mBlob);
618 :
619 : // It can happen that this IDB is chrome code, so there is no parent, but
620 : // still we want to set a correct parent for the new File object.
621 0 : nsCOMPtr<nsISupports> parent;
622 0 : if (NS_IsMainThread()) {
623 0 : if (aDatabase && aDatabase->GetParentObject()) {
624 0 : parent = aDatabase->GetParentObject();
625 : } else {
626 0 : parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
627 : }
628 : } else {
629 0 : WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
630 0 : MOZ_ASSERT(workerPrivate);
631 :
632 0 : WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
633 0 : MOZ_ASSERT(globalScope);
634 :
635 0 : parent = do_QueryObject(globalScope);
636 : }
637 :
638 0 : MOZ_ASSERT(parent);
639 :
640 0 : if (aData.tag == SCTAG_DOM_BLOB) {
641 0 : aFile.mBlob->Impl()->SetLazyData(
642 0 : NullString(), aData.type, aData.size, INT64_MAX);
643 0 : MOZ_ASSERT(!aFile.mBlob->IsFile());
644 :
645 : // ActorsParent sends here a kind of half blob and half file wrapped into
646 : // a DOM File object. DOM File and DOM Blob are a WebIDL wrapper around a
647 : // BlobImpl object. SetLazyData() has just changed the BlobImpl to be a
648 : // Blob (see the previous assert), but 'aFile.mBlob' still has the WebIDL
649 : // DOM File wrapping.
650 : // Before exposing it to content, we must recreate a DOM Blob object.
651 :
652 : RefPtr<Blob> blob =
653 0 : Blob::Create(aFile.mBlob->GetParentObject(), aFile.mBlob->Impl());
654 0 : MOZ_ASSERT(blob);
655 0 : JS::Rooted<JS::Value> wrappedBlob(aCx);
656 0 : if (!ToJSValue(aCx, blob, &wrappedBlob)) {
657 0 : return false;
658 : }
659 :
660 0 : aResult.set(&wrappedBlob.toObject());
661 0 : return true;
662 : }
663 :
664 0 : aFile.mBlob->Impl()->SetLazyData(
665 0 : aData.name, aData.type, aData.size,
666 0 : aData.lastModifiedDate * PR_USEC_PER_MSEC);
667 :
668 0 : MOZ_ASSERT(aFile.mBlob->IsFile());
669 0 : RefPtr<File> file = aFile.mBlob->ToFile();
670 0 : MOZ_ASSERT(file);
671 :
672 0 : JS::Rooted<JS::Value> wrappedFile(aCx);
673 0 : if (!ToJSValue(aCx, file, &wrappedFile)) {
674 0 : return false;
675 : }
676 :
677 0 : aResult.set(&wrappedFile.toObject());
678 0 : return true;
679 : }
680 :
681 : static bool
682 0 : CreateAndWrapWasmModule(JSContext* aCx,
683 : StructuredCloneFile& aFile,
684 : const WasmModuleData& aData,
685 : JS::MutableHandle<JSObject*> aResult)
686 : {
687 0 : MOZ_ASSERT(aCx);
688 0 : MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmCompiled);
689 0 : MOZ_ASSERT(!aFile.mBlob);
690 0 : MOZ_ASSERT(aFile.mWasmModule);
691 :
692 0 : JS::Rooted<JSObject*> moduleObj(aCx, aFile.mWasmModule->createObject(aCx));
693 0 : if (NS_WARN_IF(!moduleObj)) {
694 0 : return false;
695 : }
696 :
697 0 : aResult.set(moduleObj);
698 0 : return true;
699 : }
700 : };
701 :
702 : class IndexDeserializationHelper
703 : {
704 : public:
705 : static bool
706 0 : CreateAndWrapMutableFile(JSContext* aCx,
707 : StructuredCloneFile& aFile,
708 : const MutableFileData& aData,
709 : JS::MutableHandle<JSObject*> aResult)
710 : {
711 : // MutableFile can't be used in index creation, so just make a dummy object.
712 0 : JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
713 0 : if (NS_WARN_IF(!obj)) {
714 0 : return false;
715 : }
716 :
717 0 : aResult.set(obj);
718 0 : return true;
719 : }
720 :
721 : static bool
722 0 : CreateAndWrapBlobOrFile(JSContext* aCx,
723 : IDBDatabase* aDatabase,
724 : StructuredCloneFile& aFile,
725 : const BlobOrFileData& aData,
726 : JS::MutableHandle<JSObject*> aResult)
727 : {
728 0 : MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
729 : aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
730 : aData.tag == SCTAG_DOM_BLOB);
731 :
732 : // The following properties are available for use in index creation
733 : // Blob.size
734 : // Blob.type
735 : // File.name
736 : // File.lastModifiedDate
737 :
738 0 : JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
739 0 : if (NS_WARN_IF(!obj)) {
740 0 : return false;
741 : }
742 :
743 : // Technically these props go on the proto, but this detail won't change
744 : // the results of index creation.
745 :
746 : JS::Rooted<JSString*> type(aCx,
747 0 : JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length()));
748 0 : if (NS_WARN_IF(!type)) {
749 0 : return false;
750 : }
751 :
752 0 : if (NS_WARN_IF(!JS_DefineProperty(aCx,
753 : obj,
754 : "size",
755 : double(aData.size),
756 : 0))) {
757 0 : return false;
758 : }
759 :
760 0 : if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "type", type, 0))) {
761 0 : return false;
762 : }
763 :
764 0 : if (aData.tag == SCTAG_DOM_BLOB) {
765 0 : aResult.set(obj);
766 0 : return true;
767 : }
768 :
769 : JS::Rooted<JSString*> name(aCx,
770 0 : JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length()));
771 0 : if (NS_WARN_IF(!name)) {
772 0 : return false;
773 : }
774 :
775 0 : JS::ClippedTime time = JS::TimeClip(aData.lastModifiedDate);
776 0 : JS::Rooted<JSObject*> date(aCx, JS::NewDateObject(aCx, time));
777 0 : if (NS_WARN_IF(!date)) {
778 0 : return false;
779 : }
780 :
781 0 : if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "name", name, 0))) {
782 0 : return false;
783 : }
784 :
785 0 : if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0))) {
786 0 : return false;
787 : }
788 :
789 0 : aResult.set(obj);
790 0 : return true;
791 : }
792 :
793 : static bool
794 0 : CreateAndWrapWasmModule(JSContext* aCx,
795 : StructuredCloneFile& aFile,
796 : const WasmModuleData& aData,
797 : JS::MutableHandle<JSObject*> aResult)
798 : {
799 : // Wasm module can't be used in index creation, so just make a dummy object.
800 0 : JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
801 0 : if (NS_WARN_IF(!obj)) {
802 0 : return false;
803 : }
804 :
805 0 : aResult.set(obj);
806 0 : return true;
807 : }
808 : };
809 :
810 : // We don't need to upgrade database on B2G. See the comment in ActorsParent.cpp,
811 : // UpgradeSchemaFrom18_0To19_0()
812 : #if !defined(MOZ_B2G)
813 :
814 : class UpgradeDeserializationHelper
815 : {
816 : public:
817 : static bool
818 0 : CreateAndWrapMutableFile(JSContext* aCx,
819 : StructuredCloneFile& aFile,
820 : const MutableFileData& aData,
821 : JS::MutableHandle<JSObject*> aResult)
822 : {
823 0 : MOZ_ASSERT(aCx);
824 0 : MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
825 :
826 0 : aFile.mType = StructuredCloneFile::eMutableFile;
827 :
828 : // Just make a dummy object. The file_ids upgrade function is only
829 : // interested in the |mType| flag.
830 0 : JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
831 :
832 0 : if (NS_WARN_IF(!obj)) {
833 0 : return false;
834 : }
835 :
836 0 : aResult.set(obj);
837 0 : return true;
838 : }
839 :
840 : static bool
841 0 : CreateAndWrapBlobOrFile(JSContext* aCx,
842 : IDBDatabase* aDatabase,
843 : StructuredCloneFile& aFile,
844 : const BlobOrFileData& aData,
845 : JS::MutableHandle<JSObject*> aResult)
846 : {
847 0 : MOZ_ASSERT(aCx);
848 0 : MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
849 0 : MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
850 : aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
851 : aData.tag == SCTAG_DOM_BLOB);
852 :
853 : // Just make a dummy object. The file_ids upgrade function is only interested
854 : // in the |mType| flag.
855 0 : JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
856 :
857 0 : if (NS_WARN_IF(!obj)) {
858 0 : return false;
859 : }
860 :
861 0 : aResult.set(obj);
862 0 : return true;
863 : }
864 :
865 : static bool
866 0 : CreateAndWrapWasmModule(JSContext* aCx,
867 : StructuredCloneFile& aFile,
868 : const WasmModuleData& aData,
869 : JS::MutableHandle<JSObject*> aResult)
870 : {
871 0 : MOZ_ASSERT(aCx);
872 0 : MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
873 :
874 0 : MOZ_ASSERT(false, "This should never be possible!");
875 :
876 : return false;
877 : }
878 : };
879 :
880 : #endif // MOZ_B2G
881 :
882 : template <class Traits>
883 : JSObject*
884 0 : CommonStructuredCloneReadCallback(JSContext* aCx,
885 : JSStructuredCloneReader* aReader,
886 : uint32_t aTag,
887 : uint32_t aData,
888 : void* aClosure)
889 : {
890 : // We need to statically assert that our tag values are what we expect
891 : // so that if people accidentally change them they notice.
892 : static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
893 : SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
894 : SCTAG_DOM_MUTABLEFILE == 0xffff8004 &&
895 : SCTAG_DOM_FILE == 0xffff8005 &&
896 : SCTAG_DOM_WASM == 0xffff8006,
897 : "You changed our structured clone tag values and just ate "
898 : "everyone's IndexedDB data. I hope you are happy.");
899 :
900 0 : if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
901 0 : aTag == SCTAG_DOM_BLOB ||
902 0 : aTag == SCTAG_DOM_FILE ||
903 0 : aTag == SCTAG_DOM_MUTABLEFILE ||
904 : aTag == SCTAG_DOM_WASM) {
905 0 : auto* cloneReadInfo = static_cast<StructuredCloneReadInfo*>(aClosure);
906 :
907 0 : JS::Rooted<JSObject*> result(aCx);
908 :
909 0 : if (aTag == SCTAG_DOM_WASM) {
910 0 : WasmModuleData data(aData);
911 0 : if (NS_WARN_IF(!ReadWasmModule(aReader, &data))) {
912 0 : return nullptr;
913 : }
914 :
915 0 : MOZ_ASSERT(data.compiledIndex == data.bytecodeIndex + 1);
916 0 : MOZ_ASSERT(!data.flags);
917 :
918 0 : if (data.bytecodeIndex >= cloneReadInfo->mFiles.Length() ||
919 0 : data.compiledIndex >= cloneReadInfo->mFiles.Length()) {
920 0 : MOZ_ASSERT(false, "Bad index value!");
921 : return nullptr;
922 : }
923 :
924 0 : StructuredCloneFile& file = cloneReadInfo->mFiles[data.compiledIndex];
925 :
926 0 : if (NS_WARN_IF(!Traits::CreateAndWrapWasmModule(aCx,
927 : file,
928 : data,
929 : &result))) {
930 0 : return nullptr;
931 : }
932 :
933 0 : return result;
934 : }
935 :
936 0 : if (aData >= cloneReadInfo->mFiles.Length()) {
937 0 : MOZ_ASSERT(false, "Bad index value!");
938 : return nullptr;
939 : }
940 :
941 0 : StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
942 :
943 0 : if (aTag == SCTAG_DOM_MUTABLEFILE) {
944 0 : MutableFileData data;
945 0 : if (NS_WARN_IF(!ReadFileHandle(aReader, &data))) {
946 0 : return nullptr;
947 : }
948 :
949 0 : if (NS_WARN_IF(!Traits::CreateAndWrapMutableFile(aCx,
950 : file,
951 : data,
952 : &result))) {
953 0 : return nullptr;
954 : }
955 :
956 0 : return result;
957 : }
958 :
959 0 : BlobOrFileData data;
960 0 : if (NS_WARN_IF(!ReadBlobOrFile(aReader, aTag, &data))) {
961 0 : return nullptr;
962 : }
963 :
964 0 : if (NS_WARN_IF(!Traits::CreateAndWrapBlobOrFile(aCx,
965 : cloneReadInfo->mDatabase,
966 : file,
967 : data,
968 : &result))) {
969 0 : return nullptr;
970 : }
971 :
972 0 : return result;
973 : }
974 :
975 0 : return StructuredCloneHolder::ReadFullySerializableObjects(aCx, aReader,
976 0 : aTag);
977 : }
978 :
979 : } // namespace
980 :
981 : const JSClass IDBObjectStore::sDummyPropJSClass = {
982 : "IDBObjectStore Dummy",
983 : 0 /* flags */
984 : };
985 :
986 0 : IDBObjectStore::IDBObjectStore(IDBTransaction* aTransaction,
987 0 : const ObjectStoreSpec* aSpec)
988 : : mTransaction(aTransaction)
989 0 : , mCachedKeyPath(JS::UndefinedValue())
990 : , mSpec(aSpec)
991 0 : , mId(aSpec->metadata().id())
992 0 : , mRooted(false)
993 : {
994 0 : MOZ_ASSERT(aTransaction);
995 0 : aTransaction->AssertIsOnOwningThread();
996 0 : MOZ_ASSERT(aSpec);
997 0 : }
998 :
999 0 : IDBObjectStore::~IDBObjectStore()
1000 : {
1001 0 : AssertIsOnOwningThread();
1002 :
1003 0 : if (mRooted) {
1004 0 : mCachedKeyPath.setUndefined();
1005 0 : mozilla::DropJSObjects(this);
1006 : }
1007 0 : }
1008 :
1009 : // static
1010 : already_AddRefed<IDBObjectStore>
1011 0 : IDBObjectStore::Create(IDBTransaction* aTransaction,
1012 : const ObjectStoreSpec& aSpec)
1013 : {
1014 0 : MOZ_ASSERT(aTransaction);
1015 0 : aTransaction->AssertIsOnOwningThread();
1016 :
1017 : RefPtr<IDBObjectStore> objectStore =
1018 0 : new IDBObjectStore(aTransaction, &aSpec);
1019 :
1020 0 : return objectStore.forget();
1021 : }
1022 :
1023 : // static
1024 : nsresult
1025 0 : IDBObjectStore::AppendIndexUpdateInfo(
1026 : int64_t aIndexID,
1027 : const KeyPath& aKeyPath,
1028 : bool aUnique,
1029 : bool aMultiEntry,
1030 : const nsCString& aLocale,
1031 : JSContext* aCx,
1032 : JS::Handle<JS::Value> aVal,
1033 : nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
1034 : {
1035 : nsresult rv;
1036 :
1037 : #ifdef ENABLE_INTL_API
1038 0 : const bool localeAware = !aLocale.IsEmpty();
1039 : #endif
1040 :
1041 0 : if (!aMultiEntry) {
1042 0 : Key key;
1043 0 : rv = aKeyPath.ExtractKey(aCx, aVal, key);
1044 :
1045 : // If an index's keyPath doesn't match an object, we ignore that object.
1046 0 : if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
1047 0 : return NS_OK;
1048 : }
1049 :
1050 0 : if (NS_FAILED(rv)) {
1051 0 : return rv;
1052 : }
1053 :
1054 0 : IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
1055 0 : updateInfo->indexId() = aIndexID;
1056 0 : updateInfo->value() = key;
1057 : #ifdef ENABLE_INTL_API
1058 0 : if (localeAware) {
1059 0 : rv = key.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
1060 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1061 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1062 : }
1063 : }
1064 : #endif
1065 :
1066 0 : return NS_OK;
1067 : }
1068 :
1069 0 : JS::Rooted<JS::Value> val(aCx);
1070 0 : if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) {
1071 0 : return NS_OK;
1072 : }
1073 :
1074 : bool isArray;
1075 0 : if (!JS_IsArrayObject(aCx, val, &isArray)) {
1076 0 : IDB_REPORT_INTERNAL_ERR();
1077 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1078 : }
1079 0 : if (isArray) {
1080 0 : JS::Rooted<JSObject*> array(aCx, &val.toObject());
1081 : uint32_t arrayLength;
1082 0 : if (NS_WARN_IF(!JS_GetArrayLength(aCx, array, &arrayLength))) {
1083 0 : IDB_REPORT_INTERNAL_ERR();
1084 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1085 : }
1086 :
1087 0 : for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
1088 0 : JS::Rooted<JS::Value> arrayItem(aCx);
1089 0 : if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) {
1090 0 : IDB_REPORT_INTERNAL_ERR();
1091 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1092 : }
1093 :
1094 0 : Key value;
1095 0 : if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
1096 0 : value.IsUnset()) {
1097 : // Not a value we can do anything with, ignore it.
1098 0 : continue;
1099 : }
1100 :
1101 0 : IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
1102 0 : updateInfo->indexId() = aIndexID;
1103 0 : updateInfo->value() = value;
1104 : #ifdef ENABLE_INTL_API
1105 0 : if (localeAware) {
1106 0 : rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
1107 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1108 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1109 : }
1110 : }
1111 : #endif
1112 : }
1113 : }
1114 : else {
1115 0 : Key value;
1116 0 : if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
1117 0 : value.IsUnset()) {
1118 : // Not a value we can do anything with, ignore it.
1119 0 : return NS_OK;
1120 : }
1121 :
1122 0 : IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
1123 0 : updateInfo->indexId() = aIndexID;
1124 0 : updateInfo->value() = value;
1125 : #ifdef ENABLE_INTL_API
1126 0 : if (localeAware) {
1127 0 : rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
1128 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1129 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1130 : }
1131 : }
1132 : #endif
1133 : }
1134 :
1135 0 : return NS_OK;
1136 : }
1137 :
1138 : // static
1139 : void
1140 0 : IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
1141 : {
1142 : // This is kind of tricky, we only want to release stuff on the main thread,
1143 : // but we can end up being called on other threads if we have already been
1144 : // cleared on the main thread.
1145 0 : if (!aReadInfo.mFiles.Length()) {
1146 0 : return;
1147 : }
1148 :
1149 0 : aReadInfo.mFiles.Clear();
1150 : }
1151 :
1152 : // static
1153 : bool
1154 0 : IDBObjectStore::DeserializeValue(JSContext* aCx,
1155 : StructuredCloneReadInfo& aCloneReadInfo,
1156 : JS::MutableHandle<JS::Value> aValue)
1157 : {
1158 0 : MOZ_ASSERT(aCx);
1159 :
1160 0 : if (!aCloneReadInfo.mData.Size()) {
1161 0 : aValue.setUndefined();
1162 0 : return true;
1163 : }
1164 :
1165 0 : MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
1166 :
1167 0 : JSAutoRequest ar(aCx);
1168 :
1169 : static const JSStructuredCloneCallbacks callbacks = {
1170 : CommonStructuredCloneReadCallback<ValueDeserializationHelper>,
1171 : nullptr,
1172 : nullptr,
1173 : nullptr,
1174 : nullptr,
1175 : nullptr
1176 : };
1177 :
1178 : // FIXME: Consider to use StructuredCloneHolder here and in other
1179 : // deserializing methods.
1180 0 : if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
1181 : JS::StructuredCloneScope::SameProcessSameThread,
1182 : aValue, &callbacks, &aCloneReadInfo)) {
1183 0 : return false;
1184 : }
1185 :
1186 0 : return true;
1187 : }
1188 :
1189 : // static
1190 : bool
1191 0 : IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
1192 : StructuredCloneReadInfo& aCloneReadInfo,
1193 : JS::MutableHandle<JS::Value> aValue)
1194 : {
1195 0 : MOZ_ASSERT(!NS_IsMainThread());
1196 0 : MOZ_ASSERT(aCx);
1197 :
1198 0 : if (!aCloneReadInfo.mData.Size()) {
1199 0 : aValue.setUndefined();
1200 0 : return true;
1201 : }
1202 :
1203 0 : MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
1204 :
1205 0 : JSAutoRequest ar(aCx);
1206 :
1207 : static const JSStructuredCloneCallbacks callbacks = {
1208 : CommonStructuredCloneReadCallback<IndexDeserializationHelper>,
1209 : nullptr,
1210 : nullptr
1211 : };
1212 :
1213 0 : if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
1214 : JS::StructuredCloneScope::SameProcessSameThread,
1215 : aValue, &callbacks, &aCloneReadInfo)) {
1216 0 : return false;
1217 : }
1218 :
1219 0 : return true;
1220 : }
1221 :
1222 : #if !defined(MOZ_B2G)
1223 :
1224 : // static
1225 : bool
1226 0 : IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
1227 : StructuredCloneReadInfo& aCloneReadInfo,
1228 : JS::MutableHandle<JS::Value> aValue)
1229 : {
1230 0 : MOZ_ASSERT(!NS_IsMainThread());
1231 0 : MOZ_ASSERT(aCx);
1232 :
1233 0 : if (!aCloneReadInfo.mData.Size()) {
1234 0 : aValue.setUndefined();
1235 0 : return true;
1236 : }
1237 :
1238 0 : MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
1239 :
1240 0 : JSAutoRequest ar(aCx);
1241 :
1242 : static JSStructuredCloneCallbacks callbacks = {
1243 : CommonStructuredCloneReadCallback<UpgradeDeserializationHelper>,
1244 : nullptr,
1245 : nullptr,
1246 : nullptr,
1247 : nullptr,
1248 : nullptr
1249 : };
1250 :
1251 0 : if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
1252 : JS::StructuredCloneScope::SameProcessSameThread,
1253 : aValue, &callbacks, &aCloneReadInfo)) {
1254 0 : return false;
1255 : }
1256 :
1257 0 : return true;
1258 : }
1259 :
1260 : #endif // MOZ_B2G
1261 :
1262 : #ifdef DEBUG
1263 :
1264 : void
1265 0 : IDBObjectStore::AssertIsOnOwningThread() const
1266 : {
1267 0 : MOZ_ASSERT(mTransaction);
1268 0 : mTransaction->AssertIsOnOwningThread();
1269 0 : }
1270 :
1271 : #endif // DEBUG
1272 :
1273 : nsresult
1274 0 : IDBObjectStore::GetAddInfo(JSContext* aCx,
1275 : JS::Handle<JS::Value> aValue,
1276 : JS::Handle<JS::Value> aKeyVal,
1277 : StructuredCloneWriteInfo& aCloneWriteInfo,
1278 : Key& aKey,
1279 : nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
1280 : {
1281 : // Return DATA_ERR if a key was passed in and this objectStore uses inline
1282 : // keys.
1283 0 : if (!aKeyVal.isUndefined() && HasValidKeyPath()) {
1284 0 : return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
1285 : }
1286 :
1287 0 : bool isAutoIncrement = AutoIncrement();
1288 :
1289 : nsresult rv;
1290 :
1291 0 : if (!HasValidKeyPath()) {
1292 : // Out-of-line keys must be passed in.
1293 0 : rv = aKey.SetFromJSVal(aCx, aKeyVal);
1294 0 : if (NS_FAILED(rv)) {
1295 0 : return rv;
1296 : }
1297 0 : } else if (!isAutoIncrement) {
1298 0 : rv = GetKeyPath().ExtractKey(aCx, aValue, aKey);
1299 0 : if (NS_FAILED(rv)) {
1300 0 : return rv;
1301 : }
1302 : }
1303 :
1304 : // Return DATA_ERR if no key was specified this isn't an autoIncrement
1305 : // objectStore.
1306 0 : if (aKey.IsUnset() && !isAutoIncrement) {
1307 0 : return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
1308 : }
1309 :
1310 : // Figure out indexes and the index values to update here.
1311 0 : const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
1312 :
1313 0 : const uint32_t idxCount = indexes.Length();
1314 0 : aUpdateInfoArray.SetCapacity(idxCount); // Pretty good estimate
1315 :
1316 0 : for (uint32_t idxIndex = 0; idxIndex < idxCount; idxIndex++) {
1317 0 : const IndexMetadata& metadata = indexes[idxIndex];
1318 :
1319 0 : rv = AppendIndexUpdateInfo(metadata.id(), metadata.keyPath(),
1320 0 : metadata.unique(), metadata.multiEntry(),
1321 : metadata.locale(), aCx, aValue,
1322 0 : aUpdateInfoArray);
1323 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1324 0 : return rv;
1325 : }
1326 : }
1327 :
1328 0 : GetAddInfoClosure data(aCloneWriteInfo, aValue);
1329 :
1330 0 : if (isAutoIncrement && HasValidKeyPath()) {
1331 0 : MOZ_ASSERT(aKey.IsUnset());
1332 :
1333 0 : rv = GetKeyPath().ExtractOrCreateKey(aCx,
1334 : aValue,
1335 : aKey,
1336 : &GetAddInfoCallback,
1337 0 : &data);
1338 : } else {
1339 0 : rv = GetAddInfoCallback(aCx, &data);
1340 : }
1341 :
1342 0 : return rv;
1343 : }
1344 :
1345 : already_AddRefed<IDBRequest>
1346 0 : IDBObjectStore::AddOrPut(JSContext* aCx,
1347 : JS::Handle<JS::Value> aValue,
1348 : JS::Handle<JS::Value> aKey,
1349 : bool aOverwrite,
1350 : bool aFromCursor,
1351 : ErrorResult& aRv)
1352 : {
1353 0 : AssertIsOnOwningThread();
1354 0 : MOZ_ASSERT(aCx);
1355 0 : MOZ_ASSERT_IF(aFromCursor, aOverwrite);
1356 :
1357 0 : if (mTransaction->GetMode() == IDBTransaction::CLEANUP ||
1358 0 : mDeletedSpec) {
1359 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
1360 0 : return nullptr;
1361 : }
1362 :
1363 0 : if (!mTransaction->IsOpen()) {
1364 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1365 0 : return nullptr;
1366 : }
1367 :
1368 0 : if (!mTransaction->IsWriteAllowed()) {
1369 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
1370 0 : return nullptr;
1371 : }
1372 :
1373 0 : JS::Rooted<JS::Value> value(aCx, aValue);
1374 0 : Key key;
1375 0 : StructuredCloneWriteInfo cloneWriteInfo(mTransaction->Database());
1376 0 : nsTArray<IndexUpdateInfo> updateInfo;
1377 :
1378 0 : aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo);
1379 0 : if (aRv.Failed()) {
1380 0 : return nullptr;
1381 : }
1382 :
1383 : // Check the size limit of the serialized message which mainly consists of
1384 : // a StructuredCloneBuffer, an encoded object key, and the encoded index keys.
1385 : // kMaxIDBMsgOverhead covers the minor stuff not included in this calculation
1386 : // because the precise calculation would slow down this AddOrPut operation.
1387 : static const size_t kMaxIDBMsgOverhead = 1024 * 1024; // 1MB
1388 : const uint32_t maximalSizeFromPref =
1389 0 : IndexedDatabaseManager::MaxSerializedMsgSize();
1390 0 : MOZ_ASSERT(maximalSizeFromPref > kMaxIDBMsgOverhead);
1391 0 : const size_t kMaxMessageSize = maximalSizeFromPref - kMaxIDBMsgOverhead;
1392 :
1393 0 : size_t indexUpdateInfoSize = 0;
1394 0 : for (size_t i = 0; i < updateInfo.Length(); i++) {
1395 0 : indexUpdateInfoSize += updateInfo[i].value().GetBuffer().Length();
1396 0 : indexUpdateInfoSize += updateInfo[i].localizedValue().GetBuffer().Length();
1397 : }
1398 :
1399 0 : size_t messageSize = cloneWriteInfo.mCloneBuffer.data().Size() +
1400 0 : key.GetBuffer().Length() + indexUpdateInfoSize;
1401 :
1402 0 : if (messageSize > kMaxMessageSize) {
1403 0 : IDB_REPORT_INTERNAL_ERR();
1404 0 : aRv.ThrowDOMException(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR,
1405 0 : nsPrintfCString("The serialized value is too large"
1406 : " (size=%zu bytes, max=%zu bytes).",
1407 0 : messageSize, kMaxMessageSize));
1408 0 : return nullptr;
1409 : }
1410 :
1411 0 : ObjectStoreAddPutParams commonParams;
1412 0 : commonParams.objectStoreId() = Id();
1413 0 : commonParams.cloneInfo().data().data = Move(cloneWriteInfo.mCloneBuffer.data());
1414 0 : commonParams.cloneInfo().offsetToKeyProp() = cloneWriteInfo.mOffsetToKeyProp;
1415 0 : commonParams.key() = key;
1416 0 : commonParams.indexUpdateInfos().SwapElements(updateInfo);
1417 :
1418 : // Convert any blobs or mutable files into FileAddInfo.
1419 0 : nsTArray<StructuredCloneFile>& files = cloneWriteInfo.mFiles;
1420 :
1421 0 : if (!files.IsEmpty()) {
1422 0 : const uint32_t count = files.Length();
1423 :
1424 0 : FallibleTArray<FileAddInfo> fileAddInfos;
1425 0 : if (NS_WARN_IF(!fileAddInfos.SetCapacity(count, fallible))) {
1426 0 : aRv = NS_ERROR_OUT_OF_MEMORY;
1427 0 : return nullptr;
1428 : }
1429 :
1430 0 : IDBDatabase* database = mTransaction->Database();
1431 :
1432 0 : for (uint32_t index = 0; index < count; index++) {
1433 0 : StructuredCloneFile& file = files[index];
1434 :
1435 0 : FileAddInfo* fileAddInfo = fileAddInfos.AppendElement(fallible);
1436 0 : MOZ_ASSERT(fileAddInfo);
1437 :
1438 0 : switch (file.mType) {
1439 : case StructuredCloneFile::eBlob: {
1440 0 : MOZ_ASSERT(file.mBlob);
1441 0 : MOZ_ASSERT(!file.mMutableFile);
1442 :
1443 : PBackgroundIDBDatabaseFileChild* fileActor =
1444 0 : database->GetOrCreateFileActorForBlob(file.mBlob);
1445 0 : if (NS_WARN_IF(!fileActor)) {
1446 0 : IDB_REPORT_INTERNAL_ERR();
1447 0 : aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1448 0 : return nullptr;
1449 : }
1450 :
1451 0 : fileAddInfo->file() = fileActor;
1452 0 : fileAddInfo->type() = StructuredCloneFile::eBlob;
1453 :
1454 0 : break;
1455 : }
1456 :
1457 : case StructuredCloneFile::eMutableFile: {
1458 0 : MOZ_ASSERT(file.mMutableFile);
1459 0 : MOZ_ASSERT(!file.mBlob);
1460 :
1461 : PBackgroundMutableFileChild* mutableFileActor =
1462 0 : file.mMutableFile->GetBackgroundActor();
1463 0 : if (NS_WARN_IF(!mutableFileActor)) {
1464 0 : IDB_REPORT_INTERNAL_ERR();
1465 0 : aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1466 0 : return nullptr;
1467 : }
1468 :
1469 0 : fileAddInfo->file() = mutableFileActor;
1470 0 : fileAddInfo->type() = StructuredCloneFile::eMutableFile;
1471 :
1472 0 : break;
1473 : }
1474 :
1475 : case StructuredCloneFile::eWasmBytecode:
1476 : case StructuredCloneFile::eWasmCompiled: {
1477 0 : MOZ_ASSERT(file.mBlob);
1478 0 : MOZ_ASSERT(!file.mMutableFile);
1479 :
1480 : PBackgroundIDBDatabaseFileChild* fileActor =
1481 0 : database->GetOrCreateFileActorForBlob(file.mBlob);
1482 0 : if (NS_WARN_IF(!fileActor)) {
1483 0 : IDB_REPORT_INTERNAL_ERR();
1484 0 : aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1485 0 : return nullptr;
1486 : }
1487 :
1488 0 : fileAddInfo->file() = fileActor;
1489 0 : fileAddInfo->type() = file.mType;
1490 :
1491 0 : break;
1492 : }
1493 :
1494 : default:
1495 0 : MOZ_CRASH("Should never get here!");
1496 : }
1497 : }
1498 :
1499 0 : commonParams.fileAddInfos().SwapElements(fileAddInfos);
1500 : }
1501 :
1502 0 : RequestParams params;
1503 0 : if (aOverwrite) {
1504 0 : params = ObjectStorePutParams(commonParams);
1505 : } else {
1506 0 : params = ObjectStoreAddParams(commonParams);
1507 : }
1508 :
1509 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
1510 0 : MOZ_ASSERT(request);
1511 :
1512 0 : if (!aFromCursor) {
1513 0 : if (aOverwrite) {
1514 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1515 : "database(%s).transaction(%s).objectStore(%s).put(%s)",
1516 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.put()",
1517 : IDB_LOG_ID_STRING(),
1518 : mTransaction->LoggingSerialNumber(),
1519 : request->LoggingSerialNumber(),
1520 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1521 : IDB_LOG_STRINGIFY(mTransaction),
1522 : IDB_LOG_STRINGIFY(this),
1523 : IDB_LOG_STRINGIFY(key));
1524 : } else {
1525 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1526 : "database(%s).transaction(%s).objectStore(%s).add(%s)",
1527 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.add()",
1528 : IDB_LOG_ID_STRING(),
1529 : mTransaction->LoggingSerialNumber(),
1530 : request->LoggingSerialNumber(),
1531 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1532 : IDB_LOG_STRINGIFY(mTransaction),
1533 : IDB_LOG_STRINGIFY(this),
1534 : IDB_LOG_STRINGIFY(key));
1535 : }
1536 : }
1537 :
1538 0 : mTransaction->StartRequest(request, params);
1539 :
1540 0 : return request.forget();
1541 : }
1542 :
1543 : already_AddRefed<IDBRequest>
1544 0 : IDBObjectStore::GetAllInternal(bool aKeysOnly,
1545 : JSContext* aCx,
1546 : JS::Handle<JS::Value> aKey,
1547 : const Optional<uint32_t>& aLimit,
1548 : ErrorResult& aRv)
1549 : {
1550 0 : AssertIsOnOwningThread();
1551 :
1552 0 : if (mDeletedSpec) {
1553 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
1554 0 : return nullptr;
1555 : }
1556 :
1557 0 : if (!mTransaction->IsOpen()) {
1558 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1559 0 : return nullptr;
1560 : }
1561 :
1562 0 : RefPtr<IDBKeyRange> keyRange;
1563 0 : aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
1564 0 : if (NS_WARN_IF(aRv.Failed())) {
1565 0 : return nullptr;
1566 : }
1567 :
1568 0 : const int64_t id = Id();
1569 :
1570 0 : OptionalKeyRange optionalKeyRange;
1571 0 : if (keyRange) {
1572 0 : SerializedKeyRange serializedKeyRange;
1573 0 : keyRange->ToSerialized(serializedKeyRange);
1574 0 : optionalKeyRange = serializedKeyRange;
1575 : } else {
1576 0 : optionalKeyRange = void_t();
1577 : }
1578 :
1579 0 : const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0;
1580 :
1581 0 : RequestParams params;
1582 0 : if (aKeysOnly) {
1583 0 : params = ObjectStoreGetAllKeysParams(id, optionalKeyRange, limit);
1584 : } else {
1585 0 : params = ObjectStoreGetAllParams(id, optionalKeyRange, limit);
1586 : }
1587 :
1588 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
1589 0 : MOZ_ASSERT(request);
1590 :
1591 0 : if (aKeysOnly) {
1592 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1593 : "database(%s).transaction(%s).objectStore(%s)."
1594 : "getAllKeys(%s, %s)",
1595 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAllKeys()",
1596 : IDB_LOG_ID_STRING(),
1597 : mTransaction->LoggingSerialNumber(),
1598 : request->LoggingSerialNumber(),
1599 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1600 : IDB_LOG_STRINGIFY(mTransaction),
1601 : IDB_LOG_STRINGIFY(this),
1602 : IDB_LOG_STRINGIFY(keyRange),
1603 : IDB_LOG_STRINGIFY(aLimit));
1604 : } else {
1605 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1606 : "database(%s).transaction(%s).objectStore(%s)."
1607 : "getAll(%s, %s)",
1608 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAll()",
1609 : IDB_LOG_ID_STRING(),
1610 : mTransaction->LoggingSerialNumber(),
1611 : request->LoggingSerialNumber(),
1612 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1613 : IDB_LOG_STRINGIFY(mTransaction),
1614 : IDB_LOG_STRINGIFY(this),
1615 : IDB_LOG_STRINGIFY(keyRange),
1616 : IDB_LOG_STRINGIFY(aLimit));
1617 : }
1618 :
1619 0 : mTransaction->StartRequest(request, params);
1620 :
1621 0 : return request.forget();
1622 : }
1623 :
1624 : already_AddRefed<IDBRequest>
1625 0 : IDBObjectStore::Clear(JSContext* aCx, ErrorResult& aRv)
1626 : {
1627 0 : AssertIsOnOwningThread();
1628 :
1629 0 : if (mDeletedSpec) {
1630 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
1631 0 : return nullptr;
1632 : }
1633 :
1634 0 : if (!mTransaction->IsOpen()) {
1635 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1636 0 : return nullptr;
1637 : }
1638 :
1639 0 : if (!mTransaction->IsWriteAllowed()) {
1640 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
1641 0 : return nullptr;
1642 : }
1643 :
1644 0 : ObjectStoreClearParams params;
1645 0 : params.objectStoreId() = Id();
1646 :
1647 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
1648 0 : MOZ_ASSERT(request);
1649 :
1650 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1651 : "database(%s).transaction(%s).objectStore(%s).clear()",
1652 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.clear()",
1653 : IDB_LOG_ID_STRING(),
1654 : mTransaction->LoggingSerialNumber(),
1655 : request->LoggingSerialNumber(),
1656 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1657 : IDB_LOG_STRINGIFY(mTransaction),
1658 : IDB_LOG_STRINGIFY(this));
1659 :
1660 0 : mTransaction->StartRequest(request, params);
1661 :
1662 0 : return request.forget();
1663 : }
1664 :
1665 : already_AddRefed<IDBIndex>
1666 0 : IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv)
1667 : {
1668 0 : AssertIsOnOwningThread();
1669 :
1670 0 : if (mTransaction->IsCommittingOrDone() || mDeletedSpec) {
1671 0 : aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1672 0 : return nullptr;
1673 : }
1674 :
1675 0 : const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
1676 :
1677 0 : const IndexMetadata* metadata = nullptr;
1678 :
1679 0 : for (uint32_t idxCount = indexes.Length(), idxIndex = 0;
1680 0 : idxIndex < idxCount;
1681 : idxIndex++) {
1682 0 : const IndexMetadata& index = indexes[idxIndex];
1683 0 : if (index.name() == aName) {
1684 0 : metadata = &index;
1685 0 : break;
1686 : }
1687 : }
1688 :
1689 0 : if (!metadata) {
1690 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
1691 0 : return nullptr;
1692 : }
1693 :
1694 0 : const int64_t desiredId = metadata->id();
1695 :
1696 0 : RefPtr<IDBIndex> index;
1697 :
1698 0 : for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
1699 0 : idxIndex < idxCount;
1700 : idxIndex++) {
1701 0 : RefPtr<IDBIndex>& existingIndex = mIndexes[idxIndex];
1702 :
1703 0 : if (existingIndex->Id() == desiredId) {
1704 0 : index = existingIndex;
1705 0 : break;
1706 : }
1707 : }
1708 :
1709 0 : if (!index) {
1710 0 : index = IDBIndex::Create(this, *metadata);
1711 0 : MOZ_ASSERT(index);
1712 :
1713 0 : mIndexes.AppendElement(index);
1714 : }
1715 :
1716 0 : return index.forget();
1717 : }
1718 :
1719 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
1720 :
1721 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore)
1722 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
1723 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
1724 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
1725 :
1726 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
1727 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
1728 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes)
1729 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes)
1730 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1731 :
1732 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
1733 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
1734 :
1735 : // Don't unlink mTransaction!
1736 :
1737 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes)
1738 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedIndexes)
1739 :
1740 0 : tmp->mCachedKeyPath.setUndefined();
1741 :
1742 0 : if (tmp->mRooted) {
1743 0 : mozilla::DropJSObjects(tmp);
1744 0 : tmp->mRooted = false;
1745 : }
1746 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1747 :
1748 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore)
1749 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1750 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
1751 0 : NS_INTERFACE_MAP_END
1752 :
1753 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore)
1754 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore)
1755 :
1756 : JSObject*
1757 0 : IDBObjectStore::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
1758 : {
1759 0 : return IDBObjectStoreBinding::Wrap(aCx, this, aGivenProto);
1760 : }
1761 :
1762 : nsPIDOMWindowInner*
1763 0 : IDBObjectStore::GetParentObject() const
1764 : {
1765 0 : return mTransaction->GetParentObject();
1766 : }
1767 :
1768 : void
1769 0 : IDBObjectStore::GetKeyPath(JSContext* aCx,
1770 : JS::MutableHandle<JS::Value> aResult,
1771 : ErrorResult& aRv)
1772 : {
1773 0 : if (!mCachedKeyPath.isUndefined()) {
1774 0 : aResult.set(mCachedKeyPath);
1775 0 : return;
1776 : }
1777 :
1778 0 : aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
1779 0 : if (NS_WARN_IF(aRv.Failed())) {
1780 0 : return;
1781 : }
1782 :
1783 0 : if (mCachedKeyPath.isGCThing()) {
1784 0 : mozilla::HoldJSObjects(this);
1785 0 : mRooted = true;
1786 : }
1787 :
1788 0 : aResult.set(mCachedKeyPath);
1789 : }
1790 :
1791 : already_AddRefed<DOMStringList>
1792 0 : IDBObjectStore::IndexNames()
1793 : {
1794 0 : AssertIsOnOwningThread();
1795 :
1796 0 : const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
1797 :
1798 0 : RefPtr<DOMStringList> list = new DOMStringList();
1799 :
1800 0 : if (!indexes.IsEmpty()) {
1801 0 : nsTArray<nsString>& listNames = list->StringArray();
1802 0 : listNames.SetCapacity(indexes.Length());
1803 :
1804 0 : for (uint32_t index = 0; index < indexes.Length(); index++) {
1805 0 : listNames.InsertElementSorted(indexes[index].name());
1806 : }
1807 : }
1808 :
1809 0 : return list.forget();
1810 : }
1811 :
1812 : already_AddRefed<IDBRequest>
1813 0 : IDBObjectStore::GetInternal(bool aKeyOnly,
1814 : JSContext* aCx,
1815 : JS::Handle<JS::Value> aKey,
1816 : ErrorResult& aRv)
1817 : {
1818 0 : AssertIsOnOwningThread();
1819 :
1820 0 : if (mDeletedSpec) {
1821 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
1822 0 : return nullptr;
1823 : }
1824 :
1825 0 : if (!mTransaction->IsOpen()) {
1826 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1827 0 : return nullptr;
1828 : }
1829 :
1830 0 : RefPtr<IDBKeyRange> keyRange;
1831 0 : aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
1832 0 : if (aRv.Failed()) {
1833 0 : return nullptr;
1834 : }
1835 :
1836 0 : if (!keyRange) {
1837 : // Must specify a key or keyRange for get().
1838 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
1839 0 : return nullptr;
1840 : }
1841 :
1842 0 : const int64_t id = Id();
1843 :
1844 0 : SerializedKeyRange serializedKeyRange;
1845 0 : keyRange->ToSerialized(serializedKeyRange);
1846 :
1847 0 : RequestParams params;
1848 0 : if (aKeyOnly) {
1849 0 : params = ObjectStoreGetKeyParams(id, serializedKeyRange);
1850 : } else {
1851 0 : params = ObjectStoreGetParams(id, serializedKeyRange);
1852 : }
1853 :
1854 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
1855 0 : MOZ_ASSERT(request);
1856 :
1857 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1858 : "database(%s).transaction(%s).objectStore(%s).get(%s)",
1859 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.get()",
1860 : IDB_LOG_ID_STRING(),
1861 : mTransaction->LoggingSerialNumber(),
1862 : request->LoggingSerialNumber(),
1863 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1864 : IDB_LOG_STRINGIFY(mTransaction),
1865 : IDB_LOG_STRINGIFY(this),
1866 : IDB_LOG_STRINGIFY(keyRange));
1867 :
1868 0 : mTransaction->StartRequest(request, params);
1869 :
1870 0 : return request.forget();
1871 : }
1872 :
1873 : already_AddRefed<IDBRequest>
1874 0 : IDBObjectStore::DeleteInternal(JSContext* aCx,
1875 : JS::Handle<JS::Value> aKey,
1876 : bool aFromCursor,
1877 : ErrorResult& aRv)
1878 : {
1879 0 : AssertIsOnOwningThread();
1880 :
1881 0 : if (mDeletedSpec) {
1882 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
1883 0 : return nullptr;
1884 : }
1885 :
1886 0 : if (!mTransaction->IsOpen()) {
1887 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1888 0 : return nullptr;
1889 : }
1890 :
1891 0 : if (!mTransaction->IsWriteAllowed()) {
1892 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
1893 0 : return nullptr;
1894 : }
1895 :
1896 0 : RefPtr<IDBKeyRange> keyRange;
1897 0 : aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
1898 0 : if (NS_WARN_IF((aRv.Failed()))) {
1899 0 : return nullptr;
1900 : }
1901 :
1902 0 : if (!keyRange) {
1903 : // Must specify a key or keyRange for delete().
1904 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
1905 0 : return nullptr;
1906 : }
1907 :
1908 0 : ObjectStoreDeleteParams params;
1909 0 : params.objectStoreId() = Id();
1910 0 : keyRange->ToSerialized(params.keyRange());
1911 :
1912 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
1913 0 : MOZ_ASSERT(request);
1914 :
1915 0 : if (!aFromCursor) {
1916 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
1917 : "database(%s).transaction(%s).objectStore(%s).delete(%s)",
1918 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.delete()",
1919 : IDB_LOG_ID_STRING(),
1920 : mTransaction->LoggingSerialNumber(),
1921 : request->LoggingSerialNumber(),
1922 : IDB_LOG_STRINGIFY(mTransaction->Database()),
1923 : IDB_LOG_STRINGIFY(mTransaction),
1924 : IDB_LOG_STRINGIFY(this),
1925 : IDB_LOG_STRINGIFY(keyRange));
1926 : }
1927 :
1928 0 : mTransaction->StartRequest(request, params);
1929 :
1930 0 : return request.forget();
1931 : }
1932 :
1933 : already_AddRefed<IDBIndex>
1934 0 : IDBObjectStore::CreateIndex(const nsAString& aName,
1935 : const StringOrStringSequence& aKeyPath,
1936 : const IDBIndexParameters& aOptionalParameters,
1937 : ErrorResult& aRv)
1938 : {
1939 0 : AssertIsOnOwningThread();
1940 :
1941 0 : if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
1942 0 : mDeletedSpec) {
1943 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
1944 0 : return nullptr;
1945 : }
1946 :
1947 0 : IDBTransaction* transaction = IDBTransaction::GetCurrent();
1948 0 : if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
1949 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1950 0 : return nullptr;
1951 : }
1952 :
1953 0 : auto& indexes = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
1954 0 : for (uint32_t count = indexes.Length(), index = 0;
1955 0 : index < count;
1956 : index++) {
1957 0 : if (aName == indexes[index].name()) {
1958 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
1959 0 : return nullptr;
1960 : }
1961 : }
1962 :
1963 0 : KeyPath keyPath(0);
1964 0 : if (aKeyPath.IsString()) {
1965 0 : if (NS_FAILED(KeyPath::Parse(aKeyPath.GetAsString(), &keyPath)) ||
1966 0 : !keyPath.IsValid()) {
1967 0 : aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
1968 0 : return nullptr;
1969 : }
1970 : } else {
1971 0 : MOZ_ASSERT(aKeyPath.IsStringSequence());
1972 0 : if (aKeyPath.GetAsStringSequence().IsEmpty() ||
1973 0 : NS_FAILED(KeyPath::Parse(aKeyPath.GetAsStringSequence(), &keyPath)) ||
1974 0 : !keyPath.IsValid()) {
1975 0 : aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
1976 0 : return nullptr;
1977 : }
1978 : }
1979 :
1980 0 : if (aOptionalParameters.mMultiEntry && keyPath.IsArray()) {
1981 0 : aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
1982 0 : return nullptr;
1983 : }
1984 :
1985 : #ifdef DEBUG
1986 0 : for (uint32_t count = mIndexes.Length(), index = 0;
1987 0 : index < count;
1988 : index++) {
1989 0 : MOZ_ASSERT(mIndexes[index]->Name() != aName);
1990 : }
1991 : #endif
1992 :
1993 : const IndexMetadata* oldMetadataElements =
1994 0 : indexes.IsEmpty() ? nullptr : indexes.Elements();
1995 :
1996 : // With this setup we only validate the passed in locale name by the time we
1997 : // get to encoding Keys. Maybe we should do it here right away and error out.
1998 :
1999 : // Valid locale names are always ASCII as per BCP-47.
2000 0 : nsCString locale = NS_LossyConvertUTF16toASCII(aOptionalParameters.mLocale);
2001 0 : bool autoLocale = locale.EqualsASCII("auto");
2002 : #ifdef ENABLE_INTL_API
2003 0 : if (autoLocale) {
2004 0 : locale = IndexedDatabaseManager::GetLocale();
2005 : }
2006 : #endif
2007 :
2008 0 : IndexMetadata* metadata = indexes.AppendElement(
2009 0 : IndexMetadata(transaction->NextIndexId(), nsString(aName), keyPath,
2010 : locale,
2011 : aOptionalParameters.mUnique,
2012 : aOptionalParameters.mMultiEntry,
2013 0 : autoLocale));
2014 :
2015 0 : if (oldMetadataElements &&
2016 0 : oldMetadataElements != indexes.Elements()) {
2017 0 : MOZ_ASSERT(indexes.Length() > 1);
2018 :
2019 : // Array got moved, update the spec pointers for all live indexes.
2020 0 : RefreshSpec(/* aMayDelete */ false);
2021 : }
2022 :
2023 0 : transaction->CreateIndex(this, *metadata);
2024 :
2025 0 : RefPtr<IDBIndex> index = IDBIndex::Create(this, *metadata);
2026 0 : MOZ_ASSERT(index);
2027 :
2028 0 : mIndexes.AppendElement(index);
2029 :
2030 : // Don't do this in the macro because we always need to increment the serial
2031 : // number to keep in sync with the parent.
2032 0 : const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
2033 :
2034 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
2035 : "database(%s).transaction(%s).objectStore(%s).createIndex(%s)",
2036 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.createIndex()",
2037 : IDB_LOG_ID_STRING(),
2038 : mTransaction->LoggingSerialNumber(),
2039 : requestSerialNumber,
2040 : IDB_LOG_STRINGIFY(mTransaction->Database()),
2041 : IDB_LOG_STRINGIFY(mTransaction),
2042 : IDB_LOG_STRINGIFY(this),
2043 : IDB_LOG_STRINGIFY(index));
2044 :
2045 0 : return index.forget();
2046 : }
2047 :
2048 : void
2049 0 : IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv)
2050 : {
2051 0 : AssertIsOnOwningThread();
2052 :
2053 0 : if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
2054 0 : mDeletedSpec) {
2055 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
2056 0 : return;
2057 : }
2058 :
2059 0 : IDBTransaction* transaction = IDBTransaction::GetCurrent();
2060 0 : if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
2061 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
2062 0 : return;
2063 : }
2064 :
2065 0 : auto& metadataArray = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
2066 :
2067 0 : int64_t foundId = 0;
2068 :
2069 0 : for (uint32_t metadataCount = metadataArray.Length(), metadataIndex = 0;
2070 0 : metadataIndex < metadataCount;
2071 : metadataIndex++) {
2072 0 : const IndexMetadata& metadata = metadataArray[metadataIndex];
2073 0 : MOZ_ASSERT(metadata.id());
2074 :
2075 0 : if (aName == metadata.name()) {
2076 0 : foundId = metadata.id();
2077 :
2078 : // Must do this before altering the metadata array!
2079 0 : for (uint32_t indexCount = mIndexes.Length(), indexIndex = 0;
2080 0 : indexIndex < indexCount;
2081 : indexIndex++) {
2082 0 : RefPtr<IDBIndex>& index = mIndexes[indexIndex];
2083 :
2084 0 : if (index->Id() == foundId) {
2085 0 : index->NoteDeletion();
2086 :
2087 : RefPtr<IDBIndex>* deletedIndex =
2088 0 : mDeletedIndexes.AppendElement();
2089 0 : deletedIndex->swap(mIndexes[indexIndex]);
2090 :
2091 0 : mIndexes.RemoveElementAt(indexIndex);
2092 0 : break;
2093 : }
2094 : }
2095 :
2096 0 : metadataArray.RemoveElementAt(metadataIndex);
2097 :
2098 0 : RefreshSpec(/* aMayDelete */ false);
2099 0 : break;
2100 : }
2101 : }
2102 :
2103 0 : if (!foundId) {
2104 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
2105 0 : return;
2106 : }
2107 :
2108 : // Don't do this in the macro because we always need to increment the serial
2109 : // number to keep in sync with the parent.
2110 0 : const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
2111 :
2112 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
2113 : "database(%s).transaction(%s).objectStore(%s)."
2114 : "deleteIndex(\"%s\")",
2115 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.deleteIndex()",
2116 : IDB_LOG_ID_STRING(),
2117 : mTransaction->LoggingSerialNumber(),
2118 : requestSerialNumber,
2119 : IDB_LOG_STRINGIFY(mTransaction->Database()),
2120 : IDB_LOG_STRINGIFY(mTransaction),
2121 : IDB_LOG_STRINGIFY(this),
2122 : NS_ConvertUTF16toUTF8(aName).get());
2123 :
2124 0 : transaction->DeleteIndex(this, foundId);
2125 : }
2126 :
2127 : already_AddRefed<IDBRequest>
2128 0 : IDBObjectStore::Count(JSContext* aCx,
2129 : JS::Handle<JS::Value> aKey,
2130 : ErrorResult& aRv)
2131 : {
2132 0 : AssertIsOnOwningThread();
2133 :
2134 0 : if (mDeletedSpec) {
2135 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
2136 0 : return nullptr;
2137 : }
2138 :
2139 0 : if (!mTransaction->IsOpen()) {
2140 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
2141 0 : return nullptr;
2142 : }
2143 :
2144 0 : RefPtr<IDBKeyRange> keyRange;
2145 0 : aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
2146 0 : if (aRv.Failed()) {
2147 0 : return nullptr;
2148 : }
2149 :
2150 0 : ObjectStoreCountParams params;
2151 0 : params.objectStoreId() = Id();
2152 :
2153 0 : if (keyRange) {
2154 0 : SerializedKeyRange serializedKeyRange;
2155 0 : keyRange->ToSerialized(serializedKeyRange);
2156 0 : params.optionalKeyRange() = serializedKeyRange;
2157 : } else {
2158 0 : params.optionalKeyRange() = void_t();
2159 : }
2160 :
2161 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
2162 0 : MOZ_ASSERT(request);
2163 :
2164 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
2165 : "database(%s).transaction(%s).objectStore(%s).count(%s)",
2166 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
2167 : IDB_LOG_ID_STRING(),
2168 : mTransaction->LoggingSerialNumber(),
2169 : request->LoggingSerialNumber(),
2170 : IDB_LOG_STRINGIFY(mTransaction->Database()),
2171 : IDB_LOG_STRINGIFY(mTransaction),
2172 : IDB_LOG_STRINGIFY(this),
2173 : IDB_LOG_STRINGIFY(keyRange));
2174 :
2175 0 : mTransaction->StartRequest(request, params);
2176 :
2177 0 : return request.forget();
2178 : }
2179 :
2180 : already_AddRefed<IDBRequest>
2181 0 : IDBObjectStore::OpenCursorInternal(bool aKeysOnly,
2182 : JSContext* aCx,
2183 : JS::Handle<JS::Value> aRange,
2184 : IDBCursorDirection aDirection,
2185 : ErrorResult& aRv)
2186 : {
2187 0 : AssertIsOnOwningThread();
2188 0 : MOZ_ASSERT(aCx);
2189 :
2190 0 : if (mDeletedSpec) {
2191 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
2192 0 : return nullptr;
2193 : }
2194 :
2195 0 : if (!mTransaction->IsOpen()) {
2196 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
2197 0 : return nullptr;
2198 : }
2199 :
2200 0 : RefPtr<IDBKeyRange> keyRange;
2201 0 : aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
2202 0 : if (NS_WARN_IF(aRv.Failed())) {
2203 0 : return nullptr;
2204 : }
2205 :
2206 0 : int64_t objectStoreId = Id();
2207 :
2208 0 : OptionalKeyRange optionalKeyRange;
2209 :
2210 0 : if (keyRange) {
2211 0 : SerializedKeyRange serializedKeyRange;
2212 0 : keyRange->ToSerialized(serializedKeyRange);
2213 :
2214 0 : optionalKeyRange = Move(serializedKeyRange);
2215 : } else {
2216 0 : optionalKeyRange = void_t();
2217 : }
2218 :
2219 0 : IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
2220 :
2221 0 : OpenCursorParams params;
2222 0 : if (aKeysOnly) {
2223 0 : ObjectStoreOpenKeyCursorParams openParams;
2224 0 : openParams.objectStoreId() = objectStoreId;
2225 0 : openParams.optionalKeyRange() = Move(optionalKeyRange);
2226 0 : openParams.direction() = direction;
2227 :
2228 0 : params = Move(openParams);
2229 : } else {
2230 0 : ObjectStoreOpenCursorParams openParams;
2231 0 : openParams.objectStoreId() = objectStoreId;
2232 0 : openParams.optionalKeyRange() = Move(optionalKeyRange);
2233 0 : openParams.direction() = direction;
2234 :
2235 0 : params = Move(openParams);
2236 : }
2237 :
2238 0 : RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
2239 0 : MOZ_ASSERT(request);
2240 :
2241 0 : if (aKeysOnly) {
2242 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
2243 : "database(%s).transaction(%s).objectStore(%s)."
2244 : "openKeyCursor(%s, %s)",
2245 : "IndexedDB %s: C T[%lld] R[%llu]: "
2246 : "IDBObjectStore.openKeyCursor()",
2247 : IDB_LOG_ID_STRING(),
2248 : mTransaction->LoggingSerialNumber(),
2249 : request->LoggingSerialNumber(),
2250 : IDB_LOG_STRINGIFY(mTransaction->Database()),
2251 : IDB_LOG_STRINGIFY(mTransaction),
2252 : IDB_LOG_STRINGIFY(this),
2253 : IDB_LOG_STRINGIFY(keyRange),
2254 : IDB_LOG_STRINGIFY(direction));
2255 : } else {
2256 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
2257 : "database(%s).transaction(%s).objectStore(%s)."
2258 : "openCursor(%s, %s)",
2259 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.openCursor()",
2260 : IDB_LOG_ID_STRING(),
2261 : mTransaction->LoggingSerialNumber(),
2262 : request->LoggingSerialNumber(),
2263 : IDB_LOG_STRINGIFY(mTransaction->Database()),
2264 : IDB_LOG_STRINGIFY(mTransaction),
2265 : IDB_LOG_STRINGIFY(this),
2266 : IDB_LOG_STRINGIFY(keyRange),
2267 : IDB_LOG_STRINGIFY(direction));
2268 : }
2269 :
2270 : BackgroundCursorChild* actor =
2271 0 : new BackgroundCursorChild(request, this, direction);
2272 :
2273 0 : mTransaction->OpenCursor(actor, params);
2274 :
2275 0 : return request.forget();
2276 : }
2277 :
2278 : void
2279 0 : IDBObjectStore::RefreshSpec(bool aMayDelete)
2280 : {
2281 0 : AssertIsOnOwningThread();
2282 0 : MOZ_ASSERT_IF(mDeletedSpec, mSpec == mDeletedSpec);
2283 :
2284 0 : const DatabaseSpec* dbSpec = mTransaction->Database()->Spec();
2285 0 : MOZ_ASSERT(dbSpec);
2286 :
2287 0 : const nsTArray<ObjectStoreSpec>& objectStores = dbSpec->objectStores();
2288 :
2289 0 : bool found = false;
2290 :
2291 0 : for (uint32_t objCount = objectStores.Length(), objIndex = 0;
2292 0 : objIndex < objCount;
2293 : objIndex++) {
2294 0 : const ObjectStoreSpec& objSpec = objectStores[objIndex];
2295 :
2296 0 : if (objSpec.metadata().id() == Id()) {
2297 0 : mSpec = &objSpec;
2298 :
2299 0 : for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
2300 0 : idxIndex < idxCount;
2301 : idxIndex++) {
2302 0 : mIndexes[idxIndex]->RefreshMetadata(aMayDelete);
2303 : }
2304 :
2305 0 : for (uint32_t idxCount = mDeletedIndexes.Length(), idxIndex = 0;
2306 0 : idxIndex < idxCount;
2307 : idxIndex++) {
2308 0 : mDeletedIndexes[idxIndex]->RefreshMetadata(false);
2309 : }
2310 :
2311 0 : found = true;
2312 0 : break;
2313 : }
2314 : }
2315 :
2316 0 : MOZ_ASSERT_IF(!aMayDelete && !mDeletedSpec, found);
2317 :
2318 0 : if (found) {
2319 0 : MOZ_ASSERT(mSpec != mDeletedSpec);
2320 0 : mDeletedSpec = nullptr;
2321 : } else {
2322 0 : NoteDeletion();
2323 : }
2324 0 : }
2325 :
2326 : const ObjectStoreSpec&
2327 0 : IDBObjectStore::Spec() const
2328 : {
2329 0 : AssertIsOnOwningThread();
2330 0 : MOZ_ASSERT(mSpec);
2331 :
2332 0 : return *mSpec;
2333 : }
2334 :
2335 : void
2336 0 : IDBObjectStore::NoteDeletion()
2337 : {
2338 0 : AssertIsOnOwningThread();
2339 0 : MOZ_ASSERT(mSpec);
2340 0 : MOZ_ASSERT(Id() == mSpec->metadata().id());
2341 :
2342 0 : if (mDeletedSpec) {
2343 0 : MOZ_ASSERT(mDeletedSpec == mSpec);
2344 0 : return;
2345 : }
2346 :
2347 : // Copy the spec here.
2348 0 : mDeletedSpec = new ObjectStoreSpec(*mSpec);
2349 0 : mDeletedSpec->indexes().Clear();
2350 :
2351 0 : mSpec = mDeletedSpec;
2352 :
2353 0 : if (!mIndexes.IsEmpty()) {
2354 0 : for (uint32_t count = mIndexes.Length(), index = 0;
2355 0 : index < count;
2356 : index++) {
2357 0 : mIndexes[index]->NoteDeletion();
2358 : }
2359 : }
2360 : }
2361 :
2362 : const nsString&
2363 0 : IDBObjectStore::Name() const
2364 : {
2365 0 : AssertIsOnOwningThread();
2366 0 : MOZ_ASSERT(mSpec);
2367 :
2368 0 : return mSpec->metadata().name();
2369 : }
2370 :
2371 : void
2372 0 : IDBObjectStore::SetName(const nsAString& aName, ErrorResult& aRv)
2373 : {
2374 0 : AssertIsOnOwningThread();
2375 :
2376 0 : if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
2377 0 : mDeletedSpec) {
2378 0 : aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
2379 0 : return;
2380 : }
2381 :
2382 0 : IDBTransaction* transaction = IDBTransaction::GetCurrent();
2383 0 : if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
2384 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
2385 0 : return;
2386 : }
2387 :
2388 0 : if (aName == mSpec->metadata().name()) {
2389 0 : return;
2390 : }
2391 :
2392 : // Cache logging string of this object store before renaming.
2393 0 : const LoggingString loggingOldObjectStore(this);
2394 :
2395 : nsresult rv =
2396 0 : transaction->Database()->RenameObjectStore(mSpec->metadata().id(),
2397 0 : aName);
2398 :
2399 0 : if (NS_FAILED(rv)) {
2400 0 : aRv.Throw(rv);
2401 0 : return;
2402 : }
2403 :
2404 : // Don't do this in the macro because we always need to increment the serial
2405 : // number to keep in sync with the parent.
2406 0 : const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
2407 :
2408 0 : IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
2409 : "database(%s).transaction(%s).objectStore(%s).rename(%s)",
2410 : "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.rename()",
2411 : IDB_LOG_ID_STRING(),
2412 : mTransaction->LoggingSerialNumber(),
2413 : requestSerialNumber,
2414 : IDB_LOG_STRINGIFY(mTransaction->Database()),
2415 : IDB_LOG_STRINGIFY(mTransaction),
2416 : loggingOldObjectStore.get(),
2417 : IDB_LOG_STRINGIFY(this));
2418 :
2419 0 : transaction->RenameObjectStore(mSpec->metadata().id(), aName);
2420 : }
2421 :
2422 : bool
2423 0 : IDBObjectStore::AutoIncrement() const
2424 : {
2425 0 : AssertIsOnOwningThread();
2426 0 : MOZ_ASSERT(mSpec);
2427 :
2428 0 : return mSpec->metadata().autoIncrement();
2429 : }
2430 :
2431 : const indexedDB::KeyPath&
2432 0 : IDBObjectStore::GetKeyPath() const
2433 : {
2434 0 : AssertIsOnOwningThread();
2435 0 : MOZ_ASSERT(mSpec);
2436 :
2437 0 : return mSpec->metadata().keyPath();
2438 : }
2439 :
2440 : bool
2441 0 : IDBObjectStore::HasValidKeyPath() const
2442 : {
2443 0 : AssertIsOnOwningThread();
2444 0 : MOZ_ASSERT(mSpec);
2445 :
2446 0 : return GetKeyPath().IsValid();
2447 : }
2448 :
2449 : } // namespace dom
2450 : } // namespace mozilla
|