2007-03-22 10:30:00 -07:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
2012-05-21 04:12:37 -07:00
* 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/. */
2007-03-22 10:30:00 -07:00
# include "imgRequest.h"
2011-07-08 10:55:03 -07:00
# include "ImageLogging.h"
2007-03-22 10:30:00 -07:00
# include "imgLoader.h"
# include "imgRequestProxy.h"
2013-02-13 13:53:42 -08:00
# include "imgStatusTracker.h"
2012-12-17 14:05:18 -08:00
# include "ImageFactory.h"
2013-02-13 13:53:42 -08:00
# include "Image.h"
2013-09-28 11:28:42 -07:00
# include "RasterImage.h"
2007-03-22 10:30:00 -07:00
# include "nsIChannel.h"
# include "nsICachingChannel.h"
2013-09-28 11:28:42 -07:00
# include "nsIThreadRetargetableRequest.h"
2007-03-22 10:30:00 -07:00
# include "nsIInputStream.h"
# include "nsIMultiPartChannel.h"
# include "nsIHttpChannel.h"
2012-11-08 10:54:00 -08:00
# include "nsIApplicationCache.h"
# include "nsIApplicationCacheChannel.h"
2013-01-08 13:40:47 -08:00
# include "nsMimeTypes.h"
2007-03-22 10:30:00 -07:00
2008-12-22 14:20:46 -08:00
# include "nsIInterfaceRequestorUtils.h"
2007-03-22 10:30:00 -07:00
# include "nsISupportsPrimitives.h"
2007-11-08 18:55:41 -08:00
# include "nsIScriptSecurityManager.h"
2014-02-14 14:56:01 -08:00
# include "nsContentUtils.h"
2007-03-22 10:30:00 -07:00
2013-09-20 02:11:25 -07:00
# include "nsICacheEntry.h"
2008-09-04 16:00:42 -07:00
2007-03-22 10:30:00 -07:00
# include "plstr.h" // PL_strcasestr(...)
2010-02-11 13:59:00 -08:00
# include "nsNetUtil.h"
# include "nsIProtocolHandler.h"
2013-09-07 06:01:08 -07:00
# include "imgIRequest.h"
2010-07-11 18:51:52 -07:00
2011-06-11 19:30:15 -07:00
using namespace mozilla ;
2012-01-06 08:02:27 -08:00
using namespace mozilla : : image ;
2010-08-13 21:09:48 -07:00
2007-03-22 10:30:00 -07:00
# if defined(PR_LOGGING)
2012-10-29 16:32:10 -07:00
PRLogModuleInfo *
GetImgLog ( )
{
static PRLogModuleInfo * sImgLog ;
if ( ! sImgLog )
sImgLog = PR_NewLogModule ( " imgRequest " ) ;
return sImgLog ;
}
2007-03-22 10:30:00 -07:00
# endif
2014-04-27 00:06:00 -07:00
NS_IMPL_ISUPPORTS ( imgRequest ,
nsIStreamListener , nsIRequestObserver ,
nsIThreadRetargetableStreamListener ,
nsIChannelEventSink ,
nsIInterfaceRequestor ,
nsIAsyncVerifyRedirectCallback )
2007-03-22 10:30:00 -07:00
2012-09-06 15:05:23 -07:00
imgRequest : : imgRequest ( imgLoader * aLoader )
: mLoader ( aLoader )
2012-12-19 13:28:54 -08:00
, mStatusTracker ( new imgStatusTracker ( nullptr ) )
2012-09-06 15:05:23 -07:00
, mValidator ( nullptr )
, mInnerWindowId ( 0 )
, mCORSMode ( imgIRequest : : CORS_NONE )
2014-07-18 18:47:11 -07:00
, mImageErrorCode ( NS_OK )
2012-09-06 15:05:23 -07:00
, mDecodeRequested ( false )
, mIsMultiPartChannel ( false )
, mGotData ( false )
, mIsInCache ( false )
, mResniffMimeType ( false )
2012-12-17 14:05:18 -08:00
{ }
2007-03-22 10:30:00 -07:00
imgRequest : : ~ imgRequest ( )
{
2011-07-01 10:03:40 -07:00
if ( mURI ) {
2012-09-01 19:35:17 -07:00
nsAutoCString spec ;
2011-07-01 10:03:40 -07:00
mURI - > GetSpec ( spec ) ;
2012-10-29 16:32:10 -07:00
LOG_FUNC_WITH_PARAM ( GetImgLog ( ) , " imgRequest::~imgRequest() " , " keyuri " , spec . get ( ) ) ;
2009-01-30 18:17:47 -08:00
} else
2012-10-29 16:32:10 -07:00
LOG_FUNC ( GetImgLog ( ) , " imgRequest::~imgRequest() " ) ;
2007-03-22 10:30:00 -07:00
}
nsresult imgRequest : : Init ( nsIURI * aURI ,
2011-07-01 10:03:40 -07:00
nsIURI * aCurrentURI ,
2007-03-22 10:30:00 -07:00
nsIRequest * aRequest ,
2008-12-22 14:20:46 -08:00
nsIChannel * aChannel ,
2008-09-04 16:00:42 -07:00
imgCacheEntry * aCacheEntry ,
2011-07-14 11:47:32 -07:00
void * aLoadId ,
2011-07-14 11:47:34 -07:00
nsIPrincipal * aLoadingPrincipal ,
2012-08-22 08:56:38 -07:00
int32_t aCORSMode )
2007-03-22 10:30:00 -07:00
{
2013-09-28 11:28:42 -07:00
MOZ_ASSERT ( NS_IsMainThread ( ) , " Cannot use nsIURI off main thread! " ) ;
2012-10-29 16:32:10 -07:00
LOG_FUNC ( GetImgLog ( ) , " imgRequest::Init " ) ;
2007-03-22 10:30:00 -07:00
2009-01-30 18:17:47 -08:00
NS_ABORT_IF_FALSE ( ! mImage , " Multiple calls to init " ) ;
NS_ABORT_IF_FALSE ( aURI , " No uri " ) ;
2011-07-01 10:03:40 -07:00
NS_ABORT_IF_FALSE ( aCurrentURI , " No current uri " ) ;
2009-01-30 18:17:47 -08:00
NS_ABORT_IF_FALSE ( aRequest , " No request " ) ;
NS_ABORT_IF_FALSE ( aChannel , " No channel " ) ;
2007-03-22 10:30:00 -07:00
mProperties = do_CreateInstance ( " @mozilla.org/properties;1 " ) ;
2010-08-13 21:09:49 -07:00
2013-09-28 11:28:42 -07:00
// Use ImageURL to ensure access to URI data off main thread.
mURI = new ImageURL ( aURI ) ;
2011-07-01 10:03:40 -07:00
mCurrentURI = aCurrentURI ;
2007-03-22 10:30:00 -07:00
mRequest = aRequest ;
2008-12-22 14:20:46 -08:00
mChannel = aChannel ;
2011-06-09 14:11:57 -07:00
mTimedChannel = do_QueryInterface ( mChannel ) ;
2011-07-14 11:47:32 -07:00
mLoadingPrincipal = aLoadingPrincipal ;
2011-07-14 11:47:34 -07:00
mCORSMode = aCORSMode ;
2011-07-14 11:47:32 -07:00
2008-12-22 14:20:46 -08:00
mChannel - > GetNotificationCallbacks ( getter_AddRefs ( mPrevChannelSink ) ) ;
NS_ASSERTION ( mPrevChannelSink ! = this ,
" Initializing with a channel that already calls back to us! " ) ;
mChannel - > SetNotificationCallbacks ( this ) ;
2007-03-22 10:30:00 -07:00
mCacheEntry = aCacheEntry ;
SetLoadId ( aLoadId ) ;
return NS_OK ;
}
2013-09-28 11:28:44 -07:00
already_AddRefed < imgStatusTracker >
2010-08-23 15:44:07 -07:00
imgRequest : : GetStatusTracker ( )
{
2012-05-19 12:32:37 -07:00
if ( mImage & & mGotData ) {
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( ! mStatusTracker ,
" Should have given mStatusTracker to mImage " ) ;
return mImage - > GetStatusTracker ( ) ;
} else {
NS_ABORT_IF_FALSE ( mStatusTracker ,
" Should have mStatusTracker until we create mImage " ) ;
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = mStatusTracker ;
MOZ_ASSERT ( statusTracker ) ;
return statusTracker . forget ( ) ;
2010-08-23 15:44:07 -07:00
}
}
2009-01-30 18:17:47 -08:00
void imgRequest : : SetCacheEntry ( imgCacheEntry * entry )
{
mCacheEntry = entry ;
}
2011-09-28 23:19:26 -07:00
bool imgRequest : : HasCacheEntry ( ) const
2009-01-30 18:17:47 -08:00
{
2012-07-30 07:20:58 -07:00
return mCacheEntry ! = nullptr ;
2009-01-30 18:17:47 -08:00
}
2012-10-12 09:11:21 -07:00
void imgRequest : : ResetCacheEntry ( )
{
if ( HasCacheEntry ( ) ) {
mCacheEntry - > SetDataSize ( 0 ) ;
}
}
2012-10-03 15:39:59 -07:00
void imgRequest : : AddProxy ( imgRequestProxy * proxy )
2007-03-22 10:30:00 -07:00
{
2007-09-22 12:40:57 -07:00
NS_PRECONDITION ( proxy , " null imgRequestProxy passed in " ) ;
2012-10-29 16:32:10 -07:00
LOG_SCOPE_WITH_PARAM ( GetImgLog ( ) , " imgRequest::AddProxy " , " proxy " , proxy ) ;
2007-03-22 10:30:00 -07:00
2009-01-30 18:17:47 -08:00
// If we're empty before adding, we have to tell the loader we now have
// proxies.
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
if ( statusTracker - > ConsumerCount ( ) = = 0 ) {
2011-07-01 10:03:40 -07:00
NS_ABORT_IF_FALSE ( mURI , " Trying to SetHasProxies without key uri. " ) ;
2012-06-25 21:20:12 -07:00
mLoader - > SetHasProxies ( mURI ) ;
2009-01-30 18:17:47 -08:00
}
2013-09-28 11:28:44 -07:00
statusTracker - > AddConsumer ( proxy ) ;
2007-03-22 10:30:00 -07:00
}
2012-10-11 09:35:43 -07:00
nsresult imgRequest : : RemoveProxy ( imgRequestProxy * proxy , nsresult aStatus )
2007-03-22 10:30:00 -07:00
{
2012-10-29 16:32:10 -07:00
LOG_SCOPE_WITH_PARAM ( GetImgLog ( ) , " imgRequest::RemoveProxy " , " proxy " , proxy ) ;
2007-03-22 10:30:00 -07:00
2010-09-07 17:33:02 -07:00
// This will remove our animation consumers, so after removing
// this proxy, we don't end up without proxies with observers, but still
// have animation consumers.
proxy - > ClearAnimationConsumers ( ) ;
2010-05-14 13:47:59 -07:00
// Let the status tracker do its thing before we potentially call Cancel()
// below, because Cancel() may result in OnStopRequest being called back
// before Cancel() returns, leaving the image in a different state then the
// one it was in at this point.
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
if ( ! statusTracker - > RemoveConsumer ( proxy , aStatus ) )
2012-10-12 09:11:20 -07:00
return NS_OK ;
2007-03-22 10:30:00 -07:00
2013-09-28 11:28:44 -07:00
if ( statusTracker - > ConsumerCount ( ) = = 0 ) {
2009-01-30 18:17:47 -08:00
// If we have no observers, there's nothing holding us alive. If we haven't
// been cancelled and thus removed from the cache, tell the image loader so
// we can be evicted from the cache.
if ( mCacheEntry ) {
2011-07-01 10:03:40 -07:00
NS_ABORT_IF_FALSE ( mURI , " Removing last observer without key uri. " ) ;
2009-01-30 18:17:47 -08:00
2012-06-25 21:20:12 -07:00
mLoader - > SetHasNoProxies ( mURI , mCacheEntry ) ;
2013-03-29 13:14:19 -07:00
}
2009-01-30 18:17:47 -08:00
# if defined(PR_LOGGING)
else {
2012-09-01 19:35:17 -07:00
nsAutoCString spec ;
2011-07-01 10:03:40 -07:00
mURI - > GetSpec ( spec ) ;
2012-10-29 16:32:10 -07:00
LOG_MSG_WITH_PARAM ( GetImgLog ( ) , " imgRequest::RemoveProxy no cache entry " , " uri " , spec . get ( ) ) ;
2009-01-30 18:17:47 -08:00
}
# endif
2007-03-22 10:30:00 -07:00
/* If |aStatus| is a failure code, then cancel the load if it is still in progress.
Otherwise , let the load continue , keeping ' this ' in the cache with no observers .
This way , if a proxy is destroyed without calling cancel on it , it won ' t leak
2012-10-12 09:11:20 -07:00
and won ' t leave a bad pointer in the observer list .
2007-03-22 10:30:00 -07:00
*/
2013-09-28 11:28:44 -07:00
if ( statusTracker - > IsLoading ( ) & & NS_FAILED ( aStatus ) ) {
2012-10-29 16:32:10 -07:00
LOG_MSG ( GetImgLog ( ) , " imgRequest::RemoveProxy " , " load in progress. canceling " ) ;
2007-03-22 10:30:00 -07:00
this - > Cancel ( NS_BINDING_ABORTED ) ;
}
/* break the cycle from the cache entry. */
2012-07-30 07:20:58 -07:00
mCacheEntry = nullptr ;
2007-03-22 10:30:00 -07:00
}
// If a proxy is removed for a reason other than its owner being
// changed, remove the proxy from the loadgroup.
if ( aStatus ! = NS_IMAGELIB_CHANGING_OWNER )
2011-10-17 07:59:28 -07:00
proxy - > RemoveFromLoadGroup ( true ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2008-12-22 14:20:46 -08:00
void imgRequest : : CancelAndAbort ( nsresult aStatus )
{
2012-10-29 16:32:10 -07:00
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::CancelAndAbort " ) ;
2009-01-30 18:17:47 -08:00
2008-12-22 14:20:46 -08:00
Cancel ( aStatus ) ;
// It's possible for the channel to fail to open after we've set our
// notification callbacks. In that case, make sure to break the cycle between
// the channel and us, because it won't.
if ( mChannel ) {
mChannel - > SetNotificationCallbacks ( mPrevChannelSink ) ;
2012-07-30 07:20:58 -07:00
mPrevChannelSink = nullptr ;
2008-12-22 14:20:46 -08:00
}
2007-03-22 10:30:00 -07:00
}
2013-10-15 16:33:11 -07:00
class imgRequestMainThreadCancel : public nsRunnable
{
public :
imgRequestMainThreadCancel ( imgRequest * aImgRequest , nsresult aStatus )
: mImgRequest ( aImgRequest )
, mStatus ( aStatus )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) , " Create me off main thread only! " ) ;
MOZ_ASSERT ( aImgRequest ) ;
}
NS_IMETHOD Run ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) , " I should be running on the main thread! " ) ;
mImgRequest - > ContinueCancel ( mStatus ) ;
return NS_OK ;
}
private :
nsRefPtr < imgRequest > mImgRequest ;
nsresult mStatus ;
} ;
2010-05-14 13:47:59 -07:00
void imgRequest : : Cancel ( nsresult aStatus )
{
/* The Cancel() method here should only be called by this class. */
2012-10-29 16:32:10 -07:00
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::Cancel " ) ;
2010-05-14 13:47:59 -07:00
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
2012-08-13 15:58:53 -07:00
2013-09-28 11:28:44 -07:00
statusTracker - > MaybeUnblockOnload ( ) ;
2012-08-13 15:58:53 -07:00
2013-09-28 11:28:44 -07:00
statusTracker - > RecordCancel ( ) ;
2010-05-14 13:47:59 -07:00
2013-09-28 11:28:42 -07:00
if ( NS_IsMainThread ( ) ) {
2013-10-15 16:33:11 -07:00
ContinueCancel ( aStatus ) ;
2013-09-28 11:28:42 -07:00
} else {
2013-10-15 16:33:11 -07:00
NS_DispatchToMainThread ( new imgRequestMainThreadCancel ( this , aStatus ) ) ;
2013-09-28 11:28:42 -07:00
}
2013-10-15 16:33:11 -07:00
}
2010-05-14 13:47:59 -07:00
2013-10-15 16:33:11 -07:00
void imgRequest : : ContinueCancel ( nsresult aStatus )
{
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
RemoveFromCache ( ) ;
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
if ( mRequest & & statusTracker - > IsLoading ( ) ) {
mRequest - > Cancel ( aStatus ) ;
}
2010-05-14 13:47:59 -07:00
}
2014-06-08 15:15:00 -07:00
class imgRequestMainThreadEvict : public nsRunnable
{
public :
2014-09-02 09:20:24 -07:00
explicit imgRequestMainThreadEvict ( imgRequest * aImgRequest )
2014-06-08 15:15:00 -07:00
: mImgRequest ( aImgRequest )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) , " Create me off main thread only! " ) ;
MOZ_ASSERT ( aImgRequest ) ;
}
NS_IMETHOD Run ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) , " I should be running on the main thread! " ) ;
mImgRequest - > ContinueEvict ( ) ;
return NS_OK ;
}
private :
nsRefPtr < imgRequest > mImgRequest ;
} ;
// EvictFromCache() is written to allowed to get called from any thread
void imgRequest : : EvictFromCache ( )
{
/* The EvictFromCache() method here should only be called by this class. */
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::EvictFromCache " ) ;
if ( NS_IsMainThread ( ) ) {
ContinueEvict ( ) ;
} else {
NS_DispatchToMainThread ( new imgRequestMainThreadEvict ( this ) ) ;
}
}
// Helper-method used by EvictFromCache()
void imgRequest : : ContinueEvict ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) ) ;
RemoveFromCache ( ) ;
}
2013-09-28 11:28:42 -07:00
nsresult imgRequest : : GetURI ( ImageURL * * aURI )
2007-03-22 10:30:00 -07:00
{
2013-09-28 11:28:42 -07:00
MOZ_ASSERT ( aURI ) ;
2012-10-29 16:32:10 -07:00
LOG_FUNC ( GetImgLog ( ) , " imgRequest::GetURI " ) ;
2007-03-22 10:30:00 -07:00
if ( mURI ) {
* aURI = mURI ;
NS_ADDREF ( * aURI ) ;
return NS_OK ;
}
return NS_ERROR_FAILURE ;
}
2014-07-18 18:47:11 -07:00
nsresult imgRequest : : GetImageErrorCode ( )
{
return mImageErrorCode ;
}
2008-09-01 13:53:59 -07:00
nsresult imgRequest : : GetSecurityInfo ( nsISupports * * aSecurityInfo )
{
2012-10-29 16:32:10 -07:00
LOG_FUNC ( GetImgLog ( ) , " imgRequest::GetSecurityInfo " ) ;
2008-09-01 13:53:59 -07:00
// Missing security info means this is not a security load
// i.e. it is not an error when security info is missing
NS_IF_ADDREF ( * aSecurityInfo = mSecurityInfo ) ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
void imgRequest : : RemoveFromCache ( )
{
2012-10-29 16:32:10 -07:00
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::RemoveFromCache " ) ;
2007-03-22 10:30:00 -07:00
2009-03-17 14:07:16 -07:00
if ( mIsInCache ) {
// mCacheEntry is nulled out when we have no more observers.
2009-03-04 19:56:14 -08:00
if ( mCacheEntry )
2012-06-25 21:20:12 -07:00
mLoader - > RemoveFromCache ( mCacheEntry ) ;
2009-03-04 19:56:14 -08:00
else
2012-06-25 21:20:12 -07:00
mLoader - > RemoveFromCache ( mURI ) ;
2009-03-04 19:56:14 -08:00
}
2009-03-17 14:07:16 -07:00
2012-07-30 07:20:58 -07:00
mCacheEntry = nullptr ;
2007-03-22 10:30:00 -07:00
}
2012-08-22 08:56:38 -07:00
int32_t imgRequest : : Priority ( ) const
2007-03-22 10:30:00 -07:00
{
2012-08-22 08:56:38 -07:00
int32_t priority = nsISupportsPriority : : PRIORITY_NORMAL ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsISupportsPriority > p = do_QueryInterface ( mRequest ) ;
if ( p )
p - > GetPriority ( & priority ) ;
return priority ;
}
2012-08-22 08:56:38 -07:00
void imgRequest : : AdjustPriority ( imgRequestProxy * proxy , int32_t delta )
2007-03-22 10:30:00 -07:00
{
// only the first proxy is allowed to modify the priority of this image load.
//
// XXX(darin): this is probably not the most optimal algorithm as we may want
// to increase the priority of requests that have a lot of proxies. the key
// concern though is that image loads remain lower priority than other pieces
// of content such as link clicks, CSS, and JS.
//
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
if ( ! statusTracker - > FirstConsumerIs ( proxy ) )
2007-03-22 10:30:00 -07:00
return ;
2012-10-13 09:47:36 -07:00
nsCOMPtr < nsISupportsPriority > p = do_QueryInterface ( mChannel ) ;
2007-03-22 10:30:00 -07:00
if ( p )
p - > AdjustPriority ( delta ) ;
}
2011-09-28 23:19:26 -07:00
void imgRequest : : SetIsInCache ( bool incache )
2009-03-04 19:56:14 -08:00
{
2012-10-29 16:32:10 -07:00
LOG_FUNC_WITH_PARAM ( GetImgLog ( ) , " imgRequest::SetIsCacheable " , " incache " , incache ) ;
2009-03-17 14:07:16 -07:00
mIsInCache = incache ;
2009-03-04 19:56:14 -08:00
}
2009-09-12 15:44:18 -07:00
void imgRequest : : UpdateCacheEntrySize ( )
2007-03-22 10:30:00 -07:00
{
2013-04-12 13:25:04 -07:00
if ( mCacheEntry )
2012-02-19 19:51:48 -08:00
mCacheEntry - > SetDataSize ( mImage - > SizeOfData ( ) ) ;
2007-03-22 10:30:00 -07:00
}
2011-07-01 10:03:33 -07:00
void imgRequest : : SetCacheValidation ( imgCacheEntry * aCacheEntry , nsIRequest * aRequest )
{
/* get the expires info */
if ( aCacheEntry ) {
nsCOMPtr < nsICachingChannel > cacheChannel ( do_QueryInterface ( aRequest ) ) ;
if ( cacheChannel ) {
nsCOMPtr < nsISupports > cacheToken ;
cacheChannel - > GetCacheToken ( getter_AddRefs ( cacheToken ) ) ;
if ( cacheToken ) {
2013-09-20 02:11:25 -07:00
nsCOMPtr < nsICacheEntry > entryDesc ( do_QueryInterface ( cacheToken ) ) ;
2011-07-01 10:03:33 -07:00
if ( entryDesc ) {
2012-08-22 08:56:38 -07:00
uint32_t expiration ;
2011-07-01 10:03:33 -07:00
/* get the expiration time from the caching channel's token */
entryDesc - > GetExpirationTime ( & expiration ) ;
// Expiration time defaults to 0. We set the expiration time on our
// entry if it hasn't been set yet.
if ( aCacheEntry - > GetExpiryTime ( ) = = 0 )
aCacheEntry - > SetExpiryTime ( expiration ) ;
}
}
}
2011-07-01 10:03:35 -07:00
// Determine whether the cache entry must be revalidated when we try to use it.
2011-07-01 10:03:33 -07:00
// Currently, only HTTP specifies this information...
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( aRequest ) ) ;
if ( httpChannel ) {
2011-09-28 23:19:26 -07:00
bool bMustRevalidate = false ;
2011-07-01 10:03:33 -07:00
httpChannel - > IsNoStoreResponse ( & bMustRevalidate ) ;
if ( ! bMustRevalidate ) {
httpChannel - > IsNoCacheResponse ( & bMustRevalidate ) ;
}
if ( ! bMustRevalidate ) {
2012-09-01 19:35:17 -07:00
nsAutoCString cacheHeader ;
2011-07-01 10:03:33 -07:00
httpChannel - > GetResponseHeader ( NS_LITERAL_CSTRING ( " Cache-Control " ) ,
cacheHeader ) ;
if ( PL_strcasestr ( cacheHeader . get ( ) , " must-revalidate " ) ) {
2011-10-17 07:59:28 -07:00
bMustRevalidate = true ;
2011-07-01 10:03:33 -07:00
}
}
// Cache entries default to not needing to validate. We ensure that
// multiple calls to this function don't override an earlier decision to
// validate by making validation a one-way decision.
if ( bMustRevalidate )
2011-07-01 10:03:35 -07:00
aCacheEntry - > SetMustValidate ( bMustRevalidate ) ;
2011-07-01 10:03:33 -07:00
}
2011-07-01 10:03:37 -07:00
// We always need to validate file URIs.
nsCOMPtr < nsIChannel > channel = do_QueryInterface ( aRequest ) ;
if ( channel ) {
nsCOMPtr < nsIURI > uri ;
channel - > GetURI ( getter_AddRefs ( uri ) ) ;
2011-09-28 23:19:26 -07:00
bool isfile = false ;
2011-07-01 10:03:37 -07:00
uri - > SchemeIs ( " file " , & isfile ) ;
if ( isfile )
aCacheEntry - > SetMustValidate ( isfile ) ;
}
2011-07-01 10:03:33 -07:00
}
}
2012-11-08 10:54:00 -08:00
namespace { // anon
already_AddRefed < nsIApplicationCache >
GetApplicationCache ( nsIRequest * aRequest )
{
nsresult rv ;
nsCOMPtr < nsIApplicationCacheChannel > appCacheChan = do_QueryInterface ( aRequest ) ;
if ( ! appCacheChan ) {
return nullptr ;
}
bool fromAppCache ;
rv = appCacheChan - > GetLoadedFromApplicationCache ( & fromAppCache ) ;
NS_ENSURE_SUCCESS ( rv , nullptr ) ;
if ( ! fromAppCache ) {
return nullptr ;
}
nsCOMPtr < nsIApplicationCache > appCache ;
rv = appCacheChan - > GetApplicationCache ( getter_AddRefs ( appCache ) ) ;
NS_ENSURE_SUCCESS ( rv , nullptr ) ;
return appCache . forget ( ) ;
}
} // anon
bool
imgRequest : : CacheChanged ( nsIRequest * aNewRequest )
{
nsCOMPtr < nsIApplicationCache > newAppCache = GetApplicationCache ( aNewRequest ) ;
// Application cache not involved at all or the same app cache involved
// in both of the loads (original and new).
if ( newAppCache = = mApplicationCache )
return false ;
// In a rare case it may happen that two objects still refer
// the same application cache version.
if ( newAppCache & & mApplicationCache ) {
2012-11-14 04:56:56 -08:00
nsresult rv ;
2012-11-08 10:54:00 -08:00
nsAutoCString oldAppCacheClientId , newAppCacheClientId ;
rv = mApplicationCache - > GetClientID ( oldAppCacheClientId ) ;
NS_ENSURE_SUCCESS ( rv , true ) ;
rv = newAppCache - > GetClientID ( newAppCacheClientId ) ;
NS_ENSURE_SUCCESS ( rv , true ) ;
if ( oldAppCacheClientId = = newAppCacheClientId )
return false ;
}
// When we get here, app caches differ or app cache is involved
// just in one of the loads what we also consider as a change
// in a loading cache.
return true ;
}
2009-09-15 17:33:14 -07:00
nsresult
imgRequest : : LockImage ( )
{
2010-05-14 13:47:59 -07:00
return mImage - > LockImage ( ) ;
2009-09-15 17:33:14 -07:00
}
nsresult
imgRequest : : UnlockImage ( )
{
2010-05-14 13:47:59 -07:00
return mImage - > UnlockImage ( ) ;
2009-09-15 17:33:14 -07:00
}
nsresult
imgRequest : : RequestDecode ( )
{
2010-05-14 13:47:59 -07:00
// If we've initialized our image, we can request a decode.
2010-08-23 15:44:07 -07:00
if ( mImage ) {
2009-09-15 17:33:14 -07:00
return mImage - > RequestDecode ( ) ;
}
// Otherwise, flag to do it when we get the image
2011-10-17 07:59:28 -07:00
mDecodeRequested = true ;
2009-09-15 17:33:14 -07:00
return NS_OK ;
}
2012-10-04 13:02:15 -07:00
nsresult
imgRequest : : StartDecoding ( )
{
// If we've initialized our image, we can request a decode.
if ( mImage ) {
return mImage - > StartDecoding ( ) ;
}
// Otherwise, flag to do it when we get the image
mDecodeRequested = true ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
/** nsIRequestObserver methods **/
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP imgRequest : : OnStartRequest ( nsIRequest * aRequest , nsISupports * ctxt )
{
2012-10-29 16:32:10 -07:00
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::OnStartRequest " ) ;
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
// Figure out if we're multipart
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIMultiPartChannel > mpchan ( do_QueryInterface ( aRequest ) ) ;
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
2012-12-19 13:28:54 -08:00
if ( mpchan ) {
mIsMultiPartChannel = true ;
2013-09-28 11:28:44 -07:00
statusTracker - > SetIsMultipart ( ) ;
2014-07-29 15:23:22 -07:00
} else {
NS_ABORT_IF_FALSE ( ! mIsMultiPartChannel , " Something went wrong " ) ;
2012-12-19 13:28:54 -08:00
}
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
// If we're not multipart, we shouldn't have an image yet
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mIsMultiPartChannel | | ! mImage ,
2009-09-12 15:44:18 -07:00
" Already have an image for non-multipart request " ) ;
2012-09-06 15:05:23 -07:00
// If we're multipart and about to load another image, signal so we can
// detect the mime type in OnDataAvailable.
2010-09-08 13:40:38 -07:00
if ( mIsMultiPartChannel & & mImage ) {
2012-09-06 15:05:23 -07:00
mResniffMimeType = true ;
2012-12-17 14:05:18 -08:00
// Tell the image to reinitialize itself. We have to do this in
// OnStartRequest so that its state machine is always in a consistent
// state.
// Note that if our MIME type changes, mImage will be replaced with a
// new object.
mImage - > OnNewSourceData ( ) ;
2009-09-12 15:44:18 -07:00
}
2008-09-29 13:46:53 -07:00
/*
* If mRequest is null here , then we need to set it so that we ' ll be able to
* cancel it if our Cancel ( ) method is called . Note that this can only
* happen for multipart channels . We could simply not null out mRequest for
* non - last parts , if GetIsLastPart ( ) were reliable , but it ' s not . See
* https : //bugzilla.mozilla.org/show_bug.cgi?id=339610
*/
if ( ! mRequest ) {
NS_ASSERTION ( mpchan ,
" We should have an mRequest here unless we're multipart " ) ;
nsCOMPtr < nsIChannel > chan ;
mpchan - > GetBaseChannel ( getter_AddRefs ( chan ) ) ;
mRequest = chan ;
}
2013-09-28 11:28:44 -07:00
// Note: refreshing statusTracker in case OnNewSourceData changed it.
statusTracker = GetStatusTracker ( ) ;
statusTracker - > OnStartRequest ( ) ;
2007-03-22 10:30:00 -07:00
2008-09-01 13:53:59 -07:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( aRequest ) ) ;
if ( channel )
channel - > GetSecurityInfo ( getter_AddRefs ( mSecurityInfo ) ) ;
2007-11-08 18:55:41 -08:00
/* Get our principal */
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIChannel > chan ( do_QueryInterface ( aRequest ) ) ;
2007-11-08 18:55:41 -08:00
if ( chan ) {
2014-02-14 14:56:01 -08:00
nsCOMPtr < nsIScriptSecurityManager > secMan = nsContentUtils : : GetSecurityManager ( ) ;
2007-11-08 18:55:41 -08:00
if ( secMan ) {
nsresult rv = secMan - > GetChannelPrincipal ( chan ,
getter_AddRefs ( mPrincipal ) ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
}
}
2007-03-22 10:30:00 -07:00
2011-07-01 10:03:33 -07:00
SetCacheValidation ( mCacheEntry , aRequest ) ;
2007-03-22 10:30:00 -07:00
2012-11-08 10:54:00 -08:00
mApplicationCache = GetApplicationCache ( aRequest ) ;
2007-03-22 10:30:00 -07:00
// Shouldn't we be dead already if this gets hit? Probably multipart/x-mixed-replace...
2013-09-28 11:28:44 -07:00
if ( statusTracker - > ConsumerCount ( ) = = 0 ) {
2007-03-22 10:30:00 -07:00
this - > Cancel ( NS_IMAGELIB_ERROR_FAILURE ) ;
}
2013-09-28 11:28:42 -07:00
// Try to retarget OnDataAvailable to a decode thread.
nsCOMPtr < nsIHttpChannel > httpChannel = do_QueryInterface ( aRequest ) ;
nsCOMPtr < nsIThreadRetargetableRequest > retargetable =
do_QueryInterface ( aRequest ) ;
if ( httpChannel & & retargetable & &
2014-04-02 19:20:25 -07:00
ImageFactory : : CanRetargetOnDataAvailable ( mURI , mIsMultiPartChannel ) ) {
2013-09-28 11:28:42 -07:00
nsAutoCString mimeType ;
nsresult rv = httpChannel - > GetContentType ( mimeType ) ;
if ( NS_SUCCEEDED ( rv ) & & ! mimeType . EqualsLiteral ( IMAGE_SVG_XML ) ) {
// Image object not created until OnDataAvailable, so forward to static
// DecodePool directly.
nsCOMPtr < nsIEventTarget > target = RasterImage : : GetEventTarget ( ) ;
rv = retargetable - > RetargetDeliveryTo ( target ) ;
}
PR_LOG ( GetImgLog ( ) , PR_LOG_WARNING ,
( " [this=%p] imgRequest::OnStartRequest -- "
" RetargetDeliveryTo rv %d=%s \n " ,
2013-12-12 13:17:35 -08:00
this , rv , NS_SUCCEEDED ( rv ) ? " succeeded " : " failed " ) ) ;
2013-09-28 11:28:42 -07:00
}
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status); */
NS_IMETHODIMP imgRequest : : OnStopRequest ( nsIRequest * aRequest , nsISupports * ctxt , nsresult status )
{
2012-10-29 16:32:10 -07:00
LOG_FUNC ( GetImgLog ( ) , " imgRequest::OnStopRequest " ) ;
2007-03-22 10:30:00 -07:00
// XXXldb What if this is a non-last part of a multipart request?
2008-12-22 14:20:46 -08:00
// xxx before we release our reference to mRequest, lets
2007-03-22 10:30:00 -07:00
// save the last status that we saw so that the
// imgRequestProxy will have access to it.
2008-12-22 14:20:46 -08:00
if ( mRequest ) {
2012-07-30 07:20:58 -07:00
mRequest = nullptr ; // we no longer need the request
2007-03-22 10:30:00 -07:00
}
2008-12-22 14:20:46 -08:00
// stop holding a ref to the channel, since we don't need it anymore
if ( mChannel ) {
mChannel - > SetNotificationCallbacks ( mPrevChannelSink ) ;
2012-07-30 07:20:58 -07:00
mPrevChannelSink = nullptr ;
mChannel = nullptr ;
2008-12-22 14:20:46 -08:00
}
2013-02-01 17:06:34 -08:00
bool lastPart = true ;
nsCOMPtr < nsIMultiPartChannel > mpchan ( do_QueryInterface ( aRequest ) ) ;
if ( mpchan )
mpchan - > GetIsLastPart ( & lastPart ) ;
2014-06-08 15:15:00 -07:00
bool isPartial = false ;
if ( mImage & & ( status = = NS_ERROR_NET_PARTIAL_TRANSFER ) ) {
isPartial = true ;
status = NS_OK ; // fake happy face
}
2009-09-12 15:44:18 -07:00
// Tell the image that it has all of the source data. Note that this can
// trigger a failure, since the image might be waiting for more non-optional
// data and this is the point where we break the news that it's not coming.
2010-09-08 13:40:38 -07:00
if ( mImage ) {
2013-02-13 18:41:10 -08:00
nsresult rv = mImage - > OnImageDataComplete ( aRequest , ctxt , status , lastPart ) ;
2009-09-12 15:44:18 -07:00
2012-12-17 14:05:18 -08:00
// If we got an error in the OnImageDataComplete() call, we don't want to
// proceed as if nothing bad happened. However, we also want to give
// precedence to failure status codes from necko, since presumably they're
// more meaningful.
2009-09-12 15:44:18 -07:00
if ( NS_FAILED ( rv ) & & NS_SUCCEEDED ( status ) )
status = rv ;
2007-03-22 10:30:00 -07:00
}
2010-05-14 13:47:59 -07:00
// If the request went through, update the cache entry size. Otherwise,
// cancel the request, which removes us from the cache.
2014-06-08 15:15:00 -07:00
if ( mImage & & NS_SUCCEEDED ( status ) & & ! isPartial ) {
2009-09-12 15:44:18 -07:00
// We update the cache entry size here because this is where we finish
// loading compressed source data, which is part of our size calculus.
UpdateCacheEntrySize ( ) ;
2007-03-22 10:30:00 -07:00
}
2014-06-08 15:15:00 -07:00
else if ( isPartial ) {
// Remove the partial image from the cache.
this - > EvictFromCache ( ) ;
}
2010-05-14 13:47:59 -07:00
else {
2014-07-18 18:47:11 -07:00
mImageErrorCode = status ;
2014-06-08 15:15:00 -07:00
// if the error isn't "just" a partial transfer
2010-05-14 13:47:59 -07:00
// stops animations, removes from cache
this - > Cancel ( status ) ;
2009-09-12 15:44:18 -07:00
}
2013-02-01 17:06:34 -08:00
if ( ! mImage ) {
// We have to fire imgStatusTracker::OnStopRequest ourselves because there's
// no image capable of doing so.
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
statusTracker - > OnStopRequest ( lastPart , status ) ;
2013-02-01 17:06:34 -08:00
}
2012-07-30 07:20:58 -07:00
mTimedChannel = nullptr ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2012-09-06 15:05:23 -07:00
struct mimetype_closure
{
nsACString * newType ;
} ;
2009-09-12 15:44:18 -07:00
/* prototype for these defined below */
2007-03-22 10:30:00 -07:00
static NS_METHOD sniff_mimetype_callback ( nsIInputStream * in , void * closure , const char * fromRawSegment ,
2012-08-22 08:56:38 -07:00
uint32_t toOffset , uint32_t count , uint32_t * writeCount ) ;
2007-03-22 10:30:00 -07:00
2013-09-28 11:28:42 -07:00
/** nsThreadRetargetableStreamListener methods **/
NS_IMETHODIMP
imgRequest : : CheckListenerChain ( )
{
// TODO Might need more checking here.
NS_ASSERTION ( NS_IsMainThread ( ) , " Should be on the main thread! " ) ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
/** nsIStreamListener methods **/
2012-09-05 19:41:02 -07:00
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long long sourceOffset, in unsigned long count); */
NS_IMETHODIMP
imgRequest : : OnDataAvailable ( nsIRequest * aRequest , nsISupports * ctxt ,
nsIInputStream * inStr , uint64_t sourceOffset ,
uint32_t count )
2007-03-22 10:30:00 -07:00
{
2012-10-29 16:32:10 -07:00
LOG_SCOPE_WITH_PARAM ( GetImgLog ( ) , " imgRequest::OnDataAvailable " , " count " , count ) ;
2007-03-22 10:30:00 -07:00
NS_ASSERTION ( aRequest , " imgRequest::OnDataAvailable -- no request! " ) ;
2009-09-12 15:44:18 -07:00
nsresult rv ;
2009-02-16 06:11:30 -08:00
2012-09-06 15:05:23 -07:00
if ( ! mGotData | | mResniffMimeType ) {
2012-10-29 16:32:10 -07:00
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::OnDataAvailable |First time through... finding mimetype| " ) ;
2007-03-22 10:30:00 -07:00
2011-10-17 07:59:28 -07:00
mGotData = true ;
2010-05-14 13:47:59 -07:00
2013-08-27 16:39:54 -07:00
// Store and reset this for the invariant that it's always false after
// calls to OnDataAvailable (see bug 907575)
bool resniffMimeType = mResniffMimeType ;
mResniffMimeType = false ;
2012-09-06 15:05:23 -07:00
mimetype_closure closure ;
nsAutoCString newType ;
closure . newType = & newType ;
2007-03-22 10:30:00 -07:00
/* look at the first few bytes and see if we can tell what the data is from that
* since servers tend to lie . : (
*/
2012-08-22 08:56:38 -07:00
uint32_t out ;
2012-09-06 15:05:23 -07:00
inStr - > ReadSegments ( sniff_mimetype_callback , & closure , count , & out ) ;
2007-03-22 10:30:00 -07:00
2011-09-09 15:41:04 -07:00
nsCOMPtr < nsIChannel > chan ( do_QueryInterface ( aRequest ) ) ;
2012-09-06 15:05:23 -07:00
if ( newType . IsEmpty ( ) ) {
2012-10-29 16:32:10 -07:00
LOG_SCOPE ( GetImgLog ( ) , " imgRequest::OnDataAvailable |sniffing of mimetype failed| " ) ;
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
rv = NS_ERROR_FAILURE ;
2007-03-22 10:30:00 -07:00
if ( chan ) {
2012-09-06 15:05:23 -07:00
rv = chan - > GetContentType ( newType ) ;
2007-03-22 10:30:00 -07:00
}
if ( NS_FAILED ( rv ) ) {
2012-10-29 16:32:10 -07:00
PR_LOG ( GetImgLog ( ) , PR_LOG_ERROR ,
2007-03-22 10:30:00 -07:00
( " [this=%p] imgRequest::OnDataAvailable -- Content type unavailable from the channel \n " ,
this ) ) ;
this - > Cancel ( NS_IMAGELIB_ERROR_FAILURE ) ;
return NS_BINDING_ABORTED ;
}
2012-10-29 16:32:10 -07:00
LOG_MSG ( GetImgLog ( ) , " imgRequest::OnDataAvailable " , " Got content type from the channel " ) ;
2007-03-22 10:30:00 -07:00
}
2012-09-06 15:05:23 -07:00
// If we're a regular image and this is the first call to OnDataAvailable,
// this will always be true. If we've resniffed our MIME type (i.e. we're a
// multipart/x-mixed-replace image), we have to be able to switch our image
// type and decoder.
// We always reinitialize for SVGs, because they have no way of
// reinitializing themselves.
2013-01-08 13:40:47 -08:00
if ( mContentType ! = newType | | newType . EqualsLiteral ( IMAGE_SVG_XML ) ) {
2012-09-06 15:05:23 -07:00
mContentType = newType ;
// If we've resniffed our MIME type and it changed, we need to create a
// new status tracker to give to the image, because we don't have one of
// our own any more.
2013-08-27 16:39:54 -07:00
if ( resniffMimeType ) {
2012-09-06 15:05:23 -07:00
NS_ABORT_IF_FALSE ( mIsMultiPartChannel , " Resniffing a non-multipart image " ) ;
2012-12-17 14:05:18 -08:00
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > freshTracker = new imgStatusTracker ( nullptr ) ;
nsRefPtr < imgStatusTracker > oldStatusTracker = GetStatusTracker ( ) ;
freshTracker - > AdoptConsumers ( oldStatusTracker ) ;
mStatusTracker = freshTracker . forget ( ) ;
2012-09-06 15:05:23 -07:00
}
2007-03-22 10:30:00 -07:00
2013-09-28 11:28:42 -07:00
SetProperties ( chan ) ;
2012-09-06 15:05:23 -07:00
2012-10-29 16:32:10 -07:00
LOG_MSG_WITH_PARAM ( GetImgLog ( ) , " imgRequest::OnDataAvailable " , " content type " , mContentType . get ( ) ) ;
2012-09-06 15:05:23 -07:00
2013-09-28 11:28:42 -07:00
// XXX If server lied about mimetype and it's SVG, we may need to copy
// the data and dispatch back to the main thread, AND tell the channel to
// dispatch there in the future.
2012-12-17 14:05:18 -08:00
// Now we can create a new image to hold the data. If we don't have a decoder
2012-09-06 15:05:23 -07:00
// for this mimetype we'll find out about it here.
2012-12-19 13:28:54 -08:00
mImage = ImageFactory : : CreateImage ( aRequest , mStatusTracker , mContentType ,
2013-01-04 19:55:23 -08:00
mURI , mIsMultiPartChannel ,
static_cast < uint32_t > ( mInnerWindowId ) ) ;
2012-12-14 15:42:18 -08:00
2012-12-19 13:28:54 -08:00
// Release our copy of the status tracker since the image owns it now.
mStatusTracker = nullptr ;
2012-12-17 14:05:18 -08:00
// Notify listeners that we have an image.
// XXX(seth): The name of this notification method is pretty misleading.
2013-09-28 11:28:44 -07:00
nsRefPtr < imgStatusTracker > statusTracker = GetStatusTracker ( ) ;
statusTracker - > OnDataAvailable ( ) ;
2012-09-06 15:05:23 -07:00
2012-12-17 14:05:18 -08:00
if ( mImage - > HasError ( ) & & ! mIsMultiPartChannel ) { // Probably bad mimetype
// We allow multipart images to fail to initialize without cancelling the
// load because subsequent images might be fine; thus only single part
// images end up here.
this - > Cancel ( NS_ERROR_FAILURE ) ;
2012-09-06 15:05:23 -07:00
return NS_BINDING_ABORTED ;
}
2013-09-28 11:28:44 -07:00
NS_ABORT_IF_FALSE ( statusTracker - > HasImage ( ) , " Status tracker should have an image! " ) ;
2012-12-17 14:05:18 -08:00
NS_ABORT_IF_FALSE ( mImage , " imgRequest should have an image! " ) ;
2010-06-25 11:21:40 -07:00
2012-12-17 14:05:18 -08:00
if ( mDecodeRequested )
mImage - > StartDecoding ( ) ;
2009-09-15 17:33:14 -07:00
}
2007-03-22 10:30:00 -07:00
}
2012-12-17 14:05:18 -08:00
// Notify the image that it has new data.
rv = mImage - > OnImageDataAvailable ( aRequest , ctxt , inStr , sourceOffset , count ) ;
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) ) {
2012-10-29 16:32:10 -07:00
PR_LOG ( GetImgLog ( ) , PR_LOG_WARNING ,
2009-09-12 15:44:18 -07:00
( " [this=%p] imgRequest::OnDataAvailable -- "
2010-08-13 21:09:51 -07:00
" copy to RasterImage failed \n " , this ) ) ;
2007-03-22 10:30:00 -07:00
this - > Cancel ( NS_IMAGELIB_ERROR_FAILURE ) ;
return NS_BINDING_ABORTED ;
}
return NS_OK ;
}
2013-09-28 11:28:42 -07:00
class SetPropertiesEvent : public nsRunnable
{
public :
SetPropertiesEvent ( imgRequest * aImgRequest , nsIChannel * aChan )
: mImgRequest ( aImgRequest )
, mChan ( aChan )
{
MOZ_ASSERT ( ! NS_IsMainThread ( ) , " Should be created off the main thread " ) ;
MOZ_ASSERT ( aImgRequest , " aImgRequest cannot be null " ) ;
}
NS_IMETHOD Run ( )
{
MOZ_ASSERT ( NS_IsMainThread ( ) , " Should run on the main thread only " ) ;
MOZ_ASSERT ( mImgRequest , " mImgRequest cannot be null " ) ;
mImgRequest - > SetProperties ( mChan ) ;
return NS_OK ;
}
private :
nsRefPtr < imgRequest > mImgRequest ;
nsCOMPtr < nsIChannel > mChan ;
} ;
void
imgRequest : : SetProperties ( nsIChannel * aChan )
{
// Force execution on main thread since some property objects are non
// threadsafe.
if ( ! NS_IsMainThread ( ) ) {
NS_DispatchToMainThread ( new SetPropertiesEvent ( this , aChan ) ) ;
return ;
}
/* set our mimetype as a property */
nsCOMPtr < nsISupportsCString > contentType ( do_CreateInstance ( " @mozilla.org/supports-cstring;1 " ) ) ;
if ( contentType ) {
contentType - > SetData ( mContentType ) ;
mProperties - > Set ( " type " , contentType ) ;
}
/* set our content disposition as a property */
nsAutoCString disposition ;
if ( aChan ) {
aChan - > GetContentDispositionHeader ( disposition ) ;
}
if ( ! disposition . IsEmpty ( ) ) {
nsCOMPtr < nsISupportsCString > contentDisposition ( do_CreateInstance ( " @mozilla.org/supports-cstring;1 " ) ) ;
if ( contentDisposition ) {
contentDisposition - > SetData ( disposition ) ;
mProperties - > Set ( " content-disposition " , contentDisposition ) ;
}
}
}
2007-03-22 10:30:00 -07:00
static NS_METHOD sniff_mimetype_callback ( nsIInputStream * in ,
2012-09-06 15:05:23 -07:00
void * data ,
2007-03-22 10:30:00 -07:00
const char * fromRawSegment ,
2012-08-22 08:56:38 -07:00
uint32_t toOffset ,
uint32_t count ,
uint32_t * writeCount )
2007-03-22 10:30:00 -07:00
{
2012-09-06 15:05:23 -07:00
mimetype_closure * closure = static_cast < mimetype_closure * > ( data ) ;
2007-03-22 10:30:00 -07:00
2012-09-06 15:05:23 -07:00
NS_ASSERTION ( closure , " closure is null! " ) ;
2007-03-22 10:30:00 -07:00
if ( count > 0 )
2012-11-20 16:08:06 -08:00
imgLoader : : GetMimeTypeFromContent ( fromRawSegment , count , * closure - > newType ) ;
2007-03-22 10:30:00 -07:00
* writeCount = 0 ;
return NS_ERROR_FAILURE ;
}
2009-09-12 15:44:18 -07:00
2008-12-22 14:20:46 -08:00
/** nsIInterfaceRequestor methods **/
NS_IMETHODIMP
imgRequest : : GetInterface ( const nsIID & aIID , void * * aResult )
{
if ( ! mPrevChannelSink | | aIID . Equals ( NS_GET_IID ( nsIChannelEventSink ) ) )
return QueryInterface ( aIID , aResult ) ;
2013-03-29 13:14:19 -07:00
NS_ASSERTION ( mPrevChannelSink ! = this ,
2008-12-22 14:20:46 -08:00
" Infinite recursion - don't keep track of channel sinks that are us! " ) ;
return mPrevChannelSink - > GetInterface ( aIID , aResult ) ;
}
/** nsIChannelEventSink methods **/
NS_IMETHODIMP
2010-08-04 19:15:55 -07:00
imgRequest : : AsyncOnChannelRedirect ( nsIChannel * oldChannel ,
2012-08-22 08:56:38 -07:00
nsIChannel * newChannel , uint32_t flags ,
2010-08-04 19:15:55 -07:00
nsIAsyncVerifyRedirectCallback * callback )
2008-12-22 14:20:46 -08:00
{
2010-08-04 19:15:55 -07:00
NS_ASSERTION ( mRequest & & mChannel , " Got a channel redirect after we nulled out mRequest! " ) ;
2008-12-22 14:20:46 -08:00
NS_ASSERTION ( mChannel = = oldChannel , " Got a channel redirect for an unknown channel! " ) ;
NS_ASSERTION ( newChannel , " Got a redirect to a NULL channel! " ) ;
2011-07-01 10:03:33 -07:00
SetCacheValidation ( mCacheEntry , oldChannel ) ;
2010-08-04 19:15:55 -07:00
// Prepare for callback
mRedirectCallback = callback ;
mNewRedirectChannel = newChannel ;
2008-12-22 14:20:46 -08:00
nsCOMPtr < nsIChannelEventSink > sink ( do_GetInterface ( mPrevChannelSink ) ) ;
if ( sink ) {
2010-08-04 19:15:55 -07:00
nsresult rv = sink - > AsyncOnChannelRedirect ( oldChannel , newChannel , flags ,
this ) ;
if ( NS_FAILED ( rv ) ) {
2012-07-30 07:20:58 -07:00
mRedirectCallback = nullptr ;
mNewRedirectChannel = nullptr ;
2010-08-04 19:15:55 -07:00
}
return rv ;
2008-12-22 14:20:46 -08:00
}
2011-07-01 10:03:30 -07:00
2010-08-04 19:15:55 -07:00
( void ) OnRedirectVerifyCallback ( NS_OK ) ;
return NS_OK ;
}
2008-12-22 14:20:46 -08:00
2010-08-04 19:15:55 -07:00
NS_IMETHODIMP
imgRequest : : OnRedirectVerifyCallback ( nsresult result )
{
NS_ASSERTION ( mRedirectCallback , " mRedirectCallback not set in callback " ) ;
NS_ASSERTION ( mNewRedirectChannel , " mNewRedirectChannel not set in callback " ) ;
2011-07-01 10:03:30 -07:00
2010-08-04 19:15:55 -07:00
if ( NS_FAILED ( result ) ) {
mRedirectCallback - > OnRedirectVerifyCallback ( result ) ;
2012-07-30 07:20:58 -07:00
mRedirectCallback = nullptr ;
mNewRedirectChannel = nullptr ;
2010-08-04 19:15:55 -07:00
return NS_OK ;
}
mChannel = mNewRedirectChannel ;
2011-06-09 14:11:57 -07:00
mTimedChannel = do_QueryInterface ( mChannel ) ;
2012-07-30 07:20:58 -07:00
mNewRedirectChannel = nullptr ;
2008-12-22 14:20:46 -08:00
2011-07-01 10:03:32 -07:00
# if defined(PR_LOGGING)
2012-09-01 19:35:17 -07:00
nsAutoCString oldspec ;
2011-07-01 10:03:40 -07:00
if ( mCurrentURI )
mCurrentURI - > GetSpec ( oldspec ) ;
2012-10-29 16:32:10 -07:00
LOG_MSG_WITH_PARAM ( GetImgLog ( ) , " imgRequest::OnChannelRedirect " , " old " , oldspec . get ( ) ) ;
2011-07-01 10:03:32 -07:00
# endif
2009-03-17 14:07:16 -07:00
2010-02-11 13:59:00 -08:00
// make sure we have a protocol that returns data rather than opens
// an external application, e.g. mailto:
2011-07-01 10:03:40 -07:00
mChannel - > GetURI ( getter_AddRefs ( mCurrentURI ) ) ;
2011-09-28 23:19:26 -07:00
bool doesNotReturnData = false ;
2010-08-04 19:15:55 -07:00
nsresult rv =
2011-07-01 10:03:40 -07:00
NS_URIChainHasFlags ( mCurrentURI , nsIProtocolHandler : : URI_DOES_NOT_RETURN_DATA ,
2010-08-04 19:15:55 -07:00
& doesNotReturnData ) ;
if ( NS_SUCCEEDED ( rv ) & & doesNotReturnData )
rv = NS_ERROR_ABORT ;
if ( NS_FAILED ( rv ) ) {
mRedirectCallback - > OnRedirectVerifyCallback ( rv ) ;
2012-07-30 07:20:58 -07:00
mRedirectCallback = nullptr ;
2010-08-04 19:15:55 -07:00
return NS_OK ;
}
2010-02-11 13:59:00 -08:00
2010-08-04 19:15:55 -07:00
mRedirectCallback - > OnRedirectVerifyCallback ( NS_OK ) ;
2012-07-30 07:20:58 -07:00
mRedirectCallback = nullptr ;
2010-08-04 19:15:55 -07:00
return NS_OK ;
2008-12-22 14:20:46 -08:00
}