--- a/netwerk/protocol/http/HttpBackgroundChannelChild.cpp
+++ b/netwerk/protocol/http/HttpBackgroundChannelChild.cpp
@@ -9,16 +9,17 @@
#include "HttpLog.h"
#include "HttpBackgroundChannelChild.h"
#include "HttpChannelChild.h"
#include "MainThreadUtils.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
+#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Unused.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
using mozilla::ipc::BackgroundChild;
using mozilla::ipc::IPCResult;
namespace mozilla {
namespace net {
@@ -113,16 +114,39 @@ HttpBackgroundChannelChild::OnChannelClo
LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
// HttpChannelChild is not going to handle any incoming message.
mChannelChild = nullptr;
}
void
+HttpBackgroundChannelChild::OnStartRequestReceived()
+{
+ LOG(("HttpBackgroundChannelChild::OnStartRequestReceived [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mChannelChild);
+ MOZ_ASSERT(!mStartReceived); // Should only be called once.
+
+ mStartReceived = true;
+
+ nsTArray<nsCOMPtr<nsIRunnable>> runnables;
+ runnables.SwapElements(mQueuedRunnables);
+
+ for (auto event : runnables) {
+ // Note: these runnables call Recv* methods on HttpBackgroundChannelChild
+ // but not the Process* methods on HttpChannelChild.
+ event->Run();
+ }
+
+ // Ensure no new message is enqueued.
+ MOZ_ASSERT(mQueuedRunnables.IsEmpty());
+}
+
+void
HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed()
{
LOG(("HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed"
" [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (mChannelChild) {
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
@@ -137,73 +161,232 @@ HttpBackgroundChannelChild::CreateBackgr
MOZ_ASSERT(NS_IsMainThread());
RefPtr<BackgroundChannelCreateCallback> callback =
new BackgroundChannelCreateCallback(this);
return BackgroundChild::GetOrCreateForCurrentThread(callback);
}
+bool
+HttpBackgroundChannelChild::IsWaitingOnStartRequest()
+{
+ // Need to wait for OnStartRequest if it is sent by
+ // parent process but not received by content process.
+ return (mStartSent && !mStartReceived);
+}
+
// PHttpBackgroundChannelChild
IPCResult
HttpBackgroundChannelChild::RecvOnStartRequestSent()
{
+ LOG(("HttpBackgroundChannelChild::RecvOnStartRequestSent [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!mStartSent); // Should only receive this message once.
+
+ mStartSent = true;
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnTransportAndData(
const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
const nsCString& aData)
{
+ LOG(("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_WARN_IF(!mChannelChild)) {
+ return IPC_OK();
+ }
+
+ if (IsWaitingOnStartRequest()) {
+ LOG((" > pending until OnStartRequest [offset=%" PRIu64 " count=%" PRIu32
+ "]\n", aOffset, aCount));
+
+ mQueuedRunnables.AppendElement(
+ NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
+ const uint32_t, const nsCString>(
+ this, &HttpBackgroundChannelChild::RecvOnTransportAndData,
+ aChannelStatus, aTransportStatus, aOffset,
+ aCount, aData));
+
+ return IPC_OK();
+ }
+
+ mChannelChild->ProcessOnTransportAndData(aChannelStatus,
+ aTransportStatus,
+ aOffset,
+ aCount,
+ aData);
+
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnStopRequest(
const nsresult& aChannelStatus,
const ResourceTimingStruct& aTiming)
{
+ LOG(("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_WARN_IF(!mChannelChild)) {
+ return IPC_OK();
+ }
+
+ if (IsWaitingOnStartRequest()) {
+ LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
+ static_cast<uint32_t>(aChannelStatus)));
+
+ mQueuedRunnables.AppendElement(
+ NewRunnableMethod<const nsresult, const ResourceTimingStruct>(
+ this, &HttpBackgroundChannelChild::RecvOnStopRequest,
+ aChannelStatus, aTiming));
+
+ return IPC_OK();
+ }
+
+ mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming);
+
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnProgress(const int64_t& aProgress,
const int64_t& aProgressMax)
{
+ LOG(("HttpBackgroundChannelChild::RecvOnProgress [this=%p progress=%"
+ PRId64 " max=%" PRId64 "]\n", this, aProgress, aProgressMax));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_WARN_IF(!mChannelChild)) {
+ return IPC_OK();
+ }
+
+ if (IsWaitingOnStartRequest()) {
+ LOG((" > pending until OnStartRequest [progress=%" PRId64 " max=%"
+ PRId64 "]\n", aProgress, aProgressMax));
+
+ mQueuedRunnables.AppendElement(
+ NewRunnableMethod<const int64_t, const int64_t>(
+ this, &HttpBackgroundChannelChild::RecvOnProgress,
+ aProgress, aProgressMax));
+
+ return IPC_OK();
+ }
+
+ mChannelChild->ProcessOnProgress(aProgress, aProgressMax);
+
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvOnStatus(const nsresult& aStatus)
{
+ LOG(("HttpBackgroundChannelChild::RecvOnStatus [this=%p status=%"
+ PRIx32 "]\n", this, static_cast<uint32_t>(aStatus)));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_WARN_IF(!mChannelChild)) {
+ return IPC_OK();
+ }
+
+ if (IsWaitingOnStartRequest()) {
+ LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
+ static_cast<uint32_t>(aStatus)));
+
+ mQueuedRunnables.AppendElement(
+ NewRunnableMethod<const nsresult>(
+ this, &HttpBackgroundChannelChild::RecvOnStatus, aStatus));
+
+ return IPC_OK();
+ }
+
+ mChannelChild->ProcessOnStatus(aStatus);
+
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvFlushedForDiversion()
{
+ LOG(("HttpBackgroundChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_WARN_IF(!mChannelChild)) {
+ return IPC_OK();
+ }
+
+ if (IsWaitingOnStartRequest()) {
+ LOG((" > pending until OnStartRequest\n"));
+
+ mQueuedRunnables.AppendElement(
+ NewRunnableMethod(this, &HttpBackgroundChannelChild::RecvFlushedForDiversion));
+
+ return IPC_OK();
+ }
+
+ mChannelChild->ProcessFlushedForDiversion();
+
return IPC_OK();
}
IPCResult
HttpBackgroundChannelChild::RecvDivertMessages()
{
+ LOG(("HttpBackgroundChannelChild::RecvDivertMessages [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (NS_WARN_IF(!mChannelChild)) {
+ return IPC_OK();
+ }
+
+ if (IsWaitingOnStartRequest()) {
+ LOG((" > pending until OnStartRequest\n"));
+
+ mQueuedRunnables.AppendElement(
+ NewRunnableMethod(this, &HttpBackgroundChannelChild::RecvDivertMessages));
+
+ return IPC_OK();
+ }
+
+ mChannelChild->ProcessDivertMessages();
+
return IPC_OK();
}
void
HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
+ // Ensure all IPC messages received before ActorDestroy can be
+ // handled correctly. If there is any pending IPC message, destroyed
+ // mChannelChild until those messages are flushed.
+ if (!mQueuedRunnables.IsEmpty()) {
+ LOG((" > pending until queued messages are flushed\n"));
+ RefPtr<HttpBackgroundChannelChild> self = this;
+ mQueuedRunnables.AppendElement(
+ NS_NewRunnableFunction([self]() {
+ MOZ_ASSERT(NS_IsMainThread());
+ RefPtr<HttpChannelChild> channelChild = self->mChannelChild.forget();
+
+ if (channelChild) {
+ channelChild->OnBackgroundChildDestroyed();
+ }
+ }));
+ return;
+ }
+
if (mChannelChild) {
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
+
channelChild->OnBackgroundChildDestroyed();
}
}
} // namespace net
} // namespace mozilla
--- a/netwerk/protocol/http/HttpBackgroundChannelChild.h
+++ b/netwerk/protocol/http/HttpBackgroundChannelChild.h
@@ -4,16 +4,18 @@
/* 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/. */
#ifndef mozilla_net_HttpBackgroundChannelChild_h
#define mozilla_net_HttpBackgroundChannelChild_h
#include "mozilla/net/PHttpBackgroundChannelChild.h"
+#include "nsIRunnable.h"
+#include "nsTArray.h"
using mozilla::ipc::IPCResult;
namespace mozilla {
namespace net {
class HttpChannelChild;
@@ -28,16 +30,20 @@ public:
// Associate this background channel with a HttpChannelChild and
// initiate the createion of the PBackground IPC channel.
nsresult Init(HttpChannelChild* aChannelChild);
// Callback while the associated HttpChannelChild is not going to
// handle any incoming messages over background channel.
void OnChannelClosed();
+ // Callback when OnStartRequest is received and handled by HttpChannelChild.
+ // Enqueued messages in background channel will be flushed.
+ void OnStartRequestReceived();
+
// Callback while failed to create PBackground IPC channel.
void OnBackgroundChannelCreationFailed();
protected:
IPCResult RecvOnTransportAndData(const nsresult& aChannelStatus,
const nsresult& aTransportStatus,
const uint64_t& aOffset,
const uint32_t& aCount,
@@ -61,19 +67,38 @@ protected:
private:
virtual ~HttpBackgroundChannelChild();
// Initiate the creation of the PBckground IPC channel.
// Return false if failed.
bool CreateBackgroundChannel();
+ // Check OnStartRequest is sent by parent process over main thread IPC
+ // but not yet received on child process.
+ // return true before RecvOnStartRequestSent is invoked.
+ // return false if RecvOnStartRequestSent is invoked but not
+ // OnStartRequestReceived.
+ // return true after both RecvOnStartRequestSend and OnStartRequestReceived
+ // are invoked.
+ bool IsWaitingOnStartRequest();
+
// Associated HttpChannelChild for handling the channel events.
// Will be removed while failed to create background channel,
// destruction of the background channel, or explicitly dissociation
// via OnChannelClosed callback.
RefPtr<HttpChannelChild> mChannelChild;
+
+ // True if OnStartRequest is received by HttpChannelChild.
+ bool mStartReceived = false;
+
+ // True if OnStartRequest is sent by HttpChannelParent.
+ bool mStartSent = false;
+
+ // Store pending messages that require to be handled after OnStartRequest.
+ // Should be flushed after OnStartRequest is received and handled.
+ nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_HttpBackgroundChannelChild_h
--- a/netwerk/protocol/http/HttpBackgroundChannelParent.cpp
+++ b/netwerk/protocol/http/HttpBackgroundChannelParent.cpp
@@ -7,16 +7,17 @@
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include "HttpBackgroundChannelParent.h"
#include "HttpChannelParent.h"
#include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Unused.h"
#include "nsIBackgroundChannelRegistrar.h"
#include "nsNetCID.h"
#include "nsQueryObject.h"
#include "nsThreadUtils.h"
using mozilla::dom::ContentParent;
using mozilla::ipc::AssertIsInMainProcess;
@@ -131,16 +132,183 @@ HttpBackgroundChannelParent::OnChannelCl
}
Unused << self->Send__delete__(self);
}), NS_DISPATCH_NORMAL);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
+bool
+HttpBackgroundChannelParent::OnStartRequestSent()
+{
+ LOG(("HttpBackgroundChannelParent::OnStartRequestSent [this=%p]\n", this));
+ AssertIsInMainProcess();
+
+ if (NS_WARN_IF(!mIPCOpened)) {
+ return false;
+ }
+
+ if (!IsOnBackgroundThread()) {
+ nsresult rv = mBackgroundThread->Dispatch(
+ NewRunnableMethod(this, &HttpBackgroundChannelParent::OnStartRequestSent),
+ NS_DISPATCH_NORMAL);
+
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_SUCCEEDED(rv);
+ }
+
+ return SendOnStartRequestSent();
+}
+
+bool
+HttpBackgroundChannelParent::OnTransportAndData(
+ const nsresult& aChannelStatus,
+ const nsresult& aTransportStatus,
+ const uint64_t& aOffset,
+ const uint32_t& aCount,
+ const nsCString& aData)
+{
+ LOG(("HttpBackgroundChannelParent::OnTransportAndData [this=%p]\n", this));
+ AssertIsInMainProcess();
+
+ if (NS_WARN_IF(!mIPCOpened)) {
+ return false;
+ }
+
+ if (!IsOnBackgroundThread()) {
+ nsresult rv = mBackgroundThread->Dispatch(
+ NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
+ const uint32_t, const nsCString>
+ (this, &HttpBackgroundChannelParent::OnTransportAndData,
+ aChannelStatus, aTransportStatus, aOffset, aCount, aData),
+ NS_DISPATCH_NORMAL);
+
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_SUCCEEDED(rv);
+ }
+
+ return SendOnTransportAndData(aChannelStatus, aTransportStatus,
+ aOffset, aCount, aData);
+}
+
+bool
+HttpBackgroundChannelParent::OnStopRequest(const nsresult& aChannelStatus,
+ const ResourceTimingStruct& aTiming)
+{
+ LOG(("HttpBackgroundChannelParent::OnStopRequest [this=%p "
+ "status=%" PRIx32 "]\n", this, static_cast<uint32_t>(aChannelStatus)));
+ AssertIsInMainProcess();
+
+ if (NS_WARN_IF(!mIPCOpened)) {
+ return false;
+ }
+
+ if (!IsOnBackgroundThread()) {
+ nsresult rv = mBackgroundThread->Dispatch(
+ NewRunnableMethod<const nsresult, const ResourceTimingStruct>
+ (this, &HttpBackgroundChannelParent::OnStopRequest,
+ aChannelStatus, aTiming),
+ NS_DISPATCH_NORMAL);
+
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_SUCCEEDED(rv);
+ }
+
+ return SendOnStopRequest(aChannelStatus, aTiming);
+}
+
+bool
+HttpBackgroundChannelParent::OnProgress(const int64_t& aProgress,
+ const int64_t& aProgressMax)
+{
+ LOG(("HttpBackgroundChannelParent::OnProgress [this=%p progress=%" PRId64
+ " max=%" PRId64 "]\n", this, aProgress, aProgressMax));
+ AssertIsInMainProcess();
+
+ if (NS_WARN_IF(!mIPCOpened)) {
+ return false;
+ }
+
+ if (!IsOnBackgroundThread()) {
+ nsresult rv = mBackgroundThread->Dispatch(
+ NewRunnableMethod<const int64_t, const int64_t>
+ (this, &HttpBackgroundChannelParent::OnProgress,
+ aProgress, aProgressMax),
+ NS_DISPATCH_NORMAL);
+
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_SUCCEEDED(rv);
+ }
+
+ return SendOnProgress(aProgress, aProgressMax);
+}
+
+bool
+HttpBackgroundChannelParent::OnStatus(const nsresult& aStatus)
+{
+ LOG(("HttpBackgroundChannelParent::OnStatus [this=%p stauts=%" PRIx32
+ "]\n", this, static_cast<uint32_t>(aStatus)));
+ AssertIsInMainProcess();
+
+ if (NS_WARN_IF(!mIPCOpened)) {
+ return false;
+ }
+
+ if (!IsOnBackgroundThread()) {
+ nsresult rv = mBackgroundThread->Dispatch(
+ NewRunnableMethod<const nsresult>
+ (this, &HttpBackgroundChannelParent::OnStatus, aStatus),
+ NS_DISPATCH_NORMAL);
+
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_SUCCEEDED(rv);
+ }
+
+ return SendOnStatus(aStatus);
+}
+
+bool
+HttpBackgroundChannelParent::OnDiversion()
+{
+ LOG(("HttpBackgroundChannelParent::OnDiversion [this=%p]\n", this));
+ AssertIsInMainProcess();
+
+ if (NS_WARN_IF(!mIPCOpened)) {
+ return false;
+ }
+
+ if (!IsOnBackgroundThread()) {
+ nsresult rv = mBackgroundThread->Dispatch(
+ NewRunnableMethod(this, &HttpBackgroundChannelParent::OnDiversion),
+ NS_DISPATCH_NORMAL);
+
+ MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
+
+ return NS_SUCCEEDED(rv);
+ }
+
+ if (!SendFlushedForDiversion()) {
+ return false;
+ }
+
+ // The listener chain should now be setup; tell HttpChannelChild to divert
+ // the OnDataAvailables and OnStopRequest to associated HttpChannelParent.
+ if (!SendDivertMessages()) {
+ return false;
+ }
+
+ return true;
+}
+
void
HttpBackgroundChannelParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("HttpBackgroundChannelParent::ActorDestroy [this=%p]\n", this));
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
mIPCOpened = false;
--- a/netwerk/protocol/http/HttpBackgroundChannelParent.h
+++ b/netwerk/protocol/http/HttpBackgroundChannelParent.h
@@ -34,16 +34,41 @@ public:
// Callbacks for BackgroundChannelRegistrar to notify
// the associated HttpChannelParent is found.
void LinkToChannel(HttpChannelParent* aChannelParent);
// Callbacks for HttpChannelParent to close the background
// IPC channel.
void OnChannelClosed();
+ // To send OnStartRequestSend message over background channel.
+ bool OnStartRequestSent();
+
+ // To send OnTransportAndData message over background channel.
+ bool OnTransportAndData(const nsresult& aChannelStatus,
+ const nsresult& aTransportStatus,
+ const uint64_t& aOffset,
+ const uint32_t& aCount,
+ const nsCString& aData);
+
+ // To send OnStopRequest message over background channel.
+ bool OnStopRequest(const nsresult& aChannelStatus,
+ const ResourceTimingStruct& aTiming);
+
+ // To send OnProgress message over background channel.
+ bool OnProgress(const int64_t& aProgress,
+ const int64_t& aProgressMax);
+
+ // To send OnStatus message over background channel.
+ bool OnStatus(const nsresult& aStatus);
+
+ // To send FlushedForDiversion and DivertMessages messages
+ // over background channel.
+ bool OnDiversion();
+
protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~HttpBackgroundChannelParent();
Atomic<bool> mIPCOpened;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -441,16 +441,22 @@ HttpChannelChild::RecvOnStartRequest(con
mEventQ->RunOrEnqueue(new StartRequestEvent(this, channelStatus, responseHead,
useResponseHead, requestHeaders,
isFromCache, cacheEntryAvailable,
cacheExpirationTime,
cachedCharset,
securityInfoSerialization,
selfAddr, peerAddr, cacheKey,
altDataType, altDataLen));
+
+ MOZ_ASSERT(mBgChild);
+ if (mBgChild) {
+ mBgChild->OnStartRequestReceived();
+ }
+
return IPC_OK();
}
void
HttpChannelChild::OnStartRequest(const nsresult& channelStatus,
const nsHttpResponseHead& responseHead,
const bool& useResponseHead,
const nsHttpHeaderArray& requestHeaders,
@@ -662,32 +668,31 @@ class TransportAndDataEvent : public Cha
HttpChannelChild* mChild;
nsresult mChannelStatus;
nsresult mTransportStatus;
nsCString mData;
uint64_t mOffset;
uint32_t mCount;
};
-mozilla::ipc::IPCResult
-HttpChannelChild::RecvOnTransportAndData(const nsresult& channelStatus,
- const nsresult& transportStatus,
- const uint64_t& offset,
- const uint32_t& count,
- const nsCString& data)
+void
+HttpChannelChild::ProcessOnTransportAndData(const nsresult& aChannelStatus,
+ const nsresult& aTransportStatus,
+ const uint64_t& aOffset,
+ const uint32_t& aCount,
+ const nsCString& aData)
{
- LOG(("HttpChannelChild::RecvOnTransportAndData [this=%p]\n", this));
+ LOG(("HttpChannelChild::ProcessOnTransportAndData [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"Should not be receiving any more callbacks from parent!");
-
- mEventQ->RunOrEnqueue(new TransportAndDataEvent(this, channelStatus,
- transportStatus, data, offset,
- count),
+ mEventQ->RunOrEnqueue(new TransportAndDataEvent(this, aChannelStatus,
+ aTransportStatus, aData,
+ aOffset, aCount),
mDivertingToParent);
- return IPC_OK();
}
class MaybeDivertOnDataHttpEvent : public ChannelEvent
{
public:
MaybeDivertOnDataHttpEvent(HttpChannelChild* child,
const nsCString& data,
const uint64_t& offset,
@@ -905,27 +910,27 @@ class StopRequestEvent : public ChannelE
return target.forget();
}
private:
HttpChannelChild* mChild;
nsresult mChannelStatus;
ResourceTimingStruct mTiming;
};
-mozilla::ipc::IPCResult
-HttpChannelChild::RecvOnStopRequest(const nsresult& channelStatus,
- const ResourceTimingStruct& timing)
+void
+HttpChannelChild::ProcessOnStopRequest(const nsresult& aChannelStatus,
+ const ResourceTimingStruct& aTiming)
{
- LOG(("HttpChannelChild::RecvOnStopRequest [this=%p]\n", this));
+ LOG(("HttpChannelChild::ProcessOnStopRequest [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"Should not be receiving any more callbacks from parent!");
- mEventQ->RunOrEnqueue(new StopRequestEvent(this, channelStatus, timing),
+ mEventQ->RunOrEnqueue(new StopRequestEvent(this, aChannelStatus, aTiming),
mDivertingToParent);
- return IPC_OK();
}
class MaybeDivertOnStopHttpEvent : public ChannelEvent
{
public:
MaybeDivertOnStopHttpEvent(HttpChannelChild* child,
const nsresult& channelStatus)
: mChild(child)
@@ -1146,22 +1151,23 @@ class ProgressEvent : public ChannelEven
nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
return target.forget();
}
private:
HttpChannelChild* mChild;
int64_t mProgress, mProgressMax;
};
-mozilla::ipc::IPCResult
-HttpChannelChild::RecvOnProgress(const int64_t& progress,
- const int64_t& progressMax)
+void
+HttpChannelChild::ProcessOnProgress(const int64_t& aProgress,
+ const int64_t& aProgressMax)
{
- mEventQ->RunOrEnqueue(new ProgressEvent(this, progress, progressMax));
- return IPC_OK();
+ LOG(("HttpChannelChild::ProcessOnProgress [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+ mEventQ->RunOrEnqueue(new ProgressEvent(this, aProgress, aProgressMax));
}
void
HttpChannelChild::OnProgress(const int64_t& progress,
const int64_t& progressMax)
{
LOG(("HttpChannelChild::OnProgress [this=%p progress=%" PRId64 "/%" PRId64 "]\n",
this, progress, progressMax));
@@ -1201,21 +1207,22 @@ class StatusEvent : public ChannelEvent
nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
return target.forget();
}
private:
HttpChannelChild* mChild;
nsresult mStatus;
};
-mozilla::ipc::IPCResult
-HttpChannelChild::RecvOnStatus(const nsresult& status)
+void
+HttpChannelChild::ProcessOnStatus(const nsresult& aStatus)
{
- mEventQ->RunOrEnqueue(new StatusEvent(this, status));
- return IPC_OK();
+ LOG(("HttpChannelChild::ProcessOnStatus [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
+ mEventQ->RunOrEnqueue(new StatusEvent(this, aStatus));
}
void
HttpChannelChild::OnStatus(const nsresult& status)
{
LOG(("HttpChannelChild::OnStatus [this=%p status=%" PRIx32 "]\n",
this, static_cast<uint32_t>(status)));
@@ -1302,18 +1309,18 @@ HttpChannelChild::FailedAsyncOpen(const
if (mIPCOpen) {
TrySendDeletingChannel();
}
}
void
HttpChannelChild::CleanupBackgroundChannel()
{
- LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p]\n", this));
-
+ LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p bgChild=%p]\n",
+ this, mBgChild.get()));
if (!mBgChild) {
return;
}
RefPtr<HttpBackgroundChannelChild> bgChild = mBgChild.forget();
if (!NS_IsMainThread()) {
SystemGroup::Dispatch(
@@ -1709,25 +1716,24 @@ class HttpFlushedForDiversionEvent : pub
MOZ_ASSERT(mChild);
nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
return target.forget();
}
private:
HttpChannelChild* mChild;
};
-mozilla::ipc::IPCResult
-HttpChannelChild::RecvFlushedForDiversion()
+void
+HttpChannelChild::ProcessFlushedForDiversion()
{
- LOG(("HttpChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
+ LOG(("HttpChannelChild::ProcessFlushedForDiversion [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mDivertingToParent);
mEventQ->RunOrEnqueue(new HttpFlushedForDiversionEvent(this), true);
-
- return IPC_OK();
}
mozilla::ipc::IPCResult
HttpChannelChild::RecvNotifyTrackingProtectionDisabled()
{
nsChannelClassifier::NotifyTrackingProtectionDisabled(this);
return IPC_OK();
}
@@ -1755,29 +1761,27 @@ HttpChannelChild::FlushedForDiversion()
mozilla::ipc::IPCResult
HttpChannelChild::RecvSetClassifierMatchedInfo(const ClassifierInfo& aInfo)
{
SetMatchedInfo(aInfo.list(), aInfo.provider(), aInfo.prefix());
return IPC_OK();
}
-
-mozilla::ipc::IPCResult
-HttpChannelChild::RecvDivertMessages()
+void
+HttpChannelChild::ProcessDivertMessages()
{
- LOG(("HttpChannelChild::RecvDivertMessages [this=%p]\n", this));
+ LOG(("HttpChannelChild::ProcessDivertMessages [this=%p]\n", this));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mDivertingToParent);
MOZ_RELEASE_ASSERT(mSuspendCount > 0);
// DivertTo() has been called on parent, so we can now start sending queued
// IPDL messages back to parent listener.
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(Resume()));
-
- return IPC_OK();
}
// Returns true if has actually completed the redirect and cleaned up the
// channel, or false the interception logic kicked in and we need to asyncly
// call FinishInterceptedRedirect and CleanupRedirectingChannel.
// The argument is an optional OverrideRunnable that we pass to the redirected
// channel.
bool
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -134,37 +134,27 @@ protected:
const nsCString& cachedCharset,
const nsCString& securityInfoSerialization,
const NetAddr& selfAddr,
const NetAddr& peerAddr,
const int16_t& redirectCount,
const uint32_t& cacheKey,
const nsCString& altDataType,
const int64_t& altDataLen) override;
- mozilla::ipc::IPCResult RecvOnTransportAndData(const nsresult& channelStatus,
- const nsresult& status,
- const uint64_t& offset,
- const uint32_t& count,
- const nsCString& data) override;
- mozilla::ipc::IPCResult RecvOnStopRequest(const nsresult& statusCode, const ResourceTimingStruct& timing) override;
- mozilla::ipc::IPCResult RecvOnProgress(const int64_t& progress, const int64_t& progressMax) override;
- mozilla::ipc::IPCResult RecvOnStatus(const nsresult& status) override;
mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override;
mozilla::ipc::IPCResult RecvRedirect1Begin(const uint32_t& registrarId,
const URIParams& newURI,
const uint32_t& redirectFlags,
const nsHttpResponseHead& responseHead,
const nsCString& securityInfoSerialization,
const uint64_t& channelId,
const NetAddr& oldPeerAddr) override;
mozilla::ipc::IPCResult RecvRedirect3Complete() override;
mozilla::ipc::IPCResult RecvAssociateApplicationCache(const nsCString& groupID,
const nsCString& clientID) override;
- mozilla::ipc::IPCResult RecvFlushedForDiversion() override;
- mozilla::ipc::IPCResult RecvDivertMessages() override;
mozilla::ipc::IPCResult RecvDeleteSelf() override;
mozilla::ipc::IPCResult RecvFinishInterceptedRedirect() override;
mozilla::ipc::IPCResult RecvReportSecurityMessage(const nsString& messageTag,
const nsString& messageCategory) override;
mozilla::ipc::IPCResult RecvIssueDeprecationWarning(const uint32_t& warning,
const bool& asError) override;
@@ -218,16 +208,30 @@ private:
// Get event target for processing network events.
already_AddRefed<nsIEventTarget> GetNeckoTarget();
// Get event target for ODA.
already_AddRefed<nsIEventTarget> GetODATarget();
MOZ_MUST_USE nsresult ContinueAsyncOpen();
+ // Callbacks while receiving OnTransportAndData/OnStopRequest/OnProgress/
+ // OnStatus/FlushedForDiversion/DivertMessages on background IPC channel.
+ void ProcessOnTransportAndData(const nsresult& aChannelStatus,
+ const nsresult& aStatus,
+ const uint64_t& aOffset,
+ const uint32_t& aCount,
+ const nsCString& aData);
+ void ProcessOnStopRequest(const nsresult& aStatusCode,
+ const ResourceTimingStruct& aTiming);
+ void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax);
+ void ProcessOnStatus(const nsresult& aStatus);
+ void ProcessFlushedForDiversion();
+ void ProcessDivertMessages();
+
void DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
void DoOnStatus(nsIRequest* aRequest, nsresult status);
void DoOnProgress(nsIRequest* aRequest, int64_t progress, int64_t progressMax);
void DoOnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream,
uint64_t offset, uint32_t count);
void DoPreOnStopRequest(nsresult aStatus);
void DoOnStopRequest(nsIRequest* aRequest, nsresult aChannelStatus, nsISupports* aContext);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1379,16 +1379,17 @@ HttpChannelParent::RecvRemoveCorsPreflig
// HttpChannelParent::nsIRequestObserver
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n",
this, aRequest));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mDivertingFromChild,
"Cannot call OnStartRequest if diverting is set!");
RefPtr<nsHttpChannel> chan = do_QueryObject(aRequest);
if (!chan) {
LOG((" aRequest is not nsHttpChannel"));
NS_ERROR("Expecting only nsHttpChannel as aRequest in HttpChannelParent::OnStartRequest");
@@ -1487,26 +1488,38 @@ HttpChannelParent::OnStartRequest(nsIReq
redirectCount,
cacheKeyValue,
altDataType,
altDataLen))
{
rv = NS_ERROR_UNEXPECTED;
}
requestHead->Exit();
+
+ // OnStartRequest is sent to content process successfully.
+ // Notify PHttpBackgroundChannelChild that all following IPC mesasges
+ // should be run after OnStartRequest is handled.
+ if (NS_SUCCEEDED(rv)) {
+ MOZ_ASSERT(mBgParent);
+ if (!mBgParent->OnStartRequestSent()) {
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ }
+
return rv;
}
NS_IMETHODIMP
HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)
{
LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%" PRIx32 "]\n",
this, aRequest, static_cast<uint32_t>(aStatusCode)));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mDivertingFromChild,
"Cannot call OnStopRequest if diverting is set!");
ResourceTimingStruct timing;
mChannel->GetDomainLookupStart(&timing.domainLookupStart);
mChannel->GetDomainLookupEnd(&timing.domainLookupEnd);
mChannel->GetConnectStart(&timing.connectStart);
mChannel->GetConnectEnd(&timing.connectEnd);
@@ -1520,35 +1533,42 @@ HttpChannelParent::OnStopRequest(nsIRequ
mChannel->GetEncodedBodySize(&timing.encodedBodySize);
// decodedBodySize can be computed in the child process so it doesn't need
// to be passed down.
mChannel->GetProtocolVersion(timing.protocolVersion);
mChannel->GetCacheReadStart(&timing.cacheReadStart);
mChannel->GetCacheReadEnd(&timing.cacheReadEnd);
- if (mIPCClosed || !SendOnStopRequest(aStatusCode, timing))
+ // Either IPC channel is closed or background channel
+ // is ready to send OnStopRequest.
+ MOZ_ASSERT(mIPCClosed || mBgParent);
+
+ if (mIPCClosed ||
+ !mBgParent || !mBgParent->OnStopRequest(aStatusCode, timing)) {
return NS_ERROR_UNEXPECTED;
+ }
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
uint64_t aOffset,
uint32_t aCount)
{
- LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p]\n",
- this, aRequest));
+ LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p offset=%" PRIu64
+ " count=%" PRIu32 "]\n", this, aRequest, aOffset, aCount));
+ MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(!mDivertingFromChild,
"Cannot call OnDataAvailable if diverting is set!");
nsresult channelStatus = NS_OK;
mChannel->GetStatus(&channelStatus);
nsresult transportStatus =
@@ -1565,18 +1585,23 @@ HttpChannelParent::OnDataAvailable(nsIRe
}
while (aCount) {
nsresult rv = NS_ReadInputStreamToString(aInputStream, data, toRead);
if (NS_FAILED(rv)) {
return rv;
}
- if (mIPCClosed || !SendOnTransportAndData(channelStatus, transportStatus,
- aOffset, toRead, data)) {
+ // Either IPC channel is closed or background channel
+ // is ready to send OnTransportAndData.
+ MOZ_ASSERT(mIPCClosed || mBgParent);
+
+ if (mIPCClosed || !mBgParent ||
+ !mBgParent->OnTransportAndData(channelStatus, transportStatus,
+ aOffset, toRead, data)) {
return NS_ERROR_UNEXPECTED;
}
aOffset += toRead;
aCount -= toRead;
toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
}
@@ -1588,50 +1613,67 @@ HttpChannelParent::OnDataAvailable(nsIRe
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::OnProgress(nsIRequest *aRequest,
nsISupports *aContext,
int64_t aProgress,
int64_t aProgressMax)
{
+ LOG(("HttpChannelParent::OnStatus [this=%p progress=%" PRId64 "max=%" PRId64
+ "]\n", this, aProgress, aProgressMax));
+ MOZ_ASSERT(NS_IsMainThread());
+
// If it indicates this precedes OnDataAvailable, child can derive the value in ODA.
if (mIgnoreProgress) {
mIgnoreProgress = false;
return NS_OK;
}
+ // Either IPC channel is closed or background channel
+ // is ready to send OnProgress.
+ MOZ_ASSERT(mIPCClosed || mBgParent);
+
// Send OnProgress events to the child for data upload progress notifications
// (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has
// LOAD_BACKGROUND set.
- if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax)) {
+ if (mIPCClosed || !mBgParent
+ || !mBgParent->OnProgress(aProgress, aProgressMax)) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
NS_IMETHODIMP
HttpChannelParent::OnStatus(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatus,
const char16_t *aStatusArg)
{
+ LOG(("HttpChannelParent::OnStatus [this=%p status=%" PRIx32 "]\n",
+ this, static_cast<uint32_t>(aStatus)));
+ MOZ_ASSERT(NS_IsMainThread());
+
// If this precedes OnDataAvailable, transportStatus will be derived in ODA.
if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
aStatus == NS_NET_STATUS_READING) {
// The transport status and progress generated by ODA will be coalesced
// into one IPC message. Therefore, we can ignore the next OnProgress event
// since it is generated by ODA as well.
mIgnoreProgress = true;
return NS_OK;
}
+ // Either IPC channel is closed or background channel
+ // is ready to send OnStatus.
+ MOZ_ASSERT(mIPCClosed || mBgParent);
+
// Otherwise, send to child now
- if (mIPCClosed || !SendOnStatus(aStatus)) {
+ if (mIPCClosed || !mBgParent || !mBgParent->OnStatus(aStatus)) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIParentChannel
@@ -1958,24 +2000,21 @@ HttpChannelParent::StartDiversion()
mDivertListener = converterListener.forget();
}
// Now mParentListener can be diverted to mDivertListener.
DebugOnly<nsresult> rvdbg = mParentListener->DivertTo(mDivertListener);
MOZ_ASSERT(NS_SUCCEEDED(rvdbg));
mDivertListener = nullptr;
- if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
+ // Either IPC channel is closed or background channel
+ // is ready to send FlushedForDiversion and DivertMessages.
+ MOZ_ASSERT(mIPCClosed || mBgParent);
- // The listener chain should now be setup; tell HttpChannelChild to divert
- // the OnDataAvailables and OnStopRequest to this HttpChannelParent.
- if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
+ if (NS_WARN_IF(mIPCClosed || !mBgParent || !mBgParent->OnDiversion())) {
FailDiversion(NS_ERROR_UNEXPECTED);
return;
}
}
class HTTPFailDiversionEvent : public Runnable
{
public:
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -104,30 +104,16 @@ child:
nsCString securityInfoSerialization,
NetAddr selfAddr,
NetAddr peerAddr,
int16_t redirectCount,
uint32_t cacheKey,
nsCString altDataType,
int64_t altDataLength);
- // Combines a single OnDataAvailable and its associated OnProgress &
- // OnStatus calls into one IPDL message
- async OnTransportAndData(nsresult channelStatus,
- nsresult transportStatus,
- uint64_t offset,
- uint32_t count,
- nsCString data);
-
- async OnStopRequest(nsresult channelStatus, ResourceTimingStruct timing);
-
- async OnProgress(int64_t progress, int64_t progressMax);
-
- async OnStatus(nsresult status);
-
// Used to cancel child channel if we hit errors during creating and
// AsyncOpen of nsHttpChannel on the parent.
async FailedAsyncOpen(nsresult status);
// Called to initiate content channel redirect, starts talking to sinks
// on the content process and reports result via Redirect2Verify above
async Redirect1Begin(uint32_t registrarId,
URIParams newUri,
@@ -146,23 +132,16 @@ child:
// Tell the child that tracking protection was disabled for this load.
async NotifyTrackingProtectionDisabled();
// Tell the child that the resource being loaded is on the tracking
// protection list.
async NotifyTrackingResource();
- // Parent has been suspended for diversion; no more events to be enqueued.
- async FlushedForDiversion();
-
- // Child should resume processing the ChannelEventQueue, i.e. diverting any
- // OnDataAvailable and OnStopRequest messages in the queue back to the parent.
- async DivertMessages();
-
// Report a security message to the console associated with this
// channel.
async ReportSecurityMessage(nsString messageTag, nsString messageCategory);
// Tell child to delete channel (all IPDL deletes must be done from child to
// avoid races: see bug 591708).
async DeleteSelf();