image/src/imgLoader.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     7 #ifndef imgLoader_h__
     8 #define imgLoader_h__
    10 #include "mozilla/Attributes.h"
    12 #include "imgILoader.h"
    13 #include "imgICache.h"
    14 #include "nsWeakReference.h"
    15 #include "nsIContentSniffer.h"
    16 #include "nsRefPtrHashtable.h"
    17 #include "nsExpirationTracker.h"
    18 #include "nsAutoPtr.h"
    19 #include "imgRequest.h"
    20 #include "nsIProgressEventSink.h"
    21 #include "nsIChannel.h"
    22 #include "mozIThirdPartyUtil.h"
    23 #include "nsIThreadRetargetableStreamListener.h"
    24 #include "imgIRequest.h"
    26 class imgLoader;
    27 class imgRequestProxy;
    28 class imgINotificationObserver;
    29 class nsILoadGroup;
    30 class imgCacheExpirationTracker;
    31 class imgMemoryReporter;
    32 class nsIChannelPolicy;
    34 namespace mozilla {
    35 namespace image {
    36 class ImageURL;
    37 }
    38 }
    40 class imgCacheEntry
    41 {
    42 public:
    43   imgCacheEntry(imgLoader* loader, imgRequest *request, bool aForcePrincipalCheck);
    44   ~imgCacheEntry();
    46   nsrefcnt AddRef()
    47   {
    48     NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
    49     NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry addref isn't thread-safe!");
    50     ++mRefCnt;
    51     NS_LOG_ADDREF(this, mRefCnt, "imgCacheEntry", sizeof(*this));
    52     return mRefCnt;
    53   }
    55   nsrefcnt Release()
    56   {
    57     NS_PRECONDITION(0 != mRefCnt, "dup release");
    58     NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry release isn't thread-safe!");
    59     --mRefCnt;
    60     NS_LOG_RELEASE(this, mRefCnt, "imgCacheEntry");
    61     if (mRefCnt == 0) {
    62       mRefCnt = 1; /* stabilize */
    63       delete this;
    64       return 0;
    65     }
    66     return mRefCnt;
    67   }
    69   uint32_t GetDataSize() const
    70   {
    71     return mDataSize;
    72   }
    73   void SetDataSize(uint32_t aDataSize)
    74   {
    75     int32_t oldsize = mDataSize;
    76     mDataSize = aDataSize;
    77     UpdateCache(mDataSize - oldsize);
    78   }
    80   int32_t GetTouchedTime() const
    81   {
    82     return mTouchedTime;
    83   }
    84   void SetTouchedTime(int32_t time)
    85   {
    86     mTouchedTime = time;
    87     Touch(/* updateTime = */ false);
    88   }
    90   int32_t GetExpiryTime() const
    91   {
    92     return mExpiryTime;
    93   }
    94   void SetExpiryTime(int32_t aExpiryTime)
    95   {
    96     mExpiryTime = aExpiryTime;
    97     Touch();
    98   }
   100   bool GetMustValidate() const
   101   {
   102     return mMustValidate;
   103   }
   104   void SetMustValidate(bool aValidate)
   105   {
   106     mMustValidate = aValidate;
   107     Touch();
   108   }
   110   already_AddRefed<imgRequest> GetRequest() const
   111   {
   112     nsRefPtr<imgRequest> req = mRequest;
   113     return req.forget();
   114   }
   116   bool Evicted() const
   117   {
   118     return mEvicted;
   119   }
   121   nsExpirationState *GetExpirationState()
   122   {
   123     return &mExpirationState;
   124   }
   126   bool HasNoProxies() const
   127   {
   128     return mHasNoProxies;
   129   }
   131   bool ForcePrincipalCheck() const
   132   {
   133     return mForcePrincipalCheck;
   134   }
   136   imgLoader* Loader() const
   137   {
   138     return mLoader;
   139   }
   141 private: // methods
   142   friend class imgLoader;
   143   friend class imgCacheQueue;
   144   void Touch(bool updateTime = true);
   145   void UpdateCache(int32_t diff = 0);
   146   void SetEvicted(bool evict)
   147   {
   148     mEvicted = evict;
   149   }
   150   void SetHasNoProxies(bool hasNoProxies);
   152   // Private, unimplemented copy constructor.
   153   imgCacheEntry(const imgCacheEntry &);
   155 private: // data
   156   nsAutoRefCnt mRefCnt;
   157   NS_DECL_OWNINGTHREAD
   159   imgLoader* mLoader;
   160   nsRefPtr<imgRequest> mRequest;
   161   uint32_t mDataSize;
   162   int32_t mTouchedTime;
   163   int32_t mExpiryTime;
   164   nsExpirationState mExpirationState;
   165   bool mMustValidate : 1;
   166   bool mEvicted : 1;
   167   bool mHasNoProxies : 1;
   168   bool mForcePrincipalCheck : 1;
   169 };
   171 #include <vector>
   173 #define NS_IMGLOADER_CID \
   174 { /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */         \
   175      0x9f6a0d2e,                                     \
   176      0x1dd1,                                         \
   177      0x11b2,                                         \
   178     {0xa5, 0xb8, 0x95, 0x1f, 0x13, 0xc8, 0x46, 0xf7} \
   179 }
   181 class imgCacheQueue
   182 {
   183 public:
   184   imgCacheQueue();
   185   void Remove(imgCacheEntry *);
   186   void Push(imgCacheEntry *);
   187   void MarkDirty();
   188   bool IsDirty();
   189   already_AddRefed<imgCacheEntry> Pop();
   190   void Refresh();
   191   uint32_t GetSize() const;
   192   void UpdateSize(int32_t diff);
   193   uint32_t GetNumElements() const;
   194   typedef std::vector<nsRefPtr<imgCacheEntry> > queueContainer;
   195   typedef queueContainer::iterator iterator;
   196   typedef queueContainer::const_iterator const_iterator;
   198   iterator begin();
   199   const_iterator begin() const;
   200   iterator end();
   201   const_iterator end() const;
   203 private:
   204   queueContainer mQueue;
   205   bool mDirty;
   206   uint32_t mSize;
   207 };
   209 class imgLoader : public imgILoader,
   210                   public nsIContentSniffer,
   211                   public imgICache,
   212                   public nsSupportsWeakReference,
   213                   public nsIObserver
   214 {
   215 public:
   216   typedef mozilla::image::ImageURL ImageURL;
   217   typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
   219   NS_DECL_ISUPPORTS
   220   NS_DECL_IMGILOADER
   221   NS_DECL_NSICONTENTSNIFFER
   222   NS_DECL_IMGICACHE
   223   NS_DECL_NSIOBSERVER
   225   static imgLoader* Singleton();
   226   static imgLoader* PBSingleton();
   228   imgLoader();
   229   virtual ~imgLoader();
   231   nsresult Init();
   233   static imgLoader* Create()
   234   {
   235       // Unfortunately, we rely on XPCOM module init happening
   236       // before imgLoader creation. For now, it's easier
   237       // to just call CallCreateInstance() which will init
   238       // the image module instead of calling new imgLoader
   239       // directly.
   240       imgILoader *loader;
   241       CallCreateInstance("@mozilla.org/image/loader;1", &loader);
   242       // There's only one imgLoader implementation so we
   243       // can safely cast to it.
   244       return static_cast<imgLoader*>(loader);
   245   }
   247   static already_AddRefed<imgLoader> GetInstance();
   249   nsresult LoadImage(nsIURI *aURI,
   250                      nsIURI *aInitialDocumentURI,
   251                      nsIURI *aReferrerURI,
   252                      nsIPrincipal* aLoadingPrincipal,
   253                      nsILoadGroup *aLoadGroup,
   254                      imgINotificationObserver *aObserver,
   255                      nsISupports *aCX,
   256                      nsLoadFlags aLoadFlags,
   257                      nsISupports *aCacheKey,
   258                      nsIChannelPolicy *aPolicy,
   259                      const nsAString& initiatorType,
   260                      imgRequestProxy **_retval);
   261   nsresult LoadImageWithChannel(nsIChannel *channel,
   262                                 imgINotificationObserver *aObserver,
   263                                 nsISupports *aCX,
   264                                 nsIStreamListener **listener,
   265                                 imgRequestProxy **_retval);
   267   static nsresult GetMimeTypeFromContent(const char* aContents, uint32_t aLength, nsACString& aContentType);
   268   // exported for use by mimei.cpp in libxul sdk builds
   269   static NS_EXPORT_(bool) SupportImageWithMimeType(const char* aMimeType);
   271   static void GlobalInit(); // for use by the factory
   272   static void Shutdown(); // for use by the factory
   274   nsresult ClearChromeImageCache();
   275   nsresult ClearImageCache();
   276   void MinimizeCaches();
   278   nsresult InitCache();
   280   nsAutoCString GetCacheKey(nsIURI *firstPartyIsolationURI,
   281                             nsIURI* uri,
   282                             bool *isIsolated);
   283   nsAutoCString GetCacheKey(nsIURI *firstPartyIsolationURI,
   284                             ImageURL *imgURI,
   285                             bool *isIsolated);
   286   bool RemoveFromCache(ImageURL *aKey);
   287   bool RemoveFromCache(nsAutoCString key,
   288                        imgCacheTable &cache,
   289                        imgCacheQueue &queue);
   290   bool RemoveFromCache(imgCacheEntry *entry);
   292   bool PutIntoCache(nsAutoCString key, imgCacheEntry *entry);
   295   // Returns true if we should prefer evicting cache entry |two| over cache
   296   // entry |one|.
   297   // This mixes units in the worst way, but provides reasonable results.
   298   inline static bool CompareCacheEntries(const nsRefPtr<imgCacheEntry> &one,
   299                                          const nsRefPtr<imgCacheEntry> &two)
   300   {
   301     if (!one)
   302       return false;
   303     if (!two)
   304       return true;
   306     const double sizeweight = 1.0 - sCacheTimeWeight;
   308     // We want large, old images to be evicted first (depending on their
   309     // relative weights). Since a larger time is actually newer, we subtract
   310     // time's weight, so an older image has a larger weight.
   311     double oneweight = double(one->GetDataSize()) * sizeweight -
   312                        double(one->GetTouchedTime()) * sCacheTimeWeight;
   313     double twoweight = double(two->GetDataSize()) * sizeweight -
   314                        double(two->GetTouchedTime()) * sCacheTimeWeight;
   316     return oneweight < twoweight;
   317   }
   319   void VerifyCacheSizes();
   321   // The image loader maintains a hash table of all imgCacheEntries. However,
   322   // only some of them will be evicted from the cache: those who have no
   323   // imgRequestProxies watching their imgRequests.
   324   //
   325   // Once an imgRequest has no imgRequestProxies, it should notify us by
   326   // calling HasNoObservers(), and null out its cache entry pointer.
   327   //
   328   // Upon having a proxy start observing again, it should notify us by calling
   329   // HasObservers(). The request's cache entry will be re-set before this
   330   // happens, by calling imgRequest::SetCacheEntry() when an entry with no
   331   // observers is re-requested.
   332   bool SetHasNoProxies(ImageURL *imgURI, imgCacheEntry *entry);
   333   bool SetHasProxies(nsIURI *firstPartyIsolationURI, ImageURL *imgURI);
   335 private: // methods
   337   bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aURI,
   338                        nsIURI *aFirstPartyIsolationURI, nsIURI *aReferrerURI,
   339                        nsILoadGroup *aLoadGroup,
   340                        imgINotificationObserver *aObserver, nsISupports *aCX,
   341                        nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
   342                        imgRequestProxy **aProxyRequest,
   343                        nsIChannelPolicy *aPolicy,
   344                        nsIPrincipal* aLoadingPrincipal,
   345                        int32_t aCORSMode);
   347   bool ValidateRequestWithNewChannel(imgRequest *request, nsIURI *aURI,
   348                                        nsIURI *aInitialDocumentURI,
   349                                        nsIURI *aReferrerURI,
   350                                        nsILoadGroup *aLoadGroup,
   351                                        imgINotificationObserver *aObserver,
   352                                        nsISupports *aCX, nsLoadFlags aLoadFlags,
   353                                        imgRequestProxy **aProxyRequest,
   354                                        nsIChannelPolicy *aPolicy,
   355                                        nsIPrincipal* aLoadingPrincipal,
   356                                        int32_t aCORSMode);
   358   nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
   359                                     imgINotificationObserver *aObserver,
   360                                     nsLoadFlags aLoadFlags, imgRequestProxy **_retval);
   362   void ReadAcceptHeaderPref();
   364   nsresult EvictEntries(imgCacheTable &aCacheToClear);
   365   nsresult EvictEntries(imgCacheQueue &aQueueToClear);
   367   imgCacheTable &GetCache(nsIURI *aURI);
   368   imgCacheQueue &GetCacheQueue(nsIURI *aURI);
   369   imgCacheTable &GetCache(ImageURL *aURI);
   370   imgCacheQueue &GetCacheQueue(ImageURL *aURI);
   371   void CacheEntriesChanged(ImageURL *aURI, int32_t sizediff = 0);
   372   void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
   373   bool RemoveMatchingUrlsFromCache(nsIURI *aImgURI);
   375 private: // data
   376   friend class imgCacheEntry;
   377   friend class imgMemoryReporter;
   378   friend class imgRequest;
   380   imgCacheTable mCache;
   381   imgCacheQueue mCacheQueue;
   383   imgCacheTable mChromeCache;
   384   imgCacheQueue mChromeCacheQueue;
   386   static double sCacheTimeWeight;
   387   static uint32_t sCacheMaxSize;
   388   static imgMemoryReporter* sMemReporter;
   390   static nsCOMPtr<mozIThirdPartyUtil> sThirdPartyUtilSvc;
   391   nsCString mAcceptHeader;
   393   nsAutoPtr<imgCacheExpirationTracker> mCacheTracker;
   394   bool mRespectPrivacy;
   395 };
   399 /**
   400  * proxy stream listener class used to handle multipart/x-mixed-replace
   401  */
   403 #include "nsCOMPtr.h"
   404 #include "nsIStreamListener.h"
   405 #include "nsIThreadRetargetableStreamListener.h"
   407 class ProxyListener : public nsIStreamListener
   408                     , public nsIThreadRetargetableStreamListener
   409 {
   410 public:
   411   ProxyListener(nsIStreamListener *dest);
   412   virtual ~ProxyListener();
   414   /* additional members */
   415   NS_DECL_ISUPPORTS
   416   NS_DECL_NSISTREAMLISTENER
   417   NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
   418   NS_DECL_NSIREQUESTOBSERVER
   420 private:
   421   nsCOMPtr<nsIStreamListener> mDestListener;
   422 };
   424 /**
   425  * A class that implements nsIProgressEventSink and forwards all calls to it to
   426  * the original notification callbacks of the channel. Also implements
   427  * nsIInterfaceRequestor and gives out itself for nsIProgressEventSink calls,
   428  * and forwards everything else to the channel's notification callbacks.
   429  */
   430 class nsProgressNotificationProxy MOZ_FINAL
   431   : public nsIProgressEventSink
   432   , public nsIChannelEventSink
   433   , public nsIInterfaceRequestor
   434 {
   435   public:
   436     nsProgressNotificationProxy(nsIChannel* channel,
   437                                 imgIRequest* proxy)
   438         : mImageRequest(proxy) {
   439       channel->GetNotificationCallbacks(getter_AddRefs(mOriginalCallbacks));
   440     }
   442     NS_DECL_ISUPPORTS
   443     NS_DECL_NSIPROGRESSEVENTSINK
   444     NS_DECL_NSICHANNELEVENTSINK
   445     NS_DECL_NSIINTERFACEREQUESTOR
   446   private:
   447     ~nsProgressNotificationProxy() {}
   449     nsCOMPtr<nsIInterfaceRequestor> mOriginalCallbacks;
   450     nsCOMPtr<nsIRequest> mImageRequest;
   451 };
   453 /**
   454  * validate checker
   455  */
   457 #include "nsCOMArray.h"
   459 class imgCacheValidator : public nsIStreamListener,
   460                           public nsIThreadRetargetableStreamListener,
   461                           public nsIChannelEventSink,
   462                           public nsIInterfaceRequestor,
   463                           public nsIAsyncVerifyRedirectCallback
   464 {
   465 public:
   466   imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader,
   467                     imgRequest *request, void *aContext, bool forcePrincipalCheckForCacheEntry);
   468   virtual ~imgCacheValidator();
   470   void AddProxy(imgRequestProxy *aProxy);
   472   NS_DECL_ISUPPORTS
   473   NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
   474   NS_DECL_NSISTREAMLISTENER
   475   NS_DECL_NSIREQUESTOBSERVER
   476   NS_DECL_NSICHANNELEVENTSINK
   477   NS_DECL_NSIINTERFACEREQUESTOR
   478   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
   480 private:
   481   nsCOMPtr<nsIStreamListener> mDestListener;
   482   nsRefPtr<nsProgressNotificationProxy> mProgressProxy;
   483   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   484   nsCOMPtr<nsIChannel> mRedirectChannel;
   486   nsRefPtr<imgRequest> mRequest;
   487   nsCOMArray<imgIRequest> mProxies;
   489   nsRefPtr<imgRequest> mNewRequest;
   490   nsRefPtr<imgCacheEntry> mNewEntry;
   492   void *mContext;
   494   imgLoader* mImgLoader;
   495 };
   497 #endif  // imgLoader_h__

mercurial