/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_image_imgRequest_h #define mozilla_image_imgRequest_h #include "nsIChannelEventSink.h" #include "nsIInterfaceRequestor.h" #include "nsIStreamListener.h" #include "nsIThreadRetargetableStreamListener.h" #include "nsIPrincipal.h" #include "nsCOMPtr.h" #include "nsProxyRelease.h" #include "nsString.h" #include "nsError.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "mozilla/Mutex.h" #include "ImageCacheKey.h" class imgCacheValidator; class imgLoader; class imgRequestProxy; class imgCacheEntry; class nsIProperties; class nsIRequest; class nsITimedChannel; class nsIURI; class nsIReferrerInfo; namespace mozilla { enum CORSMode : uint8_t; namespace image { class Image; class ProgressTracker; } // namespace image } // namespace mozilla struct NewPartResult; class imgRequest final : public nsIStreamListener, public nsIThreadRetargetableStreamListener, public nsIChannelEventSink, public nsIInterfaceRequestor, public nsIAsyncVerifyRedirectCallback { typedef mozilla::image::Image Image; typedef mozilla::image::ImageCacheKey ImageCacheKey; typedef mozilla::image::ProgressTracker ProgressTracker; typedef mozilla::dom::ReferrerPolicy ReferrerPolicy; public: imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISTREAMLISTENER NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK [[nodiscard]] nsresult Init(nsIURI* aURI, nsIURI* aFinalURI, bool aHadInsecureRedirect, nsIRequest* aRequest, nsIChannel* aChannel, imgCacheEntry* aCacheEntry, mozilla::dom::Document* aLoadingDocument, nsIPrincipal* aTriggeringPrincipal, mozilla::CORSMode aCORSMode, nsIReferrerInfo* aReferrerInfo); void ClearLoader(); // Callers must call imgRequestProxy::Notify later. void AddProxy(imgRequestProxy* proxy); // Whether a given document is allowed to reuse this request without any // revalidation. bool CanReuseWithoutValidation(mozilla::dom::Document*) const; nsresult RemoveProxy(imgRequestProxy* proxy, nsresult aStatus); // Cancel, but also ensure that all work done in Init() is undone. Call this // only when the channel has failed to open, and so calling Cancel() on it // won't be sufficient. void CancelAndAbort(nsresult aStatus); // Called or dispatched by cancel for main thread only execution. void ContinueCancel(nsresult aStatus); // Called or dispatched by EvictFromCache for main thread only execution. void ContinueEvict(); // Request that we start decoding the image as soon as data becomes available. void StartDecoding(); inline uint64_t InnerWindowID() const { return mInnerWindowId; } void SetInnerWindowID(uint64_t aInnerWindowId) { mInnerWindowId = aInnerWindowId; } // Set the cache validation information (expiry time, whether we must // validate, etc) on the cache entry based on the request information. // If this function is called multiple times, the information set earliest // wins. static void SetCacheValidation(imgCacheEntry* aEntry, nsIRequest* aRequest); bool GetMultipart() const; // Returns whether we went through an insecure (non-HTTPS) redirect at some // point during loading. This does not consider the final URI. bool HadInsecureRedirect() const; // The CORS mode for which we loaded this image. mozilla::CORSMode GetCORSMode() const { return mCORSMode; } // The ReferrerInfo in effect when loading this image. nsIReferrerInfo* GetReferrerInfo() const { return mReferrerInfo; } // The principal for the document that loaded this image. Used when trying to // validate a CORS image load. already_AddRefed GetTriggeringPrincipal() const { nsCOMPtr principal = mTriggeringPrincipal; return principal.forget(); } // Return the ProgressTracker associated with this imgRequest. It may live // in |mProgressTracker| or in |mImage.mProgressTracker|, depending on whether // mImage has been instantiated yet. already_AddRefed GetProgressTracker() const; /// Returns the Image associated with this imgRequest, if it's ready. already_AddRefed GetImage() const; // Get the current principal of the image. No AddRefing. inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); } /// Get the ImageCacheKey associated with this request. const ImageCacheKey& CacheKey() const { return mCacheKey; } // Resize the cache entry to 0 if it exists void ResetCacheEntry(); // OK to use on any thread. nsresult GetURI(nsIURI** aURI); nsresult GetFinalURI(nsIURI** aURI); bool IsChrome() const; bool IsData() const; nsresult GetImageErrorCode(void); /// Returns a non-owning pointer to this imgRequest's MIME type. const char* GetMimeType() const { return mContentType.get(); } /// @return the priority of the underlying network request, or /// PRIORITY_NORMAL if it doesn't support nsISupportsPriority. int32_t Priority() const; /// Adjust the priority of the underlying network request by @aDelta on behalf /// of @aProxy. void AdjustPriority(imgRequestProxy* aProxy, int32_t aDelta); void BoostPriority(uint32_t aCategory); /// Returns a weak pointer to the underlying request. nsIRequest* GetRequest() const { return mRequest; } nsITimedChannel* GetTimedChannel() const { return mTimedChannel; } imgCacheValidator* GetValidator() const { return mValidator; } void SetValidator(imgCacheValidator* aValidator) { mValidator = aValidator; } void* LoadId() const { return mLoadId; } void SetLoadId(void* aLoadId) { mLoadId = aLoadId; } /// Reset the cache entry after we've dropped our reference to it. Used by /// imgLoader when our cache entry is re-requested after we've dropped our /// reference to it. void SetCacheEntry(imgCacheEntry* aEntry); /// Returns whether we've got a reference to the cache entry. bool HasCacheEntry() const; /// Set whether this request is stored in the cache. If it isn't, regardless /// of whether this request has a non-null mCacheEntry, this imgRequest won't /// try to update or modify the image cache. void SetIsInCache(bool aCacheable); void EvictFromCache(); void RemoveFromCache(); // Sets properties for this image; will dispatch to main thread if needed. void SetProperties(const nsACString& aContentType, const nsACString& aContentDisposition); nsIProperties* Properties() const { return mProperties; } bool HasConsumers() const; bool ImageAvailable() const; bool IsDeniedCrossSiteCORSRequest() const { return mIsDeniedCrossSiteCORSRequest; } bool IsCrossSiteNoCORSRequest() const { return mIsCrossSiteNoCORSRequest; } private: friend class FinishPreparingForNewPartRunnable; virtual ~imgRequest(); void FinishPreparingForNewPart(const NewPartResult& aResult); void Cancel(nsresult aStatus); // Update the cache entry size based on the image container. void UpdateCacheEntrySize(); /// Returns true if StartDecoding() was called. bool IsDecodeRequested() const; void AdjustPriorityInternal(int32_t aDelta); // Weak reference to parent loader; this request cannot outlive its owner. imgLoader* mLoader; nsCOMPtr mRequest; // The original URI we were loaded with. This is the same as the URI we are // keyed on in the cache. We store a string here to avoid off main thread // refcounting issues with nsStandardURL. nsCOMPtr mURI; // The URI of the resource we ended up loading after all redirects, etc. nsCOMPtr mFinalURI; // The principal which triggered the load of this image. Generally either // the principal of the document the image is being loaded into, or of the // stylesheet which specified the image to load. Used when validating for // CORS. nsCOMPtr mTriggeringPrincipal; // The principal of this image. nsCOMPtr mPrincipal; nsCOMPtr mProperties; nsCOMPtr mChannel; nsCOMPtr mPrevChannelSink; nsCOMPtr mTimedChannel; nsCString mContentType; /* we hold on to this to this so long as we have observers */ RefPtr mCacheEntry; /// The key under which this imgRequest is stored in the image cache. ImageCacheKey mCacheKey; void* mLoadId; /// Raw pointer to the first proxy that was added to this imgRequest. Use only /// pointer comparisons; there's no guarantee this will remain valid. void* mFirstProxy; imgCacheValidator* mValidator; nsCOMPtr mRedirectCallback; nsCOMPtr mNewRedirectChannel; // The ID of the inner window origin, used for error reporting. uint64_t mInnerWindowId; // The CORS mode (defined in imgIRequest) this image was loaded with. By // default, CORS_NONE. mozilla::CORSMode mCORSMode; // The ReferrerInfo used for this image. nsCOMPtr mReferrerInfo; nsresult mImageErrorCode; // The categories of prioritization strategy that have been requested. uint32_t mBoostCategoriesRequested = 0; // If we've called OnImageAvailable. bool mImageAvailable; bool mIsDeniedCrossSiteCORSRequest; bool mIsCrossSiteNoCORSRequest; mutable mozilla::Mutex mMutex; // Member variables protected by mMutex. Note that *all* flags in our bitfield // are protected by mMutex; if you're adding a new flag that isn'protected, it // must not be a part of this bitfield. RefPtr mProgressTracker; RefPtr mImage; bool mIsMultiPartChannel : 1; bool mIsInCache : 1; bool mDecodeRequested : 1; bool mNewPartPending : 1; bool mHadInsecureRedirect : 1; }; #endif // mozilla_image_imgRequest_h