image/src/imgLoader.h

branch
TOR_BUG_9701
changeset 10
ac0c01689b40
equal deleted inserted replaced
-1:000000000000 0:058d3ab89909
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
7 #ifndef imgLoader_h__
8 #define imgLoader_h__
9
10 #include "mozilla/Attributes.h"
11
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"
25
26 class imgLoader;
27 class imgRequestProxy;
28 class imgINotificationObserver;
29 class nsILoadGroup;
30 class imgCacheExpirationTracker;
31 class imgMemoryReporter;
32 class nsIChannelPolicy;
33
34 namespace mozilla {
35 namespace image {
36 class ImageURL;
37 }
38 }
39
40 class imgCacheEntry
41 {
42 public:
43 imgCacheEntry(imgLoader* loader, imgRequest *request, bool aForcePrincipalCheck);
44 ~imgCacheEntry();
45
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 }
54
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 }
68
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 }
79
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 }
89
90 int32_t GetExpiryTime() const
91 {
92 return mExpiryTime;
93 }
94 void SetExpiryTime(int32_t aExpiryTime)
95 {
96 mExpiryTime = aExpiryTime;
97 Touch();
98 }
99
100 bool GetMustValidate() const
101 {
102 return mMustValidate;
103 }
104 void SetMustValidate(bool aValidate)
105 {
106 mMustValidate = aValidate;
107 Touch();
108 }
109
110 already_AddRefed<imgRequest> GetRequest() const
111 {
112 nsRefPtr<imgRequest> req = mRequest;
113 return req.forget();
114 }
115
116 bool Evicted() const
117 {
118 return mEvicted;
119 }
120
121 nsExpirationState *GetExpirationState()
122 {
123 return &mExpirationState;
124 }
125
126 bool HasNoProxies() const
127 {
128 return mHasNoProxies;
129 }
130
131 bool ForcePrincipalCheck() const
132 {
133 return mForcePrincipalCheck;
134 }
135
136 imgLoader* Loader() const
137 {
138 return mLoader;
139 }
140
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);
151
152 // Private, unimplemented copy constructor.
153 imgCacheEntry(const imgCacheEntry &);
154
155 private: // data
156 nsAutoRefCnt mRefCnt;
157 NS_DECL_OWNINGTHREAD
158
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 };
170
171 #include <vector>
172
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 }
180
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;
197
198 iterator begin();
199 const_iterator begin() const;
200 iterator end();
201 const_iterator end() const;
202
203 private:
204 queueContainer mQueue;
205 bool mDirty;
206 uint32_t mSize;
207 };
208
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;
218
219 NS_DECL_ISUPPORTS
220 NS_DECL_IMGILOADER
221 NS_DECL_NSICONTENTSNIFFER
222 NS_DECL_IMGICACHE
223 NS_DECL_NSIOBSERVER
224
225 static imgLoader* Singleton();
226 static imgLoader* PBSingleton();
227
228 imgLoader();
229 virtual ~imgLoader();
230
231 nsresult Init();
232
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 }
246
247 static already_AddRefed<imgLoader> GetInstance();
248
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);
266
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);
270
271 static void GlobalInit(); // for use by the factory
272 static void Shutdown(); // for use by the factory
273
274 nsresult ClearChromeImageCache();
275 nsresult ClearImageCache();
276 void MinimizeCaches();
277
278 nsresult InitCache();
279
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);
291
292 bool PutIntoCache(nsAutoCString key, imgCacheEntry *entry);
293
294
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;
305
306 const double sizeweight = 1.0 - sCacheTimeWeight;
307
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;
315
316 return oneweight < twoweight;
317 }
318
319 void VerifyCacheSizes();
320
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);
334
335 private: // methods
336
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);
346
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);
357
358 nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
359 imgINotificationObserver *aObserver,
360 nsLoadFlags aLoadFlags, imgRequestProxy **_retval);
361
362 void ReadAcceptHeaderPref();
363
364 nsresult EvictEntries(imgCacheTable &aCacheToClear);
365 nsresult EvictEntries(imgCacheQueue &aQueueToClear);
366
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);
374
375 private: // data
376 friend class imgCacheEntry;
377 friend class imgMemoryReporter;
378 friend class imgRequest;
379
380 imgCacheTable mCache;
381 imgCacheQueue mCacheQueue;
382
383 imgCacheTable mChromeCache;
384 imgCacheQueue mChromeCacheQueue;
385
386 static double sCacheTimeWeight;
387 static uint32_t sCacheMaxSize;
388 static imgMemoryReporter* sMemReporter;
389
390 static nsCOMPtr<mozIThirdPartyUtil> sThirdPartyUtilSvc;
391 nsCString mAcceptHeader;
392
393 nsAutoPtr<imgCacheExpirationTracker> mCacheTracker;
394 bool mRespectPrivacy;
395 };
396
397
398
399 /**
400 * proxy stream listener class used to handle multipart/x-mixed-replace
401 */
402
403 #include "nsCOMPtr.h"
404 #include "nsIStreamListener.h"
405 #include "nsIThreadRetargetableStreamListener.h"
406
407 class ProxyListener : public nsIStreamListener
408 , public nsIThreadRetargetableStreamListener
409 {
410 public:
411 ProxyListener(nsIStreamListener *dest);
412 virtual ~ProxyListener();
413
414 /* additional members */
415 NS_DECL_ISUPPORTS
416 NS_DECL_NSISTREAMLISTENER
417 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
418 NS_DECL_NSIREQUESTOBSERVER
419
420 private:
421 nsCOMPtr<nsIStreamListener> mDestListener;
422 };
423
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 }
441
442 NS_DECL_ISUPPORTS
443 NS_DECL_NSIPROGRESSEVENTSINK
444 NS_DECL_NSICHANNELEVENTSINK
445 NS_DECL_NSIINTERFACEREQUESTOR
446 private:
447 ~nsProgressNotificationProxy() {}
448
449 nsCOMPtr<nsIInterfaceRequestor> mOriginalCallbacks;
450 nsCOMPtr<nsIRequest> mImageRequest;
451 };
452
453 /**
454 * validate checker
455 */
456
457 #include "nsCOMArray.h"
458
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();
469
470 void AddProxy(imgRequestProxy *aProxy);
471
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
479
480 private:
481 nsCOMPtr<nsIStreamListener> mDestListener;
482 nsRefPtr<nsProgressNotificationProxy> mProgressProxy;
483 nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
484 nsCOMPtr<nsIChannel> mRedirectChannel;
485
486 nsRefPtr<imgRequest> mRequest;
487 nsCOMArray<imgIRequest> mProxies;
488
489 nsRefPtr<imgRequest> mNewRequest;
490 nsRefPtr<imgCacheEntry> mNewEntry;
491
492 void *mContext;
493
494 imgLoader* mImgLoader;
495 };
496
497 #endif // imgLoader_h__

mercurial