imgLoader.cpp 95 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986
  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 "ImageLogging.h"
  6. #include "imgLoader.h"
  7. #include "mozilla/Attributes.h"
  8. #include "mozilla/ClearOnShutdown.h"
  9. #include "mozilla/Move.h"
  10. #include "mozilla/Preferences.h"
  11. #include "mozilla/ChaosMode.h"
  12. #include "nsImageModule.h"
  13. #include "imgRequestProxy.h"
  14. #include "nsCOMPtr.h"
  15. #include "nsContentPolicyUtils.h"
  16. #include "nsContentUtils.h"
  17. #include "nsNetUtil.h"
  18. #include "nsNetCID.h"
  19. #include "nsIProtocolHandler.h"
  20. #include "nsMimeTypes.h"
  21. #include "nsStreamUtils.h"
  22. #include "nsIHttpChannel.h"
  23. #include "nsICacheInfoChannel.h"
  24. #include "nsIInterfaceRequestor.h"
  25. #include "nsIInterfaceRequestorUtils.h"
  26. #include "nsIProgressEventSink.h"
  27. #include "nsIChannelEventSink.h"
  28. #include "nsIAsyncVerifyRedirectCallback.h"
  29. #include "nsIFileURL.h"
  30. #include "nsIFile.h"
  31. #include "nsCRT.h"
  32. #include "nsINetworkPredictor.h"
  33. #include "mozilla/dom/ContentParent.h"
  34. #include "mozilla/dom/nsMixedContentBlocker.h"
  35. #include "nsIApplicationCache.h"
  36. #include "nsIApplicationCacheContainer.h"
  37. #include "nsIMemoryReporter.h"
  38. #include "DecoderFactory.h"
  39. #include "Image.h"
  40. #include "gfxPrefs.h"
  41. #include "prtime.h"
  42. // we want to explore making the document own the load group
  43. // so we can associate the document URI with the load group.
  44. // until this point, we have an evil hack:
  45. #include "nsIHttpChannelInternal.h"
  46. #include "nsILoadContext.h"
  47. #include "nsILoadGroupChild.h"
  48. #include "nsIDOMDocument.h"
  49. using namespace mozilla;
  50. using namespace mozilla::dom;
  51. using namespace mozilla::image;
  52. using namespace mozilla::net;
  53. MOZ_DEFINE_MALLOC_SIZE_OF(ImagesMallocSizeOf)
  54. class imgMemoryReporter final : public nsIMemoryReporter
  55. {
  56. ~imgMemoryReporter() { }
  57. public:
  58. NS_DECL_ISUPPORTS
  59. NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
  60. nsISupports* aData, bool aAnonymize) override
  61. {
  62. nsTArray<ImageMemoryCounter> chrome;
  63. nsTArray<ImageMemoryCounter> content;
  64. nsTArray<ImageMemoryCounter> uncached;
  65. for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) {
  66. for (auto iter = mKnownLoaders[i]->mChromeCache.Iter(); !iter.Done(); iter.Next()) {
  67. imgCacheEntry* entry = iter.UserData();
  68. RefPtr<imgRequest> req = entry->GetRequest();
  69. RecordCounterForRequest(req, &chrome, !entry->HasNoProxies());
  70. }
  71. for (auto iter = mKnownLoaders[i]->mCache.Iter(); !iter.Done(); iter.Next()) {
  72. imgCacheEntry* entry = iter.UserData();
  73. RefPtr<imgRequest> req = entry->GetRequest();
  74. RecordCounterForRequest(req, &content, !entry->HasNoProxies());
  75. }
  76. MutexAutoLock lock(mKnownLoaders[i]->mUncachedImagesMutex);
  77. for (auto iter = mKnownLoaders[i]->mUncachedImages.Iter();
  78. !iter.Done();
  79. iter.Next()) {
  80. nsPtrHashKey<imgRequest>* entry = iter.Get();
  81. RefPtr<imgRequest> req = entry->GetKey();
  82. RecordCounterForRequest(req, &uncached, req->HasConsumers());
  83. }
  84. }
  85. // Note that we only need to anonymize content image URIs.
  86. ReportCounterArray(aHandleReport, aData, chrome, "images/chrome");
  87. ReportCounterArray(aHandleReport, aData, content, "images/content",
  88. aAnonymize);
  89. // Uncached images may be content or chrome, so anonymize them.
  90. ReportCounterArray(aHandleReport, aData, uncached, "images/uncached",
  91. aAnonymize);
  92. return NS_OK;
  93. }
  94. static int64_t ImagesContentUsedUncompressedDistinguishedAmount()
  95. {
  96. size_t n = 0;
  97. for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length();
  98. i++) {
  99. for (auto iter = imgLoader::sMemReporter->mKnownLoaders[i]->mCache.Iter();
  100. !iter.Done();
  101. iter.Next()) {
  102. imgCacheEntry* entry = iter.UserData();
  103. if (entry->HasNoProxies()) {
  104. continue;
  105. }
  106. RefPtr<imgRequest> req = entry->GetRequest();
  107. RefPtr<Image> image = req->GetImage();
  108. if (!image) {
  109. continue;
  110. }
  111. // Both this and EntryImageSizes measure images/content/raster/used/decoded
  112. // memory. This function's measurement is secondary -- the result doesn't
  113. // go in the "explicit" tree -- so we use moz_malloc_size_of instead of
  114. // ImagesMallocSizeOf to prevent DMD from seeing it reported twice.
  115. ImageMemoryCounter counter(image, moz_malloc_size_of, /* aIsUsed = */ true);
  116. n += counter.Values().DecodedHeap();
  117. n += counter.Values().DecodedNonHeap();
  118. }
  119. }
  120. return n;
  121. }
  122. void RegisterLoader(imgLoader* aLoader)
  123. {
  124. mKnownLoaders.AppendElement(aLoader);
  125. }
  126. void UnregisterLoader(imgLoader* aLoader)
  127. {
  128. mKnownLoaders.RemoveElement(aLoader);
  129. }
  130. private:
  131. nsTArray<imgLoader*> mKnownLoaders;
  132. struct MemoryTotal
  133. {
  134. MemoryTotal& operator+=(const ImageMemoryCounter& aImageCounter)
  135. {
  136. if (aImageCounter.Type() == imgIContainer::TYPE_RASTER) {
  137. if (aImageCounter.IsUsed()) {
  138. mUsedRasterCounter += aImageCounter.Values();
  139. } else {
  140. mUnusedRasterCounter += aImageCounter.Values();
  141. }
  142. } else if (aImageCounter.Type() == imgIContainer::TYPE_VECTOR) {
  143. if (aImageCounter.IsUsed()) {
  144. mUsedVectorCounter += aImageCounter.Values();
  145. } else {
  146. mUnusedVectorCounter += aImageCounter.Values();
  147. }
  148. } else {
  149. MOZ_CRASH("Unexpected image type");
  150. }
  151. return *this;
  152. }
  153. const MemoryCounter& UsedRaster() const { return mUsedRasterCounter; }
  154. const MemoryCounter& UnusedRaster() const { return mUnusedRasterCounter; }
  155. const MemoryCounter& UsedVector() const { return mUsedVectorCounter; }
  156. const MemoryCounter& UnusedVector() const { return mUnusedVectorCounter; }
  157. private:
  158. MemoryCounter mUsedRasterCounter;
  159. MemoryCounter mUnusedRasterCounter;
  160. MemoryCounter mUsedVectorCounter;
  161. MemoryCounter mUnusedVectorCounter;
  162. };
  163. // Reports all images of a single kind, e.g. all used chrome images.
  164. void ReportCounterArray(nsIHandleReportCallback* aHandleReport,
  165. nsISupports* aData,
  166. nsTArray<ImageMemoryCounter>& aCounterArray,
  167. const char* aPathPrefix,
  168. bool aAnonymize = false)
  169. {
  170. MemoryTotal summaryTotal;
  171. MemoryTotal nonNotableTotal;
  172. // Report notable images, and compute total and non-notable aggregate sizes.
  173. for (uint32_t i = 0; i < aCounterArray.Length(); i++) {
  174. ImageMemoryCounter& counter = aCounterArray[i];
  175. if (aAnonymize) {
  176. counter.URI().Truncate();
  177. counter.URI().AppendPrintf("<anonymized-%u>", i);
  178. } else {
  179. // The URI could be an extremely long data: URI. Truncate if needed.
  180. static const size_t max = 256;
  181. if (counter.URI().Length() > max) {
  182. counter.URI().Truncate(max);
  183. counter.URI().AppendLiteral(" (truncated)");
  184. }
  185. counter.URI().ReplaceChar('/', '\\');
  186. }
  187. summaryTotal += counter;
  188. if (counter.IsNotable()) {
  189. ReportImage(aHandleReport, aData, aPathPrefix, counter);
  190. } else {
  191. nonNotableTotal += counter;
  192. }
  193. }
  194. // Report non-notable images in aggregate.
  195. ReportTotal(aHandleReport, aData, /* aExplicit = */ true,
  196. aPathPrefix, "<non-notable images>/", nonNotableTotal);
  197. // Report a summary in aggregate, outside of the explicit tree.
  198. ReportTotal(aHandleReport, aData, /* aExplicit = */ false,
  199. aPathPrefix, "", summaryTotal);
  200. }
  201. static void ReportImage(nsIHandleReportCallback* aHandleReport,
  202. nsISupports* aData,
  203. const char* aPathPrefix,
  204. const ImageMemoryCounter& aCounter)
  205. {
  206. nsAutoCString pathPrefix(NS_LITERAL_CSTRING("explicit/"));
  207. pathPrefix.Append(aPathPrefix);
  208. pathPrefix.Append(aCounter.Type() == imgIContainer::TYPE_RASTER
  209. ? "/raster/"
  210. : "/vector/");
  211. pathPrefix.Append(aCounter.IsUsed() ? "used/" : "unused/");
  212. pathPrefix.Append("image(");
  213. pathPrefix.AppendInt(aCounter.IntrinsicSize().width);
  214. pathPrefix.Append("x");
  215. pathPrefix.AppendInt(aCounter.IntrinsicSize().height);
  216. pathPrefix.Append(", ");
  217. if (aCounter.URI().IsEmpty()) {
  218. pathPrefix.Append("<unknown URI>");
  219. } else {
  220. pathPrefix.Append(aCounter.URI());
  221. }
  222. pathPrefix.Append(")/");
  223. ReportSurfaces(aHandleReport, aData, pathPrefix, aCounter);
  224. ReportSourceValue(aHandleReport, aData, pathPrefix, aCounter.Values());
  225. }
  226. static void ReportSurfaces(nsIHandleReportCallback* aHandleReport,
  227. nsISupports* aData,
  228. const nsACString& aPathPrefix,
  229. const ImageMemoryCounter& aCounter)
  230. {
  231. for (const SurfaceMemoryCounter& counter : aCounter.Surfaces()) {
  232. nsAutoCString surfacePathPrefix(aPathPrefix);
  233. surfacePathPrefix.Append(counter.IsLocked() ? "locked/" : "unlocked/");
  234. surfacePathPrefix.Append("surface(");
  235. surfacePathPrefix.AppendInt(counter.Key().Size().width);
  236. surfacePathPrefix.Append("x");
  237. surfacePathPrefix.AppendInt(counter.Key().Size().height);
  238. if (counter.Type() == SurfaceMemoryCounterType::NORMAL) {
  239. PlaybackType playback = counter.Key().Playback();
  240. surfacePathPrefix.Append(playback == PlaybackType::eAnimated
  241. ? " (animation)"
  242. : "");
  243. if (counter.Key().Flags() != DefaultSurfaceFlags()) {
  244. surfacePathPrefix.Append(", flags:");
  245. surfacePathPrefix.AppendInt(uint32_t(counter.Key().Flags()),
  246. /* aRadix = */ 16);
  247. }
  248. } else if (counter.Type() == SurfaceMemoryCounterType::COMPOSITING) {
  249. surfacePathPrefix.Append(", compositing frame");
  250. } else if (counter.Type() == SurfaceMemoryCounterType::COMPOSITING_PREV) {
  251. surfacePathPrefix.Append(", compositing prev frame");
  252. } else {
  253. MOZ_ASSERT_UNREACHABLE("Unknown counter type");
  254. }
  255. surfacePathPrefix.Append(")/");
  256. ReportValues(aHandleReport, aData, surfacePathPrefix, counter.Values());
  257. }
  258. }
  259. static void ReportTotal(nsIHandleReportCallback* aHandleReport,
  260. nsISupports* aData,
  261. bool aExplicit,
  262. const char* aPathPrefix,
  263. const char* aPathInfix,
  264. const MemoryTotal& aTotal)
  265. {
  266. nsAutoCString pathPrefix;
  267. if (aExplicit) {
  268. pathPrefix.Append("explicit/");
  269. }
  270. pathPrefix.Append(aPathPrefix);
  271. nsAutoCString rasterUsedPrefix(pathPrefix);
  272. rasterUsedPrefix.Append("/raster/used/");
  273. rasterUsedPrefix.Append(aPathInfix);
  274. ReportValues(aHandleReport, aData, rasterUsedPrefix, aTotal.UsedRaster());
  275. nsAutoCString rasterUnusedPrefix(pathPrefix);
  276. rasterUnusedPrefix.Append("/raster/unused/");
  277. rasterUnusedPrefix.Append(aPathInfix);
  278. ReportValues(aHandleReport, aData, rasterUnusedPrefix,
  279. aTotal.UnusedRaster());
  280. nsAutoCString vectorUsedPrefix(pathPrefix);
  281. vectorUsedPrefix.Append("/vector/used/");
  282. vectorUsedPrefix.Append(aPathInfix);
  283. ReportValues(aHandleReport, aData, vectorUsedPrefix, aTotal.UsedVector());
  284. nsAutoCString vectorUnusedPrefix(pathPrefix);
  285. vectorUnusedPrefix.Append("/vector/unused/");
  286. vectorUnusedPrefix.Append(aPathInfix);
  287. ReportValues(aHandleReport, aData, vectorUnusedPrefix,
  288. aTotal.UnusedVector());
  289. }
  290. static void ReportValues(nsIHandleReportCallback* aHandleReport,
  291. nsISupports* aData,
  292. const nsACString& aPathPrefix,
  293. const MemoryCounter& aCounter)
  294. {
  295. ReportSourceValue(aHandleReport, aData, aPathPrefix, aCounter);
  296. ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix,
  297. "decoded-heap",
  298. "Decoded image data which is stored on the heap.",
  299. aCounter.DecodedHeap());
  300. ReportValue(aHandleReport, aData, KIND_NONHEAP, aPathPrefix,
  301. "decoded-nonheap",
  302. "Decoded image data which isn't stored on the heap.",
  303. aCounter.DecodedNonHeap());
  304. }
  305. static void ReportSourceValue(nsIHandleReportCallback* aHandleReport,
  306. nsISupports* aData,
  307. const nsACString& aPathPrefix,
  308. const MemoryCounter& aCounter)
  309. {
  310. ReportValue(aHandleReport, aData, KIND_HEAP, aPathPrefix,
  311. "source",
  312. "Raster image source data and vector image documents.",
  313. aCounter.Source());
  314. }
  315. static void ReportValue(nsIHandleReportCallback* aHandleReport,
  316. nsISupports* aData,
  317. int32_t aKind,
  318. const nsACString& aPathPrefix,
  319. const char* aPathSuffix,
  320. const char* aDescription,
  321. size_t aValue)
  322. {
  323. if (aValue == 0) {
  324. return;
  325. }
  326. nsAutoCString desc(aDescription);
  327. nsAutoCString path(aPathPrefix);
  328. path.Append(aPathSuffix);
  329. aHandleReport->Callback(EmptyCString(), path, aKind, UNITS_BYTES,
  330. aValue, desc, aData);
  331. }
  332. static void RecordCounterForRequest(imgRequest* aRequest,
  333. nsTArray<ImageMemoryCounter>* aArray,
  334. bool aIsUsed)
  335. {
  336. RefPtr<Image> image = aRequest->GetImage();
  337. if (!image) {
  338. return;
  339. }
  340. ImageMemoryCounter counter(image, ImagesMallocSizeOf, aIsUsed);
  341. aArray->AppendElement(Move(counter));
  342. }
  343. };
  344. NS_IMPL_ISUPPORTS(imgMemoryReporter, nsIMemoryReporter)
  345. NS_IMPL_ISUPPORTS(nsProgressNotificationProxy,
  346. nsIProgressEventSink,
  347. nsIChannelEventSink,
  348. nsIInterfaceRequestor)
  349. NS_IMETHODIMP
  350. nsProgressNotificationProxy::OnProgress(nsIRequest* request,
  351. nsISupports* ctxt,
  352. int64_t progress,
  353. int64_t progressMax)
  354. {
  355. nsCOMPtr<nsILoadGroup> loadGroup;
  356. request->GetLoadGroup(getter_AddRefs(loadGroup));
  357. nsCOMPtr<nsIProgressEventSink> target;
  358. NS_QueryNotificationCallbacks(mOriginalCallbacks,
  359. loadGroup,
  360. NS_GET_IID(nsIProgressEventSink),
  361. getter_AddRefs(target));
  362. if (!target) {
  363. return NS_OK;
  364. }
  365. return target->OnProgress(mImageRequest, ctxt, progress, progressMax);
  366. }
  367. NS_IMETHODIMP
  368. nsProgressNotificationProxy::OnStatus(nsIRequest* request,
  369. nsISupports* ctxt,
  370. nsresult status,
  371. const char16_t* statusArg)
  372. {
  373. nsCOMPtr<nsILoadGroup> loadGroup;
  374. request->GetLoadGroup(getter_AddRefs(loadGroup));
  375. nsCOMPtr<nsIProgressEventSink> target;
  376. NS_QueryNotificationCallbacks(mOriginalCallbacks,
  377. loadGroup,
  378. NS_GET_IID(nsIProgressEventSink),
  379. getter_AddRefs(target));
  380. if (!target) {
  381. return NS_OK;
  382. }
  383. return target->OnStatus(mImageRequest, ctxt, status, statusArg);
  384. }
  385. NS_IMETHODIMP
  386. nsProgressNotificationProxy::
  387. AsyncOnChannelRedirect(nsIChannel* oldChannel,
  388. nsIChannel* newChannel,
  389. uint32_t flags,
  390. nsIAsyncVerifyRedirectCallback* cb)
  391. {
  392. // Tell the original original callbacks about it too
  393. nsCOMPtr<nsILoadGroup> loadGroup;
  394. newChannel->GetLoadGroup(getter_AddRefs(loadGroup));
  395. nsCOMPtr<nsIChannelEventSink> target;
  396. NS_QueryNotificationCallbacks(mOriginalCallbacks,
  397. loadGroup,
  398. NS_GET_IID(nsIChannelEventSink),
  399. getter_AddRefs(target));
  400. if (!target) {
  401. cb->OnRedirectVerifyCallback(NS_OK);
  402. return NS_OK;
  403. }
  404. // Delegate to |target| if set, reusing |cb|
  405. return target->AsyncOnChannelRedirect(oldChannel, newChannel, flags, cb);
  406. }
  407. NS_IMETHODIMP
  408. nsProgressNotificationProxy::GetInterface(const nsIID& iid,
  409. void** result)
  410. {
  411. if (iid.Equals(NS_GET_IID(nsIProgressEventSink))) {
  412. *result = static_cast<nsIProgressEventSink*>(this);
  413. NS_ADDREF_THIS();
  414. return NS_OK;
  415. }
  416. if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
  417. *result = static_cast<nsIChannelEventSink*>(this);
  418. NS_ADDREF_THIS();
  419. return NS_OK;
  420. }
  421. if (mOriginalCallbacks) {
  422. return mOriginalCallbacks->GetInterface(iid, result);
  423. }
  424. return NS_NOINTERFACE;
  425. }
  426. static void
  427. NewRequestAndEntry(bool aForcePrincipalCheckForCacheEntry, imgLoader* aLoader,
  428. const ImageCacheKey& aKey,
  429. imgRequest** aRequest, imgCacheEntry** aEntry)
  430. {
  431. RefPtr<imgRequest> request = new imgRequest(aLoader, aKey);
  432. RefPtr<imgCacheEntry> entry =
  433. new imgCacheEntry(aLoader, request, aForcePrincipalCheckForCacheEntry);
  434. aLoader->AddToUncachedImages(request);
  435. request.forget(aRequest);
  436. entry.forget(aEntry);
  437. }
  438. static bool
  439. ShouldRevalidateEntry(imgCacheEntry* aEntry,
  440. nsLoadFlags aFlags,
  441. bool aHasExpired)
  442. {
  443. bool bValidateEntry = false;
  444. if (aFlags & nsIRequest::LOAD_BYPASS_CACHE) {
  445. return false;
  446. }
  447. if (aFlags & nsIRequest::VALIDATE_ALWAYS) {
  448. bValidateEntry = true;
  449. } else if (aEntry->GetMustValidate()) {
  450. bValidateEntry = true;
  451. } else if (aHasExpired) {
  452. // The cache entry has expired... Determine whether the stale cache
  453. // entry can be used without validation...
  454. if (aFlags & (nsIRequest::VALIDATE_NEVER |
  455. nsIRequest::VALIDATE_ONCE_PER_SESSION)) {
  456. // VALIDATE_NEVER and VALIDATE_ONCE_PER_SESSION allow stale cache
  457. // entries to be used unless they have been explicitly marked to
  458. // indicate that revalidation is necessary.
  459. bValidateEntry = false;
  460. } else if (!(aFlags & nsIRequest::LOAD_FROM_CACHE)) {
  461. // LOAD_FROM_CACHE allows a stale cache entry to be used... Otherwise,
  462. // the entry must be revalidated.
  463. bValidateEntry = true;
  464. }
  465. }
  466. return bValidateEntry;
  467. }
  468. /* Call content policies on cached images that went through a redirect */
  469. static bool
  470. ShouldLoadCachedImage(imgRequest* aImgRequest,
  471. nsISupports* aLoadingContext,
  472. nsIPrincipal* aLoadingPrincipal,
  473. nsContentPolicyType aPolicyType)
  474. {
  475. /* Call content policies on cached images - Bug 1082837
  476. * Cached images are keyed off of the first uri in a redirect chain.
  477. * Hence content policies don't get a chance to test the intermediate hops
  478. * or the final desitnation. Here we test the final destination using
  479. * mCurrentURI off of the imgRequest and passing it into content policies.
  480. * For Mixed Content Blocker, we do an additional check to determine if any
  481. * of the intermediary hops went through an insecure redirect with the
  482. * mHadInsecureRedirect flag
  483. */
  484. bool insecureRedirect = aImgRequest->HadInsecureRedirect();
  485. nsCOMPtr<nsIURI> contentLocation;
  486. aImgRequest->GetCurrentURI(getter_AddRefs(contentLocation));
  487. nsresult rv;
  488. int16_t decision = nsIContentPolicy::REJECT_REQUEST;
  489. rv = NS_CheckContentLoadPolicy(aPolicyType,
  490. contentLocation,
  491. aLoadingPrincipal,
  492. aLoadingContext,
  493. EmptyCString(), //mime guess
  494. nullptr, //aExtra
  495. &decision,
  496. nsContentUtils::GetContentPolicy(),
  497. nsContentUtils::GetSecurityManager());
  498. if (NS_FAILED(rv) || !NS_CP_ACCEPTED(decision)) {
  499. return false;
  500. }
  501. // We call all Content Policies above, but we also have to call mcb
  502. // individually to check the intermediary redirect hops are secure.
  503. if (insecureRedirect) {
  504. if (!nsContentUtils::IsSystemPrincipal(aLoadingPrincipal)) {
  505. // Set the requestingLocation from the aLoadingPrincipal.
  506. nsCOMPtr<nsIURI> requestingLocation;
  507. if (aLoadingPrincipal) {
  508. rv = aLoadingPrincipal->GetURI(getter_AddRefs(requestingLocation));
  509. NS_ENSURE_SUCCESS(rv, false);
  510. }
  511. // reset the decision for mixed content blocker check
  512. decision = nsIContentPolicy::REJECT_REQUEST;
  513. rv = nsMixedContentBlocker::ShouldLoad(insecureRedirect,
  514. aPolicyType,
  515. contentLocation,
  516. requestingLocation,
  517. aLoadingContext,
  518. EmptyCString(), //mime guess
  519. nullptr,
  520. aLoadingPrincipal,
  521. &decision);
  522. if (NS_FAILED(rv) || !NS_CP_ACCEPTED(decision)) {
  523. return false;
  524. }
  525. }
  526. }
  527. return true;
  528. }
  529. // Returns true if this request is compatible with the given CORS mode on the
  530. // given loading principal, and false if the request may not be reused due
  531. // to CORS. Also checks the Referrer Policy, since requests with different
  532. // referrers/policies may generate different responses.
  533. static bool
  534. ValidateSecurityInfo(imgRequest* request, bool forcePrincipalCheck,
  535. int32_t corsmode, nsIPrincipal* loadingPrincipal,
  536. nsISupports* aCX, nsContentPolicyType aPolicyType,
  537. ReferrerPolicy referrerPolicy)
  538. {
  539. // If the entry's Referrer Policy doesn't match, we can't use this request.
  540. // XXX: this will return false if an image has different referrer attributes,
  541. // i.e. we currently don't use the cached image but reload the image with
  542. // the new referrer policy bug 1174921
  543. if (referrerPolicy != request->GetReferrerPolicy()) {
  544. return false;
  545. }
  546. // If the entry's CORS mode doesn't match, or the CORS mode matches but the
  547. // document principal isn't the same, we can't use this request.
  548. if (request->GetCORSMode() != corsmode) {
  549. return false;
  550. } else if (request->GetCORSMode() != imgIRequest::CORS_NONE ||
  551. forcePrincipalCheck) {
  552. nsCOMPtr<nsIPrincipal> otherprincipal = request->GetLoadingPrincipal();
  553. // If we previously had a principal, but we don't now, we can't use this
  554. // request.
  555. if (otherprincipal && !loadingPrincipal) {
  556. return false;
  557. }
  558. if (otherprincipal && loadingPrincipal) {
  559. bool equals = false;
  560. otherprincipal->Equals(loadingPrincipal, &equals);
  561. if (!equals) {
  562. return false;
  563. }
  564. }
  565. }
  566. // Content Policy Check on Cached Images
  567. return ShouldLoadCachedImage(request, aCX, loadingPrincipal, aPolicyType);
  568. }
  569. static nsresult
  570. NewImageChannel(nsIChannel** aResult,
  571. // If aForcePrincipalCheckForCacheEntry is true, then we will
  572. // force a principal check even when not using CORS before
  573. // assuming we have a cache hit on a cache entry that we
  574. // create for this channel. This is an out param that should
  575. // be set to true if this channel ends up depending on
  576. // aLoadingPrincipal and false otherwise.
  577. bool* aForcePrincipalCheckForCacheEntry,
  578. nsIURI* aURI,
  579. nsIURI* aInitialDocumentURI,
  580. int32_t aCORSMode,
  581. nsIURI* aReferringURI,
  582. ReferrerPolicy aReferrerPolicy,
  583. nsILoadGroup* aLoadGroup,
  584. const nsCString& aAcceptHeader,
  585. nsLoadFlags aLoadFlags,
  586. nsContentPolicyType aPolicyType,
  587. nsIPrincipal* aLoadingPrincipal,
  588. nsISupports* aRequestingContext,
  589. bool aRespectPrivacy)
  590. {
  591. MOZ_ASSERT(aResult);
  592. nsresult rv;
  593. nsCOMPtr<nsIHttpChannel> newHttpChannel;
  594. nsCOMPtr<nsIInterfaceRequestor> callbacks;
  595. if (aLoadGroup) {
  596. // Get the notification callbacks from the load group for the new channel.
  597. //
  598. // XXX: This is not exactly correct, because the network request could be
  599. // referenced by multiple windows... However, the new channel needs
  600. // something. So, using the 'first' notification callbacks is better
  601. // than nothing...
  602. //
  603. aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
  604. }
  605. // Pass in a nullptr loadgroup because this is the underlying network
  606. // request. This request may be referenced by several proxy image requests
  607. // (possibly in different documents).
  608. // If all of the proxy requests are canceled then this request should be
  609. // canceled too.
  610. //
  611. aLoadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
  612. nsCOMPtr<nsINode> requestingNode = do_QueryInterface(aRequestingContext);
  613. nsSecurityFlags securityFlags =
  614. aCORSMode == imgIRequest::CORS_NONE
  615. ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS
  616. : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
  617. if (aCORSMode == imgIRequest::CORS_ANONYMOUS) {
  618. securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
  619. } else if (aCORSMode == imgIRequest::CORS_USE_CREDENTIALS) {
  620. securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
  621. }
  622. securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
  623. // Note we are calling NS_NewChannelWithTriggeringPrincipal() here with a
  624. // node and a principal. This is for things like background images that are
  625. // specified by user stylesheets, where the document is being styled, but
  626. // the principal is that of the user stylesheet.
  627. if (requestingNode && aLoadingPrincipal) {
  628. rv = NS_NewChannelWithTriggeringPrincipal(aResult,
  629. aURI,
  630. requestingNode,
  631. aLoadingPrincipal,
  632. securityFlags,
  633. aPolicyType,
  634. nullptr, // loadGroup
  635. callbacks,
  636. aLoadFlags);
  637. if (NS_FAILED(rv)) {
  638. return rv;
  639. }
  640. if (aPolicyType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
  641. // If this is a favicon loading, we will use the originAttributes from the
  642. // loadingPrincipal as the channel's originAttributes. This allows the favicon
  643. // loading from XUL will use the correct originAttributes.
  644. NeckoOriginAttributes neckoAttrs;
  645. neckoAttrs.InheritFromDocToNecko(BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef());
  646. nsCOMPtr<nsILoadInfo> loadInfo = (*aResult)->GetLoadInfo();
  647. rv = loadInfo->SetOriginAttributes(neckoAttrs);
  648. }
  649. } else {
  650. // either we are loading something inside a document, in which case
  651. // we should always have a requestingNode, or we are loading something
  652. // outside a document, in which case the loadingPrincipal and
  653. // triggeringPrincipal should always be the systemPrincipal.
  654. // However, there are exceptions: one is Notifications which create a
  655. // channel in the parent prcoess in which case we can't get a requestingNode.
  656. rv = NS_NewChannel(aResult,
  657. aURI,
  658. nsContentUtils::GetSystemPrincipal(),
  659. securityFlags,
  660. aPolicyType,
  661. nullptr, // loadGroup
  662. callbacks,
  663. aLoadFlags);
  664. if (NS_FAILED(rv)) {
  665. return rv;
  666. }
  667. // Use the OriginAttributes from the loading principal, if one is available,
  668. // and adjust the private browsing ID based on what kind of load the caller
  669. // has asked us to perform.
  670. NeckoOriginAttributes neckoAttrs;
  671. if (aLoadingPrincipal) {
  672. neckoAttrs.InheritFromDocToNecko(BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef());
  673. }
  674. neckoAttrs.mPrivateBrowsingId = aRespectPrivacy ? 1 : 0;
  675. nsCOMPtr<nsILoadInfo> loadInfo = (*aResult)->GetLoadInfo();
  676. rv = loadInfo->SetOriginAttributes(neckoAttrs);
  677. }
  678. if (NS_FAILED(rv)) {
  679. return rv;
  680. }
  681. // only inherit if we have a principal
  682. *aForcePrincipalCheckForCacheEntry =
  683. aLoadingPrincipal &&
  684. nsContentUtils::ChannelShouldInheritPrincipal(
  685. aLoadingPrincipal,
  686. aURI,
  687. /* aInheritForAboutBlank */ false,
  688. /* aForceInherit */ false);
  689. // Initialize HTTP-specific attributes
  690. newHttpChannel = do_QueryInterface(*aResult);
  691. if (newHttpChannel) {
  692. newHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
  693. aAcceptHeader,
  694. false);
  695. nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
  696. do_QueryInterface(newHttpChannel);
  697. NS_ENSURE_TRUE(httpChannelInternal, NS_ERROR_UNEXPECTED);
  698. httpChannelInternal->SetDocumentURI(aInitialDocumentURI);
  699. newHttpChannel->SetReferrerWithPolicy(aReferringURI, aReferrerPolicy);
  700. }
  701. // Image channels are loaded by default with reduced priority.
  702. nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(*aResult);
  703. if (p) {
  704. uint32_t priority = nsISupportsPriority::PRIORITY_LOW;
  705. if (aLoadFlags & nsIRequest::LOAD_BACKGROUND) {
  706. ++priority; // further reduce priority for background loads
  707. }
  708. p->AdjustPriority(priority);
  709. }
  710. // Create a new loadgroup for this new channel, using the old group as
  711. // the parent. The indirection keeps the channel insulated from cancels,
  712. // but does allow a way for this revalidation to be associated with at
  713. // least one base load group for scheduling/caching purposes.
  714. nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
  715. nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(loadGroup);
  716. if (childLoadGroup) {
  717. childLoadGroup->SetParentLoadGroup(aLoadGroup);
  718. }
  719. (*aResult)->SetLoadGroup(loadGroup);
  720. return NS_OK;
  721. }
  722. static uint32_t
  723. SecondsFromPRTime(PRTime prTime)
  724. {
  725. return uint32_t(int64_t(prTime) / int64_t(PR_USEC_PER_SEC));
  726. }
  727. imgCacheEntry::imgCacheEntry(imgLoader* loader, imgRequest* request,
  728. bool forcePrincipalCheck)
  729. : mLoader(loader),
  730. mRequest(request),
  731. mDataSize(0),
  732. mTouchedTime(SecondsFromPRTime(PR_Now())),
  733. mLoadTime(SecondsFromPRTime(PR_Now())),
  734. mExpiryTime(0),
  735. mMustValidate(false),
  736. // We start off as evicted so we don't try to update the cache. PutIntoCache
  737. // will set this to false.
  738. mEvicted(true),
  739. mHasNoProxies(true),
  740. mForcePrincipalCheck(forcePrincipalCheck)
  741. { }
  742. imgCacheEntry::~imgCacheEntry()
  743. {
  744. LOG_FUNC(gImgLog, "imgCacheEntry::~imgCacheEntry()");
  745. }
  746. void
  747. imgCacheEntry::Touch(bool updateTime /* = true */)
  748. {
  749. LOG_SCOPE(gImgLog, "imgCacheEntry::Touch");
  750. if (updateTime) {
  751. mTouchedTime = SecondsFromPRTime(PR_Now());
  752. }
  753. UpdateCache();
  754. }
  755. void
  756. imgCacheEntry::UpdateCache(int32_t diff /* = 0 */)
  757. {
  758. // Don't update the cache if we've been removed from it or it doesn't care
  759. // about our size or usage.
  760. if (!Evicted() && HasNoProxies()) {
  761. mLoader->CacheEntriesChanged(mRequest->IsChrome(), diff);
  762. }
  763. }
  764. void imgCacheEntry::UpdateLoadTime()
  765. {
  766. mLoadTime = SecondsFromPRTime(PR_Now());
  767. }
  768. void
  769. imgCacheEntry::SetHasNoProxies(bool hasNoProxies)
  770. {
  771. if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
  772. if (hasNoProxies) {
  773. LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheEntry::SetHasNoProxies true",
  774. "uri", mRequest->CacheKey().Spec());
  775. } else {
  776. LOG_FUNC_WITH_PARAM(gImgLog, "imgCacheEntry::SetHasNoProxies false",
  777. "uri", mRequest->CacheKey().Spec());
  778. }
  779. }
  780. mHasNoProxies = hasNoProxies;
  781. }
  782. imgCacheQueue::imgCacheQueue()
  783. : mDirty(false),
  784. mSize(0)
  785. { }
  786. void
  787. imgCacheQueue::UpdateSize(int32_t diff)
  788. {
  789. mSize += diff;
  790. }
  791. uint32_t
  792. imgCacheQueue::GetSize() const
  793. {
  794. return mSize;
  795. }
  796. #include <algorithm>
  797. using namespace std;
  798. void
  799. imgCacheQueue::Remove(imgCacheEntry* entry)
  800. {
  801. queueContainer::iterator it = find(mQueue.begin(), mQueue.end(), entry);
  802. if (it != mQueue.end()) {
  803. mSize -= (*it)->GetDataSize();
  804. mQueue.erase(it);
  805. MarkDirty();
  806. }
  807. }
  808. void
  809. imgCacheQueue::Push(imgCacheEntry* entry)
  810. {
  811. mSize += entry->GetDataSize();
  812. RefPtr<imgCacheEntry> refptr(entry);
  813. mQueue.push_back(refptr);
  814. MarkDirty();
  815. }
  816. already_AddRefed<imgCacheEntry>
  817. imgCacheQueue::Pop()
  818. {
  819. if (mQueue.empty()) {
  820. return nullptr;
  821. }
  822. if (IsDirty()) {
  823. Refresh();
  824. }
  825. RefPtr<imgCacheEntry> entry = mQueue[0];
  826. std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
  827. mQueue.pop_back();
  828. mSize -= entry->GetDataSize();
  829. return entry.forget();
  830. }
  831. void
  832. imgCacheQueue::Refresh()
  833. {
  834. std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
  835. mDirty = false;
  836. }
  837. void
  838. imgCacheQueue::MarkDirty()
  839. {
  840. mDirty = true;
  841. }
  842. bool
  843. imgCacheQueue::IsDirty()
  844. {
  845. return mDirty;
  846. }
  847. uint32_t
  848. imgCacheQueue::GetNumElements() const
  849. {
  850. return mQueue.size();
  851. }
  852. imgCacheQueue::iterator
  853. imgCacheQueue::begin()
  854. {
  855. return mQueue.begin();
  856. }
  857. imgCacheQueue::const_iterator
  858. imgCacheQueue::begin() const
  859. {
  860. return mQueue.begin();
  861. }
  862. imgCacheQueue::iterator
  863. imgCacheQueue::end()
  864. {
  865. return mQueue.end();
  866. }
  867. imgCacheQueue::const_iterator
  868. imgCacheQueue::end() const
  869. {
  870. return mQueue.end();
  871. }
  872. nsresult
  873. imgLoader::CreateNewProxyForRequest(imgRequest* aRequest,
  874. nsILoadGroup* aLoadGroup,
  875. imgINotificationObserver* aObserver,
  876. nsLoadFlags aLoadFlags,
  877. imgRequestProxy** _retval)
  878. {
  879. LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::CreateNewProxyForRequest",
  880. "imgRequest", aRequest);
  881. /* XXX If we move decoding onto separate threads, we should save off the
  882. calling thread here and pass it off to |proxyRequest| so that it call
  883. proxy calls to |aObserver|.
  884. */
  885. RefPtr<imgRequestProxy> proxyRequest = new imgRequestProxy();
  886. /* It is important to call |SetLoadFlags()| before calling |Init()| because
  887. |Init()| adds the request to the loadgroup.
  888. */
  889. proxyRequest->SetLoadFlags(aLoadFlags);
  890. RefPtr<ImageURL> uri;
  891. aRequest->GetURI(getter_AddRefs(uri));
  892. // init adds itself to imgRequest's list of observers
  893. nsresult rv = proxyRequest->Init(aRequest, aLoadGroup, uri, aObserver);
  894. if (NS_WARN_IF(NS_FAILED(rv))) {
  895. return rv;
  896. }
  897. proxyRequest.forget(_retval);
  898. return NS_OK;
  899. }
  900. class imgCacheExpirationTracker final
  901. : public nsExpirationTracker<imgCacheEntry, 3>
  902. {
  903. enum { TIMEOUT_SECONDS = 10 };
  904. public:
  905. imgCacheExpirationTracker();
  906. protected:
  907. void NotifyExpired(imgCacheEntry* entry);
  908. };
  909. imgCacheExpirationTracker::imgCacheExpirationTracker()
  910. : nsExpirationTracker<imgCacheEntry, 3>(TIMEOUT_SECONDS * 1000,
  911. "imgCacheExpirationTracker")
  912. { }
  913. void
  914. imgCacheExpirationTracker::NotifyExpired(imgCacheEntry* entry)
  915. {
  916. // Hold on to a reference to this entry, because the expiration tracker
  917. // mechanism doesn't.
  918. RefPtr<imgCacheEntry> kungFuDeathGrip(entry);
  919. if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
  920. RefPtr<imgRequest> req = entry->GetRequest();
  921. if (req) {
  922. LOG_FUNC_WITH_PARAM(gImgLog,
  923. "imgCacheExpirationTracker::NotifyExpired",
  924. "entry", req->CacheKey().Spec());
  925. }
  926. }
  927. // We can be called multiple times on the same entry. Don't do work multiple
  928. // times.
  929. if (!entry->Evicted()) {
  930. entry->Loader()->RemoveFromCache(entry);
  931. }
  932. entry->Loader()->VerifyCacheSizes();
  933. }
  934. ///////////////////////////////////////////////////////////////////////////////
  935. // imgLoader
  936. ///////////////////////////////////////////////////////////////////////////////
  937. double imgLoader::sCacheTimeWeight;
  938. uint32_t imgLoader::sCacheMaxSize;
  939. imgMemoryReporter* imgLoader::sMemReporter;
  940. NS_IMPL_ISUPPORTS(imgLoader, imgILoader, nsIContentSniffer, imgICache,
  941. nsISupportsWeakReference, nsIObserver)
  942. static imgLoader* gNormalLoader = nullptr;
  943. static imgLoader* gPrivateBrowsingLoader = nullptr;
  944. /* static */ already_AddRefed<imgLoader>
  945. imgLoader::CreateImageLoader()
  946. {
  947. // In some cases, such as xpctests, XPCOM modules are not automatically
  948. // initialized. We need to make sure that our module is initialized before
  949. // we hand out imgLoader instances and code starts using them.
  950. mozilla::image::EnsureModuleInitialized();
  951. RefPtr<imgLoader> loader = new imgLoader();
  952. loader->Init();
  953. return loader.forget();
  954. }
  955. imgLoader*
  956. imgLoader::NormalLoader()
  957. {
  958. if (!gNormalLoader) {
  959. gNormalLoader = CreateImageLoader().take();
  960. }
  961. return gNormalLoader;
  962. }
  963. imgLoader*
  964. imgLoader::PrivateBrowsingLoader()
  965. {
  966. if (!gPrivateBrowsingLoader) {
  967. gPrivateBrowsingLoader = CreateImageLoader().take();
  968. gPrivateBrowsingLoader->RespectPrivacyNotifications();
  969. }
  970. return gPrivateBrowsingLoader;
  971. }
  972. imgLoader::imgLoader()
  973. : mUncachedImagesMutex("imgLoader::UncachedImages"), mRespectPrivacy(false)
  974. {
  975. sMemReporter->AddRef();
  976. sMemReporter->RegisterLoader(this);
  977. }
  978. imgLoader::~imgLoader()
  979. {
  980. ClearChromeImageCache();
  981. ClearImageCache();
  982. {
  983. // If there are any of our imgRequest's left they are in the uncached
  984. // images set, so clear their pointer to us.
  985. MutexAutoLock lock(mUncachedImagesMutex);
  986. for (auto iter = mUncachedImages.Iter(); !iter.Done(); iter.Next()) {
  987. nsPtrHashKey<imgRequest>* entry = iter.Get();
  988. RefPtr<imgRequest> req = entry->GetKey();
  989. req->ClearLoader();
  990. }
  991. }
  992. sMemReporter->UnregisterLoader(this);
  993. sMemReporter->Release();
  994. }
  995. void
  996. imgLoader::VerifyCacheSizes()
  997. {
  998. #ifdef DEBUG
  999. if (!mCacheTracker) {
  1000. return;
  1001. }
  1002. uint32_t cachesize = mCache.Count() + mChromeCache.Count();
  1003. uint32_t queuesize =
  1004. mCacheQueue.GetNumElements() + mChromeCacheQueue.GetNumElements();
  1005. uint32_t trackersize = 0;
  1006. for (nsExpirationTracker<imgCacheEntry, 3>::Iterator it(mCacheTracker.get());
  1007. it.Next(); ){
  1008. trackersize++;
  1009. }
  1010. MOZ_ASSERT(queuesize == trackersize, "Queue and tracker sizes out of sync!");
  1011. MOZ_ASSERT(queuesize <= cachesize, "Queue has more elements than cache!");
  1012. #endif
  1013. }
  1014. imgLoader::imgCacheTable&
  1015. imgLoader::GetCache(bool aForChrome)
  1016. {
  1017. return aForChrome ? mChromeCache : mCache;
  1018. }
  1019. imgLoader::imgCacheTable&
  1020. imgLoader::GetCache(const ImageCacheKey& aKey)
  1021. {
  1022. return GetCache(aKey.IsChrome());
  1023. }
  1024. imgCacheQueue&
  1025. imgLoader::GetCacheQueue(bool aForChrome)
  1026. {
  1027. return aForChrome ? mChromeCacheQueue : mCacheQueue;
  1028. }
  1029. imgCacheQueue&
  1030. imgLoader::GetCacheQueue(const ImageCacheKey& aKey)
  1031. {
  1032. return GetCacheQueue(aKey.IsChrome());
  1033. }
  1034. void imgLoader::GlobalInit()
  1035. {
  1036. sCacheTimeWeight = gfxPrefs::ImageCacheTimeWeight() / 1000.0;
  1037. int32_t cachesize = gfxPrefs::ImageCacheSize();
  1038. sCacheMaxSize = cachesize > 0 ? cachesize : 0;
  1039. sMemReporter = new imgMemoryReporter();
  1040. RegisterStrongMemoryReporter(sMemReporter);
  1041. RegisterImagesContentUsedUncompressedDistinguishedAmount(
  1042. imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount);
  1043. }
  1044. void imgLoader::ShutdownMemoryReporter()
  1045. {
  1046. UnregisterImagesContentUsedUncompressedDistinguishedAmount();
  1047. UnregisterStrongMemoryReporter(sMemReporter);
  1048. }
  1049. nsresult
  1050. imgLoader::InitCache()
  1051. {
  1052. nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  1053. if (!os) {
  1054. return NS_ERROR_FAILURE;
  1055. }
  1056. os->AddObserver(this, "memory-pressure", false);
  1057. os->AddObserver(this, "chrome-flush-skin-caches", false);
  1058. os->AddObserver(this, "chrome-flush-caches", false);
  1059. os->AddObserver(this, "last-pb-context-exited", false);
  1060. os->AddObserver(this, "profile-before-change", false);
  1061. os->AddObserver(this, "xpcom-shutdown", false);
  1062. mCacheTracker = MakeUnique<imgCacheExpirationTracker>();
  1063. return NS_OK;
  1064. }
  1065. nsresult
  1066. imgLoader::Init()
  1067. {
  1068. InitCache();
  1069. ReadAcceptHeaderPref();
  1070. Preferences::AddWeakObserver(this, "image.http.accept");
  1071. return NS_OK;
  1072. }
  1073. NS_IMETHODIMP
  1074. imgLoader::RespectPrivacyNotifications()
  1075. {
  1076. mRespectPrivacy = true;
  1077. return NS_OK;
  1078. }
  1079. NS_IMETHODIMP
  1080. imgLoader::Observe(nsISupports* aSubject, const char* aTopic,
  1081. const char16_t* aData)
  1082. {
  1083. // We listen for pref change notifications...
  1084. if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
  1085. if (!NS_strcmp(aData, u"image.http.accept")) {
  1086. ReadAcceptHeaderPref();
  1087. }
  1088. } else if (strcmp(aTopic, "memory-pressure") == 0) {
  1089. MinimizeCaches();
  1090. } else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
  1091. strcmp(aTopic, "chrome-flush-caches") == 0) {
  1092. MinimizeCaches();
  1093. ClearChromeImageCache();
  1094. } else if (strcmp(aTopic, "last-pb-context-exited") == 0) {
  1095. if (mRespectPrivacy) {
  1096. ClearImageCache();
  1097. ClearChromeImageCache();
  1098. }
  1099. } else if (strcmp(aTopic, "profile-before-change") == 0) {
  1100. mCacheTracker = nullptr;
  1101. } else if (strcmp(aTopic, "xpcom-shutdown") == 0) {
  1102. mCacheTracker = nullptr;
  1103. ShutdownMemoryReporter();
  1104. } else {
  1105. // (Nothing else should bring us here)
  1106. MOZ_ASSERT(0, "Invalid topic received");
  1107. }
  1108. return NS_OK;
  1109. }
  1110. void imgLoader::ReadAcceptHeaderPref()
  1111. {
  1112. nsAdoptingCString accept = Preferences::GetCString("image.http.accept");
  1113. if (accept) {
  1114. mAcceptHeader = accept;
  1115. } else {
  1116. mAcceptHeader =
  1117. IMAGE_PNG "," IMAGE_WILDCARD ";q=0.8," ANY_WILDCARD ";q=0.5";
  1118. }
  1119. }
  1120. NS_IMETHODIMP
  1121. imgLoader::ClearCache(bool chrome)
  1122. {
  1123. if (XRE_IsParentProcess()) {
  1124. bool privateLoader = this == gPrivateBrowsingLoader;
  1125. for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
  1126. Unused << cp->SendClearImageCache(privateLoader, chrome);
  1127. }
  1128. }
  1129. if (chrome) {
  1130. return ClearChromeImageCache();
  1131. } else {
  1132. return ClearImageCache();
  1133. }
  1134. }
  1135. NS_IMETHODIMP
  1136. imgLoader::FindEntryProperties(nsIURI* uri,
  1137. nsIDOMDocument* aDOMDoc,
  1138. nsIProperties** _retval)
  1139. {
  1140. *_retval = nullptr;
  1141. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDoc);
  1142. PrincipalOriginAttributes attrs;
  1143. if (doc) {
  1144. nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
  1145. if (principal) {
  1146. attrs = BasePrincipal::Cast(principal)->OriginAttributesRef();
  1147. }
  1148. }
  1149. nsresult rv;
  1150. ImageCacheKey key(uri, attrs, doc, rv);
  1151. NS_ENSURE_SUCCESS(rv, rv);
  1152. imgCacheTable& cache = GetCache(key);
  1153. RefPtr<imgCacheEntry> entry;
  1154. if (cache.Get(key, getter_AddRefs(entry)) && entry) {
  1155. if (mCacheTracker && entry->HasNoProxies()) {
  1156. mCacheTracker->MarkUsed(entry);
  1157. }
  1158. RefPtr<imgRequest> request = entry->GetRequest();
  1159. if (request) {
  1160. nsCOMPtr<nsIProperties> properties = request->Properties();
  1161. properties.forget(_retval);
  1162. }
  1163. }
  1164. return NS_OK;
  1165. }
  1166. NS_IMETHODIMP_(void)
  1167. imgLoader::ClearCacheForControlledDocument(nsIDocument* aDoc)
  1168. {
  1169. MOZ_ASSERT(aDoc);
  1170. AutoTArray<RefPtr<imgCacheEntry>, 128> entriesToBeRemoved;
  1171. imgCacheTable& cache = GetCache(false);
  1172. for (auto iter = cache.Iter(); !iter.Done(); iter.Next()) {
  1173. auto& key = iter.Key();
  1174. if (key.ControlledDocument() == aDoc) {
  1175. entriesToBeRemoved.AppendElement(iter.Data());
  1176. }
  1177. }
  1178. for (auto& entry : entriesToBeRemoved) {
  1179. if (!RemoveFromCache(entry)) {
  1180. NS_WARNING("Couldn't remove an entry from the cache in ClearCacheForControlledDocument()\n");
  1181. }
  1182. }
  1183. }
  1184. void
  1185. imgLoader::Shutdown()
  1186. {
  1187. NS_IF_RELEASE(gNormalLoader);
  1188. gNormalLoader = nullptr;
  1189. NS_IF_RELEASE(gPrivateBrowsingLoader);
  1190. gPrivateBrowsingLoader = nullptr;
  1191. }
  1192. nsresult
  1193. imgLoader::ClearChromeImageCache()
  1194. {
  1195. return EvictEntries(mChromeCache);
  1196. }
  1197. nsresult
  1198. imgLoader::ClearImageCache()
  1199. {
  1200. return EvictEntries(mCache);
  1201. }
  1202. void
  1203. imgLoader::MinimizeCaches()
  1204. {
  1205. EvictEntries(mCacheQueue);
  1206. EvictEntries(mChromeCacheQueue);
  1207. }
  1208. bool
  1209. imgLoader::PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* entry)
  1210. {
  1211. imgCacheTable& cache = GetCache(aKey);
  1212. LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
  1213. "imgLoader::PutIntoCache", "uri", aKey.Spec());
  1214. // Check to see if this request already exists in the cache. If so, we'll
  1215. // replace the old version.
  1216. RefPtr<imgCacheEntry> tmpCacheEntry;
  1217. if (cache.Get(aKey, getter_AddRefs(tmpCacheEntry)) && tmpCacheEntry) {
  1218. MOZ_LOG(gImgLog, LogLevel::Debug,
  1219. ("[this=%p] imgLoader::PutIntoCache -- Element already in the cache",
  1220. nullptr));
  1221. RefPtr<imgRequest> tmpRequest = tmpCacheEntry->GetRequest();
  1222. // If it already exists, and we're putting the same key into the cache, we
  1223. // should remove the old version.
  1224. MOZ_LOG(gImgLog, LogLevel::Debug,
  1225. ("[this=%p] imgLoader::PutIntoCache -- Replacing cached element",
  1226. nullptr));
  1227. RemoveFromCache(aKey);
  1228. } else {
  1229. MOZ_LOG(gImgLog, LogLevel::Debug,
  1230. ("[this=%p] imgLoader::PutIntoCache --"
  1231. " Element NOT already in the cache", nullptr));
  1232. }
  1233. cache.Put(aKey, entry);
  1234. // We can be called to resurrect an evicted entry.
  1235. if (entry->Evicted()) {
  1236. entry->SetEvicted(false);
  1237. }
  1238. // If we're resurrecting an entry with no proxies, put it back in the
  1239. // tracker and queue.
  1240. if (entry->HasNoProxies()) {
  1241. nsresult addrv = NS_OK;
  1242. if (mCacheTracker) {
  1243. addrv = mCacheTracker->AddObject(entry);
  1244. }
  1245. if (NS_SUCCEEDED(addrv)) {
  1246. imgCacheQueue& queue = GetCacheQueue(aKey);
  1247. queue.Push(entry);
  1248. }
  1249. }
  1250. RefPtr<imgRequest> request = entry->GetRequest();
  1251. request->SetIsInCache(true);
  1252. RemoveFromUncachedImages(request);
  1253. return true;
  1254. }
  1255. bool
  1256. imgLoader::SetHasNoProxies(imgRequest* aRequest, imgCacheEntry* aEntry)
  1257. {
  1258. LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
  1259. "imgLoader::SetHasNoProxies", "uri",
  1260. aRequest->CacheKey().Spec());
  1261. aEntry->SetHasNoProxies(true);
  1262. if (aEntry->Evicted()) {
  1263. return false;
  1264. }
  1265. imgCacheQueue& queue = GetCacheQueue(aRequest->IsChrome());
  1266. nsresult addrv = NS_OK;
  1267. if (mCacheTracker) {
  1268. addrv = mCacheTracker->AddObject(aEntry);
  1269. }
  1270. if (NS_SUCCEEDED(addrv)) {
  1271. queue.Push(aEntry);
  1272. }
  1273. imgCacheTable& cache = GetCache(aRequest->IsChrome());
  1274. CheckCacheLimits(cache, queue);
  1275. return true;
  1276. }
  1277. bool
  1278. imgLoader::SetHasProxies(imgRequest* aRequest)
  1279. {
  1280. VerifyCacheSizes();
  1281. const ImageCacheKey& key = aRequest->CacheKey();
  1282. imgCacheTable& cache = GetCache(key);
  1283. LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
  1284. "imgLoader::SetHasProxies", "uri", key.Spec());
  1285. RefPtr<imgCacheEntry> entry;
  1286. if (cache.Get(key, getter_AddRefs(entry)) && entry) {
  1287. // Make sure the cache entry is for the right request
  1288. RefPtr<imgRequest> entryRequest = entry->GetRequest();
  1289. if (entryRequest == aRequest && entry->HasNoProxies()) {
  1290. imgCacheQueue& queue = GetCacheQueue(key);
  1291. queue.Remove(entry);
  1292. if (mCacheTracker) {
  1293. mCacheTracker->RemoveObject(entry);
  1294. }
  1295. entry->SetHasNoProxies(false);
  1296. return true;
  1297. }
  1298. }
  1299. return false;
  1300. }
  1301. void
  1302. imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
  1303. {
  1304. imgCacheQueue& queue = GetCacheQueue(aForChrome);
  1305. queue.MarkDirty();
  1306. queue.UpdateSize(aSizeDiff);
  1307. }
  1308. void
  1309. imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue)
  1310. {
  1311. if (queue.GetNumElements() == 0) {
  1312. NS_ASSERTION(queue.GetSize() == 0,
  1313. "imgLoader::CheckCacheLimits -- incorrect cache size");
  1314. }
  1315. // Remove entries from the cache until we're back at our desired max size.
  1316. while (queue.GetSize() > sCacheMaxSize) {
  1317. // Remove the first entry in the queue.
  1318. RefPtr<imgCacheEntry> entry(queue.Pop());
  1319. NS_ASSERTION(entry, "imgLoader::CheckCacheLimits -- NULL entry pointer");
  1320. if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
  1321. RefPtr<imgRequest> req = entry->GetRequest();
  1322. if (req) {
  1323. LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
  1324. "imgLoader::CheckCacheLimits",
  1325. "entry", req->CacheKey().Spec());
  1326. }
  1327. }
  1328. if (entry) {
  1329. RemoveFromCache(entry);
  1330. }
  1331. }
  1332. }
  1333. bool
  1334. imgLoader::ValidateRequestWithNewChannel(imgRequest* request,
  1335. nsIURI* aURI,
  1336. nsIURI* aInitialDocumentURI,
  1337. nsIURI* aReferrerURI,
  1338. ReferrerPolicy aReferrerPolicy,
  1339. nsILoadGroup* aLoadGroup,
  1340. imgINotificationObserver* aObserver,
  1341. nsISupports* aCX,
  1342. nsLoadFlags aLoadFlags,
  1343. nsContentPolicyType aLoadPolicyType,
  1344. imgRequestProxy** aProxyRequest,
  1345. nsIPrincipal* aLoadingPrincipal,
  1346. int32_t aCORSMode)
  1347. {
  1348. // now we need to insert a new channel request object inbetween the real
  1349. // request and the proxy that basically delays loading the image until it
  1350. // gets a 304 or figures out that this needs to be a new request
  1351. nsresult rv;
  1352. // If we're currently in the middle of validating this request, just hand
  1353. // back a proxy to it; the required work will be done for us.
  1354. if (request->GetValidator()) {
  1355. rv = CreateNewProxyForRequest(request, aLoadGroup, aObserver,
  1356. aLoadFlags, aProxyRequest);
  1357. if (NS_FAILED(rv)) {
  1358. return false;
  1359. }
  1360. if (*aProxyRequest) {
  1361. imgRequestProxy* proxy = static_cast<imgRequestProxy*>(*aProxyRequest);
  1362. // We will send notifications from imgCacheValidator::OnStartRequest().
  1363. // In the mean time, we must defer notifications because we are added to
  1364. // the imgRequest's proxy list, and we can get extra notifications
  1365. // resulting from methods such as StartDecoding(). See bug 579122.
  1366. proxy->SetNotificationsDeferred(true);
  1367. // Attach the proxy without notifying
  1368. request->GetValidator()->AddProxy(proxy);
  1369. }
  1370. return NS_SUCCEEDED(rv);
  1371. } else {
  1372. // We will rely on Necko to cache this request when it's possible, and to
  1373. // tell imgCacheValidator::OnStartRequest whether the request came from its
  1374. // cache.
  1375. nsCOMPtr<nsIChannel> newChannel;
  1376. bool forcePrincipalCheck;
  1377. rv = NewImageChannel(getter_AddRefs(newChannel),
  1378. &forcePrincipalCheck,
  1379. aURI,
  1380. aInitialDocumentURI,
  1381. aCORSMode,
  1382. aReferrerURI,
  1383. aReferrerPolicy,
  1384. aLoadGroup,
  1385. mAcceptHeader,
  1386. aLoadFlags,
  1387. aLoadPolicyType,
  1388. aLoadingPrincipal,
  1389. aCX,
  1390. mRespectPrivacy);
  1391. if (NS_FAILED(rv)) {
  1392. return false;
  1393. }
  1394. RefPtr<imgRequestProxy> req;
  1395. rv = CreateNewProxyForRequest(request, aLoadGroup, aObserver,
  1396. aLoadFlags, getter_AddRefs(req));
  1397. if (NS_FAILED(rv)) {
  1398. return false;
  1399. }
  1400. // Make sure that OnStatus/OnProgress calls have the right request set...
  1401. RefPtr<nsProgressNotificationProxy> progressproxy =
  1402. new nsProgressNotificationProxy(newChannel, req);
  1403. if (!progressproxy) {
  1404. return false;
  1405. }
  1406. RefPtr<imgCacheValidator> hvc =
  1407. new imgCacheValidator(progressproxy, this, request, aCX,
  1408. forcePrincipalCheck);
  1409. // Casting needed here to get past multiple inheritance.
  1410. nsCOMPtr<nsIStreamListener> listener =
  1411. do_QueryInterface(static_cast<nsIThreadRetargetableStreamListener*>(hvc));
  1412. NS_ENSURE_TRUE(listener, false);
  1413. // We must set the notification callbacks before setting up the
  1414. // CORS listener, because that's also interested inthe
  1415. // notification callbacks.
  1416. newChannel->SetNotificationCallbacks(hvc);
  1417. request->SetValidator(hvc);
  1418. // We will send notifications from imgCacheValidator::OnStartRequest().
  1419. // In the mean time, we must defer notifications because we are added to
  1420. // the imgRequest's proxy list, and we can get extra notifications
  1421. // resulting from methods such as StartDecoding(). See bug 579122.
  1422. req->SetNotificationsDeferred(true);
  1423. // Add the proxy without notifying
  1424. hvc->AddProxy(req);
  1425. mozilla::net::PredictorLearn(aURI, aInitialDocumentURI,
  1426. nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, aLoadGroup);
  1427. rv = newChannel->AsyncOpen2(listener);
  1428. if (NS_WARN_IF(NS_FAILED(rv))) {
  1429. req->CancelAndForgetObserver(rv);
  1430. return false;
  1431. }
  1432. req.forget(aProxyRequest);
  1433. return true;
  1434. }
  1435. }
  1436. bool
  1437. imgLoader::ValidateEntry(imgCacheEntry* aEntry,
  1438. nsIURI* aURI,
  1439. nsIURI* aInitialDocumentURI,
  1440. nsIURI* aReferrerURI,
  1441. ReferrerPolicy aReferrerPolicy,
  1442. nsILoadGroup* aLoadGroup,
  1443. imgINotificationObserver* aObserver,
  1444. nsISupports* aCX,
  1445. nsLoadFlags aLoadFlags,
  1446. nsContentPolicyType aLoadPolicyType,
  1447. bool aCanMakeNewChannel,
  1448. imgRequestProxy** aProxyRequest,
  1449. nsIPrincipal* aLoadingPrincipal,
  1450. int32_t aCORSMode)
  1451. {
  1452. LOG_SCOPE(gImgLog, "imgLoader::ValidateEntry");
  1453. bool hasExpired;
  1454. uint32_t expirationTime = aEntry->GetExpiryTime();
  1455. if (expirationTime <= SecondsFromPRTime(PR_Now())) {
  1456. hasExpired = true;
  1457. } else {
  1458. hasExpired = false;
  1459. }
  1460. nsresult rv;
  1461. // Special treatment for file URLs - aEntry has expired if file has changed
  1462. nsCOMPtr<nsIFileURL> fileUrl(do_QueryInterface(aURI));
  1463. if (fileUrl) {
  1464. uint32_t lastModTime = aEntry->GetLoadTime();
  1465. nsCOMPtr<nsIFile> theFile;
  1466. rv = fileUrl->GetFile(getter_AddRefs(theFile));
  1467. if (NS_SUCCEEDED(rv)) {
  1468. PRTime fileLastMod;
  1469. rv = theFile->GetLastModifiedTime(&fileLastMod);
  1470. if (NS_SUCCEEDED(rv)) {
  1471. // nsIFile uses millisec, NSPR usec
  1472. fileLastMod *= 1000;
  1473. hasExpired = SecondsFromPRTime((PRTime)fileLastMod) > lastModTime;
  1474. }
  1475. }
  1476. }
  1477. RefPtr<imgRequest> request(aEntry->GetRequest());
  1478. if (!request) {
  1479. return false;
  1480. }
  1481. if (!ValidateSecurityInfo(request, aEntry->ForcePrincipalCheck(),
  1482. aCORSMode, aLoadingPrincipal,
  1483. aCX, aLoadPolicyType, aReferrerPolicy))
  1484. return false;
  1485. // data URIs are immutable and by their nature can't leak data, so we can
  1486. // just return true in that case. Doing so would mean that shift-reload
  1487. // doesn't reload data URI documents/images though (which is handy for
  1488. // debugging during gecko development) so we make an exception in that case.
  1489. nsAutoCString scheme;
  1490. aURI->GetScheme(scheme);
  1491. if (scheme.EqualsLiteral("data") &&
  1492. !(aLoadFlags & nsIRequest::LOAD_BYPASS_CACHE)) {
  1493. return true;
  1494. }
  1495. bool validateRequest = false;
  1496. // If the request's loadId is the same as the aCX, then it is ok to use
  1497. // this one because it has already been validated for this context.
  1498. //
  1499. // XXX: nullptr seems to be a 'special' key value that indicates that NO
  1500. // validation is required.
  1501. //
  1502. void *key = (void*) aCX;
  1503. if (request->LoadId() != key) {
  1504. // If we would need to revalidate this entry, but we're being told to
  1505. // bypass the cache, we don't allow this entry to be used.
  1506. if (aLoadFlags & nsIRequest::LOAD_BYPASS_CACHE) {
  1507. return false;
  1508. }
  1509. if (MOZ_UNLIKELY(ChaosMode::isActive(ChaosFeature::ImageCache))) {
  1510. if (ChaosMode::randomUint32LessThan(4) < 1) {
  1511. return false;
  1512. }
  1513. }
  1514. // Determine whether the cache aEntry must be revalidated...
  1515. validateRequest = ShouldRevalidateEntry(aEntry, aLoadFlags, hasExpired);
  1516. MOZ_LOG(gImgLog, LogLevel::Debug,
  1517. ("imgLoader::ValidateEntry validating cache entry. "
  1518. "validateRequest = %d", validateRequest));
  1519. } else if (!key && MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
  1520. MOZ_LOG(gImgLog, LogLevel::Debug,
  1521. ("imgLoader::ValidateEntry BYPASSING cache validation for %s "
  1522. "because of NULL LoadID", aURI->GetSpecOrDefault().get()));
  1523. }
  1524. // We can't use a cached request if it comes from a different
  1525. // application cache than this load is expecting.
  1526. nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
  1527. nsCOMPtr<nsIApplicationCache> requestAppCache;
  1528. nsCOMPtr<nsIApplicationCache> groupAppCache;
  1529. if ((appCacheContainer = do_GetInterface(request->GetRequest()))) {
  1530. appCacheContainer->GetApplicationCache(getter_AddRefs(requestAppCache));
  1531. }
  1532. if ((appCacheContainer = do_QueryInterface(aLoadGroup))) {
  1533. appCacheContainer->GetApplicationCache(getter_AddRefs(groupAppCache));
  1534. }
  1535. if (requestAppCache != groupAppCache) {
  1536. MOZ_LOG(gImgLog, LogLevel::Debug,
  1537. ("imgLoader::ValidateEntry - Unable to use cached imgRequest "
  1538. "[request=%p] because of mismatched application caches\n",
  1539. address_of(request)));
  1540. return false;
  1541. }
  1542. if (validateRequest && aCanMakeNewChannel) {
  1543. LOG_SCOPE(gImgLog,
  1544. "imgLoader::ValidateRequest |cache hit| must validate");
  1545. return ValidateRequestWithNewChannel(request, aURI, aInitialDocumentURI,
  1546. aReferrerURI, aReferrerPolicy,
  1547. aLoadGroup, aObserver,
  1548. aCX, aLoadFlags, aLoadPolicyType,
  1549. aProxyRequest, aLoadingPrincipal,
  1550. aCORSMode);
  1551. }
  1552. return !validateRequest;
  1553. }
  1554. bool
  1555. imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
  1556. {
  1557. LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
  1558. "imgLoader::RemoveFromCache", "uri", aKey.Spec());
  1559. imgCacheTable& cache = GetCache(aKey);
  1560. imgCacheQueue& queue = GetCacheQueue(aKey);
  1561. RefPtr<imgCacheEntry> entry;
  1562. if (cache.Get(aKey, getter_AddRefs(entry)) && entry) {
  1563. cache.Remove(aKey);
  1564. MOZ_ASSERT(!entry->Evicted(), "Evicting an already-evicted cache entry!");
  1565. // Entries with no proxies are in the tracker.
  1566. if (entry->HasNoProxies()) {
  1567. if (mCacheTracker) {
  1568. mCacheTracker->RemoveObject(entry);
  1569. }
  1570. queue.Remove(entry);
  1571. }
  1572. entry->SetEvicted(true);
  1573. RefPtr<imgRequest> request = entry->GetRequest();
  1574. request->SetIsInCache(false);
  1575. AddToUncachedImages(request);
  1576. return true;
  1577. } else {
  1578. return false;
  1579. }
  1580. }
  1581. bool
  1582. imgLoader::RemoveFromCache(imgCacheEntry* entry)
  1583. {
  1584. LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
  1585. RefPtr<imgRequest> request = entry->GetRequest();
  1586. if (request) {
  1587. const ImageCacheKey& key = request->CacheKey();
  1588. imgCacheTable& cache = GetCache(key);
  1589. imgCacheQueue& queue = GetCacheQueue(key);
  1590. LOG_STATIC_FUNC_WITH_PARAM(gImgLog,
  1591. "imgLoader::RemoveFromCache", "entry's uri",
  1592. key.Spec());
  1593. cache.Remove(key);
  1594. if (entry->HasNoProxies()) {
  1595. LOG_STATIC_FUNC(gImgLog,
  1596. "imgLoader::RemoveFromCache removing from tracker");
  1597. if (mCacheTracker) {
  1598. mCacheTracker->RemoveObject(entry);
  1599. }
  1600. queue.Remove(entry);
  1601. }
  1602. entry->SetEvicted(true);
  1603. request->SetIsInCache(false);
  1604. AddToUncachedImages(request);
  1605. return true;
  1606. }
  1607. return false;
  1608. }
  1609. nsresult
  1610. imgLoader::EvictEntries(imgCacheTable& aCacheToClear)
  1611. {
  1612. LOG_STATIC_FUNC(gImgLog, "imgLoader::EvictEntries table");
  1613. // We have to make a temporary, since RemoveFromCache removes the element
  1614. // from the queue, invalidating iterators.
  1615. nsTArray<RefPtr<imgCacheEntry> > entries;
  1616. for (auto iter = aCacheToClear.Iter(); !iter.Done(); iter.Next()) {
  1617. RefPtr<imgCacheEntry>& data = iter.Data();
  1618. entries.AppendElement(data);
  1619. }
  1620. for (uint32_t i = 0; i < entries.Length(); ++i) {
  1621. if (!RemoveFromCache(entries[i])) {
  1622. return NS_ERROR_FAILURE;
  1623. }
  1624. }
  1625. MOZ_ASSERT(aCacheToClear.Count() == 0);
  1626. return NS_OK;
  1627. }
  1628. nsresult
  1629. imgLoader::EvictEntries(imgCacheQueue& aQueueToClear)
  1630. {
  1631. LOG_STATIC_FUNC(gImgLog, "imgLoader::EvictEntries queue");
  1632. // We have to make a temporary, since RemoveFromCache removes the element
  1633. // from the queue, invalidating iterators.
  1634. nsTArray<RefPtr<imgCacheEntry> > entries(aQueueToClear.GetNumElements());
  1635. for (imgCacheQueue::const_iterator i = aQueueToClear.begin();
  1636. i != aQueueToClear.end(); ++i) {
  1637. entries.AppendElement(*i);
  1638. }
  1639. for (uint32_t i = 0; i < entries.Length(); ++i) {
  1640. if (!RemoveFromCache(entries[i])) {
  1641. return NS_ERROR_FAILURE;
  1642. }
  1643. }
  1644. MOZ_ASSERT(aQueueToClear.GetNumElements() == 0);
  1645. return NS_OK;
  1646. }
  1647. void
  1648. imgLoader::AddToUncachedImages(imgRequest* aRequest)
  1649. {
  1650. MutexAutoLock lock(mUncachedImagesMutex);
  1651. mUncachedImages.PutEntry(aRequest);
  1652. }
  1653. void
  1654. imgLoader::RemoveFromUncachedImages(imgRequest* aRequest)
  1655. {
  1656. MutexAutoLock lock(mUncachedImagesMutex);
  1657. mUncachedImages.RemoveEntry(aRequest);
  1658. }
  1659. #define LOAD_FLAGS_CACHE_MASK (nsIRequest::LOAD_BYPASS_CACHE | \
  1660. nsIRequest::LOAD_FROM_CACHE)
  1661. #define LOAD_FLAGS_VALIDATE_MASK (nsIRequest::VALIDATE_ALWAYS | \
  1662. nsIRequest::VALIDATE_NEVER | \
  1663. nsIRequest::VALIDATE_ONCE_PER_SESSION)
  1664. NS_IMETHODIMP
  1665. imgLoader::LoadImageXPCOM(nsIURI* aURI,
  1666. nsIURI* aInitialDocumentURI,
  1667. nsIURI* aReferrerURI,
  1668. const nsAString& aReferrerPolicy,
  1669. nsIPrincipal* aLoadingPrincipal,
  1670. nsILoadGroup* aLoadGroup,
  1671. imgINotificationObserver* aObserver,
  1672. nsISupports* aCX,
  1673. nsLoadFlags aLoadFlags,
  1674. nsISupports* aCacheKey,
  1675. nsContentPolicyType aContentPolicyType,
  1676. imgIRequest** _retval)
  1677. {
  1678. // Optional parameter, so defaults to 0 (== TYPE_INVALID)
  1679. if (!aContentPolicyType) {
  1680. aContentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
  1681. }
  1682. imgRequestProxy* proxy;
  1683. ReferrerPolicy refpol = ReferrerPolicyFromString(aReferrerPolicy);
  1684. nsCOMPtr<nsINode> node = do_QueryInterface(aCX);
  1685. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
  1686. nsresult rv = LoadImage(aURI,
  1687. aInitialDocumentURI,
  1688. aReferrerURI,
  1689. refpol == mozilla::net::RP_Unset ?
  1690. mozilla::net::RP_Default : refpol,
  1691. aLoadingPrincipal,
  1692. aLoadGroup,
  1693. aObserver,
  1694. node,
  1695. doc,
  1696. aLoadFlags,
  1697. aCacheKey,
  1698. aContentPolicyType,
  1699. EmptyString(),
  1700. &proxy);
  1701. *_retval = proxy;
  1702. return rv;
  1703. }
  1704. nsresult
  1705. imgLoader::LoadImage(nsIURI* aURI,
  1706. nsIURI* aInitialDocumentURI,
  1707. nsIURI* aReferrerURI,
  1708. ReferrerPolicy aReferrerPolicy,
  1709. nsIPrincipal* aLoadingPrincipal,
  1710. nsILoadGroup* aLoadGroup,
  1711. imgINotificationObserver* aObserver,
  1712. nsINode *aContext,
  1713. nsIDocument* aLoadingDocument,
  1714. nsLoadFlags aLoadFlags,
  1715. nsISupports* aCacheKey,
  1716. nsContentPolicyType aContentPolicyType,
  1717. const nsAString& initiatorType,
  1718. imgRequestProxy** _retval)
  1719. {
  1720. VerifyCacheSizes();
  1721. NS_ASSERTION(aURI, "imgLoader::LoadImage -- NULL URI pointer");
  1722. if (!aURI) {
  1723. return NS_ERROR_NULL_POINTER;
  1724. }
  1725. LOG_SCOPE_WITH_PARAM(gImgLog, "imgLoader::LoadImage", "aURI",
  1726. aURI->GetSpecOrDefault().get());
  1727. *_retval = nullptr;
  1728. RefPtr<imgRequest> request;
  1729. nsresult rv;
  1730. nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
  1731. #ifdef DEBUG
  1732. bool isPrivate = false;
  1733. if (aLoadGroup) {
  1734. nsCOMPtr<nsIInterfaceRequestor> callbacks;
  1735. aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
  1736. if (callbacks) {
  1737. nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
  1738. isPrivate = loadContext && loadContext->UsePrivateBrowsing();
  1739. }
  1740. }
  1741. MOZ_ASSERT(isPrivate == mRespectPrivacy);
  1742. #endif
  1743. // Get the default load flags from the loadgroup (if possible)...
  1744. if (aLoadGroup) {
  1745. aLoadGroup->GetLoadFlags(&requestFlags);
  1746. }
  1747. //
  1748. // Merge the default load flags with those passed in via aLoadFlags.
  1749. // Currently, *only* the caching, validation and background load flags
  1750. // are merged...
  1751. //
  1752. // The flags in aLoadFlags take precedence over the default flags!
  1753. //
  1754. if (aLoadFlags & LOAD_FLAGS_CACHE_MASK) {
  1755. // Override the default caching flags...
  1756. requestFlags = (requestFlags & ~LOAD_FLAGS_CACHE_MASK) |
  1757. (aLoadFlags & LOAD_FLAGS_CACHE_MASK);
  1758. }
  1759. if (aLoadFlags & LOAD_FLAGS_VALIDATE_MASK) {
  1760. // Override the default validation flags...
  1761. requestFlags = (requestFlags & ~LOAD_FLAGS_VALIDATE_MASK) |
  1762. (aLoadFlags & LOAD_FLAGS_VALIDATE_MASK);
  1763. }
  1764. if (aLoadFlags & nsIRequest::LOAD_BACKGROUND) {
  1765. // Propagate background loading...
  1766. requestFlags |= nsIRequest::LOAD_BACKGROUND;
  1767. }
  1768. int32_t corsmode = imgIRequest::CORS_NONE;
  1769. if (aLoadFlags & imgILoader::LOAD_CORS_ANONYMOUS) {
  1770. corsmode = imgIRequest::CORS_ANONYMOUS;
  1771. } else if (aLoadFlags & imgILoader::LOAD_CORS_USE_CREDENTIALS) {
  1772. corsmode = imgIRequest::CORS_USE_CREDENTIALS;
  1773. }
  1774. RefPtr<imgCacheEntry> entry;
  1775. // Look in the cache for our URI, and then validate it.
  1776. // XXX For now ignore aCacheKey. We will need it in the future
  1777. // for correctly dealing with image load requests that are a result
  1778. // of post data.
  1779. PrincipalOriginAttributes attrs;
  1780. if (aLoadingPrincipal) {
  1781. attrs = BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef();
  1782. }
  1783. ImageCacheKey key(aURI, attrs, aLoadingDocument, rv);
  1784. NS_ENSURE_SUCCESS(rv, rv);
  1785. imgCacheTable& cache = GetCache(key);
  1786. if (cache.Get(key, getter_AddRefs(entry)) && entry) {
  1787. if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
  1788. aReferrerPolicy, aLoadGroup, aObserver, aLoadingDocument,
  1789. requestFlags, aContentPolicyType, true, _retval,
  1790. aLoadingPrincipal, corsmode)) {
  1791. request = entry->GetRequest();
  1792. // If this entry has no proxies, its request has no reference to the
  1793. // entry.
  1794. if (entry->HasNoProxies()) {
  1795. LOG_FUNC_WITH_PARAM(gImgLog,
  1796. "imgLoader::LoadImage() adding proxyless entry", "uri", key.Spec());
  1797. MOZ_ASSERT(!request->HasCacheEntry(),
  1798. "Proxyless entry's request has cache entry!");
  1799. request->SetCacheEntry(entry);
  1800. if (mCacheTracker && entry->GetExpirationState()->IsTracked()) {
  1801. mCacheTracker->MarkUsed(entry);
  1802. }
  1803. }
  1804. entry->Touch();
  1805. } else {
  1806. // We can't use this entry. We'll try to load it off the network, and if
  1807. // successful, overwrite the old entry in the cache with a new one.
  1808. entry = nullptr;
  1809. }
  1810. }
  1811. // Keep the channel in this scope, so we can adjust its notificationCallbacks
  1812. // later when we create the proxy.
  1813. nsCOMPtr<nsIChannel> newChannel;
  1814. // If we didn't get a cache hit, we need to load from the network.
  1815. if (!request) {
  1816. LOG_SCOPE(gImgLog, "imgLoader::LoadImage |cache miss|");
  1817. bool forcePrincipalCheck;
  1818. rv = NewImageChannel(getter_AddRefs(newChannel),
  1819. &forcePrincipalCheck,
  1820. aURI,
  1821. aInitialDocumentURI,
  1822. corsmode,
  1823. aReferrerURI,
  1824. aReferrerPolicy,
  1825. aLoadGroup,
  1826. mAcceptHeader,
  1827. requestFlags,
  1828. aContentPolicyType,
  1829. aLoadingPrincipal,
  1830. aContext,
  1831. mRespectPrivacy);
  1832. if (NS_FAILED(rv)) {
  1833. return NS_ERROR_FAILURE;
  1834. }
  1835. MOZ_ASSERT(NS_UsePrivateBrowsing(newChannel) == mRespectPrivacy);
  1836. NewRequestAndEntry(forcePrincipalCheck, this, key,
  1837. getter_AddRefs(request),
  1838. getter_AddRefs(entry));
  1839. MOZ_LOG(gImgLog, LogLevel::Debug,
  1840. ("[this=%p] imgLoader::LoadImage -- Created new imgRequest"
  1841. " [request=%p]\n", this, request.get()));
  1842. nsCOMPtr<nsILoadGroup> channelLoadGroup;
  1843. newChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
  1844. rv = request->Init(aURI, aURI, /* aHadInsecureRedirect = */ false,
  1845. channelLoadGroup, newChannel, entry, aLoadingDocument,
  1846. aLoadingPrincipal, corsmode, aReferrerPolicy);
  1847. if (NS_FAILED(rv)) {
  1848. return NS_ERROR_FAILURE;
  1849. }
  1850. // Add the initiator type for this image load
  1851. nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(newChannel);
  1852. if (timedChannel) {
  1853. timedChannel->SetInitiatorType(initiatorType);
  1854. }
  1855. // create the proxy listener
  1856. nsCOMPtr<nsIStreamListener> listener = new ProxyListener(request.get());
  1857. MOZ_LOG(gImgLog, LogLevel::Debug,
  1858. ("[this=%p] imgLoader::LoadImage -- Calling channel->AsyncOpen2()\n",
  1859. this));
  1860. mozilla::net::PredictorLearn(aURI, aInitialDocumentURI,
  1861. nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, aLoadGroup);
  1862. nsresult openRes = newChannel->AsyncOpen2(listener);
  1863. if (NS_FAILED(openRes)) {
  1864. MOZ_LOG(gImgLog, LogLevel::Debug,
  1865. ("[this=%p] imgLoader::LoadImage -- AsyncOpen2() failed: 0x%x\n",
  1866. this, openRes));
  1867. request->CancelAndAbort(openRes);
  1868. return openRes;
  1869. }
  1870. // Try to add the new request into the cache.
  1871. PutIntoCache(key, entry);
  1872. } else {
  1873. LOG_MSG_WITH_PARAM(gImgLog,
  1874. "imgLoader::LoadImage |cache hit|", "request", request);
  1875. }
  1876. // If we didn't get a proxy when validating the cache entry, we need to
  1877. // create one.
  1878. if (!*_retval) {
  1879. // ValidateEntry() has three return values: "Is valid," "might be valid --
  1880. // validating over network", and "not valid." If we don't have a _retval,
  1881. // we know ValidateEntry is not validating over the network, so it's safe
  1882. // to SetLoadId here because we know this request is valid for this context.
  1883. //
  1884. // Note, however, that this doesn't guarantee the behaviour we want (one
  1885. // URL maps to the same image on a page) if we load the same image in a
  1886. // different tab (see bug 528003), because its load id will get re-set, and
  1887. // that'll cause us to validate over the network.
  1888. request->SetLoadId(aLoadingDocument);
  1889. LOG_MSG(gImgLog, "imgLoader::LoadImage", "creating proxy request.");
  1890. rv = CreateNewProxyForRequest(request, aLoadGroup, aObserver,
  1891. requestFlags, _retval);
  1892. if (NS_FAILED(rv)) {
  1893. return rv;
  1894. }
  1895. imgRequestProxy* proxy = *_retval;
  1896. // Make sure that OnStatus/OnProgress calls have the right request set, if
  1897. // we did create a channel here.
  1898. if (newChannel) {
  1899. nsCOMPtr<nsIInterfaceRequestor> requestor(
  1900. new nsProgressNotificationProxy(newChannel, proxy));
  1901. if (!requestor) {
  1902. return NS_ERROR_OUT_OF_MEMORY;
  1903. }
  1904. newChannel->SetNotificationCallbacks(requestor);
  1905. }
  1906. // Note that it's OK to add here even if the request is done. If it is,
  1907. // it'll send a OnStopRequest() to the proxy in imgRequestProxy::Notify and
  1908. // the proxy will be removed from the loadgroup.
  1909. proxy->AddToLoadGroup();
  1910. // If we're loading off the network, explicitly don't notify our proxy,
  1911. // because necko (or things called from necko, such as imgCacheValidator)
  1912. // are going to call our notifications asynchronously, and we can't make it
  1913. // further asynchronous because observers might rely on imagelib completing
  1914. // its work between the channel's OnStartRequest and OnStopRequest.
  1915. if (!newChannel) {
  1916. proxy->NotifyListener();
  1917. }
  1918. return rv;
  1919. }
  1920. NS_ASSERTION(*_retval, "imgLoader::LoadImage -- no return value");
  1921. return NS_OK;
  1922. }
  1923. NS_IMETHODIMP
  1924. imgLoader::LoadImageWithChannelXPCOM(nsIChannel* channel,
  1925. imgINotificationObserver* aObserver,
  1926. nsISupports* aCX,
  1927. nsIStreamListener** listener,
  1928. imgIRequest** _retval)
  1929. {
  1930. nsresult result;
  1931. imgRequestProxy* proxy;
  1932. result = LoadImageWithChannel(channel,
  1933. aObserver,
  1934. aCX,
  1935. listener,
  1936. &proxy);
  1937. *_retval = proxy;
  1938. return result;
  1939. }
  1940. nsresult
  1941. imgLoader::LoadImageWithChannel(nsIChannel* channel,
  1942. imgINotificationObserver* aObserver,
  1943. nsISupports* aCX,
  1944. nsIStreamListener** listener,
  1945. imgRequestProxy** _retval)
  1946. {
  1947. NS_ASSERTION(channel,
  1948. "imgLoader::LoadImageWithChannel -- NULL channel pointer");
  1949. MOZ_ASSERT(NS_UsePrivateBrowsing(channel) == mRespectPrivacy);
  1950. RefPtr<imgRequest> request;
  1951. nsCOMPtr<nsIURI> uri;
  1952. channel->GetURI(getter_AddRefs(uri));
  1953. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
  1954. NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
  1955. nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
  1956. PrincipalOriginAttributes attrs;
  1957. if (loadInfo) {
  1958. attrs.InheritFromNecko(loadInfo->GetOriginAttributes());
  1959. }
  1960. nsresult rv;
  1961. ImageCacheKey key(uri, attrs, doc, rv);
  1962. NS_ENSURE_SUCCESS(rv, rv);
  1963. nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
  1964. channel->GetLoadFlags(&requestFlags);
  1965. RefPtr<imgCacheEntry> entry;
  1966. if (requestFlags & nsIRequest::LOAD_BYPASS_CACHE) {
  1967. RemoveFromCache(key);
  1968. } else {
  1969. // Look in the cache for our URI, and then validate it.
  1970. // XXX For now ignore aCacheKey. We will need it in the future
  1971. // for correctly dealing with image load requests that are a result
  1972. // of post data.
  1973. imgCacheTable& cache = GetCache(key);
  1974. if (cache.Get(key, getter_AddRefs(entry)) && entry) {
  1975. // We don't want to kick off another network load. So we ask
  1976. // ValidateEntry to only do validation without creating a new proxy. If
  1977. // it says that the entry isn't valid any more, we'll only use the entry
  1978. // we're getting if the channel is loading from the cache anyways.
  1979. //
  1980. // XXX -- should this be changed? it's pretty much verbatim from the old
  1981. // code, but seems nonsensical.
  1982. //
  1983. // Since aCanMakeNewChannel == false, we don't need to pass content policy
  1984. // type/principal/etc
  1985. nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
  1986. // if there is a loadInfo, use the right contentType, otherwise
  1987. // default to the internal image type
  1988. nsContentPolicyType policyType = loadInfo
  1989. ? loadInfo->InternalContentPolicyType()
  1990. : nsIContentPolicy::TYPE_INTERNAL_IMAGE;
  1991. if (ValidateEntry(entry, uri, nullptr, nullptr, RP_Default,
  1992. nullptr, aObserver, aCX, requestFlags,
  1993. policyType, false, nullptr,
  1994. nullptr, imgIRequest::CORS_NONE)) {
  1995. request = entry->GetRequest();
  1996. } else {
  1997. nsCOMPtr<nsICacheInfoChannel> cacheChan(do_QueryInterface(channel));
  1998. bool bUseCacheCopy;
  1999. if (cacheChan) {
  2000. cacheChan->IsFromCache(&bUseCacheCopy);
  2001. } else {
  2002. bUseCacheCopy = false;
  2003. }
  2004. if (!bUseCacheCopy) {
  2005. entry = nullptr;
  2006. } else {
  2007. request = entry->GetRequest();
  2008. }
  2009. }
  2010. if (request && entry) {
  2011. // If this entry has no proxies, its request has no reference to
  2012. // the entry.
  2013. if (entry->HasNoProxies()) {
  2014. LOG_FUNC_WITH_PARAM(gImgLog,
  2015. "imgLoader::LoadImageWithChannel() adding proxyless entry",
  2016. "uri", key.Spec());
  2017. MOZ_ASSERT(!request->HasCacheEntry(),
  2018. "Proxyless entry's request has cache entry!");
  2019. request->SetCacheEntry(entry);
  2020. if (mCacheTracker && entry->GetExpirationState()->IsTracked()) {
  2021. mCacheTracker->MarkUsed(entry);
  2022. }
  2023. }
  2024. }
  2025. }
  2026. }
  2027. nsCOMPtr<nsILoadGroup> loadGroup;
  2028. channel->GetLoadGroup(getter_AddRefs(loadGroup));
  2029. // Filter out any load flags not from nsIRequest
  2030. requestFlags &= nsIRequest::LOAD_REQUESTMASK;
  2031. rv = NS_OK;
  2032. if (request) {
  2033. // we have this in our cache already.. cancel the current (document) load
  2034. // this should fire an OnStopRequest
  2035. channel->Cancel(NS_ERROR_PARSED_DATA_CACHED);
  2036. *listener = nullptr; // give them back a null nsIStreamListener
  2037. rv = CreateNewProxyForRequest(request, loadGroup, aObserver,
  2038. requestFlags, _retval);
  2039. static_cast<imgRequestProxy*>(*_retval)->NotifyListener();
  2040. } else {
  2041. // We use originalURI here to fulfil the imgIRequest contract on GetURI.
  2042. nsCOMPtr<nsIURI> originalURI;
  2043. channel->GetOriginalURI(getter_AddRefs(originalURI));
  2044. // XXX(seth): We should be able to just use |key| here, except that |key| is
  2045. // constructed above with the *current URI* and not the *original URI*. I'm
  2046. // pretty sure this is a bug, and it's preventing us from ever getting a
  2047. // cache hit in LoadImageWithChannel when redirects are involved.
  2048. ImageCacheKey originalURIKey(originalURI, attrs, doc, rv);
  2049. NS_ENSURE_SUCCESS(rv, rv);
  2050. // Default to doing a principal check because we don't know who
  2051. // started that load and whether their principal ended up being
  2052. // inherited on the channel.
  2053. NewRequestAndEntry(/* aForcePrincipalCheckForCacheEntry = */ true,
  2054. this, originalURIKey,
  2055. getter_AddRefs(request),
  2056. getter_AddRefs(entry));
  2057. // No principal specified here, because we're not passed one.
  2058. // In LoadImageWithChannel, the redirects that may have been
  2059. // assoicated with this load would have gone through necko.
  2060. // We only have the final URI in ImageLib and hence don't know
  2061. // if the request went through insecure redirects. But if it did,
  2062. // the necko cache should have handled that (since all necko cache hits
  2063. // including the redirects will go through content policy). Hence, we
  2064. // can set aHadInsecureRedirect to false here.
  2065. rv = request->Init(originalURI, uri, /* aHadInsecureRedirect = */ false,
  2066. channel, channel, entry, aCX, nullptr,
  2067. imgIRequest::CORS_NONE, RP_Default);
  2068. NS_ENSURE_SUCCESS(rv, rv);
  2069. RefPtr<ProxyListener> pl =
  2070. new ProxyListener(static_cast<nsIStreamListener*>(request.get()));
  2071. pl.forget(listener);
  2072. // Try to add the new request into the cache.
  2073. PutIntoCache(originalURIKey, entry);
  2074. rv = CreateNewProxyForRequest(request, loadGroup, aObserver,
  2075. requestFlags, _retval);
  2076. // Explicitly don't notify our proxy, because we're loading off the
  2077. // network, and necko (or things called from necko, such as
  2078. // imgCacheValidator) are going to call our notifications asynchronously,
  2079. // and we can't make it further asynchronous because observers might rely
  2080. // on imagelib completing its work between the channel's OnStartRequest and
  2081. // OnStopRequest.
  2082. }
  2083. return rv;
  2084. }
  2085. bool
  2086. imgLoader::SupportImageWithMimeType(const char* aMimeType,
  2087. AcceptedMimeTypes aAccept
  2088. /* = AcceptedMimeTypes::IMAGES */)
  2089. {
  2090. nsAutoCString mimeType(aMimeType);
  2091. ToLowerCase(mimeType);
  2092. if (aAccept == AcceptedMimeTypes::IMAGES_AND_DOCUMENTS &&
  2093. mimeType.EqualsLiteral("image/svg+xml")) {
  2094. return true;
  2095. }
  2096. DecoderType type = DecoderFactory::GetDecoderType(mimeType.get());
  2097. return type != DecoderType::UNKNOWN;
  2098. }
  2099. NS_IMETHODIMP
  2100. imgLoader::GetMIMETypeFromContent(nsIRequest* aRequest,
  2101. const uint8_t* aContents,
  2102. uint32_t aLength,
  2103. nsACString& aContentType)
  2104. {
  2105. return GetMimeTypeFromContent((const char*)aContents, aLength, aContentType);
  2106. }
  2107. /* static */
  2108. nsresult
  2109. imgLoader::GetMimeTypeFromContent(const char* aContents,
  2110. uint32_t aLength,
  2111. nsACString& aContentType)
  2112. {
  2113. /* Is it a GIF? */
  2114. if (aLength >= 6 && (!nsCRT::strncmp(aContents, "GIF87a", 6) ||
  2115. !nsCRT::strncmp(aContents, "GIF89a", 6))) {
  2116. aContentType.AssignLiteral(IMAGE_GIF);
  2117. /* or a PNG? */
  2118. } else if (aLength >= 8 && ((unsigned char)aContents[0]==0x89 &&
  2119. (unsigned char)aContents[1]==0x50 &&
  2120. (unsigned char)aContents[2]==0x4E &&
  2121. (unsigned char)aContents[3]==0x47 &&
  2122. (unsigned char)aContents[4]==0x0D &&
  2123. (unsigned char)aContents[5]==0x0A &&
  2124. (unsigned char)aContents[6]==0x1A &&
  2125. (unsigned char)aContents[7]==0x0A)) {
  2126. aContentType.AssignLiteral(IMAGE_PNG);
  2127. /* maybe a JPEG (JFIF)? */
  2128. /* JFIF files start with SOI APP0 but older files can start with SOI DQT
  2129. * so we test for SOI followed by any marker, i.e. FF D8 FF
  2130. * this will also work for SPIFF JPEG files if they appear in the future.
  2131. *
  2132. * (JFIF is 0XFF 0XD8 0XFF 0XE0 <skip 2> 0X4A 0X46 0X49 0X46 0X00)
  2133. */
  2134. } else if (aLength >= 3 &&
  2135. ((unsigned char)aContents[0])==0xFF &&
  2136. ((unsigned char)aContents[1])==0xD8 &&
  2137. ((unsigned char)aContents[2])==0xFF) {
  2138. aContentType.AssignLiteral(IMAGE_JPEG);
  2139. /* or how about ART? */
  2140. /* ART begins with JG (4A 47). Major version offset 2.
  2141. * Minor version offset 3. Offset 4 must be nullptr.
  2142. */
  2143. } else if (aLength >= 5 &&
  2144. ((unsigned char) aContents[0])==0x4a &&
  2145. ((unsigned char) aContents[1])==0x47 &&
  2146. ((unsigned char) aContents[4])==0x00 ) {
  2147. aContentType.AssignLiteral(IMAGE_ART);
  2148. } else if (aLength >= 2 && !nsCRT::strncmp(aContents, "BM", 2)) {
  2149. aContentType.AssignLiteral(IMAGE_BMP);
  2150. // ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
  2151. // CURs begin with 2-byte 0 followed by 2-byte 2.
  2152. } else if (aLength >= 4 && (!memcmp(aContents, "\000\000\001\000", 4) ||
  2153. !memcmp(aContents, "\000\000\002\000", 4))) {
  2154. aContentType.AssignLiteral(IMAGE_ICO);
  2155. // WebPs always begin with RIFF, a 32-bit length, and WEBP.
  2156. } else if (aLength >= 12 && !memcmp(aContents, "RIFF", 4) &&
  2157. !memcmp(aContents + 8, "WEBP", 4)) {
  2158. aContentType.AssignLiteral(IMAGE_WEBP);
  2159. } else {
  2160. /* none of the above? I give up */
  2161. return NS_ERROR_NOT_AVAILABLE;
  2162. }
  2163. return NS_OK;
  2164. }
  2165. /**
  2166. * proxy stream listener class used to handle multipart/x-mixed-replace
  2167. */
  2168. #include "nsIRequest.h"
  2169. #include "nsIStreamConverterService.h"
  2170. NS_IMPL_ISUPPORTS(ProxyListener,
  2171. nsIStreamListener,
  2172. nsIThreadRetargetableStreamListener,
  2173. nsIRequestObserver)
  2174. ProxyListener::ProxyListener(nsIStreamListener* dest) :
  2175. mDestListener(dest)
  2176. {
  2177. /* member initializers and constructor code */
  2178. }
  2179. ProxyListener::~ProxyListener()
  2180. {
  2181. /* destructor code */
  2182. }
  2183. /** nsIRequestObserver methods **/
  2184. NS_IMETHODIMP
  2185. ProxyListener::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
  2186. {
  2187. if (!mDestListener) {
  2188. return NS_ERROR_FAILURE;
  2189. }
  2190. nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  2191. if (channel) {
  2192. // We need to set the initiator type for the image load
  2193. nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(channel);
  2194. if (timedChannel) {
  2195. nsAutoString type;
  2196. timedChannel->GetInitiatorType(type);
  2197. if (type.IsEmpty()) {
  2198. timedChannel->SetInitiatorType(NS_LITERAL_STRING("img"));
  2199. }
  2200. }
  2201. nsAutoCString contentType;
  2202. nsresult rv = channel->GetContentType(contentType);
  2203. if (!contentType.IsEmpty()) {
  2204. /* If multipart/x-mixed-replace content, we'll insert a MIME decoder
  2205. in the pipeline to handle the content and pass it along to our
  2206. original listener.
  2207. */
  2208. if (NS_LITERAL_CSTRING("multipart/x-mixed-replace").Equals(contentType)) {
  2209. nsCOMPtr<nsIStreamConverterService> convServ(
  2210. do_GetService("@mozilla.org/streamConverters;1", &rv));
  2211. if (NS_SUCCEEDED(rv)) {
  2212. nsCOMPtr<nsIStreamListener> toListener(mDestListener);
  2213. nsCOMPtr<nsIStreamListener> fromListener;
  2214. rv = convServ->AsyncConvertData("multipart/x-mixed-replace",
  2215. "*/*",
  2216. toListener,
  2217. nullptr,
  2218. getter_AddRefs(fromListener));
  2219. if (NS_SUCCEEDED(rv)) {
  2220. mDestListener = fromListener;
  2221. }
  2222. }
  2223. }
  2224. }
  2225. }
  2226. return mDestListener->OnStartRequest(aRequest, ctxt);
  2227. }
  2228. NS_IMETHODIMP
  2229. ProxyListener::OnStopRequest(nsIRequest* aRequest,
  2230. nsISupports* ctxt,
  2231. nsresult status)
  2232. {
  2233. if (!mDestListener) {
  2234. return NS_ERROR_FAILURE;
  2235. }
  2236. return mDestListener->OnStopRequest(aRequest, ctxt, status);
  2237. }
  2238. /** nsIStreamListener methods **/
  2239. NS_IMETHODIMP
  2240. ProxyListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
  2241. nsIInputStream* inStr, uint64_t sourceOffset,
  2242. uint32_t count)
  2243. {
  2244. if (!mDestListener) {
  2245. return NS_ERROR_FAILURE;
  2246. }
  2247. return mDestListener->OnDataAvailable(aRequest, ctxt, inStr,
  2248. sourceOffset, count);
  2249. }
  2250. /** nsThreadRetargetableStreamListener methods **/
  2251. NS_IMETHODIMP
  2252. ProxyListener::CheckListenerChain()
  2253. {
  2254. NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
  2255. nsresult rv = NS_OK;
  2256. nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
  2257. do_QueryInterface(mDestListener, &rv);
  2258. if (retargetableListener) {
  2259. rv = retargetableListener->CheckListenerChain();
  2260. }
  2261. MOZ_LOG(gImgLog, LogLevel::Debug,
  2262. ("ProxyListener::CheckListenerChain %s [this=%p listener=%p rv=%x]",
  2263. (NS_SUCCEEDED(rv) ? "success" : "failure"),
  2264. this, (nsIStreamListener*)mDestListener, rv));
  2265. return rv;
  2266. }
  2267. /**
  2268. * http validate class. check a channel for a 304
  2269. */
  2270. NS_IMPL_ISUPPORTS(imgCacheValidator, nsIStreamListener, nsIRequestObserver,
  2271. nsIThreadRetargetableStreamListener,
  2272. nsIChannelEventSink, nsIInterfaceRequestor,
  2273. nsIAsyncVerifyRedirectCallback)
  2274. imgCacheValidator::imgCacheValidator(nsProgressNotificationProxy* progress,
  2275. imgLoader* loader, imgRequest* request,
  2276. nsISupports* aContext,
  2277. bool forcePrincipalCheckForCacheEntry)
  2278. : mProgressProxy(progress),
  2279. mRequest(request),
  2280. mContext(aContext),
  2281. mImgLoader(loader),
  2282. mHadInsecureRedirect(false)
  2283. {
  2284. NewRequestAndEntry(forcePrincipalCheckForCacheEntry, loader,
  2285. mRequest->CacheKey(),
  2286. getter_AddRefs(mNewRequest),
  2287. getter_AddRefs(mNewEntry));
  2288. }
  2289. imgCacheValidator::~imgCacheValidator()
  2290. {
  2291. if (mRequest) {
  2292. mRequest->SetValidator(nullptr);
  2293. }
  2294. }
  2295. void
  2296. imgCacheValidator::AddProxy(imgRequestProxy* aProxy)
  2297. {
  2298. // aProxy needs to be in the loadgroup since we're validating from
  2299. // the network.
  2300. aProxy->AddToLoadGroup();
  2301. mProxies.AppendObject(aProxy);
  2302. }
  2303. /** nsIRequestObserver methods **/
  2304. NS_IMETHODIMP
  2305. imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
  2306. {
  2307. // We may be holding on to a document, so ensure that it's released.
  2308. nsCOMPtr<nsISupports> context = mContext.forget();
  2309. // If for some reason we don't still have an existing request (probably
  2310. // because OnStartRequest got delivered more than once), just bail.
  2311. if (!mRequest) {
  2312. MOZ_ASSERT_UNREACHABLE("OnStartRequest delivered more than once?");
  2313. aRequest->Cancel(NS_BINDING_ABORTED);
  2314. return NS_ERROR_FAILURE;
  2315. }
  2316. // If this request is coming from cache and has the same URI as our
  2317. // imgRequest, the request all our proxies are pointing at is valid, and all
  2318. // we have to do is tell them to notify their listeners.
  2319. nsCOMPtr<nsICacheInfoChannel> cacheChan(do_QueryInterface(aRequest));
  2320. nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  2321. if (cacheChan && channel && !mRequest->CacheChanged(aRequest)) {
  2322. bool isFromCache = false;
  2323. cacheChan->IsFromCache(&isFromCache);
  2324. nsCOMPtr<nsIURI> channelURI;
  2325. channel->GetURI(getter_AddRefs(channelURI));
  2326. nsCOMPtr<nsIURI> currentURI;
  2327. mRequest->GetCurrentURI(getter_AddRefs(currentURI));
  2328. bool sameURI = false;
  2329. if (channelURI && currentURI) {
  2330. channelURI->Equals(currentURI, &sameURI);
  2331. }
  2332. if (isFromCache && sameURI) {
  2333. uint32_t count = mProxies.Count();
  2334. for (int32_t i = count-1; i>=0; i--) {
  2335. imgRequestProxy* proxy = static_cast<imgRequestProxy*>(mProxies[i]);
  2336. // Proxies waiting on cache validation should be deferring
  2337. // notifications. Undefer them.
  2338. MOZ_ASSERT(proxy->NotificationsDeferred(),
  2339. "Proxies waiting on cache validation should be "
  2340. "deferring notifications!");
  2341. proxy->SetNotificationsDeferred(false);
  2342. // Notify synchronously, because we're already in OnStartRequest, an
  2343. // asynchronously-called function.
  2344. proxy->SyncNotifyListener();
  2345. }
  2346. // We don't need to load this any more.
  2347. aRequest->Cancel(NS_BINDING_ABORTED);
  2348. mRequest->SetLoadId(context);
  2349. mRequest->SetValidator(nullptr);
  2350. mRequest = nullptr;
  2351. mNewRequest = nullptr;
  2352. mNewEntry = nullptr;
  2353. return NS_OK;
  2354. }
  2355. }
  2356. // We can't load out of cache. We have to create a whole new request for the
  2357. // data that's coming in off the channel.
  2358. nsCOMPtr<nsIURI> uri;
  2359. {
  2360. RefPtr<ImageURL> imageURL;
  2361. mRequest->GetURI(getter_AddRefs(imageURL));
  2362. uri = imageURL->ToIURI();
  2363. }
  2364. if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
  2365. LOG_MSG_WITH_PARAM(gImgLog,
  2366. "imgCacheValidator::OnStartRequest creating new request",
  2367. "uri", uri->GetSpecOrDefault().get());
  2368. }
  2369. int32_t corsmode = mRequest->GetCORSMode();
  2370. ReferrerPolicy refpol = mRequest->GetReferrerPolicy();
  2371. nsCOMPtr<nsIPrincipal> loadingPrincipal = mRequest->GetLoadingPrincipal();
  2372. // Doom the old request's cache entry
  2373. mRequest->RemoveFromCache();
  2374. mRequest->SetValidator(nullptr);
  2375. mRequest = nullptr;
  2376. // We use originalURI here to fulfil the imgIRequest contract on GetURI.
  2377. nsCOMPtr<nsIURI> originalURI;
  2378. channel->GetOriginalURI(getter_AddRefs(originalURI));
  2379. nsresult rv =
  2380. mNewRequest->Init(originalURI, uri, mHadInsecureRedirect, aRequest, channel,
  2381. mNewEntry, context, loadingPrincipal, corsmode, refpol);
  2382. if (NS_FAILED(rv)) {
  2383. return rv;
  2384. }
  2385. mDestListener = new ProxyListener(mNewRequest);
  2386. // Try to add the new request into the cache. Note that the entry must be in
  2387. // the cache before the proxies' ownership changes, because adding a proxy
  2388. // changes the caching behaviour for imgRequests.
  2389. mImgLoader->PutIntoCache(mNewRequest->CacheKey(), mNewEntry);
  2390. uint32_t count = mProxies.Count();
  2391. for (int32_t i = count-1; i>=0; i--) {
  2392. imgRequestProxy* proxy = static_cast<imgRequestProxy*>(mProxies[i]);
  2393. proxy->ChangeOwner(mNewRequest);
  2394. // Notify synchronously, because we're already in OnStartRequest, an
  2395. // asynchronously-called function.
  2396. proxy->SetNotificationsDeferred(false);
  2397. proxy->SyncNotifyListener();
  2398. }
  2399. mNewRequest = nullptr;
  2400. mNewEntry = nullptr;
  2401. return mDestListener->OnStartRequest(aRequest, ctxt);
  2402. }
  2403. NS_IMETHODIMP
  2404. imgCacheValidator::OnStopRequest(nsIRequest* aRequest,
  2405. nsISupports* ctxt,
  2406. nsresult status)
  2407. {
  2408. // Be sure we've released the document that we may have been holding on to.
  2409. mContext = nullptr;
  2410. if (!mDestListener) {
  2411. return NS_OK;
  2412. }
  2413. return mDestListener->OnStopRequest(aRequest, ctxt, status);
  2414. }
  2415. /** nsIStreamListener methods **/
  2416. NS_IMETHODIMP
  2417. imgCacheValidator::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
  2418. nsIInputStream* inStr,
  2419. uint64_t sourceOffset, uint32_t count)
  2420. {
  2421. if (!mDestListener) {
  2422. // XXX see bug 113959
  2423. uint32_t _retval;
  2424. inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &_retval);
  2425. return NS_OK;
  2426. }
  2427. return mDestListener->OnDataAvailable(aRequest, ctxt, inStr, sourceOffset,
  2428. count);
  2429. }
  2430. /** nsIThreadRetargetableStreamListener methods **/
  2431. NS_IMETHODIMP
  2432. imgCacheValidator::CheckListenerChain()
  2433. {
  2434. NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
  2435. nsresult rv = NS_OK;
  2436. nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
  2437. do_QueryInterface(mDestListener, &rv);
  2438. if (retargetableListener) {
  2439. rv = retargetableListener->CheckListenerChain();
  2440. }
  2441. MOZ_LOG(gImgLog, LogLevel::Debug,
  2442. ("[this=%p] imgCacheValidator::CheckListenerChain -- rv %d=%s",
  2443. this, NS_SUCCEEDED(rv) ? "succeeded" : "failed", rv));
  2444. return rv;
  2445. }
  2446. /** nsIInterfaceRequestor methods **/
  2447. NS_IMETHODIMP
  2448. imgCacheValidator::GetInterface(const nsIID& aIID, void** aResult)
  2449. {
  2450. if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
  2451. return QueryInterface(aIID, aResult);
  2452. }
  2453. return mProgressProxy->GetInterface(aIID, aResult);
  2454. }
  2455. // These functions are materially the same as the same functions in imgRequest.
  2456. // We duplicate them because we're verifying whether cache loads are necessary,
  2457. // not unconditionally loading.
  2458. /** nsIChannelEventSink methods **/
  2459. NS_IMETHODIMP
  2460. imgCacheValidator::
  2461. AsyncOnChannelRedirect(nsIChannel* oldChannel,
  2462. nsIChannel* newChannel,
  2463. uint32_t flags,
  2464. nsIAsyncVerifyRedirectCallback* callback)
  2465. {
  2466. // Note all cache information we get from the old channel.
  2467. mNewRequest->SetCacheValidation(mNewEntry, oldChannel);
  2468. // If the previous URI is a non-HTTPS URI, record that fact for later use by
  2469. // security code, which needs to know whether there is an insecure load at any
  2470. // point in the redirect chain.
  2471. nsCOMPtr<nsIURI> oldURI;
  2472. bool isHttps = false;
  2473. bool isChrome = false;
  2474. bool schemeLocal = false;
  2475. if (NS_FAILED(oldChannel->GetURI(getter_AddRefs(oldURI))) ||
  2476. NS_FAILED(oldURI->SchemeIs("https", &isHttps)) ||
  2477. NS_FAILED(oldURI->SchemeIs("chrome", &isChrome)) ||
  2478. NS_FAILED(NS_URIChainHasFlags(oldURI,
  2479. nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
  2480. &schemeLocal)) ||
  2481. (!isHttps && !isChrome && !schemeLocal)) {
  2482. mHadInsecureRedirect = true;
  2483. }
  2484. // Prepare for callback
  2485. mRedirectCallback = callback;
  2486. mRedirectChannel = newChannel;
  2487. return mProgressProxy->AsyncOnChannelRedirect(oldChannel, newChannel, flags,
  2488. this);
  2489. }
  2490. NS_IMETHODIMP
  2491. imgCacheValidator::OnRedirectVerifyCallback(nsresult aResult)
  2492. {
  2493. // If we've already been told to abort, just do so.
  2494. if (NS_FAILED(aResult)) {
  2495. mRedirectCallback->OnRedirectVerifyCallback(aResult);
  2496. mRedirectCallback = nullptr;
  2497. mRedirectChannel = nullptr;
  2498. return NS_OK;
  2499. }
  2500. // make sure we have a protocol that returns data rather than opens
  2501. // an external application, e.g. mailto:
  2502. nsCOMPtr<nsIURI> uri;
  2503. mRedirectChannel->GetURI(getter_AddRefs(uri));
  2504. bool doesNotReturnData = false;
  2505. NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
  2506. &doesNotReturnData);
  2507. nsresult result = NS_OK;
  2508. if (doesNotReturnData) {
  2509. result = NS_ERROR_ABORT;
  2510. }
  2511. mRedirectCallback->OnRedirectVerifyCallback(result);
  2512. mRedirectCallback = nullptr;
  2513. mRedirectChannel = nullptr;
  2514. return NS_OK;
  2515. }