forked from mirrors/gecko-dev
The aim of this patch is to send trailers to child process via SendOnStopRequest. --HG-- extra : rebase_source : 1a5e16e140ef20cfe2e723c3800d7feeebd9a5af
429 lines
12 KiB
C++
429 lines
12 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set sw=2 ts=8 et tw=80 : */
|
|
|
|
/* 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/. */
|
|
|
|
// HttpLog.h should generally be included first
|
|
#include "HttpLog.h"
|
|
|
|
#include "HttpBackgroundChannelChild.h"
|
|
|
|
#include "HttpChannelChild.h"
|
|
#include "mozilla/ipc/BackgroundChild.h"
|
|
#include "mozilla/ipc/PBackgroundChild.h"
|
|
#include "mozilla/IntegerPrintfMacros.h"
|
|
#include "mozilla/Unused.h"
|
|
#include "nsSocketTransportService2.h"
|
|
|
|
using mozilla::ipc::BackgroundChild;
|
|
using mozilla::ipc::IPCResult;
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
// HttpBackgroundChannelChild
|
|
HttpBackgroundChannelChild::HttpBackgroundChannelChild()
|
|
{
|
|
}
|
|
|
|
HttpBackgroundChannelChild::~HttpBackgroundChannelChild()
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild)
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::Init [this=%p httpChannel=%p channelId=%"
|
|
PRIu64 "]\n", this, aChannelChild, aChannelChild->ChannelId()));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
NS_ENSURE_ARG(aChannelChild);
|
|
|
|
mChannelChild = aChannelChild;
|
|
|
|
if (NS_WARN_IF(!CreateBackgroundChannel())) {
|
|
mChannelChild = nullptr;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
HttpBackgroundChannelChild::OnChannelClosed()
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
|
|
// HttpChannelChild is not going to handle any incoming message.
|
|
mChannelChild = nullptr;
|
|
|
|
// Remove pending IPC messages as well.
|
|
mQueuedRunnables.Clear();
|
|
}
|
|
|
|
void
|
|
HttpBackgroundChannelChild::OnStartRequestReceived()
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::OnStartRequestReceived [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
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());
|
|
}
|
|
|
|
bool
|
|
HttpBackgroundChannelChild::CreateBackgroundChannel()
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::CreateBackgroundChannel [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
MOZ_ASSERT(mChannelChild);
|
|
|
|
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
|
|
if (NS_WARN_IF(!actorChild)) {
|
|
return false;
|
|
}
|
|
|
|
const uint64_t channelId = mChannelChild->ChannelId();
|
|
if (!actorChild->SendPHttpBackgroundChannelConstructor(this, channelId)) {
|
|
return false;
|
|
}
|
|
|
|
// hold extra reference for IPDL
|
|
RefPtr<HttpBackgroundChannelChild> self = this;
|
|
Unused << self.forget().take();
|
|
|
|
mChannelChild->OnBackgroundChildReady(this);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
HttpBackgroundChannelChild::IsWaitingOnStartRequest()
|
|
{
|
|
MOZ_ASSERT(OnSocketThread());
|
|
// 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(OnSocketThread());
|
|
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(OnSocketThread());
|
|
|
|
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>(
|
|
"HttpBackgroundChannelChild::RecvOnTransportAndData",
|
|
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,
|
|
const TimeStamp& aLastActiveTabOptHit,
|
|
const nsHttpHeaderArray& aResponseTrailers)
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
|
|
// It's enough to set this from (just before) OnStopRequest notification, since
|
|
// we don't need this value sooner than a channel was done loading - everything
|
|
// this timestamp affects takes place only after a channel's OnStopRequest.
|
|
nsHttp::SetLastActiveTabLoadOptimizationHit(aLastActiveTabOptHit);
|
|
|
|
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,
|
|
const TimeStamp,
|
|
const nsHttpHeaderArray>(
|
|
"HttpBackgroundChannelChild::RecvOnStopRequest",
|
|
this,
|
|
&HttpBackgroundChannelChild::RecvOnStopRequest,
|
|
aChannelStatus,
|
|
aTiming,
|
|
aLastActiveTabOptHit,
|
|
aResponseTrailers));
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming, aResponseTrailers);
|
|
|
|
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(OnSocketThread());
|
|
|
|
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>(
|
|
"HttpBackgroundChannelChild::RecvOnProgress",
|
|
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(OnSocketThread());
|
|
|
|
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>(
|
|
"HttpBackgroundChannelChild::RecvOnStatus",
|
|
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(OnSocketThread());
|
|
|
|
if (NS_WARN_IF(!mChannelChild)) {
|
|
return IPC_OK();
|
|
}
|
|
|
|
if (IsWaitingOnStartRequest()) {
|
|
LOG((" > pending until OnStartRequest\n"));
|
|
|
|
mQueuedRunnables.AppendElement(NewRunnableMethod(
|
|
"HttpBackgroundChannelChild::RecvFlushedForDiversion",
|
|
this,
|
|
&HttpBackgroundChannelChild::RecvFlushedForDiversion));
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
mChannelChild->ProcessFlushedForDiversion();
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult
|
|
HttpBackgroundChannelChild::RecvDivertMessages()
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::RecvDivertMessages [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
|
|
if (NS_WARN_IF(!mChannelChild)) {
|
|
return IPC_OK();
|
|
}
|
|
|
|
if (IsWaitingOnStartRequest()) {
|
|
LOG((" > pending until OnStartRequest\n"));
|
|
|
|
mQueuedRunnables.AppendElement(
|
|
NewRunnableMethod("HttpBackgroundChannelChild::RecvDivertMessages",
|
|
this,
|
|
&HttpBackgroundChannelChild::RecvDivertMessages));
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
mChannelChild->ProcessDivertMessages();
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult
|
|
HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled()
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
|
|
if (NS_WARN_IF(!mChannelChild)) {
|
|
return IPC_OK();
|
|
}
|
|
|
|
// NotifyTrackingProtectionDisabled has no order dependency to OnStartRequest.
|
|
// It this be handled as soon as possible
|
|
mChannelChild->ProcessNotifyTrackingProtectionDisabled();
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult
|
|
HttpBackgroundChannelChild::RecvNotifyTrackingResource()
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingResource [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
|
|
if (NS_WARN_IF(!mChannelChild)) {
|
|
return IPC_OK();
|
|
}
|
|
|
|
// NotifyTrackingResource has no order dependency to OnStartRequest.
|
|
// It this be handled as soon as possible
|
|
mChannelChild->ProcessNotifyTrackingResource();
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult
|
|
HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo(const ClassifierInfo& info)
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo [this=%p]\n", this));
|
|
MOZ_ASSERT(OnSocketThread());
|
|
|
|
if (NS_WARN_IF(!mChannelChild)) {
|
|
return IPC_OK();
|
|
}
|
|
|
|
// SetClassifierMatchedInfo has no order dependency to OnStartRequest.
|
|
// It this be handled as soon as possible
|
|
mChannelChild->ProcessSetClassifierMatchedInfo(info.list(),
|
|
info.provider(),
|
|
info.fullhash());
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
void
|
|
HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this));
|
|
// This function might be called during shutdown phase, so OnSocketThread()
|
|
// might return false even on STS thread. Use IsOnCurrentThreadInfallible()
|
|
// to get correct information.
|
|
MOZ_ASSERT(gSocketTransportService);
|
|
MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible());
|
|
|
|
// 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 background channel is not closed by normal IPDL actor deletion,
|
|
// remove the HttpChannelChild reference and notify background channel
|
|
// destroyed immediately.
|
|
if (aWhy == Deletion && !mQueuedRunnables.IsEmpty()) {
|
|
LOG((" > pending until queued messages are flushed\n"));
|
|
RefPtr<HttpBackgroundChannelChild> self = this;
|
|
mQueuedRunnables.AppendElement(NS_NewRunnableFunction(
|
|
"HttpBackgroundChannelChild::ActorDestroy", [self]() {
|
|
MOZ_ASSERT(OnSocketThread());
|
|
RefPtr<HttpChannelChild> channelChild = self->mChannelChild.forget();
|
|
|
|
if (channelChild) {
|
|
channelChild->OnBackgroundChildDestroyed(self);
|
|
}
|
|
}));
|
|
return;
|
|
}
|
|
|
|
if (mChannelChild) {
|
|
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
|
|
|
|
channelChild->OnBackgroundChildDestroyed(this);
|
|
}
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|