Manager.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952
  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/Manager.h"
  6. #include "mozilla/AutoRestore.h"
  7. #include "mozilla/Mutex.h"
  8. #include "mozilla/StaticMutex.h"
  9. #include "mozilla/StaticPtr.h"
  10. #include "mozilla/Unused.h"
  11. #include "mozilla/dom/cache/Context.h"
  12. #include "mozilla/dom/cache/DBAction.h"
  13. #include "mozilla/dom/cache/DBSchema.h"
  14. #include "mozilla/dom/cache/FileUtils.h"
  15. #include "mozilla/dom/cache/ManagerId.h"
  16. #include "mozilla/dom/cache/CacheTypes.h"
  17. #include "mozilla/dom/cache/SavedTypes.h"
  18. #include "mozilla/dom/cache/StreamList.h"
  19. #include "mozilla/dom/cache/Types.h"
  20. #include "mozilla/ipc/BackgroundParent.h"
  21. #include "mozStorageHelper.h"
  22. #include "nsIInputStream.h"
  23. #include "nsID.h"
  24. #include "nsIFile.h"
  25. #include "nsIThread.h"
  26. #include "nsThreadUtils.h"
  27. #include "nsTObserverArray.h"
  28. namespace mozilla {
  29. namespace dom {
  30. namespace cache {
  31. namespace {
  32. // An Action that is executed when a Context is first created. It ensures that
  33. // the directory and database are setup properly. This lets other actions
  34. // not worry about these details.
  35. class SetupAction final : public SyncDBAction
  36. {
  37. public:
  38. SetupAction()
  39. : SyncDBAction(DBAction::Create)
  40. { }
  41. virtual nsresult
  42. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  43. mozIStorageConnection* aConn) override
  44. {
  45. nsresult rv = BodyCreateDir(aDBDir);
  46. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  47. // executes in its own transaction
  48. rv = db::CreateOrMigrateSchema(aConn);
  49. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  50. // If the Context marker file exists, then the last session was
  51. // not cleanly shutdown. In these cases sqlite will ensure that
  52. // the database is valid, but we might still orphan data. Both
  53. // Cache objects and body files can be referenced by DOM objects
  54. // after they are "removed" from their parent. So we need to
  55. // look and see if any of these late access objects have been
  56. // orphaned.
  57. //
  58. // Note, this must be done after any schema version updates to
  59. // ensure our DBSchema methods work correctly.
  60. if (MarkerFileExists(aQuotaInfo)) {
  61. NS_WARNING("Cache not shutdown cleanly! Cleaning up stale data...");
  62. mozStorageTransaction trans(aConn, false,
  63. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  64. // Clean up orphaned Cache objects
  65. AutoTArray<CacheId, 8> orphanedCacheIdList;
  66. nsresult rv = db::FindOrphanedCacheIds(aConn, orphanedCacheIdList);
  67. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  68. for (uint32_t i = 0; i < orphanedCacheIdList.Length(); ++i) {
  69. AutoTArray<nsID, 16> deletedBodyIdList;
  70. rv = db::DeleteCacheId(aConn, orphanedCacheIdList[i], deletedBodyIdList);
  71. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  72. rv = BodyDeleteFiles(aDBDir, deletedBodyIdList);
  73. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  74. }
  75. // Clean up orphaned body objects
  76. AutoTArray<nsID, 64> knownBodyIdList;
  77. rv = db::GetKnownBodyIds(aConn, knownBodyIdList);
  78. rv = BodyDeleteOrphanedFiles(aDBDir, knownBodyIdList);
  79. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  80. }
  81. return rv;
  82. }
  83. };
  84. // ----------------------------------------------------------------------------
  85. // Action that is executed when we determine that content has stopped using
  86. // a body file that has been orphaned.
  87. class DeleteOrphanedBodyAction final : public Action
  88. {
  89. public:
  90. explicit DeleteOrphanedBodyAction(const nsTArray<nsID>& aDeletedBodyIdList)
  91. : mDeletedBodyIdList(aDeletedBodyIdList)
  92. { }
  93. explicit DeleteOrphanedBodyAction(const nsID& aBodyId)
  94. {
  95. mDeletedBodyIdList.AppendElement(aBodyId);
  96. }
  97. virtual void
  98. RunOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo, Data*) override
  99. {
  100. MOZ_DIAGNOSTIC_ASSERT(aResolver);
  101. MOZ_DIAGNOSTIC_ASSERT(aQuotaInfo.mDir);
  102. // Note that since DeleteOrphanedBodyAction isn't used while the context is
  103. // being initialized, we don't need to check for cancellation here.
  104. nsCOMPtr<nsIFile> dbDir;
  105. nsresult rv = aQuotaInfo.mDir->Clone(getter_AddRefs(dbDir));
  106. if (NS_WARN_IF(NS_FAILED(rv))) {
  107. aResolver->Resolve(rv);
  108. return;
  109. }
  110. rv = dbDir->Append(NS_LITERAL_STRING("cache"));
  111. if (NS_WARN_IF(NS_FAILED(rv))) {
  112. aResolver->Resolve(rv);
  113. return;
  114. }
  115. rv = BodyDeleteFiles(dbDir, mDeletedBodyIdList);
  116. Unused << NS_WARN_IF(NS_FAILED(rv));
  117. aResolver->Resolve(rv);
  118. }
  119. private:
  120. nsTArray<nsID> mDeletedBodyIdList;
  121. };
  122. bool IsHeadRequest(const CacheRequest& aRequest, const CacheQueryParams& aParams)
  123. {
  124. return !aParams.ignoreMethod() && aRequest.method().LowerCaseEqualsLiteral("head");
  125. }
  126. bool IsHeadRequest(const CacheRequestOrVoid& aRequest, const CacheQueryParams& aParams)
  127. {
  128. if (aRequest.type() == CacheRequestOrVoid::TCacheRequest) {
  129. return !aParams.ignoreMethod() &&
  130. aRequest.get_CacheRequest().method().LowerCaseEqualsLiteral("head");
  131. }
  132. return false;
  133. }
  134. } // namespace
  135. // ----------------------------------------------------------------------------
  136. // Singleton class to track Manager instances and ensure there is only
  137. // one for each unique ManagerId.
  138. class Manager::Factory
  139. {
  140. public:
  141. friend class StaticAutoPtr<Manager::Factory>;
  142. static nsresult
  143. GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut)
  144. {
  145. mozilla::ipc::AssertIsOnBackgroundThread();
  146. // Ensure there is a factory instance. This forces the Get() call
  147. // below to use the same factory.
  148. nsresult rv = MaybeCreateInstance();
  149. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  150. RefPtr<Manager> ref = Get(aManagerId);
  151. if (!ref) {
  152. // TODO: replace this with a thread pool (bug 1119864)
  153. nsCOMPtr<nsIThread> ioThread;
  154. rv = NS_NewNamedThread("DOMCacheThread", getter_AddRefs(ioThread));
  155. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  156. ref = new Manager(aManagerId, ioThread);
  157. // There may be an old manager for this origin in the process of
  158. // cleaning up. We need to tell the new manager about this so
  159. // that it won't actually start until the old manager is done.
  160. RefPtr<Manager> oldManager = Get(aManagerId, Closing);
  161. ref->Init(oldManager);
  162. MOZ_ASSERT(!sFactory->mManagerList.Contains(ref));
  163. sFactory->mManagerList.AppendElement(ref);
  164. }
  165. ref.forget(aManagerOut);
  166. return NS_OK;
  167. }
  168. static already_AddRefed<Manager>
  169. Get(ManagerId* aManagerId, State aState = Open)
  170. {
  171. mozilla::ipc::AssertIsOnBackgroundThread();
  172. nsresult rv = MaybeCreateInstance();
  173. if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
  174. // Iterate in reverse to find the most recent, matching Manager. This
  175. // is important when looking for a Closing Manager. If a new Manager
  176. // chains to an old Manager we want it to be the most recent one.
  177. ManagerList::BackwardIterator iter(sFactory->mManagerList);
  178. while (iter.HasMore()) {
  179. RefPtr<Manager> manager = iter.GetNext();
  180. if (aState == manager->GetState() && *manager->mManagerId == *aManagerId) {
  181. return manager.forget();
  182. }
  183. }
  184. return nullptr;
  185. }
  186. static void
  187. Remove(Manager* aManager)
  188. {
  189. mozilla::ipc::AssertIsOnBackgroundThread();
  190. MOZ_DIAGNOSTIC_ASSERT(aManager);
  191. MOZ_DIAGNOSTIC_ASSERT(sFactory);
  192. MOZ_ALWAYS_TRUE(sFactory->mManagerList.RemoveElement(aManager));
  193. // clean up the factory singleton if there are no more managers
  194. MaybeDestroyInstance();
  195. }
  196. static void
  197. Abort(const nsACString& aOrigin)
  198. {
  199. mozilla::ipc::AssertIsOnBackgroundThread();
  200. if (!sFactory) {
  201. return;
  202. }
  203. MOZ_DIAGNOSTIC_ASSERT(!sFactory->mManagerList.IsEmpty());
  204. {
  205. ManagerList::ForwardIterator iter(sFactory->mManagerList);
  206. while (iter.HasMore()) {
  207. RefPtr<Manager> manager = iter.GetNext();
  208. if (aOrigin.IsVoid() ||
  209. manager->mManagerId->QuotaOrigin() == aOrigin) {
  210. manager->Abort();
  211. }
  212. }
  213. }
  214. }
  215. static void
  216. ShutdownAll()
  217. {
  218. mozilla::ipc::AssertIsOnBackgroundThread();
  219. if (!sFactory) {
  220. return;
  221. }
  222. MOZ_DIAGNOSTIC_ASSERT(!sFactory->mManagerList.IsEmpty());
  223. {
  224. // Note that we are synchronously calling shutdown code here. If any
  225. // of the shutdown code synchronously decides to delete the Factory
  226. // we need to delay that delete until the end of this method.
  227. AutoRestore<bool> restore(sFactory->mInSyncShutdown);
  228. sFactory->mInSyncShutdown = true;
  229. ManagerList::ForwardIterator iter(sFactory->mManagerList);
  230. while (iter.HasMore()) {
  231. RefPtr<Manager> manager = iter.GetNext();
  232. manager->Shutdown();
  233. }
  234. }
  235. MaybeDestroyInstance();
  236. }
  237. static bool
  238. IsShutdownAllComplete()
  239. {
  240. mozilla::ipc::AssertIsOnBackgroundThread();
  241. return !sFactory;
  242. }
  243. private:
  244. Factory()
  245. : mInSyncShutdown(false)
  246. {
  247. MOZ_COUNT_CTOR(cache::Manager::Factory);
  248. }
  249. ~Factory()
  250. {
  251. MOZ_COUNT_DTOR(cache::Manager::Factory);
  252. MOZ_DIAGNOSTIC_ASSERT(mManagerList.IsEmpty());
  253. MOZ_DIAGNOSTIC_ASSERT(!mInSyncShutdown);
  254. }
  255. static nsresult
  256. MaybeCreateInstance()
  257. {
  258. mozilla::ipc::AssertIsOnBackgroundThread();
  259. if (!sFactory) {
  260. // Be clear about what we are locking. sFactory is bg thread only, so
  261. // we don't need to lock it here. Just protect sFactoryShutdown and
  262. // sBackgroundThread.
  263. {
  264. StaticMutexAutoLock lock(sMutex);
  265. if (sFactoryShutdown) {
  266. return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
  267. }
  268. }
  269. // We cannot use ClearOnShutdown() here because we're not on the main
  270. // thread. Instead, we delete sFactory in Factory::Remove() after the
  271. // last manager is removed. ShutdownObserver ensures this happens
  272. // before shutdown.
  273. sFactory = new Factory();
  274. }
  275. // Never return sFactory to code outside Factory. We need to delete it
  276. // out from under ourselves just before we return from Remove(). This
  277. // would be (even more) dangerous if other code had a pointer to the
  278. // factory itself.
  279. return NS_OK;
  280. }
  281. static void
  282. MaybeDestroyInstance()
  283. {
  284. mozilla::ipc::AssertIsOnBackgroundThread();
  285. MOZ_DIAGNOSTIC_ASSERT(sFactory);
  286. // If the factory is is still in use then we cannot delete yet. This
  287. // could be due to managers still existing or because we are in the
  288. // middle of shutting down. We need to be careful not to delete ourself
  289. // synchronously during shutdown.
  290. if (!sFactory->mManagerList.IsEmpty() || sFactory->mInSyncShutdown) {
  291. return;
  292. }
  293. sFactory = nullptr;
  294. }
  295. // Singleton created on demand and deleted when last Manager is cleared
  296. // in Remove().
  297. // PBackground thread only.
  298. static StaticAutoPtr<Factory> sFactory;
  299. // protects following static attribute
  300. static StaticMutex sMutex;
  301. // Indicate if shutdown has occurred to block re-creation of sFactory.
  302. // Must hold sMutex to access.
  303. static bool sFactoryShutdown;
  304. // Weak references as we don't want to keep Manager objects alive forever.
  305. // When a Manager is destroyed it calls Factory::Remove() to clear itself.
  306. // PBackground thread only.
  307. typedef nsTObserverArray<Manager*> ManagerList;
  308. ManagerList mManagerList;
  309. // This flag is set when we are looping through the list and calling
  310. // Shutdown() on each Manager. We need to be careful not to synchronously
  311. // trigger the deletion of the factory while still executing this loop.
  312. bool mInSyncShutdown;
  313. };
  314. // static
  315. StaticAutoPtr<Manager::Factory> Manager::Factory::sFactory;
  316. // static
  317. StaticMutex Manager::Factory::sMutex;
  318. // static
  319. bool Manager::Factory::sFactoryShutdown = false;
  320. // ----------------------------------------------------------------------------
  321. // Abstract class to help implement the various Actions. The vast majority
  322. // of Actions are synchronous and need to report back to a Listener on the
  323. // Manager.
  324. class Manager::BaseAction : public SyncDBAction
  325. {
  326. protected:
  327. BaseAction(Manager* aManager, ListenerId aListenerId)
  328. : SyncDBAction(DBAction::Existing)
  329. , mManager(aManager)
  330. , mListenerId(aListenerId)
  331. {
  332. }
  333. virtual void
  334. Complete(Listener* aListener, ErrorResult&& aRv) = 0;
  335. virtual void
  336. CompleteOnInitiatingThread(nsresult aRv) override
  337. {
  338. NS_ASSERT_OWNINGTHREAD(Manager::BaseAction);
  339. Listener* listener = mManager->GetListener(mListenerId);
  340. if (listener) {
  341. Complete(listener, ErrorResult(aRv));
  342. }
  343. // ensure we release the manager on the initiating thread
  344. mManager = nullptr;
  345. }
  346. RefPtr<Manager> mManager;
  347. const ListenerId mListenerId;
  348. };
  349. // ----------------------------------------------------------------------------
  350. // Action that is executed when we determine that content has stopped using
  351. // a Cache object that has been orphaned.
  352. class Manager::DeleteOrphanedCacheAction final : public SyncDBAction
  353. {
  354. public:
  355. DeleteOrphanedCacheAction(Manager* aManager, CacheId aCacheId)
  356. : SyncDBAction(DBAction::Existing)
  357. , mManager(aManager)
  358. , mCacheId(aCacheId)
  359. { }
  360. virtual nsresult
  361. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  362. mozIStorageConnection* aConn) override
  363. {
  364. mozStorageTransaction trans(aConn, false,
  365. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  366. nsresult rv = db::DeleteCacheId(aConn, mCacheId, mDeletedBodyIdList);
  367. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  368. rv = trans.Commit();
  369. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  370. return rv;
  371. }
  372. virtual void
  373. CompleteOnInitiatingThread(nsresult aRv) override
  374. {
  375. mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
  376. // ensure we release the manager on the initiating thread
  377. mManager = nullptr;
  378. }
  379. private:
  380. RefPtr<Manager> mManager;
  381. const CacheId mCacheId;
  382. nsTArray<nsID> mDeletedBodyIdList;
  383. };
  384. // ----------------------------------------------------------------------------
  385. class Manager::CacheMatchAction final : public Manager::BaseAction
  386. {
  387. public:
  388. CacheMatchAction(Manager* aManager, ListenerId aListenerId,
  389. CacheId aCacheId, const CacheMatchArgs& aArgs,
  390. StreamList* aStreamList)
  391. : BaseAction(aManager, aListenerId)
  392. , mCacheId(aCacheId)
  393. , mArgs(aArgs)
  394. , mStreamList(aStreamList)
  395. , mFoundResponse(false)
  396. { }
  397. virtual nsresult
  398. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  399. mozIStorageConnection* aConn) override
  400. {
  401. nsresult rv = db::CacheMatch(aConn, mCacheId, mArgs.request(),
  402. mArgs.params(), &mFoundResponse, &mResponse);
  403. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  404. if (!mFoundResponse || !mResponse.mHasBodyId
  405. || IsHeadRequest(mArgs.request(), mArgs.params())) {
  406. mResponse.mHasBodyId = false;
  407. return rv;
  408. }
  409. nsCOMPtr<nsIInputStream> stream;
  410. rv = BodyOpen(aQuotaInfo, aDBDir, mResponse.mBodyId, getter_AddRefs(stream));
  411. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  412. if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
  413. mStreamList->Add(mResponse.mBodyId, stream);
  414. return rv;
  415. }
  416. virtual void
  417. Complete(Listener* aListener, ErrorResult&& aRv) override
  418. {
  419. if (!mFoundResponse) {
  420. aListener->OnOpComplete(Move(aRv), CacheMatchResult(void_t()));
  421. } else {
  422. mStreamList->Activate(mCacheId);
  423. aListener->OnOpComplete(Move(aRv), CacheMatchResult(void_t()), mResponse,
  424. mStreamList);
  425. }
  426. mStreamList = nullptr;
  427. }
  428. virtual bool MatchesCacheId(CacheId aCacheId) const override
  429. {
  430. return aCacheId == mCacheId;
  431. }
  432. private:
  433. const CacheId mCacheId;
  434. const CacheMatchArgs mArgs;
  435. RefPtr<StreamList> mStreamList;
  436. bool mFoundResponse;
  437. SavedResponse mResponse;
  438. };
  439. // ----------------------------------------------------------------------------
  440. class Manager::CacheMatchAllAction final : public Manager::BaseAction
  441. {
  442. public:
  443. CacheMatchAllAction(Manager* aManager, ListenerId aListenerId,
  444. CacheId aCacheId, const CacheMatchAllArgs& aArgs,
  445. StreamList* aStreamList)
  446. : BaseAction(aManager, aListenerId)
  447. , mCacheId(aCacheId)
  448. , mArgs(aArgs)
  449. , mStreamList(aStreamList)
  450. { }
  451. virtual nsresult
  452. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  453. mozIStorageConnection* aConn) override
  454. {
  455. nsresult rv = db::CacheMatchAll(aConn, mCacheId, mArgs.requestOrVoid(),
  456. mArgs.params(), mSavedResponses);
  457. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  458. for (uint32_t i = 0; i < mSavedResponses.Length(); ++i) {
  459. if (!mSavedResponses[i].mHasBodyId
  460. || IsHeadRequest(mArgs.requestOrVoid(), mArgs.params())) {
  461. mSavedResponses[i].mHasBodyId = false;
  462. continue;
  463. }
  464. nsCOMPtr<nsIInputStream> stream;
  465. rv = BodyOpen(aQuotaInfo, aDBDir, mSavedResponses[i].mBodyId,
  466. getter_AddRefs(stream));
  467. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  468. if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
  469. mStreamList->Add(mSavedResponses[i].mBodyId, stream);
  470. }
  471. return rv;
  472. }
  473. virtual void
  474. Complete(Listener* aListener, ErrorResult&& aRv) override
  475. {
  476. mStreamList->Activate(mCacheId);
  477. aListener->OnOpComplete(Move(aRv), CacheMatchAllResult(), mSavedResponses,
  478. mStreamList);
  479. mStreamList = nullptr;
  480. }
  481. virtual bool MatchesCacheId(CacheId aCacheId) const override
  482. {
  483. return aCacheId == mCacheId;
  484. }
  485. private:
  486. const CacheId mCacheId;
  487. const CacheMatchAllArgs mArgs;
  488. RefPtr<StreamList> mStreamList;
  489. nsTArray<SavedResponse> mSavedResponses;
  490. };
  491. // ----------------------------------------------------------------------------
  492. // This is the most complex Action. It puts a request/response pair into the
  493. // Cache. It does not complete until all of the body data has been saved to
  494. // disk. This means its an asynchronous Action.
  495. class Manager::CachePutAllAction final : public DBAction
  496. {
  497. public:
  498. CachePutAllAction(Manager* aManager, ListenerId aListenerId,
  499. CacheId aCacheId,
  500. const nsTArray<CacheRequestResponse>& aPutList,
  501. const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
  502. const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList)
  503. : DBAction(DBAction::Existing)
  504. , mManager(aManager)
  505. , mListenerId(aListenerId)
  506. , mCacheId(aCacheId)
  507. , mList(aPutList.Length())
  508. , mExpectedAsyncCopyCompletions(1)
  509. , mAsyncResult(NS_OK)
  510. , mMutex("cache::Manager::CachePutAllAction")
  511. {
  512. MOZ_DIAGNOSTIC_ASSERT(!aPutList.IsEmpty());
  513. MOZ_DIAGNOSTIC_ASSERT(aPutList.Length() == aRequestStreamList.Length());
  514. MOZ_DIAGNOSTIC_ASSERT(aPutList.Length() == aResponseStreamList.Length());
  515. for (uint32_t i = 0; i < aPutList.Length(); ++i) {
  516. Entry* entry = mList.AppendElement();
  517. entry->mRequest = aPutList[i].request();
  518. entry->mRequestStream = aRequestStreamList[i];
  519. entry->mResponse = aPutList[i].response();
  520. entry->mResponseStream = aResponseStreamList[i];
  521. }
  522. }
  523. private:
  524. ~CachePutAllAction() { }
  525. virtual void
  526. RunWithDBOnTarget(Resolver* aResolver, const QuotaInfo& aQuotaInfo,
  527. nsIFile* aDBDir, mozIStorageConnection* aConn) override
  528. {
  529. MOZ_DIAGNOSTIC_ASSERT(aResolver);
  530. MOZ_DIAGNOSTIC_ASSERT(aDBDir);
  531. MOZ_DIAGNOSTIC_ASSERT(aConn);
  532. MOZ_DIAGNOSTIC_ASSERT(!mResolver);
  533. MOZ_DIAGNOSTIC_ASSERT(!mDBDir);
  534. MOZ_DIAGNOSTIC_ASSERT(!mConn);
  535. MOZ_DIAGNOSTIC_ASSERT(!mTargetThread);
  536. mTargetThread = NS_GetCurrentThread();
  537. MOZ_DIAGNOSTIC_ASSERT(mTargetThread);
  538. // We should be pre-initialized to expect one async completion. This is
  539. // the "manual" completion we call at the end of this method in all
  540. // cases.
  541. MOZ_DIAGNOSTIC_ASSERT(mExpectedAsyncCopyCompletions == 1);
  542. mResolver = aResolver;
  543. mDBDir = aDBDir;
  544. mConn = aConn;
  545. // File bodies are streamed to disk via asynchronous copying. Start
  546. // this copying now. Each copy will eventually result in a call
  547. // to OnAsyncCopyComplete().
  548. nsresult rv = NS_OK;
  549. for (uint32_t i = 0; i < mList.Length(); ++i) {
  550. rv = StartStreamCopy(aQuotaInfo, mList[i], RequestStream,
  551. &mExpectedAsyncCopyCompletions);
  552. if (NS_WARN_IF(NS_FAILED(rv))) {
  553. break;
  554. }
  555. rv = StartStreamCopy(aQuotaInfo, mList[i], ResponseStream,
  556. &mExpectedAsyncCopyCompletions);
  557. if (NS_WARN_IF(NS_FAILED(rv))) {
  558. break;
  559. }
  560. }
  561. // Always call OnAsyncCopyComplete() manually here. This covers the
  562. // case where there is no async copying and also reports any startup
  563. // errors correctly. If we hit an error, then OnAsyncCopyComplete()
  564. // will cancel any async copying.
  565. OnAsyncCopyComplete(rv);
  566. }
  567. // Called once for each asynchronous file copy whether it succeeds or
  568. // fails. If a file copy is canceled, it still calls this method with
  569. // an error code.
  570. void
  571. OnAsyncCopyComplete(nsresult aRv)
  572. {
  573. MOZ_ASSERT(mTargetThread == NS_GetCurrentThread());
  574. MOZ_DIAGNOSTIC_ASSERT(mConn);
  575. MOZ_DIAGNOSTIC_ASSERT(mResolver);
  576. MOZ_DIAGNOSTIC_ASSERT(mExpectedAsyncCopyCompletions > 0);
  577. // Explicitly check for cancellation here to catch a race condition.
  578. // Consider:
  579. //
  580. // 1) NS_AsyncCopy() executes on IO thread, but has not saved its
  581. // copy context yet.
  582. // 2) CancelAllStreamCopying() occurs on PBackground thread
  583. // 3) Copy context from (1) is saved on IO thread.
  584. //
  585. // Checking for cancellation here catches this condition when we
  586. // first call OnAsyncCopyComplete() manually from RunWithDBOnTarget().
  587. //
  588. // This explicit cancellation check also handles the case where we
  589. // are canceled just after all stream copying completes. We should
  590. // abort the synchronous DB operations in this case if we have not
  591. // started them yet.
  592. if (NS_SUCCEEDED(aRv) && IsCanceled()) {
  593. aRv = NS_ERROR_ABORT;
  594. }
  595. // If any of the async copies fail, we need to still wait for them all to
  596. // complete. Cancel any other streams still working and remember the
  597. // error. All canceled streams will call OnAsyncCopyComplete().
  598. if (NS_FAILED(aRv) && NS_SUCCEEDED(mAsyncResult)) {
  599. CancelAllStreamCopying();
  600. mAsyncResult = aRv;
  601. }
  602. // Check to see if async copying is still on-going. If so, then simply
  603. // return for now. We must wait for a later OnAsyncCopyComplete() call.
  604. mExpectedAsyncCopyCompletions -= 1;
  605. if (mExpectedAsyncCopyCompletions > 0) {
  606. return;
  607. }
  608. // We have finished with all async copying. Indicate this by clearing all
  609. // our copy contexts.
  610. {
  611. MutexAutoLock lock(mMutex);
  612. mCopyContextList.Clear();
  613. }
  614. // An error occurred while async copying. Terminate the Action.
  615. // DoResolve() will clean up any files we may have written.
  616. if (NS_FAILED(mAsyncResult)) {
  617. DoResolve(mAsyncResult);
  618. return;
  619. }
  620. mozStorageTransaction trans(mConn, false,
  621. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  622. nsresult rv = NS_OK;
  623. for (uint32_t i = 0; i < mList.Length(); ++i) {
  624. Entry& e = mList[i];
  625. if (e.mRequestStream) {
  626. rv = BodyFinalizeWrite(mDBDir, e.mRequestBodyId);
  627. if (NS_WARN_IF(NS_FAILED(rv))) {
  628. DoResolve(rv);
  629. return;
  630. }
  631. }
  632. if (e.mResponseStream) {
  633. rv = BodyFinalizeWrite(mDBDir, e.mResponseBodyId);
  634. if (NS_WARN_IF(NS_FAILED(rv))) {
  635. DoResolve(rv);
  636. return;
  637. }
  638. }
  639. rv = db::CachePut(mConn, mCacheId, e.mRequest,
  640. e.mRequestStream ? &e.mRequestBodyId : nullptr,
  641. e.mResponse,
  642. e.mResponseStream ? &e.mResponseBodyId : nullptr,
  643. mDeletedBodyIdList);
  644. if (NS_WARN_IF(NS_FAILED(rv))) {
  645. DoResolve(rv);
  646. return;
  647. }
  648. }
  649. rv = trans.Commit();
  650. Unused << NS_WARN_IF(NS_FAILED(rv));
  651. DoResolve(rv);
  652. }
  653. virtual void
  654. CompleteOnInitiatingThread(nsresult aRv) override
  655. {
  656. NS_ASSERT_OWNINGTHREAD(Action);
  657. for (uint32_t i = 0; i < mList.Length(); ++i) {
  658. mList[i].mRequestStream = nullptr;
  659. mList[i].mResponseStream = nullptr;
  660. }
  661. mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
  662. Listener* listener = mManager->GetListener(mListenerId);
  663. mManager = nullptr;
  664. if (listener) {
  665. listener->OnOpComplete(ErrorResult(aRv), CachePutAllResult());
  666. }
  667. }
  668. virtual void
  669. CancelOnInitiatingThread() override
  670. {
  671. NS_ASSERT_OWNINGTHREAD(Action);
  672. Action::CancelOnInitiatingThread();
  673. CancelAllStreamCopying();
  674. }
  675. virtual bool MatchesCacheId(CacheId aCacheId) const override
  676. {
  677. NS_ASSERT_OWNINGTHREAD(Action);
  678. return aCacheId == mCacheId;
  679. }
  680. struct Entry
  681. {
  682. CacheRequest mRequest;
  683. nsCOMPtr<nsIInputStream> mRequestStream;
  684. nsID mRequestBodyId;
  685. nsCOMPtr<nsISupports> mRequestCopyContext;
  686. CacheResponse mResponse;
  687. nsCOMPtr<nsIInputStream> mResponseStream;
  688. nsID mResponseBodyId;
  689. nsCOMPtr<nsISupports> mResponseCopyContext;
  690. };
  691. enum StreamId
  692. {
  693. RequestStream,
  694. ResponseStream
  695. };
  696. nsresult
  697. StartStreamCopy(const QuotaInfo& aQuotaInfo, Entry& aEntry,
  698. StreamId aStreamId, uint32_t* aCopyCountOut)
  699. {
  700. MOZ_ASSERT(mTargetThread == NS_GetCurrentThread());
  701. MOZ_DIAGNOSTIC_ASSERT(aCopyCountOut);
  702. if (IsCanceled()) {
  703. return NS_ERROR_ABORT;
  704. }
  705. nsCOMPtr<nsIInputStream> source;
  706. nsID* bodyId;
  707. if (aStreamId == RequestStream) {
  708. source = aEntry.mRequestStream;
  709. bodyId = &aEntry.mRequestBodyId;
  710. } else {
  711. MOZ_DIAGNOSTIC_ASSERT(aStreamId == ResponseStream);
  712. source = aEntry.mResponseStream;
  713. bodyId = &aEntry.mResponseBodyId;
  714. }
  715. if (!source) {
  716. return NS_OK;
  717. }
  718. nsCOMPtr<nsISupports> copyContext;
  719. nsresult rv = BodyStartWriteStream(aQuotaInfo, mDBDir, source, this,
  720. AsyncCopyCompleteFunc, bodyId,
  721. getter_AddRefs(copyContext));
  722. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  723. mBodyIdWrittenList.AppendElement(*bodyId);
  724. if (copyContext) {
  725. MutexAutoLock lock(mMutex);
  726. mCopyContextList.AppendElement(copyContext);
  727. }
  728. *aCopyCountOut += 1;
  729. return rv;
  730. }
  731. void
  732. CancelAllStreamCopying()
  733. {
  734. // May occur on either owning thread or target thread
  735. MutexAutoLock lock(mMutex);
  736. for (uint32_t i = 0; i < mCopyContextList.Length(); ++i) {
  737. BodyCancelWrite(mDBDir, mCopyContextList[i]);
  738. }
  739. mCopyContextList.Clear();
  740. }
  741. static void
  742. AsyncCopyCompleteFunc(void* aClosure, nsresult aRv)
  743. {
  744. // May be on any thread, including STS event target.
  745. MOZ_DIAGNOSTIC_ASSERT(aClosure);
  746. // Weak ref as we are guaranteed to the action is alive until
  747. // CompleteOnInitiatingThread is called.
  748. CachePutAllAction* action = static_cast<CachePutAllAction*>(aClosure);
  749. action->CallOnAsyncCopyCompleteOnTargetThread(aRv);
  750. }
  751. void
  752. CallOnAsyncCopyCompleteOnTargetThread(nsresult aRv)
  753. {
  754. // May be on any thread, including STS event target. Non-owning runnable
  755. // here since we are guaranteed the Action will survive until
  756. // CompleteOnInitiatingThread is called.
  757. nsCOMPtr<nsIRunnable> runnable = NewNonOwningRunnableMethod<nsresult>(
  758. this, &CachePutAllAction::OnAsyncCopyComplete, aRv);
  759. MOZ_ALWAYS_SUCCEEDS(
  760. mTargetThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL));
  761. }
  762. void
  763. DoResolve(nsresult aRv)
  764. {
  765. MOZ_ASSERT(mTargetThread == NS_GetCurrentThread());
  766. // DoResolve() must not be called until all async copying has completed.
  767. #ifdef DEBUG
  768. {
  769. MutexAutoLock lock(mMutex);
  770. MOZ_ASSERT(mCopyContextList.IsEmpty());
  771. }
  772. #endif
  773. // Clean up any files we might have written before hitting the error.
  774. if (NS_FAILED(aRv)) {
  775. BodyDeleteFiles(mDBDir, mBodyIdWrittenList);
  776. }
  777. // Must be released on the target thread where it was opened.
  778. mConn = nullptr;
  779. // Drop our ref to the target thread as we are done with this thread.
  780. // Also makes our thread assertions catch any incorrect method calls
  781. // after resolve.
  782. mTargetThread = nullptr;
  783. // Make sure to de-ref the resolver per the Action API contract.
  784. RefPtr<Action::Resolver> resolver;
  785. mResolver.swap(resolver);
  786. resolver->Resolve(aRv);
  787. }
  788. // initiating thread only
  789. RefPtr<Manager> mManager;
  790. const ListenerId mListenerId;
  791. // Set on initiating thread, read on target thread. State machine guarantees
  792. // these are not modified while being read by the target thread.
  793. const CacheId mCacheId;
  794. nsTArray<Entry> mList;
  795. uint32_t mExpectedAsyncCopyCompletions;
  796. // target thread only
  797. RefPtr<Resolver> mResolver;
  798. nsCOMPtr<nsIFile> mDBDir;
  799. nsCOMPtr<mozIStorageConnection> mConn;
  800. nsCOMPtr<nsIThread> mTargetThread;
  801. nsresult mAsyncResult;
  802. nsTArray<nsID> mBodyIdWrittenList;
  803. // Written to on target thread, accessed on initiating thread after target
  804. // thread activity is guaranteed complete
  805. nsTArray<nsID> mDeletedBodyIdList;
  806. // accessed from any thread while mMutex locked
  807. Mutex mMutex;
  808. nsTArray<nsCOMPtr<nsISupports>> mCopyContextList;
  809. };
  810. // ----------------------------------------------------------------------------
  811. class Manager::CacheDeleteAction final : public Manager::BaseAction
  812. {
  813. public:
  814. CacheDeleteAction(Manager* aManager, ListenerId aListenerId,
  815. CacheId aCacheId, const CacheDeleteArgs& aArgs)
  816. : BaseAction(aManager, aListenerId)
  817. , mCacheId(aCacheId)
  818. , mArgs(aArgs)
  819. , mSuccess(false)
  820. { }
  821. virtual nsresult
  822. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  823. mozIStorageConnection* aConn) override
  824. {
  825. mozStorageTransaction trans(aConn, false,
  826. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  827. nsresult rv = db::CacheDelete(aConn, mCacheId, mArgs.request(),
  828. mArgs.params(), mDeletedBodyIdList,
  829. &mSuccess);
  830. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  831. rv = trans.Commit();
  832. if (NS_WARN_IF(NS_FAILED(rv))) {
  833. mSuccess = false;
  834. return rv;
  835. }
  836. return rv;
  837. }
  838. virtual void
  839. Complete(Listener* aListener, ErrorResult&& aRv) override
  840. {
  841. mManager->NoteOrphanedBodyIdList(mDeletedBodyIdList);
  842. aListener->OnOpComplete(Move(aRv), CacheDeleteResult(mSuccess));
  843. }
  844. virtual bool MatchesCacheId(CacheId aCacheId) const override
  845. {
  846. return aCacheId == mCacheId;
  847. }
  848. private:
  849. const CacheId mCacheId;
  850. const CacheDeleteArgs mArgs;
  851. bool mSuccess;
  852. nsTArray<nsID> mDeletedBodyIdList;
  853. };
  854. // ----------------------------------------------------------------------------
  855. class Manager::CacheKeysAction final : public Manager::BaseAction
  856. {
  857. public:
  858. CacheKeysAction(Manager* aManager, ListenerId aListenerId,
  859. CacheId aCacheId, const CacheKeysArgs& aArgs,
  860. StreamList* aStreamList)
  861. : BaseAction(aManager, aListenerId)
  862. , mCacheId(aCacheId)
  863. , mArgs(aArgs)
  864. , mStreamList(aStreamList)
  865. { }
  866. virtual nsresult
  867. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  868. mozIStorageConnection* aConn) override
  869. {
  870. nsresult rv = db::CacheKeys(aConn, mCacheId, mArgs.requestOrVoid(),
  871. mArgs.params(), mSavedRequests);
  872. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  873. for (uint32_t i = 0; i < mSavedRequests.Length(); ++i) {
  874. if (!mSavedRequests[i].mHasBodyId
  875. || IsHeadRequest(mArgs.requestOrVoid(), mArgs.params())) {
  876. mSavedRequests[i].mHasBodyId = false;
  877. continue;
  878. }
  879. nsCOMPtr<nsIInputStream> stream;
  880. rv = BodyOpen(aQuotaInfo, aDBDir, mSavedRequests[i].mBodyId,
  881. getter_AddRefs(stream));
  882. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  883. if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
  884. mStreamList->Add(mSavedRequests[i].mBodyId, stream);
  885. }
  886. return rv;
  887. }
  888. virtual void
  889. Complete(Listener* aListener, ErrorResult&& aRv) override
  890. {
  891. mStreamList->Activate(mCacheId);
  892. aListener->OnOpComplete(Move(aRv), CacheKeysResult(), mSavedRequests,
  893. mStreamList);
  894. mStreamList = nullptr;
  895. }
  896. virtual bool MatchesCacheId(CacheId aCacheId) const override
  897. {
  898. return aCacheId == mCacheId;
  899. }
  900. private:
  901. const CacheId mCacheId;
  902. const CacheKeysArgs mArgs;
  903. RefPtr<StreamList> mStreamList;
  904. nsTArray<SavedRequest> mSavedRequests;
  905. };
  906. // ----------------------------------------------------------------------------
  907. class Manager::StorageMatchAction final : public Manager::BaseAction
  908. {
  909. public:
  910. StorageMatchAction(Manager* aManager, ListenerId aListenerId,
  911. Namespace aNamespace,
  912. const StorageMatchArgs& aArgs,
  913. StreamList* aStreamList)
  914. : BaseAction(aManager, aListenerId)
  915. , mNamespace(aNamespace)
  916. , mArgs(aArgs)
  917. , mStreamList(aStreamList)
  918. , mFoundResponse(false)
  919. { }
  920. virtual nsresult
  921. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  922. mozIStorageConnection* aConn) override
  923. {
  924. nsresult rv = db::StorageMatch(aConn, mNamespace, mArgs.request(),
  925. mArgs.params(), &mFoundResponse,
  926. &mSavedResponse);
  927. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  928. if (!mFoundResponse || !mSavedResponse.mHasBodyId
  929. || IsHeadRequest(mArgs.request(), mArgs.params())) {
  930. mSavedResponse.mHasBodyId = false;
  931. return rv;
  932. }
  933. nsCOMPtr<nsIInputStream> stream;
  934. rv = BodyOpen(aQuotaInfo, aDBDir, mSavedResponse.mBodyId,
  935. getter_AddRefs(stream));
  936. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  937. if (NS_WARN_IF(!stream)) { return NS_ERROR_FILE_NOT_FOUND; }
  938. mStreamList->Add(mSavedResponse.mBodyId, stream);
  939. return rv;
  940. }
  941. virtual void
  942. Complete(Listener* aListener, ErrorResult&& aRv) override
  943. {
  944. if (!mFoundResponse) {
  945. aListener->OnOpComplete(Move(aRv), StorageMatchResult(void_t()));
  946. } else {
  947. mStreamList->Activate(mSavedResponse.mCacheId);
  948. aListener->OnOpComplete(Move(aRv), StorageMatchResult(void_t()), mSavedResponse,
  949. mStreamList);
  950. }
  951. mStreamList = nullptr;
  952. }
  953. private:
  954. const Namespace mNamespace;
  955. const StorageMatchArgs mArgs;
  956. RefPtr<StreamList> mStreamList;
  957. bool mFoundResponse;
  958. SavedResponse mSavedResponse;
  959. };
  960. // ----------------------------------------------------------------------------
  961. class Manager::StorageHasAction final : public Manager::BaseAction
  962. {
  963. public:
  964. StorageHasAction(Manager* aManager, ListenerId aListenerId,
  965. Namespace aNamespace, const StorageHasArgs& aArgs)
  966. : BaseAction(aManager, aListenerId)
  967. , mNamespace(aNamespace)
  968. , mArgs(aArgs)
  969. , mCacheFound(false)
  970. { }
  971. virtual nsresult
  972. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  973. mozIStorageConnection* aConn) override
  974. {
  975. CacheId cacheId;
  976. return db::StorageGetCacheId(aConn, mNamespace, mArgs.key(),
  977. &mCacheFound, &cacheId);
  978. }
  979. virtual void
  980. Complete(Listener* aListener, ErrorResult&& aRv) override
  981. {
  982. aListener->OnOpComplete(Move(aRv), StorageHasResult(mCacheFound));
  983. }
  984. private:
  985. const Namespace mNamespace;
  986. const StorageHasArgs mArgs;
  987. bool mCacheFound;
  988. };
  989. // ----------------------------------------------------------------------------
  990. class Manager::StorageOpenAction final : public Manager::BaseAction
  991. {
  992. public:
  993. StorageOpenAction(Manager* aManager, ListenerId aListenerId,
  994. Namespace aNamespace, const StorageOpenArgs& aArgs)
  995. : BaseAction(aManager, aListenerId)
  996. , mNamespace(aNamespace)
  997. , mArgs(aArgs)
  998. , mCacheId(INVALID_CACHE_ID)
  999. { }
  1000. virtual nsresult
  1001. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  1002. mozIStorageConnection* aConn) override
  1003. {
  1004. // Cache does not exist, create it instead
  1005. mozStorageTransaction trans(aConn, false,
  1006. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  1007. // Look for existing cache
  1008. bool cacheFound;
  1009. nsresult rv = db::StorageGetCacheId(aConn, mNamespace, mArgs.key(),
  1010. &cacheFound, &mCacheId);
  1011. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1012. if (cacheFound) {
  1013. MOZ_DIAGNOSTIC_ASSERT(mCacheId != INVALID_CACHE_ID);
  1014. return rv;
  1015. }
  1016. rv = db::CreateCacheId(aConn, &mCacheId);
  1017. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1018. rv = db::StoragePutCache(aConn, mNamespace, mArgs.key(), mCacheId);
  1019. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1020. rv = trans.Commit();
  1021. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1022. MOZ_DIAGNOSTIC_ASSERT(mCacheId != INVALID_CACHE_ID);
  1023. return rv;
  1024. }
  1025. virtual void
  1026. Complete(Listener* aListener, ErrorResult&& aRv) override
  1027. {
  1028. MOZ_DIAGNOSTIC_ASSERT(aRv.Failed() || mCacheId != INVALID_CACHE_ID);
  1029. aListener->OnOpComplete(Move(aRv), StorageOpenResult(), mCacheId);
  1030. }
  1031. private:
  1032. const Namespace mNamespace;
  1033. const StorageOpenArgs mArgs;
  1034. CacheId mCacheId;
  1035. };
  1036. // ----------------------------------------------------------------------------
  1037. class Manager::StorageDeleteAction final : public Manager::BaseAction
  1038. {
  1039. public:
  1040. StorageDeleteAction(Manager* aManager, ListenerId aListenerId,
  1041. Namespace aNamespace, const StorageDeleteArgs& aArgs)
  1042. : BaseAction(aManager, aListenerId)
  1043. , mNamespace(aNamespace)
  1044. , mArgs(aArgs)
  1045. , mCacheDeleted(false)
  1046. , mCacheId(INVALID_CACHE_ID)
  1047. { }
  1048. virtual nsresult
  1049. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  1050. mozIStorageConnection* aConn) override
  1051. {
  1052. mozStorageTransaction trans(aConn, false,
  1053. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  1054. bool exists;
  1055. nsresult rv = db::StorageGetCacheId(aConn, mNamespace, mArgs.key(),
  1056. &exists, &mCacheId);
  1057. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1058. if (!exists) {
  1059. mCacheDeleted = false;
  1060. return NS_OK;
  1061. }
  1062. rv = db::StorageForgetCache(aConn, mNamespace, mArgs.key());
  1063. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1064. rv = trans.Commit();
  1065. if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
  1066. mCacheDeleted = true;
  1067. return rv;
  1068. }
  1069. virtual void
  1070. Complete(Listener* aListener, ErrorResult&& aRv) override
  1071. {
  1072. if (mCacheDeleted) {
  1073. // If content is referencing this cache, mark it orphaned to be
  1074. // deleted later.
  1075. if (!mManager->SetCacheIdOrphanedIfRefed(mCacheId)) {
  1076. // no outstanding references, delete immediately
  1077. RefPtr<Context> context = mManager->mContext;
  1078. if (context->IsCanceled()) {
  1079. context->NoteOrphanedData();
  1080. } else {
  1081. context->CancelForCacheId(mCacheId);
  1082. RefPtr<Action> action =
  1083. new DeleteOrphanedCacheAction(mManager, mCacheId);
  1084. context->Dispatch(action);
  1085. }
  1086. }
  1087. }
  1088. aListener->OnOpComplete(Move(aRv), StorageDeleteResult(mCacheDeleted));
  1089. }
  1090. private:
  1091. const Namespace mNamespace;
  1092. const StorageDeleteArgs mArgs;
  1093. bool mCacheDeleted;
  1094. CacheId mCacheId;
  1095. };
  1096. // ----------------------------------------------------------------------------
  1097. class Manager::StorageKeysAction final : public Manager::BaseAction
  1098. {
  1099. public:
  1100. StorageKeysAction(Manager* aManager, ListenerId aListenerId,
  1101. Namespace aNamespace)
  1102. : BaseAction(aManager, aListenerId)
  1103. , mNamespace(aNamespace)
  1104. { }
  1105. virtual nsresult
  1106. RunSyncWithDBOnTarget(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
  1107. mozIStorageConnection* aConn) override
  1108. {
  1109. return db::StorageGetKeys(aConn, mNamespace, mKeys);
  1110. }
  1111. virtual void
  1112. Complete(Listener* aListener, ErrorResult&& aRv) override
  1113. {
  1114. if (aRv.Failed()) {
  1115. mKeys.Clear();
  1116. }
  1117. aListener->OnOpComplete(Move(aRv), StorageKeysResult(mKeys));
  1118. }
  1119. private:
  1120. const Namespace mNamespace;
  1121. nsTArray<nsString> mKeys;
  1122. };
  1123. // ----------------------------------------------------------------------------
  1124. //static
  1125. Manager::ListenerId Manager::sNextListenerId = 0;
  1126. void
  1127. Manager::Listener::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult)
  1128. {
  1129. OnOpComplete(Move(aRv), aResult, INVALID_CACHE_ID, nsTArray<SavedResponse>(),
  1130. nsTArray<SavedRequest>(), nullptr);
  1131. }
  1132. void
  1133. Manager::Listener::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
  1134. CacheId aOpenedCacheId)
  1135. {
  1136. OnOpComplete(Move(aRv), aResult, aOpenedCacheId, nsTArray<SavedResponse>(),
  1137. nsTArray<SavedRequest>(), nullptr);
  1138. }
  1139. void
  1140. Manager::Listener::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
  1141. const SavedResponse& aSavedResponse,
  1142. StreamList* aStreamList)
  1143. {
  1144. AutoTArray<SavedResponse, 1> responseList;
  1145. responseList.AppendElement(aSavedResponse);
  1146. OnOpComplete(Move(aRv), aResult, INVALID_CACHE_ID, responseList,
  1147. nsTArray<SavedRequest>(), aStreamList);
  1148. }
  1149. void
  1150. Manager::Listener::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
  1151. const nsTArray<SavedResponse>& aSavedResponseList,
  1152. StreamList* aStreamList)
  1153. {
  1154. OnOpComplete(Move(aRv), aResult, INVALID_CACHE_ID, aSavedResponseList,
  1155. nsTArray<SavedRequest>(), aStreamList);
  1156. }
  1157. void
  1158. Manager::Listener::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
  1159. const nsTArray<SavedRequest>& aSavedRequestList,
  1160. StreamList* aStreamList)
  1161. {
  1162. OnOpComplete(Move(aRv), aResult, INVALID_CACHE_ID, nsTArray<SavedResponse>(),
  1163. aSavedRequestList, aStreamList);
  1164. }
  1165. // static
  1166. nsresult
  1167. Manager::GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut)
  1168. {
  1169. mozilla::ipc::AssertIsOnBackgroundThread();
  1170. return Factory::GetOrCreate(aManagerId, aManagerOut);
  1171. }
  1172. // static
  1173. already_AddRefed<Manager>
  1174. Manager::Get(ManagerId* aManagerId)
  1175. {
  1176. mozilla::ipc::AssertIsOnBackgroundThread();
  1177. return Factory::Get(aManagerId);
  1178. }
  1179. // static
  1180. void
  1181. Manager::ShutdownAll()
  1182. {
  1183. mozilla::ipc::AssertIsOnBackgroundThread();
  1184. Factory::ShutdownAll();
  1185. while (!Factory::IsShutdownAllComplete()) {
  1186. if (!NS_ProcessNextEvent()) {
  1187. NS_WARNING("Something bad happened!");
  1188. break;
  1189. }
  1190. }
  1191. }
  1192. // static
  1193. void
  1194. Manager::Abort(const nsACString& aOrigin)
  1195. {
  1196. mozilla::ipc::AssertIsOnBackgroundThread();
  1197. Factory::Abort(aOrigin);
  1198. }
  1199. void
  1200. Manager::RemoveListener(Listener* aListener)
  1201. {
  1202. NS_ASSERT_OWNINGTHREAD(Manager);
  1203. // There may not be a listener here in the case where an actor is killed
  1204. // before it can perform any actual async requests on Manager.
  1205. mListeners.RemoveElement(aListener, ListenerEntryListenerComparator());
  1206. MOZ_ASSERT(!mListeners.Contains(aListener,
  1207. ListenerEntryListenerComparator()));
  1208. MaybeAllowContextToClose();
  1209. }
  1210. void
  1211. Manager::RemoveContext(Context* aContext)
  1212. {
  1213. NS_ASSERT_OWNINGTHREAD(Manager);
  1214. MOZ_DIAGNOSTIC_ASSERT(mContext);
  1215. MOZ_DIAGNOSTIC_ASSERT(mContext == aContext);
  1216. // Whether the Context destruction was triggered from the Manager going
  1217. // idle or the underlying storage being invalidated, we should know we
  1218. // are closing before the Context is destroyed.
  1219. MOZ_DIAGNOSTIC_ASSERT(mState == Closing);
  1220. // Before forgetting the Context, check to see if we have any outstanding
  1221. // cache or body objects waiting for deletion. If so, note that we've
  1222. // orphaned data so it will be cleaned up on the next open.
  1223. for (uint32_t i = 0; i < mCacheIdRefs.Length(); ++i) {
  1224. if (mCacheIdRefs[i].mOrphaned) {
  1225. aContext->NoteOrphanedData();
  1226. break;
  1227. }
  1228. }
  1229. for (uint32_t i = 0; i < mBodyIdRefs.Length(); ++i) {
  1230. if (mBodyIdRefs[i].mOrphaned) {
  1231. aContext->NoteOrphanedData();
  1232. break;
  1233. }
  1234. }
  1235. mContext = nullptr;
  1236. // Once the context is gone, we can immediately remove ourself from the
  1237. // Factory list. We don't need to block shutdown by staying in the list
  1238. // any more.
  1239. Factory::Remove(this);
  1240. }
  1241. void
  1242. Manager::NoteClosing()
  1243. {
  1244. NS_ASSERT_OWNINGTHREAD(Manager);
  1245. // This can be called more than once legitimately through different paths.
  1246. mState = Closing;
  1247. }
  1248. Manager::State
  1249. Manager::GetState() const
  1250. {
  1251. NS_ASSERT_OWNINGTHREAD(Manager);
  1252. return mState;
  1253. }
  1254. void
  1255. Manager::AddRefCacheId(CacheId aCacheId)
  1256. {
  1257. NS_ASSERT_OWNINGTHREAD(Manager);
  1258. for (uint32_t i = 0; i < mCacheIdRefs.Length(); ++i) {
  1259. if (mCacheIdRefs[i].mCacheId == aCacheId) {
  1260. mCacheIdRefs[i].mCount += 1;
  1261. return;
  1262. }
  1263. }
  1264. CacheIdRefCounter* entry = mCacheIdRefs.AppendElement();
  1265. entry->mCacheId = aCacheId;
  1266. entry->mCount = 1;
  1267. entry->mOrphaned = false;
  1268. }
  1269. void
  1270. Manager::ReleaseCacheId(CacheId aCacheId)
  1271. {
  1272. NS_ASSERT_OWNINGTHREAD(Manager);
  1273. for (uint32_t i = 0; i < mCacheIdRefs.Length(); ++i) {
  1274. if (mCacheIdRefs[i].mCacheId == aCacheId) {
  1275. #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
  1276. uint32_t oldRef = mCacheIdRefs[i].mCount;
  1277. #endif
  1278. mCacheIdRefs[i].mCount -= 1;
  1279. MOZ_DIAGNOSTIC_ASSERT(mCacheIdRefs[i].mCount < oldRef);
  1280. if (mCacheIdRefs[i].mCount == 0) {
  1281. bool orphaned = mCacheIdRefs[i].mOrphaned;
  1282. mCacheIdRefs.RemoveElementAt(i);
  1283. RefPtr<Context> context = mContext;
  1284. // If the context is already gone, then orphan flag should have been
  1285. // set in RemoveContext().
  1286. if (orphaned && context) {
  1287. if (context->IsCanceled()) {
  1288. context->NoteOrphanedData();
  1289. } else {
  1290. context->CancelForCacheId(aCacheId);
  1291. RefPtr<Action> action = new DeleteOrphanedCacheAction(this,
  1292. aCacheId);
  1293. context->Dispatch(action);
  1294. }
  1295. }
  1296. }
  1297. MaybeAllowContextToClose();
  1298. return;
  1299. }
  1300. }
  1301. MOZ_ASSERT_UNREACHABLE("Attempt to release CacheId that is not referenced!");
  1302. }
  1303. void
  1304. Manager::AddRefBodyId(const nsID& aBodyId)
  1305. {
  1306. NS_ASSERT_OWNINGTHREAD(Manager);
  1307. for (uint32_t i = 0; i < mBodyIdRefs.Length(); ++i) {
  1308. if (mBodyIdRefs[i].mBodyId == aBodyId) {
  1309. mBodyIdRefs[i].mCount += 1;
  1310. return;
  1311. }
  1312. }
  1313. BodyIdRefCounter* entry = mBodyIdRefs.AppendElement();
  1314. entry->mBodyId = aBodyId;
  1315. entry->mCount = 1;
  1316. entry->mOrphaned = false;
  1317. }
  1318. void
  1319. Manager::ReleaseBodyId(const nsID& aBodyId)
  1320. {
  1321. NS_ASSERT_OWNINGTHREAD(Manager);
  1322. for (uint32_t i = 0; i < mBodyIdRefs.Length(); ++i) {
  1323. if (mBodyIdRefs[i].mBodyId == aBodyId) {
  1324. #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
  1325. uint32_t oldRef = mBodyIdRefs[i].mCount;
  1326. #endif
  1327. mBodyIdRefs[i].mCount -= 1;
  1328. MOZ_DIAGNOSTIC_ASSERT(mBodyIdRefs[i].mCount < oldRef);
  1329. if (mBodyIdRefs[i].mCount < 1) {
  1330. bool orphaned = mBodyIdRefs[i].mOrphaned;
  1331. mBodyIdRefs.RemoveElementAt(i);
  1332. RefPtr<Context> context = mContext;
  1333. // If the context is already gone, then orphan flag should have been
  1334. // set in RemoveContext().
  1335. if (orphaned && context) {
  1336. if (context->IsCanceled()) {
  1337. context->NoteOrphanedData();
  1338. } else {
  1339. RefPtr<Action> action = new DeleteOrphanedBodyAction(aBodyId);
  1340. context->Dispatch(action);
  1341. }
  1342. }
  1343. }
  1344. MaybeAllowContextToClose();
  1345. return;
  1346. }
  1347. }
  1348. MOZ_ASSERT_UNREACHABLE("Attempt to release BodyId that is not referenced!");
  1349. }
  1350. already_AddRefed<ManagerId>
  1351. Manager::GetManagerId() const
  1352. {
  1353. RefPtr<ManagerId> ref = mManagerId;
  1354. return ref.forget();
  1355. }
  1356. void
  1357. Manager::AddStreamList(StreamList* aStreamList)
  1358. {
  1359. NS_ASSERT_OWNINGTHREAD(Manager);
  1360. MOZ_DIAGNOSTIC_ASSERT(aStreamList);
  1361. mStreamLists.AppendElement(aStreamList);
  1362. }
  1363. void
  1364. Manager::RemoveStreamList(StreamList* aStreamList)
  1365. {
  1366. NS_ASSERT_OWNINGTHREAD(Manager);
  1367. MOZ_DIAGNOSTIC_ASSERT(aStreamList);
  1368. mStreamLists.RemoveElement(aStreamList);
  1369. }
  1370. void
  1371. Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
  1372. const CacheOpArgs& aOpArgs)
  1373. {
  1374. NS_ASSERT_OWNINGTHREAD(Manager);
  1375. MOZ_DIAGNOSTIC_ASSERT(aListener);
  1376. MOZ_DIAGNOSTIC_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
  1377. if (NS_WARN_IF(mState == Closing)) {
  1378. aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
  1379. return;
  1380. }
  1381. RefPtr<Context> context = mContext;
  1382. MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
  1383. RefPtr<StreamList> streamList = new StreamList(this, context);
  1384. ListenerId listenerId = SaveListener(aListener);
  1385. RefPtr<Action> action;
  1386. switch(aOpArgs.type()) {
  1387. case CacheOpArgs::TCacheMatchArgs:
  1388. action = new CacheMatchAction(this, listenerId, aCacheId,
  1389. aOpArgs.get_CacheMatchArgs(), streamList);
  1390. break;
  1391. case CacheOpArgs::TCacheMatchAllArgs:
  1392. action = new CacheMatchAllAction(this, listenerId, aCacheId,
  1393. aOpArgs.get_CacheMatchAllArgs(),
  1394. streamList);
  1395. break;
  1396. case CacheOpArgs::TCacheDeleteArgs:
  1397. action = new CacheDeleteAction(this, listenerId, aCacheId,
  1398. aOpArgs.get_CacheDeleteArgs());
  1399. break;
  1400. case CacheOpArgs::TCacheKeysArgs:
  1401. action = new CacheKeysAction(this, listenerId, aCacheId,
  1402. aOpArgs.get_CacheKeysArgs(), streamList);
  1403. break;
  1404. default:
  1405. MOZ_CRASH("Unknown Cache operation!");
  1406. }
  1407. context->Dispatch(action);
  1408. }
  1409. void
  1410. Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace,
  1411. const CacheOpArgs& aOpArgs)
  1412. {
  1413. NS_ASSERT_OWNINGTHREAD(Manager);
  1414. MOZ_DIAGNOSTIC_ASSERT(aListener);
  1415. if (NS_WARN_IF(mState == Closing)) {
  1416. aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t());
  1417. return;
  1418. }
  1419. RefPtr<Context> context = mContext;
  1420. MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
  1421. RefPtr<StreamList> streamList = new StreamList(this, context);
  1422. ListenerId listenerId = SaveListener(aListener);
  1423. RefPtr<Action> action;
  1424. switch(aOpArgs.type()) {
  1425. case CacheOpArgs::TStorageMatchArgs:
  1426. action = new StorageMatchAction(this, listenerId, aNamespace,
  1427. aOpArgs.get_StorageMatchArgs(),
  1428. streamList);
  1429. break;
  1430. case CacheOpArgs::TStorageHasArgs:
  1431. action = new StorageHasAction(this, listenerId, aNamespace,
  1432. aOpArgs.get_StorageHasArgs());
  1433. break;
  1434. case CacheOpArgs::TStorageOpenArgs:
  1435. action = new StorageOpenAction(this, listenerId, aNamespace,
  1436. aOpArgs.get_StorageOpenArgs());
  1437. break;
  1438. case CacheOpArgs::TStorageDeleteArgs:
  1439. action = new StorageDeleteAction(this, listenerId, aNamespace,
  1440. aOpArgs.get_StorageDeleteArgs());
  1441. break;
  1442. case CacheOpArgs::TStorageKeysArgs:
  1443. action = new StorageKeysAction(this, listenerId, aNamespace);
  1444. break;
  1445. default:
  1446. MOZ_CRASH("Unknown CacheStorage operation!");
  1447. }
  1448. context->Dispatch(action);
  1449. }
  1450. void
  1451. Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId,
  1452. const nsTArray<CacheRequestResponse>& aPutList,
  1453. const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList,
  1454. const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList)
  1455. {
  1456. NS_ASSERT_OWNINGTHREAD(Manager);
  1457. MOZ_DIAGNOSTIC_ASSERT(aListener);
  1458. if (NS_WARN_IF(mState == Closing)) {
  1459. aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult());
  1460. return;
  1461. }
  1462. RefPtr<Context> context = mContext;
  1463. MOZ_DIAGNOSTIC_ASSERT(!context->IsCanceled());
  1464. ListenerId listenerId = SaveListener(aListener);
  1465. RefPtr<Action> action = new CachePutAllAction(this, listenerId, aCacheId,
  1466. aPutList, aRequestStreamList,
  1467. aResponseStreamList);
  1468. context->Dispatch(action);
  1469. }
  1470. Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread)
  1471. : mManagerId(aManagerId)
  1472. , mIOThread(aIOThread)
  1473. , mContext(nullptr)
  1474. , mShuttingDown(false)
  1475. , mState(Open)
  1476. {
  1477. MOZ_DIAGNOSTIC_ASSERT(mManagerId);
  1478. MOZ_DIAGNOSTIC_ASSERT(mIOThread);
  1479. }
  1480. Manager::~Manager()
  1481. {
  1482. NS_ASSERT_OWNINGTHREAD(Manager);
  1483. MOZ_DIAGNOSTIC_ASSERT(mState == Closing);
  1484. MOZ_DIAGNOSTIC_ASSERT(!mContext);
  1485. nsCOMPtr<nsIThread> ioThread;
  1486. mIOThread.swap(ioThread);
  1487. // Don't spin the event loop in the destructor waiting for the thread to
  1488. // shutdown. Defer this to the main thread, instead.
  1489. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewRunnableMethod(ioThread, &nsIThread::Shutdown)));
  1490. }
  1491. void
  1492. Manager::Init(Manager* aOldManager)
  1493. {
  1494. NS_ASSERT_OWNINGTHREAD(Manager);
  1495. RefPtr<Context> oldContext;
  1496. if (aOldManager) {
  1497. oldContext = aOldManager->mContext;
  1498. }
  1499. // Create the context immediately. Since there can at most be one Context
  1500. // per Manager now, this lets us cleanly call Factory::Remove() once the
  1501. // Context goes away.
  1502. RefPtr<Action> setupAction = new SetupAction();
  1503. RefPtr<Context> ref = Context::Create(this, mIOThread, setupAction,
  1504. oldContext);
  1505. mContext = ref;
  1506. }
  1507. void
  1508. Manager::Shutdown()
  1509. {
  1510. NS_ASSERT_OWNINGTHREAD(Manager);
  1511. // Ignore duplicate attempts to shutdown. This can occur when we start
  1512. // a browser initiated shutdown and then run ~Manager() which also
  1513. // calls Shutdown().
  1514. if (mShuttingDown) {
  1515. return;
  1516. }
  1517. mShuttingDown = true;
  1518. // Note that we are closing to prevent any new requests from coming in and
  1519. // creating a new Context. We must ensure all Contexts and IO operations are
  1520. // complete before shutdown proceeds.
  1521. NoteClosing();
  1522. // If there is a context, then cancel and only note that we are done after
  1523. // its cleaned up.
  1524. if (mContext) {
  1525. RefPtr<Context> context = mContext;
  1526. context->CancelAll();
  1527. return;
  1528. }
  1529. }
  1530. void
  1531. Manager::Abort()
  1532. {
  1533. NS_ASSERT_OWNINGTHREAD(Manager);
  1534. MOZ_DIAGNOSTIC_ASSERT(mContext);
  1535. // Note that we are closing to prevent any new requests from coming in and
  1536. // creating a new Context. We must ensure all Contexts and IO operations are
  1537. // complete before origin clear proceeds.
  1538. NoteClosing();
  1539. // Cancel and only note that we are done after the context is cleaned up.
  1540. RefPtr<Context> context = mContext;
  1541. context->CancelAll();
  1542. }
  1543. Manager::ListenerId
  1544. Manager::SaveListener(Listener* aListener)
  1545. {
  1546. NS_ASSERT_OWNINGTHREAD(Manager);
  1547. // Once a Listener is added, we keep a reference to it until its
  1548. // removed. Since the same Listener might make multiple requests,
  1549. // ensure we only have a single reference in our list.
  1550. ListenerList::index_type index =
  1551. mListeners.IndexOf(aListener, 0, ListenerEntryListenerComparator());
  1552. if (index != ListenerList::NoIndex) {
  1553. return mListeners[index].mId;
  1554. }
  1555. ListenerId id = sNextListenerId;
  1556. sNextListenerId += 1;
  1557. mListeners.AppendElement(ListenerEntry(id, aListener));
  1558. return id;
  1559. }
  1560. Manager::Listener*
  1561. Manager::GetListener(ListenerId aListenerId) const
  1562. {
  1563. NS_ASSERT_OWNINGTHREAD(Manager);
  1564. ListenerList::index_type index =
  1565. mListeners.IndexOf(aListenerId, 0, ListenerEntryIdComparator());
  1566. if (index != ListenerList::NoIndex) {
  1567. return mListeners[index].mListener;
  1568. }
  1569. // This can legitimately happen if the actor is deleted while a request is
  1570. // in process. For example, the child process OOMs.
  1571. return nullptr;
  1572. }
  1573. bool
  1574. Manager::SetCacheIdOrphanedIfRefed(CacheId aCacheId)
  1575. {
  1576. NS_ASSERT_OWNINGTHREAD(Manager);
  1577. for (uint32_t i = 0; i < mCacheIdRefs.Length(); ++i) {
  1578. if (mCacheIdRefs[i].mCacheId == aCacheId) {
  1579. MOZ_DIAGNOSTIC_ASSERT(mCacheIdRefs[i].mCount > 0);
  1580. MOZ_DIAGNOSTIC_ASSERT(!mCacheIdRefs[i].mOrphaned);
  1581. mCacheIdRefs[i].mOrphaned = true;
  1582. return true;
  1583. }
  1584. }
  1585. return false;
  1586. }
  1587. // TODO: provide way to set body non-orphaned if its added back to a cache (bug 1110479)
  1588. bool
  1589. Manager::SetBodyIdOrphanedIfRefed(const nsID& aBodyId)
  1590. {
  1591. NS_ASSERT_OWNINGTHREAD(Manager);
  1592. for (uint32_t i = 0; i < mBodyIdRefs.Length(); ++i) {
  1593. if (mBodyIdRefs[i].mBodyId == aBodyId) {
  1594. MOZ_DIAGNOSTIC_ASSERT(mBodyIdRefs[i].mCount > 0);
  1595. MOZ_DIAGNOSTIC_ASSERT(!mBodyIdRefs[i].mOrphaned);
  1596. mBodyIdRefs[i].mOrphaned = true;
  1597. return true;
  1598. }
  1599. }
  1600. return false;
  1601. }
  1602. void
  1603. Manager::NoteOrphanedBodyIdList(const nsTArray<nsID>& aDeletedBodyIdList)
  1604. {
  1605. NS_ASSERT_OWNINGTHREAD(Manager);
  1606. AutoTArray<nsID, 64> deleteNowList;
  1607. deleteNowList.SetCapacity(aDeletedBodyIdList.Length());
  1608. for (uint32_t i = 0; i < aDeletedBodyIdList.Length(); ++i) {
  1609. if (!SetBodyIdOrphanedIfRefed(aDeletedBodyIdList[i])) {
  1610. deleteNowList.AppendElement(aDeletedBodyIdList[i]);
  1611. }
  1612. }
  1613. // TODO: note that we need to check these bodies for staleness on startup (bug 1110446)
  1614. RefPtr<Context> context = mContext;
  1615. if (!deleteNowList.IsEmpty() && context && !context->IsCanceled()) {
  1616. RefPtr<Action> action = new DeleteOrphanedBodyAction(deleteNowList);
  1617. context->Dispatch(action);
  1618. }
  1619. }
  1620. void
  1621. Manager::MaybeAllowContextToClose()
  1622. {
  1623. NS_ASSERT_OWNINGTHREAD(Manager);
  1624. // If we have an active context, but we have no more users of the Manager,
  1625. // then let it shut itself down. We must wait for all possible users of
  1626. // Cache state information to complete before doing this. Once we allow
  1627. // the Context to close we may not reliably get notified of storage
  1628. // invalidation.
  1629. RefPtr<Context> context = mContext;
  1630. if (context && mListeners.IsEmpty()
  1631. && mCacheIdRefs.IsEmpty()
  1632. && mBodyIdRefs.IsEmpty()) {
  1633. // Mark this Manager as invalid so that it won't get used again. We don't
  1634. // want to start any new operations once we allow the Context to close since
  1635. // it may race with the underlying storage getting invalidated.
  1636. NoteClosing();
  1637. context->AllowToClose();
  1638. }
  1639. }
  1640. } // namespace cache
  1641. } // namespace dom
  1642. } // namespace mozilla