CacheStorage.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/dom/cache/CacheStorage.h"
  6. #include "mozilla/Unused.h"
  7. #include "mozilla/dom/CacheBinding.h"
  8. #include "mozilla/dom/CacheStorageBinding.h"
  9. #include "mozilla/dom/Promise.h"
  10. #include "mozilla/dom/Response.h"
  11. #include "mozilla/dom/cache/AutoUtils.h"
  12. #include "mozilla/dom/cache/Cache.h"
  13. #include "mozilla/dom/cache/CacheChild.h"
  14. #include "mozilla/dom/cache/CacheStorageChild.h"
  15. #include "mozilla/dom/cache/CacheWorkerHolder.h"
  16. #include "mozilla/dom/cache/PCacheChild.h"
  17. #include "mozilla/dom/cache/ReadStream.h"
  18. #include "mozilla/dom/cache/TypeUtils.h"
  19. #include "mozilla/ipc/BackgroundChild.h"
  20. #include "mozilla/ipc/BackgroundUtils.h"
  21. #include "mozilla/ipc/PBackgroundChild.h"
  22. #include "mozilla/ipc/PBackgroundSharedTypes.h"
  23. #include "nsContentUtils.h"
  24. #include "nsIDocument.h"
  25. #include "nsIGlobalObject.h"
  26. #include "nsIScriptSecurityManager.h"
  27. #include "nsURLParsers.h"
  28. #include "WorkerPrivate.h"
  29. using namespace mozilla::dom;
  30. namespace mozilla {
  31. namespace dom {
  32. namespace cache {
  33. using mozilla::Unused;
  34. using mozilla::ErrorResult;
  35. using mozilla::dom::workers::WorkerPrivate;
  36. using mozilla::ipc::BackgroundChild;
  37. using mozilla::ipc::PBackgroundChild;
  38. using mozilla::ipc::IProtocol;
  39. using mozilla::ipc::PrincipalInfo;
  40. using mozilla::ipc::PrincipalToPrincipalInfo;
  41. NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::CacheStorage);
  42. NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::CacheStorage);
  43. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::CacheStorage,
  44. mGlobal);
  45. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CacheStorage)
  46. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  47. NS_INTERFACE_MAP_ENTRY(nsISupports)
  48. NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
  49. NS_INTERFACE_MAP_END
  50. // We cannot reference IPC types in a webidl binding implementation header. So
  51. // define this in the .cpp and use heap storage in the mPendingRequests list.
  52. struct CacheStorage::Entry final
  53. {
  54. RefPtr<Promise> mPromise;
  55. CacheOpArgs mArgs;
  56. // We cannot add the requests until after the actor is present. So store
  57. // the request data separately for now.
  58. RefPtr<InternalRequest> mRequest;
  59. };
  60. namespace {
  61. bool
  62. IsTrusted(const PrincipalInfo& aPrincipalInfo, bool aTestingPrefEnabled)
  63. {
  64. // Can happen on main thread or worker thread
  65. if (aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
  66. return true;
  67. }
  68. // Require a ContentPrincipal to avoid null principal, etc.
  69. //
  70. // Also, an unknown appId means that this principal was created for the
  71. // codebase without all the security information from the end document or
  72. // worker. We require exact knowledge of this information before allowing
  73. // the caller to touch the disk using the Cache API.
  74. if (NS_WARN_IF(aPrincipalInfo.type() != PrincipalInfo::TContentPrincipalInfo ||
  75. aPrincipalInfo.get_ContentPrincipalInfo().attrs().mAppId ==
  76. nsIScriptSecurityManager::UNKNOWN_APP_ID)) {
  77. return false;
  78. }
  79. // If we're in testing mode, then don't do any more work to determing if
  80. // the origin is trusted. We have to run some tests as http.
  81. if (aTestingPrefEnabled) {
  82. return true;
  83. }
  84. // Now parse the scheme of the principal's origin. This is a short term
  85. // method for determining "trust". In the long term we need to implement
  86. // the full algorithm here:
  87. //
  88. // https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-secure
  89. //
  90. // TODO: Implement full secure setting algorithm. (bug 1177856)
  91. const nsCString& flatURL = aPrincipalInfo.get_ContentPrincipalInfo().spec();
  92. const char* url = flatURL.get();
  93. // off the main thread URL parsing using nsStdURLParser.
  94. nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
  95. uint32_t schemePos;
  96. int32_t schemeLen;
  97. uint32_t authPos;
  98. int32_t authLen;
  99. nsresult rv = urlParser->ParseURL(url, flatURL.Length(),
  100. &schemePos, &schemeLen,
  101. &authPos, &authLen,
  102. nullptr, nullptr); // ignore path
  103. if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
  104. nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
  105. if (scheme.LowerCaseEqualsLiteral("https") ||
  106. scheme.LowerCaseEqualsLiteral("file")) {
  107. return true;
  108. }
  109. uint32_t hostPos;
  110. int32_t hostLen;
  111. rv = urlParser->ParseAuthority(url + authPos, authLen,
  112. nullptr, nullptr, // ignore username
  113. nullptr, nullptr, // ignore password
  114. &hostPos, &hostLen,
  115. nullptr); // ignore port
  116. if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
  117. nsDependentCSubstring hostname(url + authPos + hostPos, hostLen);
  118. return hostname.EqualsLiteral("localhost") ||
  119. hostname.EqualsLiteral("127.0.0.1") ||
  120. hostname.EqualsLiteral("::1");
  121. }
  122. } // namespace
  123. // static
  124. already_AddRefed<CacheStorage>
  125. CacheStorage::CreateOnMainThread(Namespace aNamespace, nsIGlobalObject* aGlobal,
  126. nsIPrincipal* aPrincipal, bool aStorageDisabled,
  127. bool aForceTrustedOrigin, ErrorResult& aRv)
  128. {
  129. MOZ_DIAGNOSTIC_ASSERT(aGlobal);
  130. MOZ_DIAGNOSTIC_ASSERT(aPrincipal);
  131. MOZ_ASSERT(NS_IsMainThread());
  132. if (aStorageDisabled) {
  133. NS_WARNING("CacheStorage has been disabled.");
  134. RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
  135. return ref.forget();
  136. }
  137. PrincipalInfo principalInfo;
  138. nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
  139. if (NS_WARN_IF(NS_FAILED(rv))) {
  140. aRv.Throw(rv);
  141. return nullptr;
  142. }
  143. bool testingEnabled = aForceTrustedOrigin ||
  144. Preferences::GetBool("dom.caches.testing.enabled", false) ||
  145. Preferences::GetBool("dom.serviceWorkers.testing.enabled", false);
  146. if (!IsTrusted(principalInfo, testingEnabled)) {
  147. NS_WARNING("CacheStorage not supported on untrusted origins.");
  148. RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
  149. return ref.forget();
  150. }
  151. RefPtr<CacheStorage> ref = new CacheStorage(aNamespace, aGlobal,
  152. principalInfo, nullptr);
  153. return ref.forget();
  154. }
  155. // static
  156. already_AddRefed<CacheStorage>
  157. CacheStorage::CreateOnWorker(Namespace aNamespace, nsIGlobalObject* aGlobal,
  158. WorkerPrivate* aWorkerPrivate, ErrorResult& aRv)
  159. {
  160. MOZ_DIAGNOSTIC_ASSERT(aGlobal);
  161. MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
  162. aWorkerPrivate->AssertIsOnWorkerThread();
  163. if (!aWorkerPrivate->IsStorageAllowed()) {
  164. NS_WARNING("CacheStorage is not allowed.");
  165. RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
  166. return ref.forget();
  167. }
  168. if (aWorkerPrivate->GetOriginAttributes().mPrivateBrowsingId > 0) {
  169. NS_WARNING("CacheStorage not supported during private browsing.");
  170. RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
  171. return ref.forget();
  172. }
  173. RefPtr<CacheWorkerHolder> workerHolder =
  174. CacheWorkerHolder::Create(aWorkerPrivate);
  175. if (!workerHolder) {
  176. NS_WARNING("Worker thread is shutting down.");
  177. aRv.Throw(NS_ERROR_FAILURE);
  178. return nullptr;
  179. }
  180. const PrincipalInfo& principalInfo = aWorkerPrivate->GetPrincipalInfo();
  181. // We have a number of cases where we want to skip the https scheme
  182. // validation:
  183. //
  184. // 1) Any worker when dom.caches.testing.enabled pref is true.
  185. // 2) Any worker when dom.serviceWorkers.testing.enabled pref is true. This
  186. // is mainly because most sites using SWs will expect Cache to work if
  187. // SWs are enabled.
  188. // 3) If the window that created this worker has the devtools SW testing
  189. // option enabled. Same reasoning as (2).
  190. // 4) If the worker itself is a ServiceWorker, then we always skip the
  191. // origin checks. The ServiceWorker has its own trusted origin checks
  192. // that are better than ours. In addition, we don't have information
  193. // about the window any more, so we can't do our own checks.
  194. bool testingEnabled = aWorkerPrivate->DOMCachesTestingEnabled() ||
  195. aWorkerPrivate->ServiceWorkersTestingEnabled() ||
  196. aWorkerPrivate->ServiceWorkersTestingInWindow() ||
  197. aWorkerPrivate->IsServiceWorker();
  198. if (!IsTrusted(principalInfo, testingEnabled)) {
  199. NS_WARNING("CacheStorage not supported on untrusted origins.");
  200. RefPtr<CacheStorage> ref = new CacheStorage(NS_ERROR_DOM_SECURITY_ERR);
  201. return ref.forget();
  202. }
  203. RefPtr<CacheStorage> ref = new CacheStorage(aNamespace, aGlobal,
  204. principalInfo, workerHolder);
  205. return ref.forget();
  206. }
  207. // static
  208. bool
  209. CacheStorage::DefineCaches(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
  210. {
  211. MOZ_ASSERT(NS_IsMainThread());
  212. MOZ_DIAGNOSTIC_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL,
  213. "Passed object is not a global object!");
  214. js::AssertSameCompartment(aCx, aGlobal);
  215. if (NS_WARN_IF(!CacheStorageBinding::GetConstructorObject(aCx) ||
  216. !CacheBinding::GetConstructorObject(aCx))) {
  217. return false;
  218. }
  219. nsIPrincipal* principal = nsContentUtils::ObjectPrincipal(aGlobal);
  220. MOZ_DIAGNOSTIC_ASSERT(principal);
  221. ErrorResult rv;
  222. RefPtr<CacheStorage> storage =
  223. CreateOnMainThread(DEFAULT_NAMESPACE, xpc::NativeGlobal(aGlobal), principal,
  224. false, /* private browsing */
  225. true, /* force trusted */
  226. rv);
  227. if (NS_WARN_IF(rv.MaybeSetPendingException(aCx))) {
  228. return false;
  229. }
  230. JS::Rooted<JS::Value> caches(aCx);
  231. if (NS_WARN_IF(!ToJSValue(aCx, storage, &caches))) {
  232. return false;
  233. }
  234. return JS_DefineProperty(aCx, aGlobal, "caches", caches, JSPROP_ENUMERATE);
  235. }
  236. CacheStorage::CacheStorage(Namespace aNamespace, nsIGlobalObject* aGlobal,
  237. const PrincipalInfo& aPrincipalInfo,
  238. CacheWorkerHolder* aWorkerHolder)
  239. : mNamespace(aNamespace)
  240. , mGlobal(aGlobal)
  241. , mPrincipalInfo(MakeUnique<PrincipalInfo>(aPrincipalInfo))
  242. , mWorkerHolder(aWorkerHolder)
  243. , mActor(nullptr)
  244. , mStatus(NS_OK)
  245. {
  246. MOZ_DIAGNOSTIC_ASSERT(mGlobal);
  247. // If the PBackground actor is already initialized then we can
  248. // immediately use it
  249. PBackgroundChild* actor = BackgroundChild::GetForCurrentThread();
  250. if (actor) {
  251. ActorCreated(actor);
  252. return;
  253. }
  254. // Otherwise we must begin the PBackground initialization process and
  255. // wait for the async ActorCreated() callback.
  256. MOZ_ASSERT(NS_IsMainThread());
  257. bool ok = BackgroundChild::GetOrCreateForCurrentThread(this);
  258. if (NS_WARN_IF(!ok)) {
  259. ActorFailed();
  260. }
  261. }
  262. CacheStorage::CacheStorage(nsresult aFailureResult)
  263. : mNamespace(INVALID_NAMESPACE)
  264. , mActor(nullptr)
  265. , mStatus(aFailureResult)
  266. {
  267. MOZ_DIAGNOSTIC_ASSERT(NS_FAILED(mStatus));
  268. }
  269. already_AddRefed<Promise>
  270. CacheStorage::Match(const RequestOrUSVString& aRequest,
  271. const CacheQueryOptions& aOptions, ErrorResult& aRv)
  272. {
  273. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  274. if (NS_WARN_IF(NS_FAILED(mStatus))) {
  275. aRv.Throw(mStatus);
  276. return nullptr;
  277. }
  278. RefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody,
  279. aRv);
  280. if (NS_WARN_IF(aRv.Failed())) {
  281. return nullptr;
  282. }
  283. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  284. if (NS_WARN_IF(!promise)) {
  285. return nullptr;
  286. }
  287. CacheQueryParams params;
  288. ToCacheQueryParams(params, aOptions);
  289. nsAutoPtr<Entry> entry(new Entry());
  290. entry->mPromise = promise;
  291. entry->mArgs = StorageMatchArgs(CacheRequest(), params);
  292. entry->mRequest = request;
  293. mPendingRequests.AppendElement(entry.forget());
  294. MaybeRunPendingRequests();
  295. return promise.forget();
  296. }
  297. already_AddRefed<Promise>
  298. CacheStorage::Has(const nsAString& aKey, ErrorResult& aRv)
  299. {
  300. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  301. if (NS_WARN_IF(NS_FAILED(mStatus))) {
  302. aRv.Throw(mStatus);
  303. return nullptr;
  304. }
  305. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  306. if (NS_WARN_IF(!promise)) {
  307. return nullptr;
  308. }
  309. nsAutoPtr<Entry> entry(new Entry());
  310. entry->mPromise = promise;
  311. entry->mArgs = StorageHasArgs(nsString(aKey));
  312. mPendingRequests.AppendElement(entry.forget());
  313. MaybeRunPendingRequests();
  314. return promise.forget();
  315. }
  316. already_AddRefed<Promise>
  317. CacheStorage::Open(const nsAString& aKey, ErrorResult& aRv)
  318. {
  319. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  320. if (NS_WARN_IF(NS_FAILED(mStatus))) {
  321. aRv.Throw(mStatus);
  322. return nullptr;
  323. }
  324. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  325. if (NS_WARN_IF(!promise)) {
  326. return nullptr;
  327. }
  328. nsAutoPtr<Entry> entry(new Entry());
  329. entry->mPromise = promise;
  330. entry->mArgs = StorageOpenArgs(nsString(aKey));
  331. mPendingRequests.AppendElement(entry.forget());
  332. MaybeRunPendingRequests();
  333. return promise.forget();
  334. }
  335. already_AddRefed<Promise>
  336. CacheStorage::Delete(const nsAString& aKey, ErrorResult& aRv)
  337. {
  338. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  339. if (NS_WARN_IF(NS_FAILED(mStatus))) {
  340. aRv.Throw(mStatus);
  341. return nullptr;
  342. }
  343. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  344. if (NS_WARN_IF(!promise)) {
  345. return nullptr;
  346. }
  347. nsAutoPtr<Entry> entry(new Entry());
  348. entry->mPromise = promise;
  349. entry->mArgs = StorageDeleteArgs(nsString(aKey));
  350. mPendingRequests.AppendElement(entry.forget());
  351. MaybeRunPendingRequests();
  352. return promise.forget();
  353. }
  354. already_AddRefed<Promise>
  355. CacheStorage::Keys(ErrorResult& aRv)
  356. {
  357. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  358. if (NS_WARN_IF(NS_FAILED(mStatus))) {
  359. aRv.Throw(mStatus);
  360. return nullptr;
  361. }
  362. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  363. if (NS_WARN_IF(!promise)) {
  364. return nullptr;
  365. }
  366. nsAutoPtr<Entry> entry(new Entry());
  367. entry->mPromise = promise;
  368. entry->mArgs = StorageKeysArgs();
  369. mPendingRequests.AppendElement(entry.forget());
  370. MaybeRunPendingRequests();
  371. return promise.forget();
  372. }
  373. // static
  374. bool
  375. CacheStorage::PrefEnabled(JSContext* aCx, JSObject* aObj)
  376. {
  377. return Cache::PrefEnabled(aCx, aObj);
  378. }
  379. // static
  380. already_AddRefed<CacheStorage>
  381. CacheStorage::Constructor(const GlobalObject& aGlobal,
  382. CacheStorageNamespace aNamespace,
  383. nsIPrincipal* aPrincipal, ErrorResult& aRv)
  384. {
  385. if (NS_WARN_IF(!NS_IsMainThread())) {
  386. aRv.Throw(NS_ERROR_FAILURE);
  387. return nullptr;
  388. }
  389. // TODO: remove Namespace in favor of CacheStorageNamespace
  390. static_assert(DEFAULT_NAMESPACE == (uint32_t)CacheStorageNamespace::Content,
  391. "Default namespace should match webidl Content enum");
  392. static_assert(CHROME_ONLY_NAMESPACE == (uint32_t)CacheStorageNamespace::Chrome,
  393. "Chrome namespace should match webidl Chrome enum");
  394. static_assert(NUMBER_OF_NAMESPACES == (uint32_t)CacheStorageNamespace::EndGuard_,
  395. "Number of namespace should match webidl endguard enum");
  396. Namespace ns = static_cast<Namespace>(aNamespace);
  397. nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
  398. bool privateBrowsing = false;
  399. if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global)) {
  400. nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
  401. if (doc) {
  402. nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
  403. privateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
  404. }
  405. }
  406. // Create a CacheStorage object bypassing the trusted origin checks
  407. // since this is a chrome-only constructor.
  408. return CreateOnMainThread(ns, global, aPrincipal, privateBrowsing,
  409. true /* force trusted origin */, aRv);
  410. }
  411. nsISupports*
  412. CacheStorage::GetParentObject() const
  413. {
  414. return mGlobal;
  415. }
  416. JSObject*
  417. CacheStorage::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto)
  418. {
  419. return mozilla::dom::CacheStorageBinding::Wrap(aContext, this, aGivenProto);
  420. }
  421. void
  422. CacheStorage::ActorCreated(PBackgroundChild* aActor)
  423. {
  424. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  425. MOZ_DIAGNOSTIC_ASSERT(aActor);
  426. if (NS_WARN_IF(mWorkerHolder && mWorkerHolder->Notified())) {
  427. ActorFailed();
  428. return;
  429. }
  430. // WorkerHolder ownership is passed to the CacheStorageChild actor and any
  431. // actors it may create. The WorkerHolder will keep the worker thread alive
  432. // until the actors can gracefully shutdown.
  433. CacheStorageChild* newActor = new CacheStorageChild(this, mWorkerHolder);
  434. PCacheStorageChild* constructedActor =
  435. aActor->SendPCacheStorageConstructor(newActor, mNamespace, *mPrincipalInfo);
  436. if (NS_WARN_IF(!constructedActor)) {
  437. ActorFailed();
  438. return;
  439. }
  440. mWorkerHolder = nullptr;
  441. MOZ_DIAGNOSTIC_ASSERT(constructedActor == newActor);
  442. mActor = newActor;
  443. MaybeRunPendingRequests();
  444. MOZ_DIAGNOSTIC_ASSERT(mPendingRequests.IsEmpty());
  445. }
  446. void
  447. CacheStorage::ActorFailed()
  448. {
  449. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  450. MOZ_DIAGNOSTIC_ASSERT(!NS_FAILED(mStatus));
  451. mStatus = NS_ERROR_UNEXPECTED;
  452. mWorkerHolder = nullptr;
  453. for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
  454. nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
  455. entry->mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
  456. }
  457. mPendingRequests.Clear();
  458. }
  459. void
  460. CacheStorage::DestroyInternal(CacheStorageChild* aActor)
  461. {
  462. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  463. MOZ_DIAGNOSTIC_ASSERT(mActor);
  464. MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
  465. mActor->ClearListener();
  466. mActor = nullptr;
  467. // Note that we will never get an actor again in case another request is
  468. // made before this object is destructed.
  469. ActorFailed();
  470. }
  471. nsIGlobalObject*
  472. CacheStorage::GetGlobalObject() const
  473. {
  474. return mGlobal;
  475. }
  476. #ifdef DEBUG
  477. void
  478. CacheStorage::AssertOwningThread() const
  479. {
  480. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  481. }
  482. #endif
  483. PBackgroundChild*
  484. CacheStorage::GetIPCManager()
  485. {
  486. // This is true because CacheStorage always uses IgnoreBody for requests.
  487. // So we should never need to get the IPC manager during Request or
  488. // Response serialization.
  489. MOZ_CRASH("CacheStorage does not implement TypeUtils::GetIPCManager()");
  490. }
  491. CacheStorage::~CacheStorage()
  492. {
  493. NS_ASSERT_OWNINGTHREAD(CacheStorage);
  494. if (mActor) {
  495. mActor->StartDestroyFromListener();
  496. // DestroyInternal() is called synchronously by StartDestroyFromListener().
  497. // So we should have already cleared the mActor.
  498. MOZ_DIAGNOSTIC_ASSERT(!mActor);
  499. }
  500. }
  501. void
  502. CacheStorage::MaybeRunPendingRequests()
  503. {
  504. if (!mActor) {
  505. return;
  506. }
  507. for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) {
  508. ErrorResult rv;
  509. nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
  510. AutoChildOpArgs args(this, entry->mArgs, 1);
  511. if (entry->mRequest) {
  512. args.Add(entry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
  513. }
  514. if (NS_WARN_IF(rv.Failed())) {
  515. entry->mPromise->MaybeReject(rv);
  516. continue;
  517. }
  518. mActor->ExecuteOp(mGlobal, entry->mPromise, this, args.SendAsOpArgs());
  519. }
  520. mPendingRequests.Clear();
  521. }
  522. } // namespace cache
  523. } // namespace dom
  524. } // namespace mozilla