Source code

Revision control

Other Tools

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 "IDBFactory.h"
8
9
#include "BackgroundChildImpl.h"
10
#include "IDBRequest.h"
11
#include "IndexedDatabaseManager.h"
12
#include "mozilla/BasePrincipal.h"
13
#include "mozilla/ErrorResult.h"
14
#include "mozilla/Preferences.h"
15
#include "mozilla/SystemGroup.h"
16
#include "mozilla/dom/BindingDeclarations.h"
17
#include "mozilla/dom/IDBFactoryBinding.h"
18
#include "mozilla/dom/quota/QuotaManager.h"
19
#include "mozilla/dom/BrowserChild.h"
20
#include "mozilla/ipc/BackgroundChild.h"
21
#include "mozilla/ipc/BackgroundUtils.h"
22
#include "mozilla/ipc/PBackground.h"
23
#include "mozilla/ipc/PBackgroundChild.h"
24
#include "mozilla/StaticPrefs_dom.h"
25
#include "mozilla/StorageAccess.h"
26
#include "mozilla/Telemetry.h"
27
#include "nsAboutProtocolUtils.h"
28
#include "nsContentUtils.h"
29
#include "nsGlobalWindow.h"
30
#include "nsIAboutModule.h"
31
#include "nsILoadContext.h"
32
#include "nsIURI.h"
33
#include "nsIUUIDGenerator.h"
34
#include "nsIWebNavigation.h"
35
#include "nsSandboxFlags.h"
36
#include "nsServiceManagerUtils.h"
37
#include "ProfilerHelpers.h"
38
#include "ReportInternalError.h"
39
40
// Include this last to avoid path problems on Windows.
41
#include "ActorsChild.h"
42
43
#ifdef DEBUG
44
# include "nsContentUtils.h" // For assertions.
45
#endif
46
47
namespace mozilla {
48
namespace dom {
49
50
using namespace mozilla::dom::indexedDB;
51
using namespace mozilla::dom::quota;
52
using namespace mozilla::ipc;
53
54
namespace {
55
56
Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT IdentifyPrincipalType(
57
const mozilla::ipc::PrincipalInfo& aPrincipalInfo) {
58
switch (aPrincipalInfo.type()) {
59
case PrincipalInfo::TSystemPrincipalInfo:
60
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::system;
61
case PrincipalInfo::TContentPrincipalInfo: {
62
const ContentPrincipalInfo& info =
63
aPrincipalInfo.get_ContentPrincipalInfo();
64
65
nsCOMPtr<nsIURI> uri;
66
67
if (NS_WARN_IF(NS_FAILED(NS_NewURI(getter_AddRefs(uri), info.spec())))) {
68
// This could be discriminated as an extra error value, but this is
69
// extremely unlikely to fail, so we just misuse ContentOther
70
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
71
content_other;
72
}
73
74
// TODO Are there constants defined for the schemes somewhere?
75
if (uri->SchemeIs("file")) {
76
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
77
content_file;
78
}
79
if (uri->SchemeIs("http") || uri->SchemeIs("https")) {
80
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
81
content_http_https;
82
}
83
if (uri->SchemeIs("moz-extension")) {
84
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
85
content_moz_ext;
86
}
87
if (uri->SchemeIs("about")) {
88
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
89
content_about;
90
}
91
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::
92
content_other;
93
}
94
case PrincipalInfo::TExpandedPrincipalInfo:
95
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::expanded;
96
default:
97
return Telemetry::LABELS_IDB_CUSTOM_OPEN_WITH_OPTIONS_COUNT::other;
98
}
99
}
100
101
} // namespace
102
103
struct IDBFactory::PendingRequestInfo {
104
RefPtr<IDBOpenDBRequest> mRequest;
105
FactoryRequestParams mParams;
106
107
PendingRequestInfo(IDBOpenDBRequest* aRequest,
108
const FactoryRequestParams& aParams)
109
: mRequest(aRequest), mParams(aParams) {
110
MOZ_ASSERT(aRequest);
111
MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
112
}
113
};
114
115
IDBFactory::IDBFactory()
116
: mBackgroundActor(nullptr),
117
mInnerWindowID(0),
118
mActiveTransactionCount(0),
119
mActiveDatabaseCount(0),
120
mBackgroundActorFailed(false),
121
mPrivateBrowsingMode(false) {
122
AssertIsOnOwningThread();
123
}
124
125
IDBFactory::~IDBFactory() {
126
MOZ_ASSERT_IF(mBackgroundActorFailed, !mBackgroundActor);
127
128
if (mBackgroundActor) {
129
mBackgroundActor->SendDeleteMeInternal();
130
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
131
}
132
}
133
134
// static
135
nsresult IDBFactory::CreateForWindow(nsPIDOMWindowInner* aWindow,
136
IDBFactory** aFactory) {
137
MOZ_ASSERT(NS_IsMainThread());
138
MOZ_ASSERT(aWindow);
139
MOZ_ASSERT(aFactory);
140
141
nsCOMPtr<nsIPrincipal> principal;
142
nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
143
144
if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) {
145
NS_WARNING("IndexedDB is not permitted in a third-party window.");
146
*aFactory = nullptr;
147
return NS_OK;
148
}
149
150
if (NS_WARN_IF(NS_FAILED(rv))) {
151
if (rv == NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR) {
152
IDB_REPORT_INTERNAL_ERR();
153
}
154
return rv;
155
}
156
157
MOZ_ASSERT(principal);
158
159
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
160
rv = PrincipalToPrincipalInfo(principal, principalInfo);
161
if (NS_WARN_IF(NS_FAILED(rv))) {
162
IDB_REPORT_INTERNAL_ERR();
163
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
164
}
165
166
MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
167
principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
168
169
if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*principalInfo))) {
170
IDB_REPORT_INTERNAL_ERR();
171
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
172
}
173
174
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
175
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
176
177
RefPtr<IDBFactory> factory = new IDBFactory();
178
factory->mPrincipalInfo = std::move(principalInfo);
179
180
factory->mGlobal = do_QueryInterface(aWindow);
181
MOZ_ASSERT(factory->mGlobal);
182
183
factory->mBrowserChild = BrowserChild::GetFrom(aWindow);
184
factory->mEventTarget =
185
nsGlobalWindowInner::Cast(aWindow)->EventTargetFor(TaskCategory::Other);
186
factory->mInnerWindowID = aWindow->WindowID();
187
factory->mPrivateBrowsingMode =
188
loadContext && loadContext->UsePrivateBrowsing();
189
190
factory.forget(aFactory);
191
return NS_OK;
192
}
193
194
// static
195
nsresult IDBFactory::CreateForMainThreadJS(nsIGlobalObject* aGlobal,
196
IDBFactory** aFactory) {
197
MOZ_ASSERT(NS_IsMainThread());
198
MOZ_ASSERT(aGlobal);
199
200
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal);
201
if (NS_WARN_IF(!sop)) {
202
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
203
}
204
205
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
206
nsIPrincipal* principal = sop->GetEffectiveStoragePrincipal();
207
MOZ_ASSERT(principal);
208
bool isSystem;
209
if (!AllowedForPrincipal(principal, &isSystem)) {
210
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
211
}
212
213
nsresult rv = PrincipalToPrincipalInfo(principal, principalInfo);
214
if (NS_WARN_IF(NS_FAILED(rv))) {
215
return rv;
216
}
217
218
if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(*principalInfo))) {
219
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
220
}
221
222
rv = CreateForMainThreadJSInternal(aGlobal, principalInfo, aFactory);
223
if (NS_WARN_IF(NS_FAILED(rv))) {
224
return rv;
225
}
226
227
MOZ_ASSERT(!principalInfo);
228
229
return NS_OK;
230
}
231
232
// static
233
nsresult IDBFactory::CreateForWorker(nsIGlobalObject* aGlobal,
234
const PrincipalInfo& aPrincipalInfo,
235
uint64_t aInnerWindowID,
236
IDBFactory** aFactory) {
237
MOZ_ASSERT(!NS_IsMainThread());
238
MOZ_ASSERT(aGlobal);
239
MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None);
240
241
nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo(aPrincipalInfo));
242
243
nsresult rv =
244
CreateInternal(aGlobal, principalInfo, aInnerWindowID, aFactory);
245
if (NS_WARN_IF(NS_FAILED(rv))) {
246
return rv;
247
}
248
249
MOZ_ASSERT(!principalInfo);
250
251
return NS_OK;
252
}
253
254
// static
255
nsresult IDBFactory::CreateForMainThreadJSInternal(
256
nsIGlobalObject* aGlobal, nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
257
IDBFactory** aFactory) {
258
MOZ_ASSERT(NS_IsMainThread());
259
MOZ_ASSERT(aGlobal);
260
MOZ_ASSERT(aPrincipalInfo);
261
262
IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
263
if (NS_WARN_IF(!mgr)) {
264
IDB_REPORT_INTERNAL_ERR();
265
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
266
}
267
268
nsresult rv =
269
CreateInternal(aGlobal, aPrincipalInfo, /* aInnerWindowID */ 0, aFactory);
270
if (NS_WARN_IF(NS_FAILED(rv))) {
271
return rv;
272
}
273
274
return NS_OK;
275
}
276
277
// static
278
nsresult IDBFactory::CreateInternal(nsIGlobalObject* aGlobal,
279
nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
280
uint64_t aInnerWindowID,
281
IDBFactory** aFactory) {
282
MOZ_ASSERT(aGlobal);
283
MOZ_ASSERT(aPrincipalInfo);
284
MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
285
MOZ_ASSERT(aFactory);
286
287
if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
288
aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
289
NS_WARNING("IndexedDB not allowed for this principal!");
290
aPrincipalInfo = nullptr;
291
*aFactory = nullptr;
292
return NS_OK;
293
}
294
295
RefPtr<IDBFactory> factory = new IDBFactory();
296
factory->mPrincipalInfo = aPrincipalInfo.forget();
297
factory->mGlobal = aGlobal;
298
factory->mEventTarget = GetCurrentThreadEventTarget();
299
factory->mInnerWindowID = aInnerWindowID;
300
301
factory.forget(aFactory);
302
return NS_OK;
303
}
304
305
// static
306
bool IDBFactory::AllowedForWindow(nsPIDOMWindowInner* aWindow) {
307
MOZ_ASSERT(NS_IsMainThread());
308
MOZ_ASSERT(aWindow);
309
310
return !NS_WARN_IF(NS_FAILED(AllowedForWindowInternal(aWindow, nullptr)));
311
}
312
313
// static
314
nsresult IDBFactory::AllowedForWindowInternal(nsPIDOMWindowInner* aWindow,
315
nsIPrincipal** aPrincipal) {
316
MOZ_ASSERT(NS_IsMainThread());
317
MOZ_ASSERT(aWindow);
318
319
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
320
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
321
}
322
323
StorageAccess access = StorageAllowedForWindow(aWindow);
324
325
// the factory callsite records whether the browser is in private browsing.
326
// and thus we don't have to respect that setting here. IndexedDB has no
327
// concept of session-local storage, and thus ignores it.
328
if (access == StorageAccess::eDeny) {
329
return NS_ERROR_DOM_SECURITY_ERR;
330
}
331
332
if (ShouldPartitionStorage(access) &&
333
!StoragePartitioningEnabled(access,
334
aWindow->GetExtantDoc()->CookieSettings())) {
335
return NS_ERROR_DOM_SECURITY_ERR;
336
}
337
338
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
339
MOZ_ASSERT(sop);
340
341
nsCOMPtr<nsIPrincipal> principal = sop->GetEffectiveStoragePrincipal();
342
if (NS_WARN_IF(!principal)) {
343
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
344
}
345
346
if (principal->IsSystemPrincipal()) {
347
principal.forget(aPrincipal);
348
return NS_OK;
349
}
350
351
// About URIs shouldn't be able to access IndexedDB unless they have the
352
// nsIAboutModule::ENABLE_INDEXED_DB flag set on them.
353
354
if (principal->SchemeIs("about")) {
355
uint32_t flags;
356
if (NS_SUCCEEDED(principal->GetAboutModuleFlags(&flags))) {
357
if (!(flags & nsIAboutModule::ENABLE_INDEXED_DB)) {
358
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
359
}
360
} else {
361
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
362
}
363
}
364
365
if (aPrincipal) {
366
principal.forget(aPrincipal);
367
}
368
return NS_OK;
369
}
370
371
// static
372
bool IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal,
373
bool* aIsSystemPrincipal) {
374
MOZ_ASSERT(NS_IsMainThread());
375
MOZ_ASSERT(aPrincipal);
376
377
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
378
return false;
379
}
380
381
if (aPrincipal->IsSystemPrincipal()) {
382
if (aIsSystemPrincipal) {
383
*aIsSystemPrincipal = true;
384
}
385
return true;
386
}
387
388
if (aIsSystemPrincipal) {
389
*aIsSystemPrincipal = false;
390
}
391
392
return !aPrincipal->GetIsNullPrincipal();
393
}
394
395
void IDBFactory::UpdateActiveTransactionCount(int32_t aDelta) {
396
AssertIsOnOwningThread();
397
MOZ_DIAGNOSTIC_ASSERT(aDelta > 0 || (mActiveTransactionCount + aDelta) <
398
mActiveTransactionCount);
399
mActiveTransactionCount += aDelta;
400
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
401
if (window) {
402
window->UpdateActiveIndexedDBTransactionCount(aDelta);
403
}
404
}
405
406
void IDBFactory::UpdateActiveDatabaseCount(int32_t aDelta) {
407
AssertIsOnOwningThread();
408
MOZ_DIAGNOSTIC_ASSERT(aDelta > 0 ||
409
(mActiveDatabaseCount + aDelta) < mActiveDatabaseCount);
410
mActiveDatabaseCount += aDelta;
411
412
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
413
if (window) {
414
window->UpdateActiveIndexedDBDatabaseCount(aDelta);
415
}
416
}
417
418
bool IDBFactory::IsChrome() const {
419
AssertIsOnOwningThread();
420
MOZ_ASSERT(mPrincipalInfo);
421
422
return mPrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo;
423
}
424
425
void IDBFactory::IncrementParentLoggingRequestSerialNumber() {
426
AssertIsOnOwningThread();
427
MOZ_ASSERT(mBackgroundActor);
428
429
mBackgroundActor->SendIncrementLoggingRequestSerialNumber();
430
}
431
432
already_AddRefed<IDBOpenDBRequest> IDBFactory::Open(JSContext* aCx,
433
const nsAString& aName,
434
uint64_t aVersion,
435
CallerType aCallerType,
436
ErrorResult& aRv) {
437
return OpenInternal(aCx,
438
/* aPrincipal */ nullptr, aName,
439
Optional<uint64_t>(aVersion), Optional<StorageType>(),
440
/* aDeleting */ false, aCallerType, aRv);
441
}
442
443
already_AddRefed<IDBOpenDBRequest> IDBFactory::Open(
444
JSContext* aCx, const nsAString& aName, const IDBOpenDBOptions& aOptions,
445
CallerType aCallerType, ErrorResult& aRv) {
446
if (!IsChrome() && aOptions.mStorage.WasPassed()) {
447
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
448
if (window && window->GetExtantDoc()) {
449
window->GetExtantDoc()->WarnOnceAbout(
450
Document::eIDBOpenDBOptions_StorageType);
451
} else if (!NS_IsMainThread()) {
452
// The method below reports on the main thread too, so we need to make
453
// sure we're on a worker. Workers don't have a WarnOnceAbout mechanism,
454
// so this will be reported every time.
455
WorkerPrivate::ReportErrorToConsole("IDBOpenDBOptions_StorageType");
456
}
457
}
458
459
// Ignore calls with empty options for telemetry of usage count.
460
// Unfortunately, we cannot distinguish between the use of the method with
461
// only a single argument (which actually is a standard overload we don't want
462
// to count) an empty dictionary passed explicitly (which is the custom
463
// overload we would like to count). However, we assume that the latter is so
464
// rare that it can be neglected.
465
if (aOptions.IsAnyMemberPresent()) {
466
Telemetry::AccumulateCategorical(IdentifyPrincipalType(*mPrincipalInfo));
467
}
468
469
return OpenInternal(aCx,
470
/* aPrincipal */ nullptr, aName, aOptions.mVersion,
471
aOptions.mStorage,
472
/* aDeleting */ false, aCallerType, aRv);
473
}
474
475
already_AddRefed<IDBOpenDBRequest> IDBFactory::DeleteDatabase(
476
JSContext* aCx, const nsAString& aName, const IDBOpenDBOptions& aOptions,
477
CallerType aCallerType, ErrorResult& aRv) {
478
return OpenInternal(aCx,
479
/* aPrincipal */ nullptr, aName, Optional<uint64_t>(),
480
aOptions.mStorage,
481
/* aDeleting */ true, aCallerType, aRv);
482
}
483
484
int16_t IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
485
JS::Handle<JS::Value> aSecond, ErrorResult& aRv) {
486
Key first, second;
487
auto result = first.SetFromJSVal(aCx, aFirst, aRv);
488
if (!result.Is(Ok, aRv)) {
489
if (result.Is(Invalid, aRv)) {
490
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
491
}
492
return 0;
493
}
494
495
result = second.SetFromJSVal(aCx, aSecond, aRv);
496
if (!result.Is(Ok, aRv)) {
497
if (result.Is(Invalid, aRv)) {
498
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
499
}
500
return 0;
501
}
502
503
if (first.IsUnset() || second.IsUnset()) {
504
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
505
return 0;
506
}
507
508
return Key::CompareKeys(first, second);
509
}
510
511
already_AddRefed<IDBOpenDBRequest> IDBFactory::OpenForPrincipal(
512
JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
513
uint64_t aVersion, SystemCallerGuarantee aGuarantee, ErrorResult& aRv) {
514
MOZ_ASSERT(aPrincipal);
515
if (!NS_IsMainThread()) {
516
MOZ_CRASH(
517
"Figure out security checks for workers! What's this aPrincipal "
518
"we have on a worker thread?");
519
}
520
521
return OpenInternal(aCx, aPrincipal, aName, Optional<uint64_t>(aVersion),
522
Optional<StorageType>(),
523
/* aDeleting */ false, aGuarantee, aRv);
524
}
525
526
already_AddRefed<IDBOpenDBRequest> IDBFactory::OpenForPrincipal(
527
JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
528
const IDBOpenDBOptions& aOptions, SystemCallerGuarantee aGuarantee,
529
ErrorResult& aRv) {
530
MOZ_ASSERT(aPrincipal);
531
if (!NS_IsMainThread()) {
532
MOZ_CRASH(
533
"Figure out security checks for workers! What's this aPrincipal "
534
"we have on a worker thread?");
535
}
536
537
return OpenInternal(aCx, aPrincipal, aName, aOptions.mVersion,
538
aOptions.mStorage,
539
/* aDeleting */ false, aGuarantee, aRv);
540
}
541
542
already_AddRefed<IDBOpenDBRequest> IDBFactory::DeleteForPrincipal(
543
JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
544
const IDBOpenDBOptions& aOptions, SystemCallerGuarantee aGuarantee,
545
ErrorResult& aRv) {
546
MOZ_ASSERT(aPrincipal);
547
if (!NS_IsMainThread()) {
548
MOZ_CRASH(
549
"Figure out security checks for workers! What's this aPrincipal "
550
"we have on a worker thread?");
551
}
552
553
return OpenInternal(aCx, aPrincipal, aName, Optional<uint64_t>(),
554
aOptions.mStorage,
555
/* aDeleting */ true, aGuarantee, aRv);
556
}
557
558
already_AddRefed<IDBOpenDBRequest> IDBFactory::OpenInternal(
559
JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName,
560
const Optional<uint64_t>& aVersion,
561
const Optional<StorageType>& aStorageType, bool aDeleting,
562
CallerType aCallerType, ErrorResult& aRv) {
563
MOZ_ASSERT(mGlobal);
564
565
CommonFactoryRequestParams commonParams;
566
567
PrincipalInfo& principalInfo = commonParams.principalInfo();
568
569
if (aPrincipal) {
570
if (!NS_IsMainThread()) {
571
MOZ_CRASH(
572
"Figure out security checks for workers! What's this "
573
"aPrincipal we have on a worker thread?");
574
}
575
MOZ_ASSERT(aCallerType == CallerType::System);
576
MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode ==
577
(aPrincipal->GetPrivateBrowsingId() > 0));
578
579
if (NS_WARN_IF(
580
NS_FAILED(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)))) {
581
IDB_REPORT_INTERNAL_ERR();
582
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
583
return nullptr;
584
}
585
586
if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
587
principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
588
IDB_REPORT_INTERNAL_ERR();
589
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
590
return nullptr;
591
}
592
593
if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(principalInfo))) {
594
IDB_REPORT_INTERNAL_ERR();
595
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
596
return nullptr;
597
}
598
} else {
599
principalInfo = *mPrincipalInfo;
600
}
601
602
uint64_t version = 0;
603
if (!aDeleting && aVersion.WasPassed()) {
604
if (aVersion.Value() < 1) {
605
aRv.ThrowTypeError(u"0 (Zero) is not a valid database version.");
606
return nullptr;
607
}
608
version = aVersion.Value();
609
}
610
611
// Nothing can be done here if we have previously failed to create a
612
// background actor.
613
if (mBackgroundActorFailed) {
614
IDB_REPORT_INTERNAL_ERR();
615
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
616
return nullptr;
617
}
618
619
PersistenceType persistenceType;
620
621
bool isInternal = principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo;
622
if (!isInternal &&
623
principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
624
nsCString origin =
625
principalInfo.get_ContentPrincipalInfo().originNoSuffix();
626
isInternal = QuotaManager::IsOriginInternal(origin);
627
}
628
629
// Allow storage attributes for add-ons independent of the pref.
630
// This works in the main thread only, workers don't have the principal.
631
bool isAddon = false;
632
if (NS_IsMainThread()) {
633
// aPrincipal is passed inconsistently, so even when we are already on
634
// the main thread, we may have been passed a null aPrincipal.
635
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(principalInfo);
636
if (principal) {
637
nsAutoString addonId;
638
Unused << NS_WARN_IF(NS_FAILED(principal->GetAddonId(addonId)));
639
isAddon = !addonId.IsEmpty();
640
}
641
}
642
643
if (isInternal) {
644
// Chrome privilege and internal origins always get persistent storage.
645
persistenceType = PERSISTENCE_TYPE_PERSISTENT;
646
} else if (isAddon || StaticPrefs::dom_indexedDB_storageOption_enabled()) {
647
persistenceType = PersistenceTypeFromStorage(aStorageType);
648
} else {
649
persistenceType = PERSISTENCE_TYPE_DEFAULT;
650
}
651
652
DatabaseMetadata& metadata = commonParams.metadata();
653
metadata.name() = aName;
654
metadata.persistenceType() = persistenceType;
655
656
FactoryRequestParams params;
657
if (aDeleting) {
658
metadata.version() = 0;
659
params = DeleteDatabaseRequestParams(commonParams);
660
} else {
661
metadata.version() = version;
662
params = OpenDatabaseRequestParams(commonParams);
663
}
664
665
if (!mBackgroundActor) {
666
BackgroundChildImpl::ThreadLocal* threadLocal =
667
BackgroundChildImpl::GetThreadLocalForCurrentThread();
668
669
nsAutoPtr<ThreadLocal> newIDBThreadLocal;
670
ThreadLocal* idbThreadLocal;
671
672
if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
673
idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
674
} else {
675
nsCOMPtr<nsIUUIDGenerator> uuidGen =
676
do_GetService("@mozilla.org/uuid-generator;1");
677
MOZ_ASSERT(uuidGen);
678
679
nsID id;
680
MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id));
681
682
newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id);
683
}
684
685
PBackgroundChild* backgroundActor =
686
BackgroundChild::GetOrCreateForCurrentThread();
687
if (NS_WARN_IF(!backgroundActor)) {
688
IDB_REPORT_INTERNAL_ERR();
689
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
690
return nullptr;
691
}
692
693
{
694
BackgroundFactoryChild* actor = new BackgroundFactoryChild(this);
695
696
// Set EventTarget for the top-level actor.
697
// All child actors created later inherit the same event target.
698
backgroundActor->SetEventTargetForActor(actor, EventTarget());
699
MOZ_ASSERT(actor->GetActorEventTarget());
700
mBackgroundActor = static_cast<BackgroundFactoryChild*>(
701
backgroundActor->SendPBackgroundIDBFactoryConstructor(
702
actor, idbThreadLocal->GetLoggingInfo()));
703
704
if (NS_WARN_IF(!mBackgroundActor)) {
705
mBackgroundActorFailed = true;
706
IDB_REPORT_INTERNAL_ERR();
707
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
708
return nullptr;
709
}
710
}
711
712
if (newIDBThreadLocal) {
713
if (!threadLocal) {
714
threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
715
}
716
MOZ_ASSERT(threadLocal);
717
MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);
718
719
threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
720
}
721
}
722
723
RefPtr<IDBOpenDBRequest> request =
724
IDBOpenDBRequest::Create(aCx, this, mGlobal);
725
if (!request) {
726
MOZ_ASSERT(!NS_IsMainThread());
727
aRv.ThrowUncatchableException();
728
return nullptr;
729
}
730
731
MOZ_ASSERT(request);
732
733
if (aDeleting) {
734
IDB_LOG_MARK_CHILD_REQUEST(
735
"indexedDB.deleteDatabase(\"%s\")", "IDBFactory.deleteDatabase()",
736
request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get());
737
} else {
738
IDB_LOG_MARK_CHILD_REQUEST(
739
"indexedDB.open(\"%s\", %s)", "IDBFactory.open()",
740
request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get(),
741
IDB_LOG_STRINGIFY(aVersion));
742
}
743
744
nsresult rv = InitiateRequest(request, params);
745
if (NS_WARN_IF(NS_FAILED(rv))) {
746
IDB_REPORT_INTERNAL_ERR();
747
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
748
return nullptr;
749
}
750
751
return request.forget();
752
}
753
754
nsresult IDBFactory::InitiateRequest(IDBOpenDBRequest* aRequest,
755
const FactoryRequestParams& aParams) {
756
MOZ_ASSERT(aRequest);
757
MOZ_ASSERT(mBackgroundActor);
758
MOZ_ASSERT(!mBackgroundActorFailed);
759
760
bool deleting;
761
uint64_t requestedVersion;
762
763
switch (aParams.type()) {
764
case FactoryRequestParams::TDeleteDatabaseRequestParams: {
765
const DatabaseMetadata& metadata =
766
aParams.get_DeleteDatabaseRequestParams().commonParams().metadata();
767
deleting = true;
768
requestedVersion = metadata.version();
769
break;
770
}
771
772
case FactoryRequestParams::TOpenDatabaseRequestParams: {
773
const DatabaseMetadata& metadata =
774
aParams.get_OpenDatabaseRequestParams().commonParams().metadata();
775
deleting = false;
776
requestedVersion = metadata.version();
777
break;
778
}
779
780
default:
781
MOZ_CRASH("Should never get here!");
782
}
783
784
auto actor = new BackgroundFactoryRequestChild(this, aRequest, deleting,
785
requestedVersion);
786
787
if (!mBackgroundActor->SendPBackgroundIDBFactoryRequestConstructor(actor,
788
aParams)) {
789
aRequest->DispatchNonTransactionError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
790
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
791
}
792
793
MOZ_ASSERT(actor->GetActorEventTarget(),
794
"The event target shall be inherited from its manager actor.");
795
796
return NS_OK;
797
}
798
799
void IDBFactory::DisconnectFromGlobal(nsIGlobalObject* aOldGlobal) {
800
MOZ_DIAGNOSTIC_ASSERT(aOldGlobal);
801
// If CC unlinks us first, then mGlobal might be nullptr
802
MOZ_DIAGNOSTIC_ASSERT(!mGlobal || mGlobal == aOldGlobal);
803
804
mGlobal = nullptr;
805
}
806
807
NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory)
808
NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory)
809
810
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory)
811
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
812
NS_INTERFACE_MAP_ENTRY(nsISupports)
813
NS_INTERFACE_MAP_END
814
815
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory)
816
817
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory)
818
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
819
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
820
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget)
821
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
822
823
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
824
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
825
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
826
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild)
827
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget)
828
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
829
830
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
831
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
832
NS_IMPL_CYCLE_COLLECTION_TRACE_END
833
834
JSObject* IDBFactory::WrapObject(JSContext* aCx,
835
JS::Handle<JSObject*> aGivenProto) {
836
return IDBFactory_Binding::Wrap(aCx, this, aGivenProto);
837
}
838
839
} // namespace dom
840
} // namespace mozilla