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 "IDBFactory.h"
8 :
9 : #include "BackgroundChildImpl.h"
10 : #include "IDBRequest.h"
11 : #include "IndexedDatabaseManager.h"
12 : #include "mozilla/ErrorResult.h"
13 : #include "mozilla/Preferences.h"
14 : #include "mozilla/SystemGroup.h"
15 : #include "mozilla/dom/BindingDeclarations.h"
16 : #include "mozilla/dom/IDBFactoryBinding.h"
17 : #include "mozilla/dom/TabChild.h"
18 : #include "mozilla/ipc/BackgroundChild.h"
19 : #include "mozilla/ipc/BackgroundUtils.h"
20 : #include "mozilla/ipc/PBackground.h"
21 : #include "mozilla/ipc/PBackgroundChild.h"
22 : #include "mozIThirdPartyUtil.h"
23 : #include "nsAboutProtocolUtils.h"
24 : #include "nsContentUtils.h"
25 : #include "nsGlobalWindow.h"
26 : #include "nsIAboutModule.h"
27 : #include "nsIIPCBackgroundChildCreateCallback.h"
28 : #include "nsILoadContext.h"
29 : #include "nsIPrincipal.h"
30 : #include "nsIURI.h"
31 : #include "nsIUUIDGenerator.h"
32 : #include "nsIWebNavigation.h"
33 : #include "nsSandboxFlags.h"
34 : #include "nsServiceManagerUtils.h"
35 : #include "ProfilerHelpers.h"
36 : #include "ReportInternalError.h"
37 :
38 : // Include this last to avoid path problems on Windows.
39 : #include "ActorsChild.h"
40 :
41 : #ifdef DEBUG
42 : #include "nsContentUtils.h" // For assertions.
43 : #endif
44 :
45 : namespace mozilla {
46 : namespace dom {
47 :
48 : using namespace mozilla::dom::indexedDB;
49 : using namespace mozilla::dom::quota;
50 : using namespace mozilla::ipc;
51 :
52 : namespace {
53 :
54 : const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
55 :
56 : } // namespace
57 :
58 : class IDBFactory::BackgroundCreateCallback final
59 : : public nsIIPCBackgroundChildCreateCallback
60 : {
61 : RefPtr<IDBFactory> mFactory;
62 : LoggingInfo mLoggingInfo;
63 :
64 : public:
65 : explicit
66 0 : BackgroundCreateCallback(IDBFactory* aFactory,
67 : const LoggingInfo& aLoggingInfo)
68 0 : : mFactory(aFactory)
69 0 : , mLoggingInfo(aLoggingInfo)
70 : {
71 0 : MOZ_ASSERT(aFactory);
72 0 : }
73 :
74 : NS_DECL_ISUPPORTS
75 :
76 : private:
77 0 : ~BackgroundCreateCallback()
78 0 : { }
79 :
80 : NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
81 : };
82 :
83 0 : struct IDBFactory::PendingRequestInfo
84 : {
85 : RefPtr<IDBOpenDBRequest> mRequest;
86 : FactoryRequestParams mParams;
87 :
88 0 : PendingRequestInfo(IDBOpenDBRequest* aRequest,
89 : const FactoryRequestParams& aParams)
90 0 : : mRequest(aRequest), mParams(aParams)
91 : {
92 0 : MOZ_ASSERT(aRequest);
93 0 : MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
94 0 : }
95 : };
96 :
97 14 : IDBFactory::IDBFactory()
98 : : mOwningObject(nullptr)
99 : , mBackgroundActor(nullptr)
100 : , mInnerWindowID(0)
101 : , mBackgroundActorFailed(false)
102 14 : , mPrivateBrowsingMode(false)
103 : {
104 14 : AssertIsOnOwningThread();
105 14 : }
106 :
107 0 : IDBFactory::~IDBFactory()
108 : {
109 0 : MOZ_ASSERT_IF(mBackgroundActorFailed, !mBackgroundActor);
110 :
111 0 : mOwningObject = nullptr;
112 0 : mozilla::DropJSObjects(this);
113 :
114 0 : if (mBackgroundActor) {
115 0 : mBackgroundActor->SendDeleteMeInternal();
116 0 : MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
117 : }
118 0 : }
119 :
120 : // static
121 : nsresult
122 0 : IDBFactory::CreateForWindow(nsPIDOMWindowInner* aWindow,
123 : IDBFactory** aFactory)
124 : {
125 0 : MOZ_ASSERT(NS_IsMainThread());
126 0 : MOZ_ASSERT(aWindow);
127 0 : MOZ_ASSERT(aFactory);
128 :
129 0 : nsCOMPtr<nsIPrincipal> principal;
130 0 : nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
131 :
132 0 : if (!(NS_SUCCEEDED(rv) && nsContentUtils::IsSystemPrincipal(principal)) &&
133 0 : NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
134 0 : *aFactory = nullptr;
135 0 : return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
136 : }
137 :
138 0 : if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) {
139 0 : NS_WARNING("IndexedDB is not permitted in a third-party window.");
140 0 : *aFactory = nullptr;
141 0 : return NS_OK;
142 : }
143 :
144 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
145 0 : if (rv == NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR) {
146 0 : IDB_REPORT_INTERNAL_ERR();
147 : }
148 0 : return rv;
149 : }
150 :
151 0 : MOZ_ASSERT(principal);
152 :
153 0 : nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
154 0 : rv = PrincipalToPrincipalInfo(principal, principalInfo);
155 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
156 0 : IDB_REPORT_INTERNAL_ERR();
157 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
158 : }
159 :
160 0 : MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo ||
161 : principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo);
162 :
163 0 : nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
164 0 : nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
165 :
166 0 : RefPtr<IDBFactory> factory = new IDBFactory();
167 0 : factory->mPrincipalInfo = Move(principalInfo);
168 0 : factory->mWindow = aWindow;
169 0 : factory->mTabChild = TabChild::GetFrom(aWindow);
170 0 : factory->mEventTarget =
171 0 : nsGlobalWindow::Cast(aWindow)->EventTargetFor(TaskCategory::Other);
172 0 : factory->mInnerWindowID = aWindow->WindowID();
173 0 : factory->mPrivateBrowsingMode =
174 0 : loadContext && loadContext->UsePrivateBrowsing();
175 :
176 0 : factory.forget(aFactory);
177 0 : return NS_OK;
178 : }
179 :
180 : // static
181 : nsresult
182 14 : IDBFactory::CreateForMainThreadJS(JSContext* aCx,
183 : JS::Handle<JSObject*> aOwningObject,
184 : IDBFactory** aFactory)
185 : {
186 14 : MOZ_ASSERT(NS_IsMainThread());
187 :
188 28 : nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo());
189 14 : nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aOwningObject);
190 14 : MOZ_ASSERT(principal);
191 : bool isSystem;
192 14 : if (!AllowedForPrincipal(principal, &isSystem)) {
193 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
194 : }
195 :
196 14 : nsresult rv = PrincipalToPrincipalInfo(principal, principalInfo);
197 14 : if (NS_WARN_IF(NS_FAILED(rv))) {
198 0 : return rv;
199 : }
200 :
201 14 : rv = CreateForMainThreadJSInternal(aCx, aOwningObject, principalInfo, aFactory);
202 14 : if (NS_WARN_IF(NS_FAILED(rv))) {
203 0 : return rv;
204 : }
205 :
206 14 : MOZ_ASSERT(!principalInfo);
207 :
208 14 : return NS_OK;
209 : }
210 :
211 : // static
212 : nsresult
213 0 : IDBFactory::CreateForWorker(JSContext* aCx,
214 : JS::Handle<JSObject*> aOwningObject,
215 : const PrincipalInfo& aPrincipalInfo,
216 : uint64_t aInnerWindowID,
217 : IDBFactory** aFactory)
218 : {
219 0 : MOZ_ASSERT(!NS_IsMainThread());
220 0 : MOZ_ASSERT(aPrincipalInfo.type() != PrincipalInfo::T__None);
221 :
222 0 : nsAutoPtr<PrincipalInfo> principalInfo(new PrincipalInfo(aPrincipalInfo));
223 :
224 : nsresult rv =
225 : CreateForJSInternal(aCx,
226 : aOwningObject,
227 : principalInfo,
228 : aInnerWindowID,
229 0 : aFactory);
230 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
231 0 : return rv;
232 : }
233 :
234 0 : MOZ_ASSERT(!principalInfo);
235 :
236 0 : return NS_OK;
237 : }
238 :
239 : // static
240 : nsresult
241 14 : IDBFactory::CreateForMainThreadJSInternal(
242 : JSContext* aCx,
243 : JS::Handle<JSObject*> aOwningObject,
244 : nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
245 : IDBFactory** aFactory)
246 : {
247 14 : MOZ_ASSERT(NS_IsMainThread());
248 14 : MOZ_ASSERT(aPrincipalInfo);
249 :
250 14 : if (aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo &&
251 0 : NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
252 0 : *aFactory = nullptr;
253 0 : return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
254 : }
255 :
256 14 : IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
257 14 : if (NS_WARN_IF(!mgr)) {
258 0 : IDB_REPORT_INTERNAL_ERR();
259 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
260 : }
261 :
262 : nsresult rv =
263 : CreateForJSInternal(aCx,
264 : aOwningObject,
265 : aPrincipalInfo,
266 : /* aInnerWindowID */ 0,
267 14 : aFactory);
268 14 : if (NS_WARN_IF(NS_FAILED(rv))) {
269 0 : return rv;
270 : }
271 :
272 14 : return NS_OK;
273 : }
274 :
275 : // static
276 : nsresult
277 14 : IDBFactory::CreateForJSInternal(JSContext* aCx,
278 : JS::Handle<JSObject*> aOwningObject,
279 : nsAutoPtr<PrincipalInfo>& aPrincipalInfo,
280 : uint64_t aInnerWindowID,
281 : IDBFactory** aFactory)
282 : {
283 14 : MOZ_ASSERT(aCx);
284 14 : MOZ_ASSERT(aOwningObject);
285 14 : MOZ_ASSERT(aPrincipalInfo);
286 14 : MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None);
287 14 : MOZ_ASSERT(aFactory);
288 14 : MOZ_ASSERT(JS_GetGlobalForObject(aCx, aOwningObject) == aOwningObject,
289 : "Not a global object!");
290 :
291 28 : if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo &&
292 14 : aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) {
293 0 : NS_WARNING("IndexedDB not allowed for this principal!");
294 0 : aPrincipalInfo = nullptr;
295 0 : *aFactory = nullptr;
296 0 : return NS_OK;
297 : }
298 :
299 28 : RefPtr<IDBFactory> factory = new IDBFactory();
300 14 : factory->mPrincipalInfo = aPrincipalInfo.forget();
301 14 : factory->mOwningObject = aOwningObject;
302 14 : mozilla::HoldJSObjects(factory.get());
303 28 : factory->mEventTarget = NS_IsMainThread() ?
304 28 : SystemGroup::EventTargetFor(TaskCategory::Other) : GetCurrentThreadEventTarget();
305 14 : factory->mInnerWindowID = aInnerWindowID;
306 :
307 14 : factory.forget(aFactory);
308 14 : return NS_OK;
309 : }
310 :
311 : // static
312 : bool
313 0 : IDBFactory::AllowedForWindow(nsPIDOMWindowInner* aWindow)
314 : {
315 0 : MOZ_ASSERT(NS_IsMainThread());
316 0 : MOZ_ASSERT(aWindow);
317 :
318 0 : nsCOMPtr<nsIPrincipal> principal;
319 0 : nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal));
320 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
321 0 : return false;
322 : }
323 :
324 0 : return true;
325 : }
326 :
327 : // static
328 : nsresult
329 0 : IDBFactory::AllowedForWindowInternal(nsPIDOMWindowInner* aWindow,
330 : nsIPrincipal** aPrincipal)
331 : {
332 0 : MOZ_ASSERT(NS_IsMainThread());
333 0 : MOZ_ASSERT(aWindow);
334 :
335 0 : if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
336 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
337 : }
338 :
339 : nsContentUtils::StorageAccess access =
340 0 : nsContentUtils::StorageAllowedForWindow(aWindow);
341 :
342 : // the factory callsite records whether the browser is in private browsing.
343 : // and thus we don't have to respect that setting here. IndexedDB has no
344 : // concept of session-local storage, and thus ignores it.
345 0 : if (access == nsContentUtils::StorageAccess::eDeny) {
346 0 : return NS_ERROR_DOM_SECURITY_ERR;
347 : }
348 :
349 0 : nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
350 0 : MOZ_ASSERT(sop);
351 :
352 0 : nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
353 0 : if (NS_WARN_IF(!principal)) {
354 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
355 :
356 : }
357 :
358 0 : if (nsContentUtils::IsSystemPrincipal(principal)) {
359 0 : principal.forget(aPrincipal);
360 0 : return NS_OK;
361 : }
362 :
363 : // About URIs shouldn't be able to access IndexedDB unless they have the
364 : // nsIAboutModule::ENABLE_INDEXED_DB flag set on them.
365 0 : nsCOMPtr<nsIURI> uri;
366 0 : MOZ_ALWAYS_SUCCEEDS(principal->GetURI(getter_AddRefs(uri)));
367 0 : MOZ_ASSERT(uri);
368 :
369 0 : bool isAbout = false;
370 0 : MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout));
371 :
372 0 : if (isAbout) {
373 0 : nsCOMPtr<nsIAboutModule> module;
374 0 : if (NS_SUCCEEDED(NS_GetAboutModule(uri, getter_AddRefs(module)))) {
375 : uint32_t flags;
376 0 : if (NS_SUCCEEDED(module->GetURIFlags(uri, &flags))) {
377 0 : if (!(flags & nsIAboutModule::ENABLE_INDEXED_DB)) {
378 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
379 : }
380 : } else {
381 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
382 : }
383 : } else {
384 0 : return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
385 : }
386 : }
387 :
388 0 : principal.forget(aPrincipal);
389 0 : return NS_OK;
390 : }
391 :
392 : // static
393 : bool
394 14 : IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal,
395 : bool* aIsSystemPrincipal)
396 : {
397 14 : MOZ_ASSERT(NS_IsMainThread());
398 14 : MOZ_ASSERT(aPrincipal);
399 :
400 14 : if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
401 0 : return false;
402 : }
403 :
404 14 : if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
405 14 : if (aIsSystemPrincipal) {
406 14 : *aIsSystemPrincipal = true;
407 : }
408 14 : return true;
409 0 : } else if (aIsSystemPrincipal) {
410 0 : *aIsSystemPrincipal = false;
411 : }
412 :
413 0 : if (aPrincipal->GetIsNullPrincipal()) {
414 0 : return false;
415 : }
416 :
417 0 : return true;
418 : }
419 :
420 : void
421 0 : IDBFactory::UpdateActiveTransactionCount(int32_t aDelta)
422 : {
423 0 : AssertIsOnOwningThread();
424 0 : if (mWindow) {
425 0 : mWindow->UpdateActiveIndexedDBTransactionCount(aDelta);
426 : }
427 0 : }
428 :
429 : void
430 0 : IDBFactory::UpdateActiveDatabaseCount(int32_t aDelta)
431 : {
432 0 : AssertIsOnOwningThread();
433 0 : if (mWindow) {
434 0 : mWindow->UpdateActiveIndexedDBDatabaseCount(aDelta);
435 : }
436 0 : }
437 :
438 : bool
439 0 : IDBFactory::IsChrome() const
440 : {
441 0 : AssertIsOnOwningThread();
442 0 : MOZ_ASSERT(mPrincipalInfo);
443 :
444 0 : return mPrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo;
445 : }
446 :
447 : void
448 0 : IDBFactory::IncrementParentLoggingRequestSerialNumber()
449 : {
450 0 : AssertIsOnOwningThread();
451 0 : MOZ_ASSERT(mBackgroundActor);
452 :
453 0 : mBackgroundActor->SendIncrementLoggingRequestSerialNumber();
454 0 : }
455 :
456 : already_AddRefed<IDBOpenDBRequest>
457 0 : IDBFactory::Open(JSContext* aCx,
458 : const nsAString& aName,
459 : uint64_t aVersion,
460 : CallerType aCallerType,
461 : ErrorResult& aRv)
462 : {
463 : return OpenInternal(aCx,
464 : /* aPrincipal */ nullptr,
465 : aName,
466 0 : Optional<uint64_t>(aVersion),
467 0 : Optional<StorageType>(),
468 : /* aDeleting */ false,
469 : aCallerType,
470 0 : aRv);
471 : }
472 :
473 : already_AddRefed<IDBOpenDBRequest>
474 0 : IDBFactory::Open(JSContext* aCx,
475 : const nsAString& aName,
476 : const IDBOpenDBOptions& aOptions,
477 : CallerType aCallerType,
478 : ErrorResult& aRv)
479 : {
480 : return OpenInternal(aCx,
481 : /* aPrincipal */ nullptr,
482 : aName,
483 : aOptions.mVersion,
484 : aOptions.mStorage,
485 : /* aDeleting */ false,
486 : aCallerType,
487 0 : aRv);
488 : }
489 :
490 : already_AddRefed<IDBOpenDBRequest>
491 0 : IDBFactory::DeleteDatabase(JSContext* aCx,
492 : const nsAString& aName,
493 : const IDBOpenDBOptions& aOptions,
494 : CallerType aCallerType,
495 : ErrorResult& aRv)
496 : {
497 : return OpenInternal(aCx,
498 : /* aPrincipal */ nullptr,
499 : aName,
500 0 : Optional<uint64_t>(),
501 : aOptions.mStorage,
502 : /* aDeleting */ true,
503 : aCallerType,
504 0 : aRv);
505 : }
506 :
507 : int16_t
508 0 : IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
509 : JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
510 : {
511 0 : Key first, second;
512 0 : nsresult rv = first.SetFromJSVal(aCx, aFirst);
513 0 : if (NS_FAILED(rv)) {
514 0 : aRv.Throw(rv);
515 0 : return 0;
516 : }
517 :
518 0 : rv = second.SetFromJSVal(aCx, aSecond);
519 0 : if (NS_FAILED(rv)) {
520 0 : aRv.Throw(rv);
521 0 : return 0;
522 : }
523 :
524 0 : if (first.IsUnset() || second.IsUnset()) {
525 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
526 0 : return 0;
527 : }
528 :
529 0 : return Key::CompareKeys(first, second);
530 : }
531 :
532 : already_AddRefed<IDBOpenDBRequest>
533 0 : IDBFactory::OpenForPrincipal(JSContext* aCx,
534 : nsIPrincipal* aPrincipal,
535 : const nsAString& aName,
536 : uint64_t aVersion,
537 : SystemCallerGuarantee aGuarantee,
538 : ErrorResult& aRv)
539 : {
540 0 : MOZ_ASSERT(aPrincipal);
541 0 : if (!NS_IsMainThread()) {
542 0 : MOZ_CRASH("Figure out security checks for workers! What's this aPrincipal "
543 : "we have on a worker thread?");
544 : }
545 :
546 : return OpenInternal(aCx,
547 : aPrincipal,
548 : aName,
549 0 : Optional<uint64_t>(aVersion),
550 0 : Optional<StorageType>(),
551 : /* aDeleting */ false,
552 : aGuarantee,
553 0 : aRv);
554 : }
555 :
556 : already_AddRefed<IDBOpenDBRequest>
557 0 : IDBFactory::OpenForPrincipal(JSContext* aCx,
558 : nsIPrincipal* aPrincipal,
559 : const nsAString& aName,
560 : const IDBOpenDBOptions& aOptions,
561 : SystemCallerGuarantee aGuarantee,
562 : ErrorResult& aRv)
563 : {
564 0 : MOZ_ASSERT(aPrincipal);
565 0 : if (!NS_IsMainThread()) {
566 0 : MOZ_CRASH("Figure out security checks for workers! What's this aPrincipal "
567 : "we have on a worker thread?");
568 : }
569 :
570 : return OpenInternal(aCx,
571 : aPrincipal,
572 : aName,
573 : aOptions.mVersion,
574 : aOptions.mStorage,
575 : /* aDeleting */ false,
576 : aGuarantee,
577 0 : aRv);
578 : }
579 :
580 : already_AddRefed<IDBOpenDBRequest>
581 0 : IDBFactory::DeleteForPrincipal(JSContext* aCx,
582 : nsIPrincipal* aPrincipal,
583 : const nsAString& aName,
584 : const IDBOpenDBOptions& aOptions,
585 : SystemCallerGuarantee aGuarantee,
586 : ErrorResult& aRv)
587 : {
588 0 : MOZ_ASSERT(aPrincipal);
589 0 : if (!NS_IsMainThread()) {
590 0 : MOZ_CRASH("Figure out security checks for workers! What's this aPrincipal "
591 : "we have on a worker thread?");
592 : }
593 :
594 : return OpenInternal(aCx,
595 : aPrincipal,
596 : aName,
597 0 : Optional<uint64_t>(),
598 : aOptions.mStorage,
599 : /* aDeleting */ true,
600 : aGuarantee,
601 0 : aRv);
602 : }
603 :
604 : already_AddRefed<IDBOpenDBRequest>
605 0 : IDBFactory::OpenInternal(JSContext* aCx,
606 : nsIPrincipal* aPrincipal,
607 : const nsAString& aName,
608 : const Optional<uint64_t>& aVersion,
609 : const Optional<StorageType>& aStorageType,
610 : bool aDeleting,
611 : CallerType aCallerType,
612 : ErrorResult& aRv)
613 : {
614 0 : MOZ_ASSERT(mWindow || mOwningObject);
615 0 : MOZ_ASSERT_IF(!mWindow, !mPrivateBrowsingMode);
616 :
617 0 : CommonFactoryRequestParams commonParams;
618 0 : commonParams.privateBrowsingMode() = mPrivateBrowsingMode;
619 :
620 0 : PrincipalInfo& principalInfo = commonParams.principalInfo();
621 :
622 0 : if (aPrincipal) {
623 0 : if (!NS_IsMainThread()) {
624 0 : MOZ_CRASH("Figure out security checks for workers! What's this "
625 : "aPrincipal we have on a worker thread?");
626 : }
627 0 : MOZ_ASSERT(aCallerType == CallerType::System);
628 0 : MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode == (aPrincipal->GetPrivateBrowsingId() > 0));
629 :
630 0 : if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal,
631 : &principalInfo)))) {
632 0 : IDB_REPORT_INTERNAL_ERR();
633 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
634 0 : return nullptr;
635 : }
636 :
637 0 : if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
638 0 : principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
639 0 : IDB_REPORT_INTERNAL_ERR();
640 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
641 0 : return nullptr;
642 : }
643 : } else {
644 0 : principalInfo = *mPrincipalInfo;
645 : }
646 :
647 0 : uint64_t version = 0;
648 0 : if (!aDeleting && aVersion.WasPassed()) {
649 0 : if (aVersion.Value() < 1) {
650 0 : aRv.ThrowTypeError<MSG_INVALID_VERSION>();
651 0 : return nullptr;
652 : }
653 0 : version = aVersion.Value();
654 : }
655 :
656 : // Nothing can be done here if we have previously failed to create a
657 : // background actor.
658 0 : if (mBackgroundActorFailed) {
659 0 : IDB_REPORT_INTERNAL_ERR();
660 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
661 0 : return nullptr;
662 : }
663 :
664 : PersistenceType persistenceType;
665 :
666 0 : if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
667 : // Chrome privilege always gets persistent storage.
668 0 : persistenceType = PERSISTENCE_TYPE_PERSISTENT;
669 : } else {
670 0 : persistenceType = PersistenceTypeFromStorage(aStorageType);
671 : }
672 :
673 0 : DatabaseMetadata& metadata = commonParams.metadata();
674 0 : metadata.name() = aName;
675 0 : metadata.persistenceType() = persistenceType;
676 :
677 0 : FactoryRequestParams params;
678 0 : if (aDeleting) {
679 0 : metadata.version() = 0;
680 0 : params = DeleteDatabaseRequestParams(commonParams);
681 : } else {
682 0 : metadata.version() = version;
683 0 : params = OpenDatabaseRequestParams(commonParams);
684 : }
685 :
686 0 : if (!mBackgroundActor && mPendingRequests.IsEmpty()) {
687 : BackgroundChildImpl::ThreadLocal* threadLocal =
688 0 : BackgroundChildImpl::GetThreadLocalForCurrentThread();
689 :
690 0 : nsAutoPtr<ThreadLocal> newIDBThreadLocal;
691 : ThreadLocal* idbThreadLocal;
692 :
693 0 : if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
694 0 : idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
695 : } else {
696 : nsCOMPtr<nsIUUIDGenerator> uuidGen =
697 0 : do_GetService("@mozilla.org/uuid-generator;1");
698 0 : MOZ_ASSERT(uuidGen);
699 :
700 : nsID id;
701 0 : MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id));
702 :
703 0 : newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id);
704 : }
705 :
706 0 : if (PBackgroundChild* actor = BackgroundChild::GetForCurrentThread()) {
707 0 : BackgroundActorCreated(actor, idbThreadLocal->GetLoggingInfo());
708 : } else {
709 : // We need to start the sequence to create a background actor for this
710 : // thread.
711 : RefPtr<BackgroundCreateCallback> cb =
712 0 : new BackgroundCreateCallback(this, idbThreadLocal->GetLoggingInfo());
713 0 : if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(cb))) {
714 0 : IDB_REPORT_INTERNAL_ERR();
715 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
716 0 : return nullptr;
717 : }
718 : }
719 :
720 0 : if (newIDBThreadLocal) {
721 0 : if (!threadLocal) {
722 0 : threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
723 : }
724 0 : MOZ_ASSERT(threadLocal);
725 0 : MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);
726 :
727 0 : threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
728 : }
729 : }
730 :
731 0 : RefPtr<IDBOpenDBRequest> request;
732 :
733 0 : if (mWindow) {
734 : JS::Rooted<JSObject*> scriptOwner(aCx,
735 0 : nsGlobalWindow::Cast(mWindow.get())->FastGetGlobalJSObject());
736 0 : MOZ_ASSERT(scriptOwner);
737 :
738 0 : request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner);
739 : } else {
740 0 : JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject);
741 :
742 0 : request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner);
743 0 : if (!request) {
744 0 : MOZ_ASSERT(!NS_IsMainThread());
745 0 : aRv.ThrowUncatchableException();
746 0 : return nullptr;
747 : }
748 : }
749 :
750 0 : MOZ_ASSERT(request);
751 :
752 0 : if (aDeleting) {
753 0 : IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
754 : "indexedDB.deleteDatabase(\"%s\")",
755 : "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()",
756 : IDB_LOG_ID_STRING(),
757 : request->LoggingSerialNumber(),
758 : NS_ConvertUTF16toUTF8(aName).get());
759 : } else {
760 0 : IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
761 : "indexedDB.open(\"%s\", %s)",
762 : "IndexedDB %s: C R[%llu]: IDBFactory.open()",
763 : IDB_LOG_ID_STRING(),
764 : request->LoggingSerialNumber(),
765 : NS_ConvertUTF16toUTF8(aName).get(),
766 : IDB_LOG_STRINGIFY(aVersion));
767 : }
768 :
769 : // If we already have a background actor then we can start this request now.
770 0 : if (mBackgroundActor) {
771 0 : nsresult rv = InitiateRequest(request, params);
772 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
773 0 : IDB_REPORT_INTERNAL_ERR();
774 0 : aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
775 0 : return nullptr;
776 : }
777 : } else {
778 0 : mPendingRequests.AppendElement(new PendingRequestInfo(request, params));
779 : }
780 :
781 0 : return request.forget();
782 : }
783 :
784 : nsresult
785 0 : IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor,
786 : const LoggingInfo& aLoggingInfo)
787 : {
788 0 : MOZ_ASSERT(aBackgroundActor);
789 0 : MOZ_ASSERT(!mBackgroundActor);
790 0 : MOZ_ASSERT(!mBackgroundActorFailed);
791 :
792 : {
793 0 : BackgroundFactoryChild* actor = new BackgroundFactoryChild(this);
794 :
795 : // Set EventTarget for the top-level actor.
796 : // All child actors created later inherit the same event target.
797 0 : aBackgroundActor->SetEventTargetForActor(actor, EventTarget());
798 0 : MOZ_ASSERT(actor->GetActorEventTarget());
799 0 : mBackgroundActor =
800 : static_cast<BackgroundFactoryChild*>(
801 0 : aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor,
802 : aLoggingInfo));
803 : }
804 :
805 0 : if (NS_WARN_IF(!mBackgroundActor)) {
806 0 : BackgroundActorFailed();
807 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
808 : }
809 :
810 0 : nsresult rv = NS_OK;
811 :
812 0 : for (uint32_t index = 0, count = mPendingRequests.Length();
813 0 : index < count;
814 : index++) {
815 0 : nsAutoPtr<PendingRequestInfo> info(mPendingRequests[index].forget());
816 :
817 0 : nsresult rv2 = InitiateRequest(info->mRequest, info->mParams);
818 :
819 : // Warn for every failure, but just return the first failure if there are
820 : // multiple failures.
821 0 : if (NS_WARN_IF(NS_FAILED(rv2)) && NS_SUCCEEDED(rv)) {
822 0 : rv = rv2;
823 : }
824 : }
825 :
826 0 : mPendingRequests.Clear();
827 :
828 0 : return rv;
829 : }
830 :
831 : void
832 0 : IDBFactory::BackgroundActorFailed()
833 : {
834 0 : MOZ_ASSERT(!mPendingRequests.IsEmpty());
835 0 : MOZ_ASSERT(!mBackgroundActor);
836 0 : MOZ_ASSERT(!mBackgroundActorFailed);
837 :
838 0 : mBackgroundActorFailed = true;
839 :
840 0 : for (uint32_t index = 0, count = mPendingRequests.Length();
841 0 : index < count;
842 : index++) {
843 0 : nsAutoPtr<PendingRequestInfo> info(mPendingRequests[index].forget());
844 0 : info->mRequest->
845 0 : DispatchNonTransactionError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
846 : }
847 :
848 0 : mPendingRequests.Clear();
849 0 : }
850 :
851 : nsresult
852 0 : IDBFactory::InitiateRequest(IDBOpenDBRequest* aRequest,
853 : const FactoryRequestParams& aParams)
854 : {
855 0 : MOZ_ASSERT(aRequest);
856 0 : MOZ_ASSERT(mBackgroundActor);
857 0 : MOZ_ASSERT(!mBackgroundActorFailed);
858 :
859 : bool deleting;
860 : uint64_t requestedVersion;
861 :
862 0 : switch (aParams.type()) {
863 : case FactoryRequestParams::TDeleteDatabaseRequestParams: {
864 : const DatabaseMetadata& metadata =
865 0 : aParams.get_DeleteDatabaseRequestParams().commonParams().metadata();
866 0 : deleting = true;
867 0 : requestedVersion = metadata.version();
868 0 : break;
869 : }
870 :
871 : case FactoryRequestParams::TOpenDatabaseRequestParams: {
872 : const DatabaseMetadata& metadata =
873 0 : aParams.get_OpenDatabaseRequestParams().commonParams().metadata();
874 0 : deleting = false;
875 0 : requestedVersion = metadata.version();
876 0 : break;
877 : }
878 :
879 : default:
880 0 : MOZ_CRASH("Should never get here!");
881 : }
882 :
883 : auto actor =
884 : new BackgroundFactoryRequestChild(this,
885 : aRequest,
886 : deleting,
887 0 : requestedVersion);
888 :
889 0 : if (!mBackgroundActor->SendPBackgroundIDBFactoryRequestConstructor(actor,
890 : aParams)) {
891 0 : aRequest->DispatchNonTransactionError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
892 0 : return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
893 : }
894 :
895 0 : MOZ_ASSERT(actor->GetActorEventTarget(),
896 : "The event target shall be inherited from its manager actor.");
897 :
898 0 : return NS_OK;
899 : }
900 :
901 28 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory)
902 14 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory)
903 :
904 196 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory)
905 14 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
906 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
907 0 : NS_INTERFACE_MAP_END
908 :
909 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory)
910 :
911 14 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory)
912 14 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
913 14 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
914 :
915 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory)
916 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
917 0 : tmp->mOwningObject = nullptr;
918 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
919 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
920 :
921 42 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory)
922 42 : NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
923 42 : NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOwningObject)
924 42 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
925 :
926 : JSObject*
927 14 : IDBFactory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
928 : {
929 14 : return IDBFactoryBinding::Wrap(aCx, this, aGivenProto);
930 : }
931 :
932 0 : NS_IMPL_ISUPPORTS(IDBFactory::BackgroundCreateCallback,
933 : nsIIPCBackgroundChildCreateCallback)
934 :
935 : void
936 0 : IDBFactory::BackgroundCreateCallback::ActorCreated(PBackgroundChild* aActor)
937 : {
938 0 : MOZ_ASSERT(aActor);
939 0 : MOZ_ASSERT(mFactory);
940 :
941 0 : RefPtr<IDBFactory> factory;
942 0 : mFactory.swap(factory);
943 :
944 0 : factory->BackgroundActorCreated(aActor, mLoggingInfo);
945 0 : }
946 :
947 : void
948 0 : IDBFactory::BackgroundCreateCallback::ActorFailed()
949 : {
950 0 : MOZ_ASSERT(mFactory);
951 :
952 0 : RefPtr<IDBFactory> factory;
953 0 : mFactory.swap(factory);
954 :
955 0 : factory->BackgroundActorFailed();
956 0 : }
957 :
958 : } // namespace dom
959 : } // namespace mozilla
|