зеркало из https://github.com/mozilla/gecko-dev.git
Bug 637339 - Improve error handling in HttpChannelChild. r=jduell
This commit is contained in:
Родитель
5921cf64d1
Коммит
ea31e2b888
|
@ -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__
|
||||
|
|
Загрузка…
Ссылка в новой задаче