1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2001
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Stuart Parmenter <pavlov@netscape.com>
25 : * Ehsan Akhgari <ehsan.akhgari@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef imgLoader_h__
42 : #define imgLoader_h__
43 :
44 : #include "mozilla/Attributes.h"
45 :
46 : #include "imgILoader.h"
47 : #include "imgICache.h"
48 : #include "nsWeakReference.h"
49 : #include "nsIContentSniffer.h"
50 : #include "nsRefPtrHashtable.h"
51 : #include "nsExpirationTracker.h"
52 : #include "nsAutoPtr.h"
53 : #include "prtypes.h"
54 : #include "imgRequest.h"
55 : #include "nsIObserverService.h"
56 : #include "nsIChannelPolicy.h"
57 : #include "nsIProgressEventSink.h"
58 : #include "nsIChannel.h"
59 :
60 : #ifdef LOADER_THREADSAFE
61 : #include "prlock.h"
62 : #endif
63 :
64 : class imgRequest;
65 : class imgRequestProxy;
66 : class imgIRequest;
67 : class imgIDecoderObserver;
68 : class nsILoadGroup;
69 :
70 : class imgCacheEntry
71 : {
72 : public:
73 : imgCacheEntry(imgRequest *request, bool aForcePrincipalCheck);
74 : ~imgCacheEntry();
75 :
76 63 : nsrefcnt AddRef()
77 : {
78 63 : NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
79 63 : NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry addref isn't thread-safe!");
80 63 : ++mRefCnt;
81 63 : NS_LOG_ADDREF(this, mRefCnt, "imgCacheEntry", sizeof(*this));
82 63 : return mRefCnt;
83 : }
84 :
85 63 : nsrefcnt Release()
86 : {
87 63 : NS_PRECONDITION(0 != mRefCnt, "dup release");
88 63 : NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry release isn't thread-safe!");
89 63 : --mRefCnt;
90 63 : NS_LOG_RELEASE(this, mRefCnt, "imgCacheEntry");
91 63 : if (mRefCnt == 0) {
92 8 : mRefCnt = 1; /* stabilize */
93 8 : delete this;
94 8 : return 0;
95 : }
96 55 : return mRefCnt;
97 : }
98 :
99 20 : PRUint32 GetDataSize() const
100 : {
101 20 : return mDataSize;
102 : }
103 8 : void SetDataSize(PRUint32 aDataSize)
104 : {
105 8 : PRInt32 oldsize = mDataSize;
106 8 : mDataSize = aDataSize;
107 8 : UpdateCache(mDataSize - oldsize);
108 8 : }
109 :
110 0 : PRInt32 GetTouchedTime() const
111 : {
112 0 : return mTouchedTime;
113 : }
114 : void SetTouchedTime(PRInt32 time)
115 : {
116 : mTouchedTime = time;
117 : Touch(/* updateTime = */ false);
118 : }
119 :
120 11 : PRInt32 GetExpiryTime() const
121 : {
122 11 : return mExpiryTime;
123 : }
124 4 : void SetExpiryTime(PRInt32 aExpiryTime)
125 : {
126 4 : mExpiryTime = aExpiryTime;
127 4 : Touch();
128 4 : }
129 :
130 0 : bool GetMustValidate() const
131 : {
132 0 : return mMustValidate;
133 : }
134 0 : void SetMustValidate(bool aValidate)
135 : {
136 0 : mMustValidate = aValidate;
137 0 : Touch();
138 0 : }
139 :
140 30 : already_AddRefed<imgRequest> GetRequest() const
141 : {
142 30 : imgRequest *req = mRequest;
143 30 : NS_ADDREF(req);
144 30 : return req;
145 : }
146 :
147 29 : bool Evicted() const
148 : {
149 29 : return mEvicted;
150 : }
151 :
152 30 : nsExpirationState *GetExpirationState()
153 : {
154 30 : return &mExpirationState;
155 : }
156 :
157 48 : bool HasNoProxies() const
158 : {
159 48 : return mHasNoProxies;
160 : }
161 :
162 7 : bool ForcePrincipalCheck() const
163 : {
164 7 : return mForcePrincipalCheck;
165 : }
166 :
167 : private: // methods
168 : friend class imgLoader;
169 : friend class imgCacheQueue;
170 : void Touch(bool updateTime = true);
171 : void UpdateCache(PRInt32 diff = 0);
172 16 : void SetEvicted(bool evict)
173 : {
174 16 : mEvicted = evict;
175 16 : }
176 : void SetHasNoProxies(bool hasNoProxies);
177 :
178 : // Private, unimplemented copy constructor.
179 : imgCacheEntry(const imgCacheEntry &);
180 :
181 : private: // data
182 : nsAutoRefCnt mRefCnt;
183 : NS_DECL_OWNINGTHREAD
184 :
185 : nsRefPtr<imgRequest> mRequest;
186 : PRUint32 mDataSize;
187 : PRInt32 mTouchedTime;
188 : PRInt32 mExpiryTime;
189 : nsExpirationState mExpirationState;
190 : bool mMustValidate : 1;
191 : bool mEvicted : 1;
192 : bool mHasNoProxies : 1;
193 : bool mForcePrincipalCheck : 1;
194 : };
195 :
196 : #include <vector>
197 :
198 : #define NS_IMGLOADER_CID \
199 : { /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \
200 : 0x9f6a0d2e, \
201 : 0x1dd1, \
202 : 0x11b2, \
203 : {0xa5, 0xb8, 0x95, 0x1f, 0x13, 0xc8, 0x46, 0xf7} \
204 : }
205 :
206 : class imgCacheQueue
207 2974 : {
208 : public:
209 : imgCacheQueue();
210 : void Remove(imgCacheEntry *);
211 : void Push(imgCacheEntry *);
212 : void MarkDirty();
213 : bool IsDirty();
214 : already_AddRefed<imgCacheEntry> Pop();
215 : void Refresh();
216 : PRUint32 GetSize() const;
217 : void UpdateSize(PRInt32 diff);
218 : PRUint32 GetNumElements() const;
219 : typedef std::vector<nsRefPtr<imgCacheEntry> > queueContainer;
220 : typedef queueContainer::iterator iterator;
221 : typedef queueContainer::const_iterator const_iterator;
222 :
223 : iterator begin();
224 : const_iterator begin() const;
225 : iterator end();
226 : const_iterator end() const;
227 :
228 : private:
229 : queueContainer mQueue;
230 : bool mDirty;
231 : PRUint32 mSize;
232 : };
233 :
234 : class imgMemoryReporter;
235 :
236 : class imgLoader : public imgILoader,
237 : public nsIContentSniffer,
238 : public imgICache,
239 : public nsSupportsWeakReference,
240 : public nsIObserver
241 : {
242 : public:
243 : NS_DECL_ISUPPORTS
244 : NS_DECL_IMGILOADER
245 : NS_DECL_NSICONTENTSNIFFER
246 : NS_DECL_IMGICACHE
247 : NS_DECL_NSIOBSERVER
248 :
249 : imgLoader();
250 : virtual ~imgLoader();
251 :
252 : nsresult Init();
253 :
254 : static nsresult GetMimeTypeFromContent(const char* aContents, PRUint32 aLength, nsACString& aContentType);
255 :
256 : static void Shutdown(); // for use by the factory
257 :
258 : static nsresult ClearChromeImageCache();
259 : static nsresult ClearImageCache();
260 : static void MinimizeCaches();
261 :
262 : static nsresult InitCache();
263 :
264 : static bool RemoveFromCache(nsIURI *aKey);
265 : static bool RemoveFromCache(imgCacheEntry *entry);
266 :
267 : static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
268 :
269 : // Returns true if we should prefer evicting cache entry |two| over cache
270 : // entry |one|.
271 : // This mixes units in the worst way, but provides reasonable results.
272 0 : inline static bool CompareCacheEntries(const nsRefPtr<imgCacheEntry> &one,
273 : const nsRefPtr<imgCacheEntry> &two)
274 : {
275 0 : if (!one)
276 0 : return false;
277 0 : if (!two)
278 0 : return true;
279 :
280 0 : const double sizeweight = 1.0 - sCacheTimeWeight;
281 :
282 : // We want large, old images to be evicted first (depending on their
283 : // relative weights). Since a larger time is actually newer, we subtract
284 : // time's weight, so an older image has a larger weight.
285 0 : double oneweight = double(one->GetDataSize()) * sizeweight -
286 0 : double(one->GetTouchedTime()) * sCacheTimeWeight;
287 0 : double twoweight = double(two->GetDataSize()) * sizeweight -
288 0 : double(two->GetTouchedTime()) * sCacheTimeWeight;
289 :
290 0 : return oneweight < twoweight;
291 : }
292 :
293 : static void VerifyCacheSizes();
294 :
295 : // The image loader maintains a hash table of all imgCacheEntries. However,
296 : // only some of them will be evicted from the cache: those who have no
297 : // imgRequestProxies watching their imgRequests.
298 : //
299 : // Once an imgRequest has no imgRequestProxies, it should notify us by
300 : // calling HasNoObservers(), and null out its cache entry pointer.
301 : //
302 : // Upon having a proxy start observing again, it should notify us by calling
303 : // HasObservers(). The request's cache entry will be re-set before this
304 : // happens, by calling imgRequest::SetCacheEntry() when an entry with no
305 : // observers is re-requested.
306 : static bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
307 : static bool SetHasProxies(nsIURI *key);
308 :
309 : private: // methods
310 :
311 :
312 : bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aKey,
313 : nsIURI *aInitialDocumentURI, nsIURI *aReferrerURI,
314 : nsILoadGroup *aLoadGroup,
315 : imgIDecoderObserver *aObserver, nsISupports *aCX,
316 : nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
317 : imgIRequest *aExistingRequest,
318 : imgIRequest **aProxyRequest,
319 : nsIChannelPolicy *aPolicy,
320 : nsIPrincipal* aLoadingPrincipal,
321 : PRInt32 aCORSMode);
322 : bool ValidateRequestWithNewChannel(imgRequest *request, nsIURI *aURI,
323 : nsIURI *aInitialDocumentURI,
324 : nsIURI *aReferrerURI,
325 : nsILoadGroup *aLoadGroup,
326 : imgIDecoderObserver *aObserver,
327 : nsISupports *aCX, nsLoadFlags aLoadFlags,
328 : imgIRequest *aExistingRequest,
329 : imgIRequest **aProxyRequest,
330 : nsIChannelPolicy *aPolicy,
331 : nsIPrincipal* aLoadingPrincipal,
332 : PRInt32 aCORSMode);
333 :
334 : nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
335 : imgIDecoderObserver *aObserver,
336 : nsLoadFlags aLoadFlags, imgIRequest *aRequestProxy,
337 : imgIRequest **_retval);
338 :
339 : void ReadAcceptHeaderPref();
340 :
341 :
342 : typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
343 :
344 : static nsresult EvictEntries(imgCacheTable &aCacheToClear);
345 : static nsresult EvictEntries(imgCacheQueue &aQueueToClear);
346 :
347 : static imgCacheTable &GetCache(nsIURI *aURI);
348 : static imgCacheQueue &GetCacheQueue(nsIURI *aURI);
349 : static void CacheEntriesChanged(nsIURI *aURI, PRInt32 sizediff = 0);
350 : static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
351 :
352 : private: // data
353 : friend class imgCacheEntry;
354 : friend class imgMemoryReporter;
355 :
356 : static imgCacheTable sCache;
357 : static imgCacheQueue sCacheQueue;
358 :
359 : static imgCacheTable sChromeCache;
360 : static imgCacheQueue sChromeCacheQueue;
361 : static PRFloat64 sCacheTimeWeight;
362 : static PRUint32 sCacheMaxSize;
363 :
364 : nsCString mAcceptHeader;
365 : };
366 :
367 :
368 :
369 : /**
370 : * proxy stream listener class used to handle multipart/x-mixed-replace
371 : */
372 :
373 : #include "nsCOMPtr.h"
374 : #include "nsIStreamListener.h"
375 :
376 : class ProxyListener : public nsIStreamListener
377 : {
378 : public:
379 : ProxyListener(nsIStreamListener *dest);
380 : virtual ~ProxyListener();
381 :
382 : /* additional members */
383 : NS_DECL_ISUPPORTS
384 : NS_DECL_NSISTREAMLISTENER
385 : NS_DECL_NSIREQUESTOBSERVER
386 :
387 : private:
388 : nsCOMPtr<nsIStreamListener> mDestListener;
389 : };
390 :
391 : /**
392 : * A class that implements nsIProgressEventSink and forwards all calls to it to
393 : * the original notification callbacks of the channel. Also implements
394 : * nsIInterfaceRequestor and gives out itself for nsIProgressEventSink calls,
395 : * and forwards everything else to the channel's notification callbacks.
396 : */
397 : class nsProgressNotificationProxy MOZ_FINAL
398 : : public nsIProgressEventSink
399 : , public nsIChannelEventSink
400 : , public nsIInterfaceRequestor
401 : {
402 : public:
403 4 : nsProgressNotificationProxy(nsIChannel* channel,
404 : imgIRequest* proxy)
405 4 : : mImageRequest(proxy) {
406 4 : channel->GetNotificationCallbacks(getter_AddRefs(mOriginalCallbacks));
407 4 : }
408 :
409 : NS_DECL_ISUPPORTS
410 : NS_DECL_NSIPROGRESSEVENTSINK
411 : NS_DECL_NSICHANNELEVENTSINK
412 : NS_DECL_NSIINTERFACEREQUESTOR
413 : private:
414 4 : ~nsProgressNotificationProxy() {}
415 :
416 : nsCOMPtr<nsIInterfaceRequestor> mOriginalCallbacks;
417 : nsCOMPtr<nsIRequest> mImageRequest;
418 : };
419 :
420 : /**
421 : * validate checker
422 : */
423 :
424 : #include "nsCOMArray.h"
425 :
426 : class imgCacheValidator : public nsIStreamListener,
427 : public nsIChannelEventSink,
428 : public nsIInterfaceRequestor,
429 : public nsIAsyncVerifyRedirectCallback
430 : {
431 : public:
432 : imgCacheValidator(nsProgressNotificationProxy* progress, imgRequest *request,
433 : void *aContext, bool forcePrincipalCheckForCacheEntry);
434 : virtual ~imgCacheValidator();
435 :
436 : void AddProxy(imgRequestProxy *aProxy);
437 :
438 : NS_DECL_ISUPPORTS
439 : NS_DECL_NSISTREAMLISTENER
440 : NS_DECL_NSIREQUESTOBSERVER
441 : NS_DECL_NSICHANNELEVENTSINK
442 : NS_DECL_NSIINTERFACEREQUESTOR
443 : NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
444 :
445 : private:
446 : nsCOMPtr<nsIStreamListener> mDestListener;
447 : nsRefPtr<nsProgressNotificationProxy> mProgressProxy;
448 : nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
449 : nsCOMPtr<nsIChannel> mRedirectChannel;
450 :
451 : nsRefPtr<imgRequest> mRequest;
452 : nsCOMArray<imgIRequest> mProxies;
453 :
454 : nsRefPtr<imgRequest> mNewRequest;
455 : nsRefPtr<imgCacheEntry> mNewEntry;
456 :
457 : void *mContext;
458 :
459 : static imgLoader sImgLoader;
460 : };
461 :
462 : #endif // imgLoader_h__
|