michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef imgRequest_h__ michael@0: #define imgRequest_h__ michael@0: michael@0: #include "nsIChannelEventSink.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIStreamListener.h" michael@0: #include "nsIThreadRetargetableStreamListener.h" michael@0: #include "nsIPrincipal.h" michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "nsStringGlue.h" michael@0: #include "nsError.h" michael@0: #include "nsIAsyncVerifyRedirectCallback.h" michael@0: michael@0: class imgCacheValidator; michael@0: class imgStatusTracker; michael@0: class imgLoader; michael@0: class imgRequestProxy; michael@0: class imgCacheEntry; michael@0: class imgMemoryReporter; michael@0: class imgRequestNotifyRunnable; michael@0: class nsIApplicationCache; michael@0: class nsIProperties; michael@0: class nsIRequest; michael@0: class nsITimedChannel; michael@0: class nsIURI; michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: class Image; michael@0: class ImageURL; michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: class imgRequest : public nsIStreamListener, michael@0: public nsIThreadRetargetableStreamListener, michael@0: public nsIChannelEventSink, michael@0: public nsIInterfaceRequestor, michael@0: public nsIAsyncVerifyRedirectCallback michael@0: { michael@0: public: michael@0: typedef mozilla::image::ImageURL ImageURL; michael@0: imgRequest(imgLoader* aLoader); michael@0: virtual ~imgRequest(); michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: nsresult Init(nsIURI *aURI, michael@0: nsIURI *aCurrentURI, michael@0: nsIURI *aFirstPartyIsolationURI, michael@0: nsIRequest *aRequest, michael@0: nsIChannel *aChannel, michael@0: imgCacheEntry *aCacheEntry, michael@0: void *aLoadId, michael@0: nsIPrincipal* aLoadingPrincipal, michael@0: int32_t aCORSMode); michael@0: michael@0: // Callers must call imgRequestProxy::Notify later. michael@0: void AddProxy(imgRequestProxy *proxy); michael@0: michael@0: nsresult RemoveProxy(imgRequestProxy *proxy, nsresult aStatus); michael@0: michael@0: // Cancel, but also ensure that all work done in Init() is undone. Call this michael@0: // only when the channel has failed to open, and so calling Cancel() on it michael@0: // won't be sufficient. michael@0: void CancelAndAbort(nsresult aStatus); michael@0: michael@0: // Called or dispatched by cancel for main thread only execution. michael@0: void ContinueCancel(nsresult aStatus); michael@0: michael@0: // Methods that get forwarded to the Image, or deferred until it's michael@0: // instantiated. michael@0: nsresult LockImage(); michael@0: nsresult UnlockImage(); michael@0: nsresult StartDecoding(); michael@0: nsresult RequestDecode(); michael@0: michael@0: inline void SetInnerWindowID(uint64_t aInnerWindowId) { michael@0: mInnerWindowId = aInnerWindowId; michael@0: } michael@0: michael@0: inline uint64_t InnerWindowID() const { michael@0: return mInnerWindowId; michael@0: } michael@0: michael@0: // Set the cache validation information (expiry time, whether we must michael@0: // validate, etc) on the cache entry based on the request information. michael@0: // If this function is called multiple times, the information set earliest michael@0: // wins. michael@0: static void SetCacheValidation(imgCacheEntry* aEntry, nsIRequest* aRequest); michael@0: michael@0: // Check if application cache of the original load is different from michael@0: // application cache of the new load. Also lack of application cache michael@0: // on one of the loads is considered a change of a loading cache since michael@0: // HTTP cache may contain a different data then app cache. michael@0: bool CacheChanged(nsIRequest* aNewRequest); michael@0: michael@0: bool GetMultipart() const { return mIsMultiPartChannel; } michael@0: michael@0: // The CORS mode for which we loaded this image. michael@0: int32_t GetCORSMode() const { return mCORSMode; } michael@0: michael@0: // The principal for the document that loaded this image. Used when trying to michael@0: // validate a CORS image load. michael@0: already_AddRefed GetLoadingPrincipal() const michael@0: { michael@0: nsCOMPtr principal = mLoadingPrincipal; michael@0: return principal.forget(); michael@0: } michael@0: michael@0: // Return the imgStatusTracker associated with this imgRequest. It may live michael@0: // in |mStatusTracker| or in |mImage.mStatusTracker|, depending on whether michael@0: // mImage has been instantiated yet. michael@0: already_AddRefed GetStatusTracker(); michael@0: michael@0: // Get the current principal of the image. No AddRefing. michael@0: inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); } michael@0: michael@0: // Resize the cache entry to 0 if it exists michael@0: void ResetCacheEntry(); michael@0: michael@0: // Update the cache entry size based on the image container michael@0: void UpdateCacheEntrySize(); michael@0: michael@0: // OK to use on any thread. michael@0: nsresult GetURI(ImageURL **aURI); michael@0: michael@0: private: michael@0: friend class imgCacheEntry; michael@0: friend class imgRequestProxy; michael@0: friend class imgLoader; michael@0: friend class imgCacheValidator; michael@0: friend class imgStatusTracker; michael@0: friend class imgCacheExpirationTracker; michael@0: friend class imgRequestNotifyRunnable; michael@0: michael@0: inline void SetLoadId(void *aLoadId) { michael@0: mLoadId = aLoadId; michael@0: } michael@0: void Cancel(nsresult aStatus); michael@0: void RemoveFromCache(); michael@0: michael@0: nsresult GetSecurityInfo(nsISupports **aSecurityInfo); michael@0: michael@0: inline const char *GetMimeType() const { michael@0: return mContentType.get(); michael@0: } michael@0: inline nsIProperties *Properties() { michael@0: return mProperties; michael@0: } michael@0: michael@0: // Reset the cache entry after we've dropped our reference to it. Used by the michael@0: // imgLoader when our cache entry is re-requested after we've dropped our michael@0: // reference to it. michael@0: void SetCacheEntry(imgCacheEntry *entry); michael@0: michael@0: // Returns whether we've got a reference to the cache entry. michael@0: bool HasCacheEntry() const; michael@0: michael@0: // Return the priority of the underlying network request, or return michael@0: // PRIORITY_NORMAL if it doesn't support nsISupportsPriority. michael@0: int32_t Priority() const; michael@0: michael@0: // Adjust the priority of the underlying network request by the given delta michael@0: // on behalf of the given proxy. michael@0: void AdjustPriority(imgRequestProxy *aProxy, int32_t aDelta); michael@0: michael@0: // Return whether we've seen some data at this point michael@0: bool HasTransferredData() const { return mGotData; } michael@0: michael@0: // Set whether this request is stored in the cache. If it isn't, regardless michael@0: // of whether this request has a non-null mCacheEntry, this imgRequest won't michael@0: // try to update or modify the image cache. michael@0: void SetIsInCache(bool cacheable); michael@0: michael@0: bool IsBlockingOnload() const; michael@0: void SetBlockingOnload(bool block) const; michael@0: michael@0: public: michael@0: NS_DECL_NSISTREAMLISTENER michael@0: NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSICHANNELEVENTSINK michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK michael@0: michael@0: // Sets properties for this image; will dispatch to main thread if needed. michael@0: void SetProperties(nsIChannel* aChan); michael@0: michael@0: private: michael@0: friend class imgMemoryReporter; michael@0: michael@0: // Weak reference to parent loader; this request cannot outlive its owner. michael@0: imgLoader* mLoader; michael@0: nsCOMPtr mRequest; michael@0: // The original URI we were loaded with. This is the same as the URI we are michael@0: // keyed on in the cache. We store a string here to avoid off main thread michael@0: // refcounting issues with nsStandardURL. michael@0: nsRefPtr mURI; michael@0: // The URI of the resource we ended up loading after all redirects, etc. michael@0: nsCOMPtr mCurrentURI; michael@0: // The first party that triggered the load -- for cookie + cache isolation michael@0: nsCOMPtr mFirstPartyIsolationURI; michael@0: // The principal of the document which loaded this image. Used when validating for CORS. michael@0: nsCOMPtr mLoadingPrincipal; michael@0: // The principal of this image. michael@0: nsCOMPtr mPrincipal; michael@0: // Status-tracker -- transferred to mImage, when it gets instantiated michael@0: nsRefPtr mStatusTracker; michael@0: nsRefPtr mImage; michael@0: nsCOMPtr mProperties; michael@0: nsCOMPtr mSecurityInfo; michael@0: nsCOMPtr mChannel; michael@0: nsCOMPtr mPrevChannelSink; michael@0: nsCOMPtr mApplicationCache; michael@0: michael@0: nsCOMPtr mTimedChannel; michael@0: michael@0: nsCString mContentType; michael@0: michael@0: nsRefPtr mCacheEntry; /* we hold on to this to this so long as we have observers */ michael@0: michael@0: void *mLoadId; michael@0: michael@0: imgCacheValidator *mValidator; michael@0: nsCOMPtr mRedirectCallback; michael@0: nsCOMPtr mNewRedirectChannel; michael@0: michael@0: // The ID of the inner window origin, used for error reporting. michael@0: uint64_t mInnerWindowId; michael@0: michael@0: // The CORS mode (defined in imgIRequest) this image was loaded with. By michael@0: // default, imgIRequest::CORS_NONE. michael@0: int32_t mCORSMode; michael@0: michael@0: // Sometimes consumers want to do things before the image is ready. Let them, michael@0: // and apply the action when the image becomes available. michael@0: bool mDecodeRequested : 1; michael@0: michael@0: bool mIsMultiPartChannel : 1; michael@0: bool mGotData : 1; michael@0: bool mIsInCache : 1; michael@0: bool mBlockingOnload : 1; michael@0: bool mResniffMimeType : 1; michael@0: }; michael@0: michael@0: #endif