imgRequest.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. *
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #include "imgRequest.h"
  7. #include "ImageLogging.h"
  8. #include "imgLoader.h"
  9. #include "imgRequestProxy.h"
  10. #include "DecodePool.h"
  11. #include "ProgressTracker.h"
  12. #include "ImageFactory.h"
  13. #include "Image.h"
  14. #include "MultipartImage.h"
  15. #include "RasterImage.h"
  16. #include "nsIChannel.h"
  17. #include "nsICacheInfoChannel.h"
  18. #include "nsIDocument.h"
  19. #include "nsIThreadRetargetableRequest.h"
  20. #include "nsIInputStream.h"
  21. #include "nsIMultiPartChannel.h"
  22. #include "nsIHttpChannel.h"
  23. #include "nsIApplicationCache.h"
  24. #include "nsIApplicationCacheChannel.h"
  25. #include "nsMimeTypes.h"
  26. #include "nsIInterfaceRequestorUtils.h"
  27. #include "nsISupportsPrimitives.h"
  28. #include "nsIScriptSecurityManager.h"
  29. #include "nsContentUtils.h"
  30. #include "plstr.h" // PL_strcasestr(...)
  31. #include "nsNetUtil.h"
  32. #include "nsIProtocolHandler.h"
  33. #include "imgIRequest.h"
  34. using namespace mozilla;
  35. using namespace mozilla::image;
  36. #define LOG_TEST(level) (MOZ_LOG_TEST(gImgLog, (level)))
  37. NS_IMPL_ISUPPORTS(imgRequest,
  38. nsIStreamListener, nsIRequestObserver,
  39. nsIThreadRetargetableStreamListener,
  40. nsIChannelEventSink,
  41. nsIInterfaceRequestor,
  42. nsIAsyncVerifyRedirectCallback)
  43. imgRequest::imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey)
  44. : mLoader(aLoader)
  45. , mCacheKey(aCacheKey)
  46. , mLoadId(nullptr)
  47. , mFirstProxy(nullptr)
  48. , mValidator(nullptr)
  49. , mInnerWindowId(0)
  50. , mCORSMode(imgIRequest::CORS_NONE)
  51. , mReferrerPolicy(mozilla::net::RP_Default)
  52. , mImageErrorCode(NS_OK)
  53. , mMutex("imgRequest")
  54. , mProgressTracker(new ProgressTracker())
  55. , mIsMultiPartChannel(false)
  56. , mGotData(false)
  57. , mIsInCache(false)
  58. , mDecodeRequested(false)
  59. , mNewPartPending(false)
  60. , mHadInsecureRedirect(false)
  61. { }
  62. imgRequest::~imgRequest()
  63. {
  64. if (mLoader) {
  65. mLoader->RemoveFromUncachedImages(this);
  66. }
  67. if (mURI) {
  68. nsAutoCString spec;
  69. mURI->GetSpec(spec);
  70. LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::~imgRequest()",
  71. "keyuri", spec.get());
  72. } else
  73. LOG_FUNC(gImgLog, "imgRequest::~imgRequest()");
  74. }
  75. nsresult
  76. imgRequest::Init(nsIURI *aURI,
  77. nsIURI *aCurrentURI,
  78. bool aHadInsecureRedirect,
  79. nsIRequest *aRequest,
  80. nsIChannel *aChannel,
  81. imgCacheEntry *aCacheEntry,
  82. nsISupports* aCX,
  83. nsIPrincipal* aLoadingPrincipal,
  84. int32_t aCORSMode,
  85. ReferrerPolicy aReferrerPolicy)
  86. {
  87. MOZ_ASSERT(NS_IsMainThread(), "Cannot use nsIURI off main thread!");
  88. LOG_FUNC(gImgLog, "imgRequest::Init");
  89. MOZ_ASSERT(!mImage, "Multiple calls to init");
  90. MOZ_ASSERT(aURI, "No uri");
  91. MOZ_ASSERT(aCurrentURI, "No current uri");
  92. MOZ_ASSERT(aRequest, "No request");
  93. MOZ_ASSERT(aChannel, "No channel");
  94. mProperties = do_CreateInstance("@mozilla.org/properties;1");
  95. // Use ImageURL to ensure access to URI data off main thread.
  96. nsresult rv;
  97. mURI = new ImageURL(aURI, rv);
  98. NS_ENSURE_SUCCESS(rv, rv);
  99. mCurrentURI = aCurrentURI;
  100. mRequest = aRequest;
  101. mChannel = aChannel;
  102. mTimedChannel = do_QueryInterface(mChannel);
  103. mLoadingPrincipal = aLoadingPrincipal;
  104. mCORSMode = aCORSMode;
  105. mReferrerPolicy = aReferrerPolicy;
  106. // If the original URI and the current URI are different, check whether the
  107. // original URI is secure. We deliberately don't take the current URI into
  108. // account, as it needs to be handled using more complicated rules than
  109. // earlier elements of the redirect chain.
  110. if (aURI != aCurrentURI) {
  111. bool isHttps = false;
  112. bool isChrome = false;
  113. bool schemeLocal = false;
  114. if (NS_FAILED(aURI->SchemeIs("https", &isHttps)) ||
  115. NS_FAILED(aURI->SchemeIs("chrome", &isChrome)) ||
  116. NS_FAILED(NS_URIChainHasFlags(
  117. aURI,
  118. nsIProtocolHandler::URI_IS_LOCAL_RESOURCE , &schemeLocal)) ||
  119. (!isHttps && !isChrome && !schemeLocal)) {
  120. mHadInsecureRedirect = true;
  121. }
  122. }
  123. // imgCacheValidator may have handled redirects before we were created, so we
  124. // allow the caller to let us know if any redirects were insecure.
  125. mHadInsecureRedirect = mHadInsecureRedirect || aHadInsecureRedirect;
  126. mChannel->GetNotificationCallbacks(getter_AddRefs(mPrevChannelSink));
  127. NS_ASSERTION(mPrevChannelSink != this,
  128. "Initializing with a channel that already calls back to us!");
  129. mChannel->SetNotificationCallbacks(this);
  130. mCacheEntry = aCacheEntry;
  131. mCacheEntry->UpdateLoadTime();
  132. SetLoadId(aCX);
  133. // Grab the inner window ID of the loading document, if possible.
  134. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
  135. if (doc) {
  136. mInnerWindowId = doc->InnerWindowID();
  137. }
  138. return NS_OK;
  139. }
  140. void
  141. imgRequest::ClearLoader() {
  142. mLoader = nullptr;
  143. }
  144. already_AddRefed<ProgressTracker>
  145. imgRequest::GetProgressTracker() const
  146. {
  147. MutexAutoLock lock(mMutex);
  148. if (mImage) {
  149. MOZ_ASSERT(!mProgressTracker,
  150. "Should have given mProgressTracker to mImage");
  151. return mImage->GetProgressTracker();
  152. } else {
  153. MOZ_ASSERT(mProgressTracker,
  154. "Should have mProgressTracker until we create mImage");
  155. RefPtr<ProgressTracker> progressTracker = mProgressTracker;
  156. MOZ_ASSERT(progressTracker);
  157. return progressTracker.forget();
  158. }
  159. }
  160. void imgRequest::SetCacheEntry(imgCacheEntry* entry)
  161. {
  162. mCacheEntry = entry;
  163. }
  164. bool
  165. imgRequest::HasCacheEntry() const
  166. {
  167. return mCacheEntry != nullptr;
  168. }
  169. void
  170. imgRequest::ResetCacheEntry()
  171. {
  172. if (HasCacheEntry()) {
  173. mCacheEntry->SetDataSize(0);
  174. }
  175. }
  176. void
  177. imgRequest::AddProxy(imgRequestProxy* proxy)
  178. {
  179. NS_PRECONDITION(proxy, "null imgRequestProxy passed in");
  180. LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::AddProxy", "proxy", proxy);
  181. if (!mFirstProxy) {
  182. // Save a raw pointer to the first proxy we see, for use in the network
  183. // priority logic.
  184. mFirstProxy = proxy;
  185. }
  186. // If we're empty before adding, we have to tell the loader we now have
  187. // proxies.
  188. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  189. if (progressTracker->ObserverCount() == 0) {
  190. MOZ_ASSERT(mURI, "Trying to SetHasProxies without key uri.");
  191. if (mLoader) {
  192. mLoader->SetHasProxies(this);
  193. }
  194. }
  195. progressTracker->AddObserver(proxy);
  196. }
  197. nsresult
  198. imgRequest::RemoveProxy(imgRequestProxy* proxy, nsresult aStatus)
  199. {
  200. LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::RemoveProxy", "proxy", proxy);
  201. // This will remove our animation consumers, so after removing
  202. // this proxy, we don't end up without proxies with observers, but still
  203. // have animation consumers.
  204. proxy->ClearAnimationConsumers();
  205. // Let the status tracker do its thing before we potentially call Cancel()
  206. // below, because Cancel() may result in OnStopRequest being called back
  207. // before Cancel() returns, leaving the image in a different state then the
  208. // one it was in at this point.
  209. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  210. if (!progressTracker->RemoveObserver(proxy)) {
  211. return NS_OK;
  212. }
  213. if (progressTracker->ObserverCount() == 0) {
  214. // If we have no observers, there's nothing holding us alive. If we haven't
  215. // been cancelled and thus removed from the cache, tell the image loader so
  216. // we can be evicted from the cache.
  217. if (mCacheEntry) {
  218. MOZ_ASSERT(mURI, "Removing last observer without key uri.");
  219. if (mLoader) {
  220. mLoader->SetHasNoProxies(this, mCacheEntry);
  221. }
  222. } else if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
  223. nsAutoCString spec;
  224. mURI->GetSpec(spec);
  225. LOG_MSG_WITH_PARAM(gImgLog,
  226. "imgRequest::RemoveProxy no cache entry",
  227. "uri", spec.get());
  228. }
  229. /* If |aStatus| is a failure code, then cancel the load if it is still in
  230. progress. Otherwise, let the load continue, keeping 'this' in the cache
  231. with no observers. This way, if a proxy is destroyed without calling
  232. cancel on it, it won't leak and won't leave a bad pointer in the observer
  233. list.
  234. */
  235. if (!(progressTracker->GetProgress() & FLAG_LAST_PART_COMPLETE) &&
  236. NS_FAILED(aStatus)) {
  237. LOG_MSG(gImgLog, "imgRequest::RemoveProxy",
  238. "load in progress. canceling");
  239. this->Cancel(NS_BINDING_ABORTED);
  240. }
  241. /* break the cycle from the cache entry. */
  242. mCacheEntry = nullptr;
  243. }
  244. // If a proxy is removed for a reason other than its owner being
  245. // changed, remove the proxy from the loadgroup.
  246. if (aStatus != NS_IMAGELIB_CHANGING_OWNER) {
  247. proxy->RemoveFromLoadGroup(true);
  248. }
  249. return NS_OK;
  250. }
  251. void
  252. imgRequest::CancelAndAbort(nsresult aStatus)
  253. {
  254. LOG_SCOPE(gImgLog, "imgRequest::CancelAndAbort");
  255. Cancel(aStatus);
  256. // It's possible for the channel to fail to open after we've set our
  257. // notification callbacks. In that case, make sure to break the cycle between
  258. // the channel and us, because it won't.
  259. if (mChannel) {
  260. mChannel->SetNotificationCallbacks(mPrevChannelSink);
  261. mPrevChannelSink = nullptr;
  262. }
  263. }
  264. class imgRequestMainThreadCancel : public Runnable
  265. {
  266. public:
  267. imgRequestMainThreadCancel(imgRequest* aImgRequest, nsresult aStatus)
  268. : mImgRequest(aImgRequest)
  269. , mStatus(aStatus)
  270. {
  271. MOZ_ASSERT(!NS_IsMainThread(), "Create me off main thread only!");
  272. MOZ_ASSERT(aImgRequest);
  273. }
  274. NS_IMETHOD Run() override
  275. {
  276. MOZ_ASSERT(NS_IsMainThread(), "I should be running on the main thread!");
  277. mImgRequest->ContinueCancel(mStatus);
  278. return NS_OK;
  279. }
  280. private:
  281. RefPtr<imgRequest> mImgRequest;
  282. nsresult mStatus;
  283. };
  284. void
  285. imgRequest::Cancel(nsresult aStatus)
  286. {
  287. /* The Cancel() method here should only be called by this class. */
  288. LOG_SCOPE(gImgLog, "imgRequest::Cancel");
  289. if (NS_IsMainThread()) {
  290. ContinueCancel(aStatus);
  291. } else {
  292. NS_DispatchToMainThread(new imgRequestMainThreadCancel(this, aStatus));
  293. }
  294. }
  295. void
  296. imgRequest::ContinueCancel(nsresult aStatus)
  297. {
  298. MOZ_ASSERT(NS_IsMainThread());
  299. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  300. progressTracker->SyncNotifyProgress(FLAG_HAS_ERROR | FLAG_ONLOAD_UNBLOCKED);
  301. RemoveFromCache();
  302. if (mRequest && !(progressTracker->GetProgress() & FLAG_LAST_PART_COMPLETE)) {
  303. mRequest->Cancel(aStatus);
  304. }
  305. }
  306. class imgRequestMainThreadEvict : public Runnable
  307. {
  308. public:
  309. explicit imgRequestMainThreadEvict(imgRequest* aImgRequest)
  310. : mImgRequest(aImgRequest)
  311. {
  312. MOZ_ASSERT(!NS_IsMainThread(), "Create me off main thread only!");
  313. MOZ_ASSERT(aImgRequest);
  314. }
  315. NS_IMETHOD Run() override
  316. {
  317. MOZ_ASSERT(NS_IsMainThread(), "I should be running on the main thread!");
  318. mImgRequest->ContinueEvict();
  319. return NS_OK;
  320. }
  321. private:
  322. RefPtr<imgRequest> mImgRequest;
  323. };
  324. // EvictFromCache() is written to allowed to get called from any thread
  325. void
  326. imgRequest::EvictFromCache()
  327. {
  328. /* The EvictFromCache() method here should only be called by this class. */
  329. LOG_SCOPE(gImgLog, "imgRequest::EvictFromCache");
  330. if (NS_IsMainThread()) {
  331. ContinueEvict();
  332. } else {
  333. NS_DispatchToMainThread(new imgRequestMainThreadEvict(this));
  334. }
  335. }
  336. // Helper-method used by EvictFromCache()
  337. void
  338. imgRequest::ContinueEvict()
  339. {
  340. MOZ_ASSERT(NS_IsMainThread());
  341. RemoveFromCache();
  342. }
  343. void
  344. imgRequest::StartDecoding()
  345. {
  346. MutexAutoLock lock(mMutex);
  347. mDecodeRequested = true;
  348. }
  349. bool
  350. imgRequest::IsDecodeRequested() const
  351. {
  352. MutexAutoLock lock(mMutex);
  353. return mDecodeRequested;
  354. }
  355. nsresult imgRequest::GetURI(ImageURL** aURI)
  356. {
  357. MOZ_ASSERT(aURI);
  358. LOG_FUNC(gImgLog, "imgRequest::GetURI");
  359. if (mURI) {
  360. *aURI = mURI;
  361. NS_ADDREF(*aURI);
  362. return NS_OK;
  363. }
  364. return NS_ERROR_FAILURE;
  365. }
  366. nsresult
  367. imgRequest::GetCurrentURI(nsIURI** aURI)
  368. {
  369. MOZ_ASSERT(aURI);
  370. LOG_FUNC(gImgLog, "imgRequest::GetCurrentURI");
  371. if (mCurrentURI) {
  372. *aURI = mCurrentURI;
  373. NS_ADDREF(*aURI);
  374. return NS_OK;
  375. }
  376. return NS_ERROR_FAILURE;
  377. }
  378. bool
  379. imgRequest::IsChrome() const
  380. {
  381. bool isChrome = false;
  382. if (NS_WARN_IF(NS_FAILED(mURI->SchemeIs("chrome", &isChrome)))) {
  383. return false;
  384. }
  385. return isChrome;
  386. }
  387. nsresult
  388. imgRequest::GetImageErrorCode()
  389. {
  390. return mImageErrorCode;
  391. }
  392. nsresult
  393. imgRequest::GetSecurityInfo(nsISupports** aSecurityInfo)
  394. {
  395. LOG_FUNC(gImgLog, "imgRequest::GetSecurityInfo");
  396. // Missing security info means this is not a security load
  397. // i.e. it is not an error when security info is missing
  398. NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
  399. return NS_OK;
  400. }
  401. void
  402. imgRequest::RemoveFromCache()
  403. {
  404. LOG_SCOPE(gImgLog, "imgRequest::RemoveFromCache");
  405. bool isInCache = false;
  406. {
  407. MutexAutoLock lock(mMutex);
  408. isInCache = mIsInCache;
  409. }
  410. if (isInCache && mLoader) {
  411. // mCacheEntry is nulled out when we have no more observers.
  412. if (mCacheEntry) {
  413. mLoader->RemoveFromCache(mCacheEntry);
  414. } else {
  415. mLoader->RemoveFromCache(mCacheKey);
  416. }
  417. }
  418. mCacheEntry = nullptr;
  419. }
  420. bool
  421. imgRequest::HasConsumers() const
  422. {
  423. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  424. return progressTracker && progressTracker->ObserverCount() > 0;
  425. }
  426. already_AddRefed<Image>
  427. imgRequest::GetImage() const
  428. {
  429. MutexAutoLock lock(mMutex);
  430. RefPtr<Image> image = mImage;
  431. return image.forget();
  432. }
  433. int32_t imgRequest::Priority() const
  434. {
  435. int32_t priority = nsISupportsPriority::PRIORITY_NORMAL;
  436. nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mRequest);
  437. if (p) {
  438. p->GetPriority(&priority);
  439. }
  440. return priority;
  441. }
  442. void
  443. imgRequest::AdjustPriority(imgRequestProxy* proxy, int32_t delta)
  444. {
  445. // only the first proxy is allowed to modify the priority of this image load.
  446. //
  447. // XXX(darin): this is probably not the most optimal algorithm as we may want
  448. // to increase the priority of requests that have a lot of proxies. the key
  449. // concern though is that image loads remain lower priority than other pieces
  450. // of content such as link clicks, CSS, and JS.
  451. //
  452. if (!mFirstProxy || proxy != mFirstProxy) {
  453. return;
  454. }
  455. nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mChannel);
  456. if (p) {
  457. p->AdjustPriority(delta);
  458. }
  459. }
  460. bool
  461. imgRequest::HasTransferredData() const
  462. {
  463. MutexAutoLock lock(mMutex);
  464. return mGotData;
  465. }
  466. void
  467. imgRequest::SetIsInCache(bool aInCache)
  468. {
  469. LOG_FUNC_WITH_PARAM(gImgLog,
  470. "imgRequest::SetIsCacheable", "aInCache", aInCache);
  471. MutexAutoLock lock(mMutex);
  472. mIsInCache = aInCache;
  473. }
  474. void
  475. imgRequest::UpdateCacheEntrySize()
  476. {
  477. if (!mCacheEntry) {
  478. return;
  479. }
  480. RefPtr<Image> image = GetImage();
  481. size_t size = image->SizeOfSourceWithComputedFallback(moz_malloc_size_of);
  482. mCacheEntry->SetDataSize(size);
  483. }
  484. void
  485. imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry, nsIRequest* aRequest)
  486. {
  487. /* get the expires info */
  488. if (aCacheEntry) {
  489. nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aRequest));
  490. if (cacheChannel) {
  491. uint32_t expiration = 0;
  492. /* get the expiration time from the caching channel's token */
  493. if (NS_SUCCEEDED(cacheChannel->GetCacheTokenExpirationTime(&expiration))) {
  494. // Expiration time defaults to 0. We set the expiration time on our
  495. // entry if it hasn't been set yet.
  496. if (aCacheEntry->GetExpiryTime() == 0) {
  497. aCacheEntry->SetExpiryTime(expiration);
  498. }
  499. }
  500. }
  501. // Determine whether the cache entry must be revalidated when we try to use
  502. // it. Currently, only HTTP specifies this information...
  503. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
  504. if (httpChannel) {
  505. bool bMustRevalidate = false;
  506. httpChannel->IsNoStoreResponse(&bMustRevalidate);
  507. if (!bMustRevalidate) {
  508. httpChannel->IsNoCacheResponse(&bMustRevalidate);
  509. }
  510. if (!bMustRevalidate) {
  511. nsAutoCString cacheHeader;
  512. httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Cache-Control"),
  513. cacheHeader);
  514. if (PL_strcasestr(cacheHeader.get(), "must-revalidate")) {
  515. bMustRevalidate = true;
  516. }
  517. }
  518. // Cache entries default to not needing to validate. We ensure that
  519. // multiple calls to this function don't override an earlier decision to
  520. // validate by making validation a one-way decision.
  521. if (bMustRevalidate) {
  522. aCacheEntry->SetMustValidate(bMustRevalidate);
  523. }
  524. }
  525. }
  526. }
  527. namespace {
  528. already_AddRefed<nsIApplicationCache>
  529. GetApplicationCache(nsIRequest* aRequest)
  530. {
  531. nsresult rv;
  532. nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
  533. do_QueryInterface(aRequest);
  534. if (!appCacheChan) {
  535. return nullptr;
  536. }
  537. bool fromAppCache;
  538. rv = appCacheChan->GetLoadedFromApplicationCache(&fromAppCache);
  539. NS_ENSURE_SUCCESS(rv, nullptr);
  540. if (!fromAppCache) {
  541. return nullptr;
  542. }
  543. nsCOMPtr<nsIApplicationCache> appCache;
  544. rv = appCacheChan->GetApplicationCache(getter_AddRefs(appCache));
  545. NS_ENSURE_SUCCESS(rv, nullptr);
  546. return appCache.forget();
  547. }
  548. } // namespace
  549. bool
  550. imgRequest::CacheChanged(nsIRequest* aNewRequest)
  551. {
  552. nsCOMPtr<nsIApplicationCache> newAppCache = GetApplicationCache(aNewRequest);
  553. // Application cache not involved at all or the same app cache involved
  554. // in both of the loads (original and new).
  555. if (newAppCache == mApplicationCache) {
  556. return false;
  557. }
  558. // In a rare case it may happen that two objects still refer
  559. // the same application cache version.
  560. if (newAppCache && mApplicationCache) {
  561. nsresult rv;
  562. nsAutoCString oldAppCacheClientId, newAppCacheClientId;
  563. rv = mApplicationCache->GetClientID(oldAppCacheClientId);
  564. NS_ENSURE_SUCCESS(rv, true);
  565. rv = newAppCache->GetClientID(newAppCacheClientId);
  566. NS_ENSURE_SUCCESS(rv, true);
  567. if (oldAppCacheClientId == newAppCacheClientId) {
  568. return false;
  569. }
  570. }
  571. // When we get here, app caches differ or app cache is involved
  572. // just in one of the loads what we also consider as a change
  573. // in a loading cache.
  574. return true;
  575. }
  576. bool
  577. imgRequest::GetMultipart() const
  578. {
  579. MutexAutoLock lock(mMutex);
  580. return mIsMultiPartChannel;
  581. }
  582. bool
  583. imgRequest::HadInsecureRedirect() const
  584. {
  585. MutexAutoLock lock(mMutex);
  586. return mHadInsecureRedirect;
  587. }
  588. /** nsIRequestObserver methods **/
  589. NS_IMETHODIMP
  590. imgRequest::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
  591. {
  592. LOG_SCOPE(gImgLog, "imgRequest::OnStartRequest");
  593. RefPtr<Image> image;
  594. // Figure out if we're multipart.
  595. nsCOMPtr<nsIMultiPartChannel> multiPartChannel = do_QueryInterface(aRequest);
  596. MOZ_ASSERT(multiPartChannel || !mIsMultiPartChannel,
  597. "Stopped being multipart?"); {
  598. MutexAutoLock lock(mMutex);
  599. mNewPartPending = true;
  600. image = mImage;
  601. mIsMultiPartChannel = bool(multiPartChannel);
  602. }
  603. // If we're not multipart, we shouldn't have an image yet.
  604. if (image && !multiPartChannel) {
  605. MOZ_ASSERT_UNREACHABLE("Already have an image for a non-multipart request");
  606. Cancel(NS_IMAGELIB_ERROR_FAILURE);
  607. return NS_ERROR_FAILURE;
  608. }
  609. /*
  610. * If mRequest is null here, then we need to set it so that we'll be able to
  611. * cancel it if our Cancel() method is called. Note that this can only
  612. * happen for multipart channels. We could simply not null out mRequest for
  613. * non-last parts, if GetIsLastPart() were reliable, but it's not. See
  614. * https://bugzilla.mozilla.org/show_bug.cgi?id=339610
  615. */
  616. if (!mRequest) {
  617. MOZ_ASSERT(multiPartChannel, "Should have mRequest unless we're multipart");
  618. nsCOMPtr<nsIChannel> baseChannel;
  619. multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
  620. mRequest = baseChannel;
  621. }
  622. nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  623. if (channel) {
  624. channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
  625. /* Get our principal */
  626. nsCOMPtr<nsIScriptSecurityManager>
  627. secMan = nsContentUtils::GetSecurityManager();
  628. if (secMan) {
  629. nsresult rv =
  630. secMan->GetChannelResultPrincipal(channel, getter_AddRefs(mPrincipal));
  631. if (NS_FAILED(rv)) {
  632. return rv;
  633. }
  634. }
  635. }
  636. SetCacheValidation(mCacheEntry, aRequest);
  637. mApplicationCache = GetApplicationCache(aRequest);
  638. // Shouldn't we be dead already if this gets hit?
  639. // Probably multipart/x-mixed-replace...
  640. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  641. if (progressTracker->ObserverCount() == 0) {
  642. this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
  643. }
  644. // Try to retarget OnDataAvailable to a decode thread.
  645. nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
  646. nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
  647. do_QueryInterface(aRequest);
  648. if (httpChannel && retargetable) {
  649. nsAutoCString mimeType;
  650. nsresult rv = httpChannel->GetContentType(mimeType);
  651. if (NS_SUCCEEDED(rv) && !mimeType.EqualsLiteral(IMAGE_SVG_XML)) {
  652. // Retarget OnDataAvailable to the DecodePool's IO thread.
  653. nsCOMPtr<nsIEventTarget> target =
  654. DecodePool::Singleton()->GetIOEventTarget();
  655. rv = retargetable->RetargetDeliveryTo(target);
  656. }
  657. MOZ_LOG(gImgLog, LogLevel::Warning,
  658. ("[this=%p] imgRequest::OnStartRequest -- "
  659. "RetargetDeliveryTo rv %d=%s\n",
  660. this, rv, NS_SUCCEEDED(rv) ? "succeeded" : "failed"));
  661. }
  662. return NS_OK;
  663. }
  664. NS_IMETHODIMP
  665. imgRequest::OnStopRequest(nsIRequest* aRequest,
  666. nsISupports* ctxt, nsresult status)
  667. {
  668. LOG_FUNC(gImgLog, "imgRequest::OnStopRequest");
  669. MOZ_ASSERT(NS_IsMainThread(), "Can't send notifications off-main-thread");
  670. RefPtr<Image> image = GetImage();
  671. RefPtr<imgRequest> strongThis = this;
  672. if (mIsMultiPartChannel && mNewPartPending) {
  673. OnDataAvailable(aRequest, ctxt, nullptr, 0, 0);
  674. }
  675. // XXXldb What if this is a non-last part of a multipart request?
  676. // xxx before we release our reference to mRequest, lets
  677. // save the last status that we saw so that the
  678. // imgRequestProxy will have access to it.
  679. if (mRequest) {
  680. mRequest = nullptr; // we no longer need the request
  681. }
  682. // stop holding a ref to the channel, since we don't need it anymore
  683. if (mChannel) {
  684. mChannel->SetNotificationCallbacks(mPrevChannelSink);
  685. mPrevChannelSink = nullptr;
  686. mChannel = nullptr;
  687. }
  688. bool lastPart = true;
  689. nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
  690. if (mpchan) {
  691. mpchan->GetIsLastPart(&lastPart);
  692. }
  693. bool isPartial = false;
  694. if (image && (status == NS_ERROR_NET_PARTIAL_TRANSFER)) {
  695. isPartial = true;
  696. status = NS_OK; // fake happy face
  697. }
  698. // Tell the image that it has all of the source data. Note that this can
  699. // trigger a failure, since the image might be waiting for more non-optional
  700. // data and this is the point where we break the news that it's not coming.
  701. if (image) {
  702. nsresult rv = image->OnImageDataComplete(aRequest, ctxt, status, lastPart);
  703. // If we got an error in the OnImageDataComplete() call, we don't want to
  704. // proceed as if nothing bad happened. However, we also want to give
  705. // precedence to failure status codes from necko, since presumably they're
  706. // more meaningful.
  707. if (NS_FAILED(rv) && NS_SUCCEEDED(status)) {
  708. status = rv;
  709. }
  710. }
  711. // If the request went through, update the cache entry size. Otherwise,
  712. // cancel the request, which removes us from the cache.
  713. if (image && NS_SUCCEEDED(status) && !isPartial) {
  714. // We update the cache entry size here because this is where we finish
  715. // loading compressed source data, which is part of our size calculus.
  716. UpdateCacheEntrySize();
  717. } else if (isPartial) {
  718. // Remove the partial image from the cache.
  719. this->EvictFromCache();
  720. } else {
  721. mImageErrorCode = status;
  722. // if the error isn't "just" a partial transfer
  723. // stops animations, removes from cache
  724. this->Cancel(status);
  725. }
  726. if (!image) {
  727. // We have to fire the OnStopRequest notifications ourselves because there's
  728. // no image capable of doing so.
  729. Progress progress =
  730. LoadCompleteProgress(lastPart, /* aError = */ false, status);
  731. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  732. progressTracker->SyncNotifyProgress(progress);
  733. }
  734. mTimedChannel = nullptr;
  735. return NS_OK;
  736. }
  737. struct mimetype_closure
  738. {
  739. nsACString* newType;
  740. };
  741. /* prototype for these defined below */
  742. static nsresult
  743. sniff_mimetype_callback(nsIInputStream* in, void* closure,
  744. const char* fromRawSegment, uint32_t toOffset,
  745. uint32_t count, uint32_t* writeCount);
  746. /** nsThreadRetargetableStreamListener methods **/
  747. NS_IMETHODIMP
  748. imgRequest::CheckListenerChain()
  749. {
  750. // TODO Might need more checking here.
  751. NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
  752. return NS_OK;
  753. }
  754. /** nsIStreamListener methods **/
  755. struct NewPartResult final
  756. {
  757. explicit NewPartResult(Image* aExistingImage)
  758. : mImage(aExistingImage)
  759. , mIsFirstPart(!aExistingImage)
  760. , mSucceeded(false)
  761. , mShouldResetCacheEntry(false)
  762. { }
  763. nsAutoCString mContentType;
  764. nsAutoCString mContentDisposition;
  765. RefPtr<Image> mImage;
  766. const bool mIsFirstPart;
  767. bool mSucceeded;
  768. bool mShouldResetCacheEntry;
  769. };
  770. static NewPartResult
  771. PrepareForNewPart(nsIRequest* aRequest, nsIInputStream* aInStr, uint32_t aCount,
  772. ImageURL* aURI, bool aIsMultipart, Image* aExistingImage,
  773. ProgressTracker* aProgressTracker, uint32_t aInnerWindowId)
  774. {
  775. NewPartResult result(aExistingImage);
  776. if (aInStr) {
  777. mimetype_closure closure;
  778. closure.newType = &result.mContentType;
  779. // Look at the first few bytes and see if we can tell what the data is from
  780. // that since servers tend to lie. :(
  781. uint32_t out;
  782. aInStr->ReadSegments(sniff_mimetype_callback, &closure, aCount, &out);
  783. }
  784. nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
  785. if (result.mContentType.IsEmpty()) {
  786. nsresult rv = chan ? chan->GetContentType(result.mContentType)
  787. : NS_ERROR_FAILURE;
  788. if (NS_FAILED(rv)) {
  789. MOZ_LOG(gImgLog,
  790. LogLevel::Error, ("imgRequest::PrepareForNewPart -- "
  791. "Content type unavailable from the channel\n"));
  792. if (!aIsMultipart) {
  793. return result;
  794. }
  795. }
  796. }
  797. if (chan) {
  798. chan->GetContentDispositionHeader(result.mContentDisposition);
  799. }
  800. MOZ_LOG(gImgLog, LogLevel::Debug,
  801. ("imgRequest::PrepareForNewPart -- Got content type %s\n",
  802. result.mContentType.get()));
  803. // XXX If server lied about mimetype and it's SVG, we may need to copy
  804. // the data and dispatch back to the main thread, AND tell the channel to
  805. // dispatch there in the future.
  806. // Create the new image and give it ownership of our ProgressTracker.
  807. if (aIsMultipart) {
  808. // Create the ProgressTracker and image for this part.
  809. RefPtr<ProgressTracker> progressTracker = new ProgressTracker();
  810. RefPtr<Image> partImage =
  811. ImageFactory::CreateImage(aRequest, progressTracker, result.mContentType,
  812. aURI, /* aIsMultipart = */ true,
  813. aInnerWindowId);
  814. if (result.mIsFirstPart) {
  815. // First part for a multipart channel. Create the MultipartImage wrapper.
  816. MOZ_ASSERT(aProgressTracker, "Shouldn't have given away tracker yet");
  817. result.mImage =
  818. ImageFactory::CreateMultipartImage(partImage, aProgressTracker);
  819. } else {
  820. // Transition to the new part.
  821. auto multipartImage = static_cast<MultipartImage*>(aExistingImage);
  822. multipartImage->BeginTransitionToPart(partImage);
  823. // Reset our cache entry size so it doesn't keep growing without bound.
  824. result.mShouldResetCacheEntry = true;
  825. }
  826. } else {
  827. MOZ_ASSERT(!aExistingImage, "New part for non-multipart channel?");
  828. MOZ_ASSERT(aProgressTracker, "Shouldn't have given away tracker yet");
  829. // Create an image using our progress tracker.
  830. result.mImage =
  831. ImageFactory::CreateImage(aRequest, aProgressTracker, result.mContentType,
  832. aURI, /* aIsMultipart = */ false,
  833. aInnerWindowId);
  834. }
  835. MOZ_ASSERT(result.mImage);
  836. if (!result.mImage->HasError() || aIsMultipart) {
  837. // We allow multipart images to fail to initialize (which generally
  838. // indicates a bad content type) without cancelling the load, because
  839. // subsequent parts might be fine.
  840. result.mSucceeded = true;
  841. }
  842. return result;
  843. }
  844. class FinishPreparingForNewPartRunnable final : public Runnable
  845. {
  846. public:
  847. FinishPreparingForNewPartRunnable(imgRequest* aImgRequest,
  848. NewPartResult&& aResult)
  849. : mImgRequest(aImgRequest)
  850. , mResult(aResult)
  851. {
  852. MOZ_ASSERT(aImgRequest);
  853. }
  854. NS_IMETHOD Run() override
  855. {
  856. mImgRequest->FinishPreparingForNewPart(mResult);
  857. return NS_OK;
  858. }
  859. private:
  860. RefPtr<imgRequest> mImgRequest;
  861. NewPartResult mResult;
  862. };
  863. void
  864. imgRequest::FinishPreparingForNewPart(const NewPartResult& aResult)
  865. {
  866. MOZ_ASSERT(NS_IsMainThread());
  867. mContentType = aResult.mContentType;
  868. SetProperties(aResult.mContentType, aResult.mContentDisposition);
  869. if (aResult.mIsFirstPart) {
  870. // Notify listeners that we have an image.
  871. RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
  872. progressTracker->OnImageAvailable();
  873. MOZ_ASSERT(progressTracker->HasImage());
  874. }
  875. if (aResult.mShouldResetCacheEntry) {
  876. ResetCacheEntry();
  877. }
  878. if (IsDecodeRequested()) {
  879. aResult.mImage->StartDecoding();
  880. }
  881. }
  882. NS_IMETHODIMP
  883. imgRequest::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
  884. nsIInputStream* aInStr, uint64_t aOffset,
  885. uint32_t aCount)
  886. {
  887. LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequest::OnDataAvailable",
  888. "count", aCount);
  889. NS_ASSERTION(aRequest, "imgRequest::OnDataAvailable -- no request!");
  890. RefPtr<Image> image;
  891. RefPtr<ProgressTracker> progressTracker;
  892. bool isMultipart = false;
  893. bool newPartPending = false;
  894. // Retrieve and update our state.
  895. {
  896. MutexAutoLock lock(mMutex);
  897. mGotData = true;
  898. image = mImage;
  899. progressTracker = mProgressTracker;
  900. isMultipart = mIsMultiPartChannel;
  901. newPartPending = mNewPartPending;
  902. mNewPartPending = false;
  903. }
  904. // If this is a new part, we need to sniff its content type and create an
  905. // appropriate image.
  906. if (newPartPending) {
  907. NewPartResult result = PrepareForNewPart(aRequest, aInStr, aCount, mURI,
  908. isMultipart, image,
  909. progressTracker, mInnerWindowId);
  910. bool succeeded = result.mSucceeded;
  911. if (result.mImage) {
  912. image = result.mImage;
  913. // Update our state to reflect this new part.
  914. {
  915. MutexAutoLock lock(mMutex);
  916. mImage = image;
  917. mProgressTracker = nullptr;
  918. }
  919. // Some property objects are not threadsafe, and we need to send
  920. // OnImageAvailable on the main thread, so finish on the main thread.
  921. if (NS_IsMainThread()) {
  922. FinishPreparingForNewPart(result);
  923. } else {
  924. nsCOMPtr<nsIRunnable> runnable =
  925. new FinishPreparingForNewPartRunnable(this, Move(result));
  926. NS_DispatchToMainThread(runnable);
  927. }
  928. }
  929. if (!succeeded) {
  930. // Something went wrong; probably a content type issue.
  931. Cancel(NS_IMAGELIB_ERROR_FAILURE);
  932. return NS_BINDING_ABORTED;
  933. }
  934. }
  935. // Notify the image that it has new data.
  936. if (aInStr) {
  937. nsresult rv =
  938. image->OnImageDataAvailable(aRequest, aContext, aInStr, aOffset, aCount);
  939. if (NS_FAILED(rv)) {
  940. MOZ_LOG(gImgLog, LogLevel::Warning,
  941. ("[this=%p] imgRequest::OnDataAvailable -- "
  942. "copy to RasterImage failed\n", this));
  943. Cancel(NS_IMAGELIB_ERROR_FAILURE);
  944. return NS_BINDING_ABORTED;
  945. }
  946. }
  947. return NS_OK;
  948. }
  949. void
  950. imgRequest::SetProperties(const nsACString& aContentType,
  951. const nsACString& aContentDisposition)
  952. {
  953. /* set our mimetype as a property */
  954. nsCOMPtr<nsISupportsCString> contentType =
  955. do_CreateInstance("@mozilla.org/supports-cstring;1");
  956. if (contentType) {
  957. contentType->SetData(aContentType);
  958. mProperties->Set("type", contentType);
  959. }
  960. /* set our content disposition as a property */
  961. if (!aContentDisposition.IsEmpty()) {
  962. nsCOMPtr<nsISupportsCString> contentDisposition =
  963. do_CreateInstance("@mozilla.org/supports-cstring;1");
  964. if (contentDisposition) {
  965. contentDisposition->SetData(aContentDisposition);
  966. mProperties->Set("content-disposition", contentDisposition);
  967. }
  968. }
  969. }
  970. static nsresult
  971. sniff_mimetype_callback(nsIInputStream* in,
  972. void* data,
  973. const char* fromRawSegment,
  974. uint32_t toOffset,
  975. uint32_t count,
  976. uint32_t* writeCount)
  977. {
  978. mimetype_closure* closure = static_cast<mimetype_closure*>(data);
  979. NS_ASSERTION(closure, "closure is null!");
  980. if (count > 0) {
  981. imgLoader::GetMimeTypeFromContent(fromRawSegment, count, *closure->newType);
  982. }
  983. *writeCount = 0;
  984. return NS_ERROR_FAILURE;
  985. }
  986. /** nsIInterfaceRequestor methods **/
  987. NS_IMETHODIMP
  988. imgRequest::GetInterface(const nsIID & aIID, void** aResult)
  989. {
  990. if (!mPrevChannelSink || aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
  991. return QueryInterface(aIID, aResult);
  992. }
  993. NS_ASSERTION(mPrevChannelSink != this,
  994. "Infinite recursion - don't keep track of channel sinks that are us!");
  995. return mPrevChannelSink->GetInterface(aIID, aResult);
  996. }
  997. /** nsIChannelEventSink methods **/
  998. NS_IMETHODIMP
  999. imgRequest::AsyncOnChannelRedirect(nsIChannel* oldChannel,
  1000. nsIChannel* newChannel, uint32_t flags,
  1001. nsIAsyncVerifyRedirectCallback* callback)
  1002. {
  1003. NS_ASSERTION(mRequest && mChannel,
  1004. "Got a channel redirect after we nulled out mRequest!");
  1005. NS_ASSERTION(mChannel == oldChannel,
  1006. "Got a channel redirect for an unknown channel!");
  1007. NS_ASSERTION(newChannel, "Got a redirect to a NULL channel!");
  1008. SetCacheValidation(mCacheEntry, oldChannel);
  1009. // Prepare for callback
  1010. mRedirectCallback = callback;
  1011. mNewRedirectChannel = newChannel;
  1012. nsCOMPtr<nsIChannelEventSink> sink(do_GetInterface(mPrevChannelSink));
  1013. if (sink) {
  1014. nsresult rv = sink->AsyncOnChannelRedirect(oldChannel, newChannel, flags,
  1015. this);
  1016. if (NS_FAILED(rv)) {
  1017. mRedirectCallback = nullptr;
  1018. mNewRedirectChannel = nullptr;
  1019. }
  1020. return rv;
  1021. }
  1022. (void) OnRedirectVerifyCallback(NS_OK);
  1023. return NS_OK;
  1024. }
  1025. NS_IMETHODIMP
  1026. imgRequest::OnRedirectVerifyCallback(nsresult result)
  1027. {
  1028. NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback");
  1029. NS_ASSERTION(mNewRedirectChannel, "mNewRedirectChannel not set in callback");
  1030. if (NS_FAILED(result)) {
  1031. mRedirectCallback->OnRedirectVerifyCallback(result);
  1032. mRedirectCallback = nullptr;
  1033. mNewRedirectChannel = nullptr;
  1034. return NS_OK;
  1035. }
  1036. mChannel = mNewRedirectChannel;
  1037. mTimedChannel = do_QueryInterface(mChannel);
  1038. mNewRedirectChannel = nullptr;
  1039. if (LOG_TEST(LogLevel::Debug)) {
  1040. LOG_MSG_WITH_PARAM(gImgLog,
  1041. "imgRequest::OnChannelRedirect", "old",
  1042. mCurrentURI ? mCurrentURI->GetSpecOrDefault().get()
  1043. : "");
  1044. }
  1045. // If the previous URI is a non-HTTPS URI, record that fact for later use by
  1046. // security code, which needs to know whether there is an insecure load at any
  1047. // point in the redirect chain.
  1048. bool isHttps = false;
  1049. bool isChrome = false;
  1050. bool schemeLocal = false;
  1051. if (NS_FAILED(mCurrentURI->SchemeIs("https", &isHttps)) ||
  1052. NS_FAILED(mCurrentURI->SchemeIs("chrome", &isChrome)) ||
  1053. NS_FAILED(NS_URIChainHasFlags(mCurrentURI,
  1054. nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
  1055. &schemeLocal)) ||
  1056. (!isHttps && !isChrome && !schemeLocal)) {
  1057. MutexAutoLock lock(mMutex);
  1058. // The csp directive upgrade-insecure-requests performs an internal redirect
  1059. // to upgrade all requests from http to https before any data is fetched from
  1060. // the network. Do not pollute mHadInsecureRedirect in case of such an internal
  1061. // redirect.
  1062. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  1063. bool upgradeInsecureRequests = loadInfo ? loadInfo->GetUpgradeInsecureRequests()
  1064. : false;
  1065. if (!upgradeInsecureRequests) {
  1066. mHadInsecureRedirect = true;
  1067. }
  1068. }
  1069. // Update the current URI.
  1070. mChannel->GetURI(getter_AddRefs(mCurrentURI));
  1071. if (LOG_TEST(LogLevel::Debug)) {
  1072. LOG_MSG_WITH_PARAM(gImgLog, "imgRequest::OnChannelRedirect", "new",
  1073. mCurrentURI ? mCurrentURI->GetSpecOrDefault().get()
  1074. : "");
  1075. }
  1076. // Make sure we have a protocol that returns data rather than opens an
  1077. // external application, e.g. 'mailto:'.
  1078. bool doesNotReturnData = false;
  1079. nsresult rv =
  1080. NS_URIChainHasFlags(mCurrentURI,
  1081. nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
  1082. &doesNotReturnData);
  1083. if (NS_SUCCEEDED(rv) && doesNotReturnData) {
  1084. rv = NS_ERROR_ABORT;
  1085. }
  1086. if (NS_FAILED(rv)) {
  1087. mRedirectCallback->OnRedirectVerifyCallback(rv);
  1088. mRedirectCallback = nullptr;
  1089. return NS_OK;
  1090. }
  1091. mRedirectCallback->OnRedirectVerifyCallback(NS_OK);
  1092. mRedirectCallback = nullptr;
  1093. return NS_OK;
  1094. }