Bug 1201174 - For FTP - in case of divertToParent, it myst be possible to delay delivering of OnDataAv./OnStopR. r=jduell

This commit is contained in:
Dragana Damjanovic 2015-09-04 03:55:00 +02:00
parent 5210ab5781
commit af1c7c6f26
2 changed files with 160 additions and 13 deletions

View File

@ -55,6 +55,8 @@ FTPChannelParent::FTPChannelParent(const PBrowserOrId& aIframeEmbedding,
}
mObserver = new OfflineObserver(this);
mEventQ = new ChannelEventQueue(static_cast<nsIParentChannel*>(this));
}
FTPChannelParent::~FTPChannelParent()
@ -243,6 +245,32 @@ FTPChannelParent::RecvResume()
return true;
}
class FTPDivertDataAvailableEvent : public ChannelEvent
{
public:
FTPDivertDataAvailableEvent(FTPChannelParent* aParent,
const nsCString& data,
const uint64_t& offset,
const uint32_t& count)
: mParent(aParent)
, mData(data)
, mOffset(offset)
, mCount(count)
{
}
void Run()
{
mParent->DivertOnDataAvailable(mData, mOffset, mCount);
}
private:
FTPChannelParent* mParent;
nsCString mData;
uint64_t mOffset;
uint32_t mCount;
};
bool
FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
const uint64_t& offset,
@ -260,6 +288,35 @@ FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
return true;
}
if (mEventQ->ShouldEnqueue()) {
mEventQ->Enqueue(new FTPDivertDataAvailableEvent(this, data, offset,
count));
return true;
}
DivertOnDataAvailable(data, offset, count);
return true;
}
void
FTPChannelParent::DivertOnDataAvailable(const nsCString& data,
const uint64_t& offset,
const uint32_t& count)
{
LOG(("FTPChannelParent::DivertOnDataAvailable [this=%p]\n", this));
if (NS_WARN_IF(!mDivertingFromChild)) {
MOZ_ASSERT(mDivertingFromChild,
"Cannot DivertOnDataAvailable if diverting is not set!");
FailDiversion(NS_ERROR_UNEXPECTED);
return;
}
// Drop OnDataAvailables if the parent was canceled already.
if (NS_FAILED(mStatus)) {
return;
}
nsCOMPtr<nsIInputStream> stringStream;
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
count, NS_ASSIGNMENT_DEPEND);
@ -268,9 +325,11 @@ FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
mChannel->Cancel(rv);
}
mStatus = rv;
return true;
return;
}
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
rv = OnDataAvailable(mChannel, nullptr, stringStream, offset, count);
stringStream->Close();
@ -280,9 +339,27 @@ FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
}
mStatus = rv;
}
return true;
}
class FTPDivertStopRequestEvent : public ChannelEvent
{
public:
FTPDivertStopRequestEvent(FTPChannelParent* aParent,
const nsresult& statusCode)
: mParent(aParent)
, mStatusCode(statusCode)
{
}
void Run() {
mParent->DivertOnStopRequest(mStatusCode);
}
private:
FTPChannelParent* mParent;
nsresult mStatusCode;
};
bool
FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
{
@ -293,6 +370,27 @@ FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
return false;
}
if (mEventQ->ShouldEnqueue()) {
mEventQ->Enqueue(new FTPDivertStopRequestEvent(this, statusCode));
return true;
}
DivertOnStopRequest(statusCode);
return true;
}
void
FTPChannelParent::DivertOnStopRequest(const nsresult& statusCode)
{
LOG(("FTPChannelParent::DivertOnStopRequest [this=%p]\n", this));
if (NS_WARN_IF(!mDivertingFromChild)) {
MOZ_ASSERT(mDivertingFromChild,
"Cannot DivertOnStopRequest if diverting is not set!");
FailDiversion(NS_ERROR_UNEXPECTED);
return;
}
// Honor the channel's status even if the underlying transaction completed.
nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
@ -304,10 +402,26 @@ FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
}
}
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
OnStopRequest(mChannel, nullptr, status);
return true;
}
class FTPDivertCompleteEvent : public ChannelEvent
{
public:
explicit FTPDivertCompleteEvent(FTPChannelParent* aParent)
: mParent(aParent)
{
}
void Run() {
mParent->DivertComplete();
}
private:
FTPChannelParent* mParent;
};
bool
FTPChannelParent::RecvDivertComplete()
{
@ -318,13 +432,31 @@ FTPChannelParent::RecvDivertComplete()
return false;
}
if (mEventQ->ShouldEnqueue()) {
mEventQ->Enqueue(new FTPDivertCompleteEvent(this));
return true;
}
DivertComplete();
return true;
}
void
FTPChannelParent::DivertComplete()
{
LOG(("FTPChannelParent::DivertComplete [this=%p]\n", this));
if (NS_WARN_IF(!mDivertingFromChild)) {
MOZ_ASSERT(mDivertingFromChild,
"Cannot DivertComplete if diverting is not set!");
FailDiversion(NS_ERROR_UNEXPECTED);
return;
}
nsresult rv = ResumeForDiversion();
if (NS_WARN_IF(NS_FAILED(rv))) {
FailDiversion(NS_ERROR_UNEXPECTED);
return false;
}
return true;
}
//-----------------------------------------------------------------------------
@ -588,14 +720,17 @@ FTPChannelParent::StartDiversion()
}
}
// Call OnStartRequest for the "DivertTo" listener.
nsresult rv = OnStartRequest(mChannel, nullptr);
if (NS_FAILED(rv)) {
if (mChannel) {
mChannel->Cancel(rv);
{
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
// Call OnStartRequest for the "DivertTo" listener.
nsresult rv = OnStartRequest(mChannel, nullptr);
if (NS_FAILED(rv)) {
if (mChannel) {
mChannel->Cancel(rv);
}
mStatus = rv;
return;
}
mStatus = rv;
return;
}
// After OnStartRequest has been called, tell FTPChannelChild to divert the

View File

@ -79,6 +79,16 @@ protected:
// ChildChannel. Used during HTTP->FTP redirects.
bool ConnectChannel(const uint32_t& channelId);
void DivertOnDataAvailable(const nsCString& data,
const uint64_t& offset,
const uint32_t& count);
void DivertOnStopRequest(const nsresult& statusCode);
void DivertComplete();
friend class FTPDivertDataAvailableEvent;
friend class FTPDivertStopRequestEvent;
friend class FTPDivertCompleteEvent;
virtual bool RecvCancel(const nsresult& status) override;
virtual bool RecvSuspend() override;
virtual bool RecvResume() override;
@ -119,6 +129,8 @@ protected:
bool mSuspendedForDiversion;
nsRefPtr<OfflineObserver> mObserver;
nsRefPtr<mozilla::dom::TabParent> mTabParent;
nsRefPtr<ChannelEventQueue> mEventQ;
};
} // namespace net