зеркало из https://github.com/mozilla/gecko-dev.git
Bug 559200 - e10s HTTP: Buffer incoming IPDL necko messages. r=dougt
--HG-- extra : rebase_source : cfee85b987fb60fac9a3536774f63139000e797f
This commit is contained in:
Родитель
73cbe59a21
Коммит
caccfbd455
|
@ -49,6 +49,14 @@
|
|||
#include "nsMimeTypes.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
using mozilla::MutexAutoLock;
|
||||
|
||||
class Callback
|
||||
{
|
||||
public:
|
||||
virtual bool Run() = 0;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
|
@ -59,6 +67,8 @@ HttpChannelChild::HttpChannelChild()
|
|||
, mCacheExpirationTime(nsICache::NO_EXPIRATION_TIME)
|
||||
, mState(HCC_NEW)
|
||||
, mIPCOpen(false)
|
||||
, mShouldBuffer(true)
|
||||
, mBufferLock("mozilla.net.HttpChannelChild.mBufferLock")
|
||||
{
|
||||
LOG(("Creating HttpChannelChild @%x\n", this));
|
||||
}
|
||||
|
@ -146,13 +156,56 @@ HttpChannelChild::RecvOnStartRequest(const nsHttpResponseHead& responseHead,
|
|||
if (mResponseHead)
|
||||
SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
|
||||
|
||||
return true;
|
||||
MutexAutoLock lock(mBufferLock);
|
||||
bool ret = true;
|
||||
nsCOMPtr<nsIHttpChannel> kungFuDeathGrip(this);
|
||||
for (PRUint32 i = 0; i < mBufferedCallbacks.Length(); i++) {
|
||||
ret = mBufferedCallbacks[i]->Run();
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
mBufferedCallbacks.Clear();
|
||||
mShouldBuffer = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
class DataAvailableEvent : public Callback
|
||||
{
|
||||
public:
|
||||
DataAvailableEvent(HttpChannelChild* child,
|
||||
const nsCString& data,
|
||||
const PRUint32& offset,
|
||||
const PRUint32& count)
|
||||
: mChild(child)
|
||||
, mData(data)
|
||||
, mOffset(offset)
|
||||
, mCount(count) {}
|
||||
|
||||
bool Run()
|
||||
{
|
||||
return mChild->OnDataAvailable(mData, mOffset, mCount);
|
||||
}
|
||||
|
||||
private:
|
||||
HttpChannelChild* mChild;
|
||||
nsCString mData;
|
||||
PRUint32 mOffset;
|
||||
PRUint32 mCount;
|
||||
};
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvOnDataAvailable(const nsCString& data,
|
||||
const PRUint32& offset,
|
||||
const PRUint32& count)
|
||||
{
|
||||
DataAvailableEvent* event = new DataAvailableEvent(this, data, offset, count);
|
||||
return BufferOrDispatch(event);
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::OnDataAvailable(const nsCString& data,
|
||||
const PRUint32& offset,
|
||||
const PRUint32& count)
|
||||
{
|
||||
LOG(("HttpChannelChild::RecvOnDataAvailable [this=%x]\n", this));
|
||||
|
||||
|
@ -182,8 +235,33 @@ HttpChannelChild::RecvOnDataAvailable(const nsCString& data,
|
|||
return true;
|
||||
}
|
||||
|
||||
class StopRequestEvent : public Callback
|
||||
{
|
||||
public:
|
||||
StopRequestEvent(HttpChannelChild* child,
|
||||
const nsresult& statusCode)
|
||||
: mChild(child)
|
||||
, mStatusCode(statusCode) {}
|
||||
|
||||
bool Run()
|
||||
{
|
||||
return mChild->OnStopRequest(mStatusCode);
|
||||
}
|
||||
|
||||
private:
|
||||
HttpChannelChild* mChild;
|
||||
nsresult mStatusCode;
|
||||
};
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvOnStopRequest(const nsresult& statusCode)
|
||||
{
|
||||
StopRequestEvent* event = new StopRequestEvent(this, statusCode);
|
||||
return BufferOrDispatch(event);
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::OnStopRequest(const nsresult& statusCode)
|
||||
{
|
||||
LOG(("HttpChannelChild::RecvOnStopRequest [this=%x status=%u]\n",
|
||||
this, statusCode));
|
||||
|
@ -206,9 +284,37 @@ HttpChannelChild::RecvOnStopRequest(const nsresult& statusCode)
|
|||
return true;
|
||||
}
|
||||
|
||||
class ProgressEvent : public Callback
|
||||
{
|
||||
public:
|
||||
ProgressEvent(HttpChannelChild* child,
|
||||
const PRUint64& progress,
|
||||
const PRUint64& progressMax)
|
||||
: mChild(child)
|
||||
, mProgress(progress)
|
||||
, mProgressMax(progressMax) {}
|
||||
|
||||
bool Run()
|
||||
{
|
||||
return mChild->OnProgress(mProgress, mProgressMax);
|
||||
}
|
||||
|
||||
private:
|
||||
HttpChannelChild* mChild;
|
||||
PRUint64 mProgress, mProgressMax;
|
||||
};
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvOnProgress(const PRUint64& progress,
|
||||
const PRUint64& progressMax)
|
||||
{
|
||||
ProgressEvent* event = new ProgressEvent(this, progress, progressMax);
|
||||
return BufferOrDispatch(event);
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::OnProgress(const PRUint64& progress,
|
||||
const PRUint64& progressMax)
|
||||
{
|
||||
LOG(("HttpChannelChild::RecvOnProgress [this=%p progress=%llu/%llu]\n",
|
||||
this, progress, progressMax));
|
||||
|
@ -230,9 +336,38 @@ HttpChannelChild::RecvOnProgress(const PRUint64& progress,
|
|||
return true;
|
||||
}
|
||||
|
||||
class StatusEvent : public Callback
|
||||
{
|
||||
public:
|
||||
StatusEvent(HttpChannelChild* child,
|
||||
const nsresult& status,
|
||||
const nsString& statusArg)
|
||||
: mChild(child)
|
||||
, mStatus(status)
|
||||
, mStatusArg(statusArg) {}
|
||||
|
||||
bool Run()
|
||||
{
|
||||
return mChild->OnStatus(mStatus, mStatusArg);
|
||||
}
|
||||
|
||||
private:
|
||||
HttpChannelChild* mChild;
|
||||
nsresult mStatus;
|
||||
nsString mStatusArg;
|
||||
};
|
||||
|
||||
bool
|
||||
HttpChannelChild::RecvOnStatus(const nsresult& status,
|
||||
const nsString& statusArg)
|
||||
{
|
||||
StatusEvent* event = new StatusEvent(this, status, statusArg);
|
||||
return BufferOrDispatch(event);
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::OnStatus(const nsresult& status,
|
||||
const nsString& statusArg)
|
||||
{
|
||||
LOG(("HttpChannelChild::RecvOnStatus [this=%p status=%x]\n", this, status));
|
||||
|
||||
|
@ -250,6 +385,25 @@ HttpChannelChild::RecvOnStatus(const nsresult& status,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HttpChannelChild::BufferOrDispatch(Callback* callback)
|
||||
{
|
||||
if (mShouldBuffer) {
|
||||
MutexAutoLock lock(mBufferLock);
|
||||
// If we can't grab the lock immediately, that means we're currently
|
||||
// emptying the buffer. Therefore, the following condition should now
|
||||
// be false, and we can resume immediate message processing.
|
||||
if (mShouldBuffer) {
|
||||
mBufferedCallbacks.AppendElement(callback);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = callback->Run();
|
||||
delete callback;
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HttpChannelChild::nsIRequest
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -58,6 +58,10 @@
|
|||
#include "nsIResumableChannel.h"
|
||||
#include "nsIProxiedChannel.h"
|
||||
#include "nsITraceableChannel.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
class nsIRunnable;
|
||||
class Callback;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
@ -143,6 +147,29 @@ private:
|
|||
// FIXME: replace with IPDL states (bug 536319)
|
||||
enum HttpChannelChildState mState;
|
||||
bool mIPCOpen;
|
||||
|
||||
// Workaround for Necko re-entrancy dangers. We buffer all messages
|
||||
// received until OnStartRequest completes.
|
||||
nsTArray<nsAutoPtr<Callback> > mBufferedCallbacks;
|
||||
bool mShouldBuffer;
|
||||
mozilla::Mutex mBufferLock;
|
||||
|
||||
bool BufferOrDispatch(Callback* callback);
|
||||
|
||||
// This class does not actually implement the stream listener interface.
|
||||
// These functions actually perform the actions associated with the
|
||||
// corresponding IPDL receivers above.
|
||||
bool OnDataAvailable(const nsCString& data,
|
||||
const PRUint32& offset,
|
||||
const PRUint32& count);
|
||||
bool OnStopRequest(const nsresult& statusCode);
|
||||
bool OnProgress(const PRUint64& progress, const PRUint64& progressMax);
|
||||
bool OnStatus(const nsresult& status, const nsString& statusArg);
|
||||
|
||||
friend class StopRequestEvent;
|
||||
friend class DataAvailableEvent;
|
||||
friend class ProgressEvent;
|
||||
friend class StatusEvent;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
Загрузка…
Ссылка в новой задаче