Bug 637339 - Improve error handling in HttpChannelChild. r=jduell

This commit is contained in:
Nick Hurley 2011-05-13 18:02:07 -07:00
Родитель 5921cf64d1
Коммит ea31e2b888
8 изменённых файлов: 220 добавлений и 152 удалений

Просмотреть файл

@ -78,6 +78,7 @@ HttpBaseChannel::HttpBaseChannel()
, mChooseApplicationCache(PR_FALSE)
, mLoadedFromApplicationCache(PR_FALSE)
, mChannelIsForDownload(PR_FALSE)
, mSuspendCount(0)
, mRedirectedCachekeys(nsnull)
{
LOG(("Creating HttpBaseChannel @%x\n", this));
@ -1311,6 +1312,28 @@ HttpBaseChannel::GetEntityID(nsACString& aEntityID)
// HttpBaseChannel helpers
//-----------------------------------------------------------------------------
void
HttpBaseChannel::DoNotifyListener()
{
// Make sure mIsPending is set to PR_FALSE. At this moment we are done from
// the point of view of our consumer and we have to report our self
// as not-pending.
if (mListener) {
mListener->OnStartRequest(this, mListenerContext);
mIsPending = PR_FALSE;
mListener->OnStopRequest(this, mListenerContext, mStatus);
mListener = 0;
mListenerContext = 0;
} else {
mIsPending = PR_FALSE;
}
// We have to make sure to drop the reference to the callbacks too
mCallbacks = nsnull;
mProgressSink = nsnull;
DoNotifyListenerCleanup();
}
void
HttpBaseChannel::AddCookiesToRequest()
{

Просмотреть файл

@ -60,6 +60,7 @@
#include "nsIApplicationCache.h"
#include "nsIResumableChannel.h"
#include "mozilla/net/NeckoCommon.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace net {
@ -204,7 +205,14 @@ public:
const PRNetAddr& GetSelfAddr() { return mSelfAddr; }
const PRNetAddr& GetPeerAddr() { return mPeerAddr; }
public: /* Necko internal use only... */
protected:
// Handle notifying listener, removing from loadgroup if request failed.
void DoNotifyListener();
virtual void DoNotifyListenerCleanup() = 0;
nsresult ApplyContentConversions();
void AddCookiesToRequest();
@ -269,10 +277,95 @@ protected:
PRUint32 mLoadedFromApplicationCache : 1;
PRUint32 mChannelIsForDownload : 1;
// Current suspension depth for this channel object
PRUint32 mSuspendCount;
nsTArray<nsCString> *mRedirectedCachekeys;
};
// Share some code while working around C++'s absurd inability to handle casting
// of member functions between base/derived types.
// - We want to store member function pointer to call at resume time, but one
// such function--HandleAsyncAbort--we want to share between the
// nsHttpChannel/HttpChannelChild. Can't define it in base class, because
// then we'd have to cast member function ptr between base/derived class
// types. Sigh...
template <class T>
class HttpAsyncAborter
{
public:
HttpAsyncAborter(T *derived) : mThis(derived), mCallOnResume(0) {}
// Aborts channel: calls OnStart/Stop with provided status, removes channel
// from loadGroup.
nsresult AsyncAbort(nsresult status);
// Does most the actual work.
void HandleAsyncAbort();
// AsyncCall calls a member function asynchronously (via an event).
// retval isn't refcounted and is set only when event was successfully
// posted, the event is returned for the purpose of cancelling when needed
nsresult AsyncCall(void (T::*funcPtr)(),
nsRunnableMethod<T> **retval = nsnull);
private:
T *mThis;
protected:
// Function to be called at resume time
void (T::* mCallOnResume)(void);
};
template <class T>
nsresult HttpAsyncAborter<T>::AsyncAbort(nsresult status)
{
LOG(("HttpAsyncAborter::AsyncAbort [this=%p status=%x]\n", mThis, status));
mThis->mStatus = status;
mThis->mIsPending = PR_FALSE;
// if this fails? Callers ignore our return value anyway....
return AsyncCall(&T::HandleAsyncAbort);
}
// Each subclass needs to define its own version of this (which just calls this
// base version), else we wind up casting base/derived member function ptrs
template <class T>
inline void HttpAsyncAborter<T>::HandleAsyncAbort()
{
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mThis->mSuspendCount) {
LOG(("Waiting until resume to do async notification [this=%p]\n",
mThis));
mCallOnResume = &T::HandleAsyncAbort;
return;
}
mThis->DoNotifyListener();
// finally remove ourselves from the load group.
if (mThis->mLoadGroup)
mThis->mLoadGroup->RemoveRequest(mThis, nsnull, mThis->mStatus);
}
template <class T>
nsresult HttpAsyncAborter<T>::AsyncCall(void (T::*funcPtr)(),
nsRunnableMethod<T> **retval)
{
nsresult rv;
nsRefPtr<nsRunnableMethod<T> > event = NS_NewRunnableMethod(mThis, funcPtr);
rv = NS_DispatchToCurrentThread(event);
if (NS_SUCCEEDED(rv) && retval) {
*retval = event;
}
return rv;
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -59,12 +59,12 @@ namespace net {
//-----------------------------------------------------------------------------
HttpChannelChild::HttpChannelChild()
: ChannelEventQueue<HttpChannelChild>(this)
: HttpAsyncAborter<HttpChannelChild>(this)
, ChannelEventQueue<HttpChannelChild>(this)
, mIsFromCache(PR_FALSE)
, mCacheEntryAvailable(PR_FALSE)
, mCacheExpirationTime(nsICache::NO_EXPIRATION_TIME)
, mSendResumeAt(false)
, mSuspendCount(0)
, mIPCOpen(false)
, mKeptAlive(false)
{
@ -573,53 +573,53 @@ HttpChannelChild::OnStatus(const nsresult& status)
}
}
class CancelEvent : public ChannelEvent
class FailedAsyncOpenEvent : public ChannelEvent
{
public:
CancelEvent(HttpChannelChild* child, const nsresult& status)
FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status)
: mChild(child)
, mStatus(status) {}
void Run() { mChild->OnCancel(mStatus); }
void Run() { mChild->FailedAsyncOpen(mStatus); }
private:
HttpChannelChild* mChild;
nsresult mStatus;
};
bool
HttpChannelChild::RecvCancelEarly(const nsresult& status)
HttpChannelChild::RecvFailedAsyncOpen(const nsresult& status)
{
if (ShouldEnqueue()) {
EnqueueEvent(new CancelEvent(this, status));
EnqueueEvent(new FailedAsyncOpenEvent(this, status));
} else {
OnCancel(status);
FailedAsyncOpen(status);
}
return true;
}
// We need to have an implementation of this function just so that we can keep
// all references to mCallOnResume of type HttpChannelChild: it's not OK in C++
// to set a member function ptr to a base class function.
void
HttpChannelChild::OnCancel(const nsresult& status)
HttpChannelChild::HandleAsyncAbort()
{
LOG(("HttpChannelChild::OnCancel [this=%p status=%x]\n", this, status));
HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
}
if (mCanceled)
return;
void
HttpChannelChild::FailedAsyncOpen(const nsresult& status)
{
LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%x]\n", this, status));
mCanceled = true;
mStatus = status;
mIsPending = PR_FALSE;
// We're already being called from IPDL, therefore already "async"
HandleAsyncAbort();
}
mIsPending = false;
if (mLoadGroup)
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
if (mListener) {
mListener->OnStartRequest(this, mListenerContext);
mListener->OnStopRequest(this, mListenerContext, mStatus);
}
mListener = NULL;
mListenerContext = NULL;
void
HttpChannelChild::DoNotifyListenerCleanup()
{
if (mIPCOpen)
PHttpChannelChild::Send__delete__(this);
}
@ -873,7 +873,10 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
if (NS_SUCCEEDED(result))
gHttpHandler->OnModifyRequest(newHttpChannel);
return SendRedirect2Verify(result, *headerTuples);
if (mIPCOpen)
SendRedirect2Verify(result, *headerTuples);
return NS_OK;
}
//-----------------------------------------------------------------------------
@ -903,23 +906,37 @@ HttpChannelChild::Suspend()
return NS_OK;
}
void
HttpChannelChild::CompleteResume()
{
if (mCallOnResume) {
(this->*mCallOnResume)();
mCallOnResume = 0;
}
FlushEventQueue();
}
NS_IMETHODIMP
HttpChannelChild::Resume()
{
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
nsresult rv = NS_OK;
SendResume();
mSuspendCount--;
if (!mSuspendCount) {
// If we were suspended outside of an event handler (bug 595972) we'll
// consider ourselves unqueued. This is a legal state of affairs but
// FlushEventQueue() can't easily ensure this fact, so we'll do some
// fudging to set the invariants correctly.
// fudging to set the invariants correctly.
if (mQueuePhase == PHASE_UNQUEUED)
mQueuePhase = PHASE_FINISHED_QUEUEING;
FlushEventQueue();
rv = AsyncCall(&HttpChannelChild::CompleteResume);
}
return NS_OK;
return rv;
}
//-----------------------------------------------------------------------------
@ -982,10 +999,7 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
// We may have been canceled already, either by on-modify-request
// listeners or by load group observers; in that case, don't create IPDL
// connection. See nsHttpChannel::AsyncOpen().
// Clear mCanceled here, or we will bail out at top of OnCancel().
mCanceled = false;
OnCancel(mStatus);
AsyncAbort(mStatus);
return NS_OK;
}

Просмотреть файл

@ -69,6 +69,7 @@ namespace net {
class HttpChannelChild : public PHttpChannelChild
, public HttpBaseChannel
, public HttpAsyncAborter<HttpChannelChild>
, public nsICacheInfoChannel
, public nsIProxiedChannel
, public nsITraceableChannel
@ -146,7 +147,7 @@ protected:
bool RecvOnStopRequest(const nsresult& statusCode);
bool RecvOnProgress(const PRUint64& progress, const PRUint64& progressMax);
bool RecvOnStatus(const nsresult& status);
bool RecvCancelEarly(const nsresult& status);
bool RecvFailedAsyncOpen(const nsresult& status);
bool RecvRedirect1Begin(const PRUint32& newChannel,
const URI& newURI,
const PRUint32& redirectFlags,
@ -157,6 +158,7 @@ protected:
bool RecvDeleteSelf();
bool GetAssociatedContentSecurity(nsIAssociatedContentSecurity** res = nsnull);
virtual void DoNotifyListenerCleanup();
private:
RequestHeaderTuples mRequestHeaders;
@ -171,8 +173,6 @@ private:
// If ResumeAt is called before AsyncOpen, we need to send extra data upstream
bool mSendResumeAt;
// Current suspension depth for this channel object
PRUint32 mSuspendCount;
bool mIPCOpen;
bool mKeptAlive;
@ -196,7 +196,8 @@ private:
void OnStopRequest(const nsresult& statusCode);
void OnProgress(const PRUint64& progress, const PRUint64& progressMax);
void OnStatus(const nsresult& status);
void OnCancel(const nsresult& status);
void FailedAsyncOpen(const nsresult& status);
void HandleAsyncAbort();
void Redirect1Begin(const PRUint32& newChannelId,
const URI& newUri,
const PRUint32& redirectFlags,
@ -204,15 +205,19 @@ private:
void Redirect3Complete();
void DeleteSelf();
// Called asynchronously from Resume: continues any pending calls into client.
void CompleteResume();
friend class StartRequestEvent;
friend class StopRequestEvent;
friend class TransportAndDataEvent;
friend class ProgressEvent;
friend class StatusEvent;
friend class CancelEvent;
friend class FailedAsyncOpenEvent;
friend class Redirect1Event;
friend class Redirect3Event;
friend class DeleteSelfEvent;
friend class HttpAsyncAborter<HttpChannelChild>;
};
//-----------------------------------------------------------------------------

Просмотреть файл

@ -157,11 +157,11 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
if (NS_FAILED(rv))
return SendCancelEarly(rv);
return SendFailedAsyncOpen(rv);
rv = NS_NewChannel(getter_AddRefs(mChannel), uri, ios, nsnull, nsnull, loadFlags);
if (NS_FAILED(rv))
return SendCancelEarly(rv);
return SendFailedAsyncOpen(rv);
nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
@ -239,7 +239,7 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
rv = httpChan->AsyncOpen(channelListener, nsnull);
if (NS_FAILED(rv))
return SendCancelEarly(rv);
return SendFailedAsyncOpen(rv);
return true;
}
@ -259,8 +259,10 @@ HttpChannelParent::RecvConnectChannel(const PRUint32& channelId)
bool
HttpChannelParent::RecvSetPriority(const PRUint16& priority)
{
nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
httpChan->SetPriority(priority);
if (mChannel) {
nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
httpChan->SetPriority(priority);
}
nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
do_QueryInterface(mRedirectChannel);
@ -273,14 +275,18 @@ HttpChannelParent::RecvSetPriority(const PRUint16& priority)
bool
HttpChannelParent::RecvSuspend()
{
mChannel->Suspend();
if (mChannel) {
mChannel->Suspend();
}
return true;
}
bool
HttpChannelParent::RecvResume()
{
mChannel->Resume();
if (mChannel) {
mChannel->Resume();
}
return true;
}

Просмотреть файл

@ -154,7 +154,7 @@ child:
// Used to cancel child channel if we hit errors during creating and
// AsyncOpen of nsHttpChannel on the parent.
CancelEarly(nsresult status);
FailedAsyncOpen(nsresult status);
// Called to initiate content channel redirect, starts talking to sinks
// on the content process and reports result via Redirect2Verify above

Просмотреть файл

@ -110,14 +110,13 @@ AutoRedirectVetoNotifier::ReportRedirectResult(bool succeeded)
//-----------------------------------------------------------------------------
nsHttpChannel::nsHttpChannel()
: mLogicalOffset(0)
: HttpAsyncAborter<nsHttpChannel>(this)
, mLogicalOffset(0)
, mCacheAccess(0)
, mPostID(0)
, mRequestTime(0)
, mOnCacheEntryAvailableCallback(nsnull)
, mAsyncCacheOpen(PR_FALSE)
, mPendingAsyncCallOnResume(nsnull)
, mSuspendCount(0)
, mCachedContentIsValid(PR_FALSE)
, mCachedContentIsPartial(PR_FALSE)
, mTransactionReplaced(PR_FALSE)
@ -171,22 +170,6 @@ nsHttpChannel::Init(nsIURI *uri,
// nsHttpChannel <private>
//-----------------------------------------------------------------------------
nsresult
nsHttpChannel::AsyncCall(nsAsyncCallback funcPtr,
nsRunnableMethod<nsHttpChannel> **retval)
{
nsresult rv;
nsRefPtr<nsRunnableMethod<nsHttpChannel> > event =
NS_NewRunnableMethod(this, funcPtr);
rv = NS_DispatchToCurrentThread(event);
if (NS_SUCCEEDED(rv) && retval) {
*retval = event;
}
return rv;
}
nsresult
nsHttpChannel::Connect(PRBool firstTime)
{
@ -331,60 +314,9 @@ nsHttpChannel::Connect(PRBool firstTime)
return NS_OK;
}
// called when Connect fails
nsresult
nsHttpChannel::AsyncAbort(nsresult status)
{
LOG(("nsHttpChannel::AsyncAbort [this=%p status=%x]\n", this, status));
mStatus = status;
mIsPending = PR_FALSE;
nsresult rv = AsyncCall(&nsHttpChannel::HandleAsyncNotifyListener);
// And if that fails? Callers ignore our return value anyway....
// finally remove ourselves from the load group.
if (mLoadGroup)
mLoadGroup->RemoveRequest(this, nsnull, status);
return rv;
}
void
nsHttpChannel::HandleAsyncNotifyListener()
nsHttpChannel::DoNotifyListenerCleanup()
{
NS_PRECONDITION(!mPendingAsyncCallOnResume, "How did that happen?");
if (mSuspendCount) {
LOG(("Waiting until resume to do async notification [this=%p]\n",
this));
mPendingAsyncCallOnResume = &nsHttpChannel::HandleAsyncNotifyListener;
return;
}
DoNotifyListener();
}
void
nsHttpChannel::DoNotifyListener()
{
// Make sure mIsPending is set to PR_FALSE. At this moment we are done from
// the point of view of our consumer and we have to report our self
// as not-pending.
if (mListener) {
mListener->OnStartRequest(this, mListenerContext);
mIsPending = PR_FALSE;
mListener->OnStopRequest(this, mListenerContext, mStatus);
mListener = 0;
mListenerContext = 0;
}
else {
mIsPending = PR_FALSE;
}
// We have to make sure to drop the reference to the callbacks too
mCallbacks = nsnull;
mProgressSink = nsnull;
// We don't need this info anymore
CleanRedirectCacheChainIfNecessary();
}
@ -392,11 +324,11 @@ nsHttpChannel::DoNotifyListener()
void
nsHttpChannel::HandleAsyncRedirect()
{
NS_PRECONDITION(!mPendingAsyncCallOnResume, "How did that happen?");
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mSuspendCount) {
LOG(("Waiting until resume to do async redirect [this=%p]\n", this));
mPendingAsyncCallOnResume = &nsHttpChannel::HandleAsyncRedirect;
mCallOnResume = &nsHttpChannel::HandleAsyncRedirect;
return;
}
@ -450,12 +382,12 @@ nsHttpChannel::ContinueHandleAsyncRedirect(nsresult rv)
void
nsHttpChannel::HandleAsyncNotModified()
{
NS_PRECONDITION(!mPendingAsyncCallOnResume, "How did that happen?");
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mSuspendCount) {
LOG(("Waiting until resume to do async not-modified [this=%p]\n",
this));
mPendingAsyncCallOnResume = &nsHttpChannel::HandleAsyncNotModified;
mCallOnResume = &nsHttpChannel::HandleAsyncNotModified;
return;
}
@ -474,11 +406,11 @@ nsHttpChannel::HandleAsyncNotModified()
void
nsHttpChannel::HandleAsyncFallback()
{
NS_PRECONDITION(!mPendingAsyncCallOnResume, "How did that happen?");
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mSuspendCount) {
LOG(("Waiting until resume to do async fallback [this=%p]\n", this));
mPendingAsyncCallOnResume = &nsHttpChannel::HandleAsyncFallback;
mCallOnResume = &nsHttpChannel::HandleAsyncFallback;
return;
}
@ -1295,13 +1227,12 @@ nsHttpChannel::ProxyFailover()
void
nsHttpChannel::HandleAsyncReplaceWithProxy()
{
NS_PRECONDITION(!mPendingAsyncCallOnResume, "How did that happen?");
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mSuspendCount) {
LOG(("Waiting until resume to do async proxy replacement [this=%p]\n",
this));
mPendingAsyncCallOnResume =
&nsHttpChannel::HandleAsyncReplaceWithProxy;
mCallOnResume = &nsHttpChannel::HandleAsyncReplaceWithProxy;
return;
}
@ -1329,7 +1260,7 @@ nsHttpChannel::ContinueHandleAsyncReplaceWithProxy(nsresult status)
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
}
else if (NS_FAILED(status)) {
AsyncAbort(status);
AsyncAbort(status);
}
// Return NS_OK here, even it seems to be breaking the async function stack
@ -1344,11 +1275,11 @@ nsHttpChannel::ContinueHandleAsyncReplaceWithProxy(nsresult status)
void
nsHttpChannel::HandleAsyncRedirectChannelToHttps()
{
NS_PRECONDITION(!mPendingAsyncCallOnResume, "How did that happen?");
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
if (mSuspendCount) {
LOG(("Waiting until resume to do async redirect to https [this=%p]\n", this));
mPendingAsyncCallOnResume = &nsHttpChannel::HandleAsyncRedirectChannelToHttps;
mCallOnResume = &nsHttpChannel::HandleAsyncRedirectChannelToHttps;
return;
}
@ -1644,6 +1575,16 @@ nsHttpChannel::ResponseWouldVary()
return PR_FALSE;
}
// We need to have an implementation of this function just so that we can keep
// all references to mCallOnResume of type nsHttpChannel: it's not OK in C++
// to set a member function ptr to a base class function.
void
nsHttpChannel::HandleAsyncAbort()
{
HttpAsyncAborter<nsHttpChannel>::HandleAsyncAbort();
}
nsresult
nsHttpChannel::Hash(const char *buf, nsACString &hash)
{
@ -3591,9 +3532,9 @@ nsHttpChannel::Resume()
LOG(("nsHttpChannel::Resume [this=%p]\n", this));
if (--mSuspendCount == 0 && mPendingAsyncCallOnResume) {
nsresult rv = AsyncCall(mPendingAsyncCallOnResume);
mPendingAsyncCallOnResume = nsnull;
if (--mSuspendCount == 0 && mCallOnResume) {
nsresult rv = AsyncCall(mCallOnResume);
mCallOnResume = nsnull;
NS_ENSURE_SUCCESS(rv, rv);
}

Просмотреть файл

@ -75,6 +75,7 @@ using namespace mozilla::net;
//-----------------------------------------------------------------------------
class nsHttpChannel : public HttpBaseChannel
, public HttpAsyncAborter<nsHttpChannel>
, public nsIStreamListener
, public nsICachingChannel
, public nsICacheListener
@ -143,7 +144,6 @@ public:
NS_IMETHOD ResumeAt(PRUint64 startPos, const nsACString& entityID);
public: /* internal necko use only */
typedef void (nsHttpChannel:: *nsAsyncCallback)(void);
void InternalSetUploadStream(nsIInputStream *uploadStream)
{ mUploadStream = uploadStream; }
@ -162,18 +162,8 @@ public: /* internal necko use only */
private:
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
// AsyncCall may be used to call a member function asynchronously.
// retval isn't refcounted and is set only when event was successfully
// posted, the event is returned for the purpose of cancelling when needed
nsresult AsyncCall(nsAsyncCallback funcPtr,
nsRunnableMethod<nsHttpChannel> **retval = nsnull);
PRBool RequestIsConditional();
nsresult Connect(PRBool firstTime = PR_TRUE);
nsresult AsyncAbort(nsresult status);
// Send OnStartRequest/OnStopRequest to our listener, if any.
void HandleAsyncNotifyListener();
void DoNotifyListener();
nsresult SetupTransaction();
nsresult CallOnStartRequest();
nsresult ProcessResponse();
@ -189,6 +179,7 @@ private:
nsresult ProcessFallback(PRBool *waitingForRedirectCallback);
nsresult ContinueProcessFallback(nsresult);
PRBool ResponseWouldVary();
void HandleAsyncAbort();
nsresult ContinueOnStartRequest1(nsresult);
nsresult ContinueOnStartRequest2(nsresult);
@ -300,24 +291,16 @@ private:
// auth specific data
nsCOMPtr<nsIHttpChannelAuthProvider> mAuthProvider;
// Function pointer that can be set to indicate that we got suspended while
// waiting on an AsyncCall. When we get resumed we should AsyncCall this
// function.
nsAsyncCallback mPendingAsyncCallOnResume;
// Proxy info to replace with
nsCOMPtr<nsIProxyInfo> mTargetProxyInfo;
// Suspend counter. This is used if someone tries to suspend/resume us
// before we have either a cache pump or a transaction pump.
PRUint32 mSuspendCount;
// If the channel is associated with a cache, and the URI matched
// a fallback namespace, this will hold the key for the fallback
// cache entry.
nsCString mFallbackKey;
friend class AutoRedirectVetoNotifier;
friend class HttpAsyncAborter<nsHttpChannel>;
nsCOMPtr<nsIURI> mRedirectURI;
nsCOMPtr<nsIChannel> mRedirectChannel;
PRUint32 mRedirectType;
@ -354,6 +337,9 @@ private:
nsresult WaitForRedirectCallback();
void PushRedirectAsyncFunc(nsContinueRedirectionFunc func);
void PopRedirectAsyncFunc(nsContinueRedirectionFunc func);
protected:
virtual void DoNotifyListenerCleanup();
};
#endif // nsHttpChannel_h__