Bug 1015466 - Part 3, PHttpBackgroundChannel lifecycle management. r=mayhemer

PHttpBackgroundChannel is created by content process because PBackground IPDL
can only be initiated from content process. The background channel deletion is
controlled by chrome process while PHttpChannel is going to be closed or canceled.

BackgroundChannelRegistrar is introduced for pairing HttpChannelParent and
HttpBackgroundChannelParent since they are created over different IPDL
asynchronously.

nsIParentRedirectingChannel.continueVerification is introduced to asynchronously
wait for background channel to be established on the new channel during the
Redirect2Verify phase.

MozReview-Commit-ID: 41l8ivan8iA

--HG--
extra : rebase_source : b8b6d7e7c037efaa9fc13df14191205c603e833a
This commit is contained in:
Shih-Chiang Chien 2017-04-24 11:09:35 +08:00
Родитель ccfe1721d6
Коммит e7a014adc4
18 изменённых файлов: 1031 добавлений и 27 удалений

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/ipc/PChildToParentStreamChild.h"
#include "mozilla/ipc/PParentToChildStreamChild.h"
#include "mozilla/layout/VsyncChild.h"
#include "mozilla/net/HttpBackgroundChannelChild.h"
#include "mozilla/net/PUDPSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "mozilla/dom/WebAuthnTransactionChild.h"
@ -569,8 +570,11 @@ BackgroundChildImpl::AllocPHttpBackgroundChannelChild(const uint64_t& aChannelId
bool
BackgroundChildImpl::DeallocPHttpBackgroundChannelChild(PHttpBackgroundChannelChild* aActor)
{
MOZ_ASSERT(aActor);
// TODO
// The reference is increased in BackgroundChannelCreateCallback::ActorCreated
// of HttpBackgroundChannelChild.cpp. We should decrease it after IPC
// destroyed.
RefPtr<net::HttpBackgroundChannelChild> child =
dont_AddRef(static_cast<net::HttpBackgroundChannelChild*>(aActor));
return true;
}

Просмотреть файл

@ -879,7 +879,11 @@ BackgroundParentImpl::AllocPHttpBackgroundChannelParent(const uint64_t& aChannel
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
return new net::HttpBackgroundChannelParent();
RefPtr<net::HttpBackgroundChannelParent> actor =
new net::HttpBackgroundChannelParent();
// hold extra refcount for IPDL
return actor.forget().take();
}
mozilla::ipc::IPCResult
@ -891,7 +895,13 @@ BackgroundParentImpl::RecvPHttpBackgroundChannelConstructor(
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
//TODO
net::HttpBackgroundChannelParent* aParent =
static_cast<net::HttpBackgroundChannelParent*>(aActor);
if (NS_WARN_IF(NS_FAILED(aParent->Init(aChannelId)))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
@ -903,7 +913,10 @@ BackgroundParentImpl::DeallocPHttpBackgroundChannelParent(
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
//TODO
// release extra refcount hold by AllocPHttpBackgroundChannelParent
RefPtr<net::HttpBackgroundChannelParent> actor =
dont_AddRef(static_cast<net::HttpBackgroundChannelParent*>(aActor));
return true;
}

Просмотреть файл

@ -8,6 +8,20 @@ interface nsITabParent;
interface nsIChannel;
interface nsIAsyncVerifyRedirectCallback;
[builtinclass, uuid(01987690-48cf-45de-bae3-e143c2adc2a8)]
interface nsIAsyncVerifyRedirectReadyCallback : nsISupports
{
/**
* Asynchronous callback when redirected channel finishes the preparation for
* completing the verification procedure.
*
* @param result
* SUCCEEDED if preparation for redirection verification succceed.
* If FAILED the redirection must be aborted.
*/
void readyToVerify(in nsresult result);
};
/**
* Implemented by chrome side of IPC protocols that support redirect responses.
*/
@ -33,6 +47,17 @@ interface nsIParentRedirectingChannel : nsIParentChannel
in uint32_t redirectFlags,
in nsIAsyncVerifyRedirectCallback callback);
/**
* Called to new channel when the original channel got Redirect2Verify
* response from child. Callback will be invoked when the new channel
* finishes the preparation for Redirect2Verify and can be called immediately.
*
* @param callback
* redirect ready callback, will be called when redirect verification
* procedure can proceed.
*/
void continueVerification(in nsIAsyncVerifyRedirectReadyCallback callback);
/**
* Called after we are done with redirecting process and we know if to
* redirect or not. Forward the redirect result to the child process. From

Просмотреть файл

@ -637,6 +637,18 @@
{0x97, 0xa7, 0x06, 0xaf, 0x5e, 0x6d, 0x84, 0xc4} \
}
// Background channel registrar used for pairing HttpChannelParent
// and its background channel
#define NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID \
"@mozilla.org/network/background-channel-registrar;1"
#define NS_BACKGROUNDCHANNELREGISTRAR_CID \
{ /* 6907788a-17cc-4c2a-a7c5-59ad2d9cc079 */ \
0x6907788a, \
0x17cc, \
0x4c2a, \
{ 0xa7, 0xc5, 0x59, 0xad, 0x2d, 0x9c, 0xc0, 0x79} \
}
/******************************************************************************
* netwerk/protocol/ftp/ classes
*/

Просмотреть файл

@ -267,6 +267,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFtpProtocolHandler, Init)
#include "nsHttpNTLMAuth.h"
#include "nsHttpActivityDistributor.h"
#include "ThrottleQueue.h"
#include "BackgroundChannelRegistrar.h"
#undef LOG
#undef LOG_ENABLED
namespace mozilla {
@ -280,6 +281,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpActivityDistributor)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpBasicAuth)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHttpDigestAuth)
NS_GENERIC_FACTORY_CONSTRUCTOR(ThrottleQueue)
NS_GENERIC_FACTORY_CONSTRUCTOR(BackgroundChannelRegistrar)
} // namespace net
} // namespace mozilla
#endif // !NECKO_PROTOCOL_http
@ -805,6 +807,7 @@ NS_DEFINE_NAMED_CID(NS_HTTPAUTHMANAGER_CID);
NS_DEFINE_NAMED_CID(NS_HTTPCHANNELAUTHPROVIDER_CID);
NS_DEFINE_NAMED_CID(NS_HTTPACTIVITYDISTRIBUTOR_CID);
NS_DEFINE_NAMED_CID(NS_THROTTLEQUEUE_CID);
NS_DEFINE_NAMED_CID(NS_BACKGROUNDCHANNELREGISTRAR_CID);
#endif // !NECKO_PROTOCOL_http
#ifdef NECKO_PROTOCOL_ftp
NS_DEFINE_NAMED_CID(NS_FTPPROTOCOLHANDLER_CID);
@ -956,6 +959,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
{ &kNS_HTTPCHANNELAUTHPROVIDER_CID, false, nullptr, mozilla::net::nsHttpChannelAuthProviderConstructor },
{ &kNS_HTTPACTIVITYDISTRIBUTOR_CID, false, nullptr, mozilla::net::nsHttpActivityDistributorConstructor },
{ &kNS_THROTTLEQUEUE_CID, false, nullptr, mozilla::net::ThrottleQueueConstructor },
{ &kNS_BACKGROUNDCHANNELREGISTRAR_CID, false, nullptr, mozilla::net::BackgroundChannelRegistrarConstructor },
#endif // !NECKO_PROTOCOL_http
#ifdef NECKO_PROTOCOL_ftp
{ &kNS_FTPPROTOCOLHANDLER_CID, false, nullptr, nsFtpProtocolHandlerConstructor },
@ -1117,6 +1121,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
{ NS_HTTPCHANNELAUTHPROVIDER_CONTRACTID, &kNS_HTTPCHANNELAUTHPROVIDER_CID },
{ NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &kNS_HTTPACTIVITYDISTRIBUTOR_CID },
{ NS_THROTTLEQUEUE_CONTRACTID, &kNS_THROTTLEQUEUE_CID },
{ NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID, &kNS_BACKGROUNDCHANNELREGISTRAR_CID },
#endif // !NECKO_PROTOCOL_http
#ifdef NECKO_PROTOCOL_ftp
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &kNS_FTPPROTOCOLHANDLER_CID },

Просмотреть файл

@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "BackgroundChannelRegistrar.h"
#include "HttpBackgroundChannelParent.h"
#include "HttpChannelParent.h"
#include "nsIInterfaceRequestor.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(BackgroundChannelRegistrar, nsIBackgroundChannelRegistrar)
BackgroundChannelRegistrar::BackgroundChannelRegistrar()
{
// BackgroundChannelRegistrar is a main-thread-only object.
// All the operations should be run on main thread.
// It should be used on chrome process only.
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
}
BackgroundChannelRegistrar::~BackgroundChannelRegistrar()
{
MOZ_ASSERT(NS_IsMainThread());
}
void
BackgroundChannelRegistrar::NotifyChannelLinked(
HttpChannelParent* aChannelParent,
HttpBackgroundChannelParent* aBgParent)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChannelParent);
MOZ_ASSERT(aBgParent);
aBgParent->LinkToChannel(aChannelParent);
aChannelParent->OnBackgroundParentReady(aBgParent);
}
// nsIBackgroundChannelRegistrar
void
BackgroundChannelRegistrar::DeleteChannel(uint64_t aKey)
{
MOZ_ASSERT(NS_IsMainThread());
mChannels.Remove(aKey);
mBgChannels.Remove(aKey);
}
void
BackgroundChannelRegistrar::LinkHttpChannel(
uint64_t aKey,
HttpChannelParent* aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChannel);
RefPtr<HttpBackgroundChannelParent> bgParent;
bool found = mBgChannels.Remove(aKey, getter_AddRefs(bgParent));
if (!found) {
mChannels.Put(aKey, aChannel);
return;
}
MOZ_ASSERT(bgParent);
NotifyChannelLinked(aChannel, bgParent);
}
void
BackgroundChannelRegistrar::LinkBackgroundChannel(
uint64_t aKey,
HttpBackgroundChannelParent* aBgChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBgChannel);
RefPtr<HttpChannelParent> parent;
bool found = mChannels.Remove(aKey, getter_AddRefs(parent));
if (!found) {
mBgChannels.Put(aKey, aBgChannel);
return;
}
MOZ_ASSERT(parent);
NotifyChannelLinked(parent, aBgChannel);
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#ifndef mozilla_net_BackgroundChannelRegistrar_h__
#define mozilla_net_BackgroundChannelRegistrar_h__
#include "nsIBackgroundChannelRegistrar.h"
#include "nsRefPtrHashtable.h"
namespace mozilla {
namespace net {
class HttpBackgroundChannelParent;
class HttpChannelParent;
class BackgroundChannelRegistrar final : public nsIBackgroundChannelRegistrar
{
typedef nsRefPtrHashtable<nsUint64HashKey, HttpChannelParent>
ChannelHashtable;
typedef nsRefPtrHashtable<nsUint64HashKey, HttpBackgroundChannelParent>
BackgroundChannelHashtable;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIBACKGROUNDCHANNELREGISTRAR
explicit BackgroundChannelRegistrar();
private:
virtual ~BackgroundChannelRegistrar();
// A helper function for BackgroundChannelRegistrar itself to callback
// HttpChannelParent and HttpBackgroundChannelParent when both objects are
// ready. aChannelParent and aBgParent is the pair of HttpChannelParent and
// HttpBackgroundChannelParent that should be linked together.
void NotifyChannelLinked(HttpChannelParent* aChannelParent,
HttpBackgroundChannelParent* aBgParent);
// Store unlinked HttpChannelParent objects.
ChannelHashtable mChannels;
// Store unlinked HttpBackgroundChannelParent objects.
BackgroundChannelHashtable mBgChannels;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_BackgroundChannelRegistrar_h__

Просмотреть файл

@ -5,13 +5,82 @@
* 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 "MainThreadUtils.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/Unused.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
using mozilla::ipc::BackgroundChild;
using mozilla::ipc::IPCResult;
namespace mozilla {
namespace net {
// Callbacks for PBackgroundChild creation
class BackgroundChannelCreateCallback final
: public nsIIPCBackgroundChildCreateCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
explicit BackgroundChannelCreateCallback(HttpBackgroundChannelChild* aBgChild)
: mBgChild(aBgChild)
{
MOZ_ASSERT(aBgChild);
}
private:
virtual ~BackgroundChannelCreateCallback() { }
RefPtr<HttpBackgroundChannelChild> mBgChild;
};
NS_IMPL_ISUPPORTS(BackgroundChannelCreateCallback,
nsIIPCBackgroundChildCreateCallback)
void
BackgroundChannelCreateCallback::ActorCreated(PBackgroundChild* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aActor);
MOZ_ASSERT(mBgChild);
if (!mBgChild->mChannelChild) {
// HttpChannelChild is closed during PBackground creation,
// abort the rest of steps.
return;
}
const uint64_t channelId = mBgChild->mChannelChild->ChannelId();
if (!aActor->SendPHttpBackgroundChannelConstructor(mBgChild,
channelId)) {
ActorFailed();
return;
}
// hold extra reference for IPDL
RefPtr<HttpBackgroundChannelChild> child = mBgChild;
Unused << child.forget().take();
}
void
BackgroundChannelCreateCallback::ActorFailed()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBgChild);
mBgChild->OnBackgroundChannelCreationFailed();
}
// HttpBackgroundChannelChild
HttpBackgroundChannelChild::HttpBackgroundChannelChild()
{
}
@ -20,6 +89,60 @@ HttpBackgroundChannelChild::~HttpBackgroundChannelChild()
{
}
nsresult
HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild)
{
LOG(("HttpBackgroundChannelChild::Init [this=%p httpChannel=%p channelId=%"
PRIu64 "]\n", this, aChannelChild, aChannelChild->ChannelId()));
MOZ_ASSERT(NS_IsMainThread());
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(NS_IsMainThread());
// HttpChannelChild is not going to handle any incoming message.
mChannelChild = nullptr;
}
void
HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed()
{
LOG(("HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed"
" [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (mChannelChild) {
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
channelChild->FailedAsyncOpen(NS_ERROR_UNEXPECTED);
}
}
bool
HttpBackgroundChannelChild::CreateBackgroundChannel()
{
LOG(("HttpBackgroundChannelChild::CreateBackgroundChannel [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
RefPtr<BackgroundChannelCreateCallback> callback =
new BackgroundChannelCreateCallback(this);
return BackgroundChild::GetOrCreateForCurrentThread(callback);
}
// PHttpBackgroundChannelChild
IPCResult
HttpBackgroundChannelChild::RecvOnStartRequestSent()
{
@ -73,6 +196,13 @@ HttpBackgroundChannelChild::RecvDivertMessages()
void
HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (mChannelChild) {
RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
channelChild->OnBackgroundChildDestroyed();
}
}
} // namespace net

Просмотреть файл

@ -15,12 +15,26 @@ using mozilla::ipc::IPCResult;
namespace mozilla {
namespace net {
class HttpChannelChild;
class HttpBackgroundChannelChild final : public PHttpBackgroundChannelChild
{
friend class BackgroundChannelCreateCallback;
public:
explicit HttpBackgroundChannelChild();
virtual ~HttpBackgroundChannelChild();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HttpBackgroundChannelChild)
// 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 while failed to create PBackground IPC channel.
void OnBackgroundChannelCreationFailed();
protected:
IPCResult RecvOnTransportAndData(const nsresult& aChannelStatus,
@ -44,6 +58,19 @@ protected:
IPCResult RecvOnStartRequestSent() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~HttpBackgroundChannelChild();
// Initiate the creation of the PBckground IPC channel.
// Return false if failed.
bool CreateBackgroundChannel();
// 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;
};
} // namespace net

Просмотреть файл

@ -5,24 +5,159 @@
* 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 "HttpBackgroundChannelParent.h"
#include "HttpChannelParent.h"
#include "mozilla/ipc/BackgroundParent.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;
using mozilla::ipc::AssertIsOnBackgroundThread;
using mozilla::ipc::BackgroundParent;
using mozilla::ipc::IPCResult;
using mozilla::ipc::IsOnBackgroundThread;
namespace mozilla {
namespace net {
HttpBackgroundChannelParent::HttpBackgroundChannelParent()
/*
* Helper class for continuing the AsyncOpen procedure on main thread.
*/
class ContinueAsyncOpenRunnable final : public Runnable
{
public:
ContinueAsyncOpenRunnable(HttpBackgroundChannelParent* aActor,
const uint64_t& aChannelId)
: mActor(aActor)
, mChannelId(aChannelId)
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(mActor);
}
NS_IMETHOD Run() override
{
LOG(("HttpBackgroundChannelParent::ContinueAsyncOpen [this=%p channelId=%"
PRIu64 "]\n", mActor.get(), mChannelId));
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(registrar);
registrar->LinkBackgroundChannel(mChannelId, mActor);
return NS_OK;
}
private:
RefPtr<HttpBackgroundChannelParent> mActor;
const uint64_t mChannelId;
};
HttpBackgroundChannelParent::HttpBackgroundChannelParent()
: mIPCOpened(true)
, mBackgroundThread(NS_GetCurrentThread())
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
}
HttpBackgroundChannelParent::~HttpBackgroundChannelParent()
{
MOZ_ASSERT(NS_IsMainThread() || IsOnBackgroundThread());
MOZ_ASSERT(!mIPCOpened);
}
nsresult
HttpBackgroundChannelParent::Init(const uint64_t& aChannelId)
{
LOG(("HttpBackgroundChannelParent::Init [this=%p channelId=%" PRIu64 "]\n",
this, aChannelId));
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
RefPtr<ContinueAsyncOpenRunnable> runnable =
new ContinueAsyncOpenRunnable(this, aChannelId);
return NS_DispatchToMainThread(runnable);
}
void
HttpBackgroundChannelParent::LinkToChannel(HttpChannelParent* aChannelParent)
{
LOG(("HttpBackgroundChannelParent::LinkToChannel [this=%p channel=%p]\n",
this, aChannelParent));
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
MOZ_DIAGNOSTIC_ASSERT(mIPCOpened);
if (!mIPCOpened) {
return;
}
mChannelParent = aChannelParent;
}
void
HttpBackgroundChannelParent::OnChannelClosed()
{
LOG(("HttpBackgroundChannelParent::OnChannelClosed [this=%p]\n", this));
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
if (!mIPCOpened) {
return;
}
nsresult rv;
RefPtr<HttpBackgroundChannelParent> self = this;
rv = mBackgroundThread->Dispatch(NS_NewRunnableFunction([self]() {
LOG(("HttpBackgroundChannelParent::DeleteRunnable [this=%p]\n", self.get()));
AssertIsOnBackgroundThread();
if (!self->mIPCOpened.compareExchange(true, false)) {
return;
}
Unused << self->Send__delete__(self);
}), NS_DISPATCH_NORMAL);
Unused << NS_WARN_IF(NS_FAILED(rv));
}
void
HttpBackgroundChannelParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("HttpBackgroundChannelParent::ActorDestroy [this=%p]\n", this));
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
mIPCOpened = false;
RefPtr<HttpBackgroundChannelParent> self = this;
DebugOnly<nsresult> rv =
NS_DispatchToMainThread(NS_NewRunnableFunction([self]() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<HttpChannelParent> channelParent =
self->mChannelParent.forget();
if (channelParent) {
channelParent->OnBackgroundParentDestroyed();
}
}));
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
} // namespace net

Просмотреть файл

@ -9,19 +9,48 @@
#define mozilla_net_HttpBackgroundChannelParent_h
#include "mozilla/net/PHttpBackgroundChannelParent.h"
#include "mozilla/Atomics.h"
#include "nsID.h"
#include "nsISupportsImpl.h"
class nsIEventTarget;
namespace mozilla {
namespace net {
class HttpChannelParent;
class HttpBackgroundChannelParent final : public PHttpBackgroundChannelParent
{
public:
explicit HttpBackgroundChannelParent();
virtual ~HttpBackgroundChannelParent();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HttpBackgroundChannelParent)
// Try to find associated HttpChannelParent with the same
// channel Id.
nsresult Init(const uint64_t& aChannelId);
// 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();
protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
virtual ~HttpBackgroundChannelParent();
Atomic<bool> mIPCOpened;
nsCOMPtr<nsIEventTarget> mBackgroundThread;
// associated HttpChannelParent for generating the channel events
RefPtr<HttpChannelParent> mChannelParent;
};
} // namespace net

Просмотреть файл

@ -364,6 +364,11 @@ public: /* Necko internal use only... */
mIsTrackingResource = true;
}
const uint64_t& ChannelId() const
{
return mChannelId;
}
protected:
// Handle notifying listener, removing from loadgroup if request failed.
void DoNotifyListener();

Просмотреть файл

@ -21,6 +21,7 @@
#include "mozilla/net/HttpChannelChild.h"
#include "AltDataOutputStreamChild.h"
#include "HttpBackgroundChannelChild.h"
#include "nsCOMPtr.h"
#include "nsISupportsPrimitives.h"
#include "nsChannelClassifier.h"
@ -272,6 +273,26 @@ HttpChannelChild::ReleaseIPDLReference()
Release();
}
void
HttpChannelChild::OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild)
{
LOG(("HttpChannelChild::OnBackgroundChildReady [this=%p, bgChild=%p]\n",
this, aBgChild));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBgChild);
MOZ_ASSERT(mBgChild == aBgChild);
}
void
HttpChannelChild::OnBackgroundChildDestroyed()
{
LOG(("HttpChannelChild::OnBackgroundChildDestroyed [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
mBgChild = nullptr;
}
class AssociateApplicationCacheEvent : public ChannelEvent
{
public:
@ -1030,6 +1051,8 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
// DoOnStopRequest() calls ReleaseListeners()
}
CleanupBackgroundChannel();
// DocumentChannelCleanup actually nulls out mCacheEntry in the parent, which
// we might need later to open the Alt-Data output stream, so just return here
if (!mPreferredCachedAltDataType.IsEmpty()) {
@ -1252,6 +1275,9 @@ void
HttpChannelChild::HandleAsyncAbort()
{
HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
// Ignore all the messages from background channel after channel aborted.
CleanupBackgroundChannel();
}
void
@ -1259,6 +1285,14 @@ HttpChannelChild::FailedAsyncOpen(const nsresult& status)
{
LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%" PRIx32 "]\n",
this, static_cast<uint32_t>(status)));
MOZ_ASSERT(NS_IsMainThread());
// Might be called twice in race condition in theory.
// (one by RecvFailedAsyncOpen, another by
// HttpBackgroundChannelChild::ActorFailed)
if (NS_WARN_IF(NS_FAILED(mStatus))) {
return;
}
mStatus = status;
@ -1270,6 +1304,27 @@ HttpChannelChild::FailedAsyncOpen(const nsresult& status)
}
}
void
HttpChannelChild::CleanupBackgroundChannel()
{
LOG(("HttpChannelChild::CleanupBackgroundChannel [this=%p]\n", this));
if (!mBgChild) {
return;
}
RefPtr<HttpBackgroundChannelChild> bgChild = mBgChild.forget();
if (!NS_IsMainThread()) {
SystemGroup::Dispatch(
"HttpChannelChild::CleanupBackgroundChannel",
TaskCategory::Other,
NewRunnableMethod(bgChild, &HttpBackgroundChannelChild::OnChannelClosed));
} else {
bgChild->OnChannelClosed();
}
}
void
HttpChannelChild::DoNotifyListenerCleanup()
{
@ -1835,6 +1890,20 @@ HttpChannelChild::ConnectParent(uint32_t registrarId)
return NS_ERROR_FAILURE;
}
{
MOZ_ASSERT(!mBgChild);
RefPtr<HttpBackgroundChannelChild> bgChild =
new HttpBackgroundChannelChild();
nsresult rv = bgChild->Init(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mBgChild = bgChild.forget();
}
return NS_OK;
}
@ -2463,6 +2532,26 @@ HttpChannelChild::ContinueAsyncOpen()
return NS_ERROR_FAILURE;
}
{
// Service worker might use the same HttpChannelChild to do async open
// twice. Need to disconnect with previous background channel before
// creating the new one.
if (mBgChild) {
RefPtr<HttpBackgroundChannelChild> prevBgChild = mBgChild.forget();
prevBgChild->OnChannelClosed();
}
RefPtr<HttpBackgroundChannelChild> bgChild =
new HttpBackgroundChannelChild();
rv = bgChild->Init(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mBgChild = bgChild.forget();
}
return NS_OK;
}

Просмотреть файл

@ -39,6 +39,7 @@ class nsInputStreamPump;
namespace mozilla {
namespace net {
class HttpBackgroundChannelChild;
class InterceptedChannelContent;
class InterceptStreamListener;
@ -117,6 +118,11 @@ public:
void OnCopyComplete(nsresult aStatus) override;
// Callback while background channel is ready.
void OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild);
// Callback while background channel is destroyed.
void OnBackgroundChildDestroyed();
protected:
mozilla::ipc::IPCResult RecvOnStartRequest(const nsresult& channelStatus,
const nsHttpResponseHead& responseHead,
@ -312,6 +318,12 @@ private:
// is synthesized.
bool mSuspendParentAfterSynthesizeResponse;
RefPtr<HttpBackgroundChannelChild> mBgChild;
// Remove the association with background channel after OnStopRequest
// or AsyncAbort.
void CleanupBackgroundChannel();
// Needed to call AsyncOpen in FinishInterceptedRedirect
nsCOMPtr<nsIStreamListener> mInterceptedRedirectListener;
nsCOMPtr<nsISupports> mInterceptedRedirectContext;
@ -403,6 +415,7 @@ private:
friend class HttpAsyncAborter<HttpChannelChild>;
friend class InterceptStreamListener;
friend class InterceptedChannelContent;
friend class HttpBackgroundChannelChild;
};
// A stream listener interposed between the nsInputStreamPump used for intercepted channels

Просмотреть файл

@ -10,16 +10,21 @@
#include "mozilla/ipc/FileDescriptorSetParent.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/net/HttpChannelParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "HttpBackgroundChannelParent.h"
#include "HttpChannelParentListener.h"
#include "nsHttpHandler.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsISupportsPriority.h"
#include "nsIAuthPromptProvider.h"
#include "nsIBackgroundChannelRegistrar.h"
#include "nsSerializationHelper.h"
#include "nsISerializable.h"
#include "nsIAssociatedContentSecurity.h"
@ -38,6 +43,7 @@
#include "nsCORSListenerProxy.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsIPrompt.h"
#include "nsIRedirectChannelRegistrar.h"
#include "nsIWindowWatcher.h"
#include "nsIDocument.h"
#include "nsStreamUtils.h"
@ -45,7 +51,6 @@
#include "nsIStorageStream.h"
#include "nsQueryObject.h"
#include "nsIURIClassifier.h"
#include "mozilla/dom/ContentParent.h"
using mozilla::BasePrincipal;
using namespace mozilla::dom;
@ -59,7 +64,6 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
PBOverrideStatus aOverrideStatus)
: mIPCClosed(false)
, mIgnoreProgress(false)
, mSentRedirect1Begin(false)
, mSentRedirect1BeginFailed(false)
, mReceivedRedirect2Verify(false)
, mPBOverride(aOverrideStatus)
@ -94,6 +98,7 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
HttpChannelParent::~HttpChannelParent()
{
LOG(("Destroying HttpChannelParent [this=%p]\n", this));
CleanupBackgroundChannel();
}
void
@ -109,6 +114,8 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
if (mParentListener) {
mParentListener->ClearInterceptedChannel();
}
CleanupBackgroundChannel();
}
bool
@ -154,6 +161,101 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
}
}
void
HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv)
{
LOG(("HttpChannelParent::TryInvokeAsyncOpen [this=%p barrier=%u rv=%" PRIx32
"]\n", this, mAsyncOpenBarrier, static_cast<uint32_t>(aRv)));
MOZ_ASSERT(NS_IsMainThread());
// TryInvokeAsyncOpen is called more than we expected.
// Assert in nightly build but ignore it in release channel.
MOZ_DIAGNOSTIC_ASSERT(mAsyncOpenBarrier > 0);
if (NS_WARN_IF(!mAsyncOpenBarrier)) {
return;
}
if (--mAsyncOpenBarrier > 0 && NS_SUCCEEDED(aRv)) {
// Need to wait for more events.
return;
}
InvokeAsyncOpen(aRv);
}
void
HttpChannelParent::OnBackgroundParentReady(
HttpBackgroundChannelParent* aBgParent)
{
LOG(("HttpChannelParent::OnBackgroundParentReady [this=%p bgParent=%p]\n",
this, aBgParent));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mBgParent);
mBgParent = aBgParent;
mPromise.ResolveIfExists(true, __func__);
}
void
HttpChannelParent::OnBackgroundParentDestroyed()
{
LOG(("HttpChannelParent::OnBackgroundParentDestroyed [this=%p]\n", this));
MOZ_ASSERT(NS_IsMainThread());
if (!mPromise.IsEmpty()) {
MOZ_ASSERT(!mBgParent);
mPromise.Reject(NS_ERROR_FAILURE, __func__);
return;
}
if (!mBgParent) {
return;
}
// Background channel is closed unexpectly, abort PHttpChannel operation.
mBgParent = nullptr;
Delete();
}
void
HttpChannelParent::CleanupBackgroundChannel()
{
LOG(("HttpChannelParent::CleanupBackgroundChannel [this=%p bgParent=%p]\n",
this, mBgParent.get()));
MOZ_ASSERT(NS_IsMainThread());
if (mBgParent) {
RefPtr<HttpBackgroundChannelParent> bgParent = mBgParent.forget();
bgParent->OnChannelClosed();
return;
}
if (!mPromise.IsEmpty()) {
mRequest.DisconnectIfExists();
mPromise.Reject(NS_ERROR_FAILURE, __func__);
if (!mChannel) {
return;
}
// This HttpChannelParent might still have a reference from
// BackgroundChannelRegistrar.
nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(registrar);
registrar->DeleteChannel(mChannel->ChannelId());
// If mAsyncOpenBarrier is greater than zero, it means AsyncOpen procedure
// is still on going. we need to abort AsyncOpen with failure to destroy
// PHttpChannel actor.
if (mAsyncOpenBarrier) {
TryInvokeAsyncOpen(NS_ERROR_FAILURE);
}
}
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsISupports
//-----------------------------------------------------------------------------
@ -169,6 +271,7 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelParent)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel)
NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel)
if (aIID.Equals(NS_GET_IID(HttpChannelParent))) {
foundInterface = static_cast<nsIInterfaceRequestor*>(this);
@ -254,6 +357,10 @@ HttpChannelParent::AsyncOpenFailed(nsresult aRv)
void
HttpChannelParent::InvokeAsyncOpen(nsresult rv)
{
LOG(("HttpChannelParent::InvokeAsyncOpen [this=%p rv=%" PRIx32 "]\n",
this, static_cast<uint32_t>(rv)));
MOZ_ASSERT(NS_IsMainThread());
if (NS_FAILED(rv)) {
AsyncOpenFailed(rv);
return;
@ -292,7 +399,7 @@ public:
NS_IMETHOD Run()
{
RefPtr<HttpChannelParent> channel = do_QueryObject(mChannel.get());
channel->InvokeAsyncOpen(mStatus);
channel->TryInvokeAsyncOpen(mStatus);
return NS_OK;
}
};
@ -459,7 +566,6 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
httpChannel->SetCorsPreflightParameters(args.unsafeHeaders());
}
bool delayAsyncOpen = false;
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream);
if (stream) {
// FIXME: The fast path of using the existing stream currently only applies to streams
@ -467,7 +573,8 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
// Once bug 1294446 and bug 1294450 are fixed it is worth revisiting this heuristic.
nsCOMPtr<nsIIPCSerializableInputStream> completeStream = do_QueryInterface(stream);
if (!completeStream) {
delayAsyncOpen = true;
// Wait for completion of async copying IPC upload stream to a local input stream.
++mAsyncOpenBarrier;
// buffer size matches PChildToParentStream transfer size.
const uint32_t kBufferSize = 32768;
@ -626,13 +733,49 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse;
if (!delayAsyncOpen) {
InvokeAsyncOpen(NS_OK);
}
MOZ_ASSERT(!mBgParent);
MOZ_ASSERT(mPromise.IsEmpty());
// Wait for HttpBackgrounChannel to continue the async open procedure.
++mAsyncOpenBarrier;
RefPtr<GenericPromise> promise = WaitForBgParent();
RefPtr<HttpChannelParent> self = this;
promise->Then(AbstractThread::MainThread(), __func__,
[self]() {
self->mRequest.Complete();
self->TryInvokeAsyncOpen(NS_OK);
},
[self](nsresult aStatus) {
self->mRequest.Complete();
self->TryInvokeAsyncOpen(aStatus);
})
->Track(mRequest);
return true;
}
already_AddRefed<GenericPromise>
HttpChannelParent::WaitForBgParent()
{
LOG(("HttpChannelParent::WaitForBgParent [this=%p]\n", this));
MOZ_ASSERT(!mBgParent);
MOZ_ASSERT(mChannel);
nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(registrar);
registrar->LinkHttpChannel(mChannel->ChannelId(), this);
if (mBgParent) {
already_AddRefed<GenericPromise> promise = mPromise.Ensure(__func__);
// resolve promise immediatedly if bg channel is ready.
mPromise.Resolve(true, __func__);
return promise;
}
return mPromise.Ensure(__func__);;
}
bool
HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept)
{
@ -673,6 +816,20 @@ HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shoul
}
}
MOZ_ASSERT(!mBgParent);
MOZ_ASSERT(mPromise.IsEmpty());
// Waiting for background channel
RefPtr<GenericPromise> promise = WaitForBgParent();
RefPtr<HttpChannelParent> self = this;
promise->Then(AbstractThread::MainThread(), __func__,
[self]() {
self->mRequest.Complete();
},
[self](const nsresult& aResult) {
NS_ERROR("failed to establish the background channel");
self->mRequest.Complete();
})
->Track(mRequest);
return true;
}
@ -829,15 +986,89 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
}
}
// Continue the verification procedure if child has veto the redirection.
if (NS_FAILED(result)) {
ContinueRedirect2Verify(result);
return IPC_OK();
}
// Wait for background channel ready on target channel
nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
do_GetService(NS_REDIRECTCHANNELREGISTRAR_CONTRACTID);
MOZ_ASSERT(redirectReg);
nsCOMPtr<nsIParentChannel> redirectParentChannel;
rv = redirectReg->GetParentChannel(mRedirectRegistrarId,
getter_AddRefs(redirectParentChannel));
MOZ_ASSERT(redirectParentChannel);
if (!redirectParentChannel) {
ContinueRedirect2Verify(rv);
return IPC_OK();
}
nsCOMPtr<nsIParentRedirectingChannel> redirectedParent =
do_QueryInterface(redirectParentChannel);
if (!redirectedParent) {
// Continue verification procedure if redirecting to non-Http protocol
ContinueRedirect2Verify(result);
return IPC_OK();
}
// Ask redirected channel if verification can proceed.
// ContinueRedirect2Verify will be invoked when redirected channel is ready.
redirectedParent->ContinueVerification(this);
return IPC_OK();
}
// from nsIParentRedirectingChannel
NS_IMETHODIMP
HttpChannelParent::ContinueVerification(nsIAsyncVerifyRedirectReadyCallback* aCallback)
{
LOG(("HttpChannelParent::ContinueVerification [this=%p callback=%p]\n",
this, aCallback));
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aCallback);
// Continue the verification procedure if background channel is ready.
if (mBgParent) {
aCallback->ReadyToVerify(NS_OK);
return NS_OK;
}
// ConnectChannel must be received before Redirect2Verify.
MOZ_ASSERT(!mPromise.IsEmpty());
// Otherwise, wait for the background channel.
RefPtr<GenericPromise> promise = WaitForBgParent();
nsCOMPtr<nsIAsyncVerifyRedirectReadyCallback> callback = aCallback;
promise->Then(AbstractThread::MainThread(), __func__,
[callback]() {
callback->ReadyToVerify(NS_OK);
},
[callback](const nsresult& aResult) {
NS_ERROR("failed to establish the background channel");
callback->ReadyToVerify(aResult);
});
return NS_OK;
}
void
HttpChannelParent::ContinueRedirect2Verify(const nsresult& aResult)
{
LOG(("HttpChannelParent::ContinueRedirect2Verify [this=%p result=%" PRIx32 "]\n",
this, static_cast<uint32_t>(aResult)));
if (!mRedirectCallback) {
// This should according the logic never happen, log the situation.
if (mReceivedRedirect2Verify)
LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
if (mSentRedirect1BeginFailed)
LOG(("RecvRedirect2Verify[%p]: Send to child failed", this));
if (mSentRedirect1Begin && NS_FAILED(result))
if ((mRedirectRegistrarId > 0) && NS_FAILED(aResult))
LOG(("RecvRedirect2Verify[%p]: Redirect failed", this));
if (mSentRedirect1Begin && NS_SUCCEEDED(result))
if ((mRedirectRegistrarId > 0) && NS_SUCCEEDED(aResult))
LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this));
if (!mRedirectChannel)
LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this));
@ -849,20 +1080,19 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
mReceivedRedirect2Verify = true;
if (mRedirectCallback) {
LOG(("HttpChannelParent::RecvRedirect2Verify call OnRedirectVerifyCallback"
LOG(("HttpChannelParent::ContinueRedirect2Verify call OnRedirectVerifyCallback"
" [this=%p result=%" PRIx32 ", mRedirectCallback=%p]\n",
this, static_cast<uint32_t>(result), mRedirectCallback.get()));
mRedirectCallback->OnRedirectVerifyCallback(result);
this, static_cast<uint32_t>(aResult), mRedirectCallback.get()));
mRedirectCallback->OnRedirectVerifyCallback(aResult);
mRedirectCallback = nullptr;
}
return IPC_OK();
}
mozilla::ipc::IPCResult
HttpChannelParent::RecvDocumentChannelCleanup()
{
// From now on only using mAssociatedContentSecurity. Free everything else.
CleanupBackgroundChannel(); // Background channel can be closed.
mChannel = nullptr; // Reclaim some memory sooner.
mCacheEntry = nullptr; // Else we'll block other channels reading same URI
return IPC_OK();
@ -1297,6 +1527,7 @@ HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
if (mIPCClosed || !SendOnStopRequest(aStatusCode, timing))
return NS_ERROR_UNEXPECTED;
return NS_OK;
}
@ -1513,7 +1744,9 @@ HttpChannelParent::StartRedirect(uint32_t registrarId,
}
// Bug 621446 investigation
mSentRedirect1Begin = true;
// Store registrar Id of the new channel to find the redirect
// HttpChannelParent later in verification phase.
mRedirectRegistrarId = registrarId;
// Result is handled in RecvRedirect2Verify above
@ -1815,12 +2048,16 @@ HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
if (!isPending) {
mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
}
mParentListener = nullptr;
mChannel = nullptr;
if (!mIPCClosed) {
Unused << DoSendDeleteSelf();
}
// DoSendDeleteSelf will need channel Id to remove the strong reference in
// BackgroundChannelRegistrar if channel pairing is aborted.
// Thus we need to keep mChannel until DoSendDeleteSelf is done.
mParentListener = nullptr;
mChannel = nullptr;
}
nsresult
@ -1863,6 +2100,9 @@ HttpChannelParent::DoSendDeleteSelf()
{
bool rv = SendDeleteSelf();
mIPCClosed = true;
CleanupBackgroundChannel();
return rv;
}
@ -1913,6 +2153,22 @@ HttpChannelParent::IssueWarning(uint32_t aWarning, bool aAsError)
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsIAsyncVerifyRedirectReadyCallback
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelParent::ReadyToVerify(nsresult aResult)
{
LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%" PRIx32 "]\n",
this, static_cast<uint32_t>(aResult)));
MOZ_ASSERT(NS_IsMainThread());
ContinueRedirect2Verify(aResult);
return NS_OK;
}
void
HttpChannelParent::DoSendSetPriority(int16_t aValue)
{

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/net/PHttpChannelParent.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/MozPromise.h"
#include "nsIObserver.h"
#include "nsIParentRedirectingChannel.h"
#include "nsIProgressEventSink.h"
@ -37,6 +38,7 @@ class PBrowserOrId;
namespace net {
class HttpBackgroundChannelParent;
class HttpChannelParentListener;
class ChannelEventQueue;
@ -52,6 +54,7 @@ class HttpChannelParent final : public nsIInterfaceRequestor
, public nsIAuthPromptProvider
, public nsIDeprecationWarner
, public HttpChannelSecurityWarningReporter
, public nsIAsyncVerifyRedirectReadyCallback
{
virtual ~HttpChannelParent();
@ -65,6 +68,7 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIAUTHPROMPTPROVIDER
NS_DECL_NSIDEPRECATIONWARNER
NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK
NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_CHANNEL_PARENT_IID)
@ -99,10 +103,22 @@ public:
MOZ_MUST_USE nsresult OpenAlternativeOutputStream(const nsACString & type,
nsIOutputStream * *_retval);
// Callbacks for each asynchronous tasks required in AsyncOpen
// procedure, will call InvokeAsyncOpen when all the expected
// tasks is finished successfully or when any failure happened.
// @see mAsyncOpenBarrier.
void TryInvokeAsyncOpen(nsresult aRv);
void InvokeAsyncOpen(nsresult rv);
// Calls SendSetPriority if mIPCClosed is false.
void DoSendSetPriority(int16_t aValue);
// Callback while background channel is ready.
void OnBackgroundParentReady(HttpBackgroundChannelParent* aBgParent);
// Callback while background channel is destroyed.
void OnBackgroundParentDestroyed();
protected:
// used to connect redirected-to channel in parent with just created
// ChildChannel. Used during redirects.
@ -217,8 +233,26 @@ private:
void MaybeFlushPendingDiversion();
void ResponseSynthesized();
// final step for Redirect2Verify procedure, will be invoked while both
// redirecting and redirected channel are ready or any error happened.
// OnRedirectVerifyCallback will be invoked for finishing the async
// redirect verification procedure.
void ContinueRedirect2Verify(const nsresult& aResult);
void AsyncOpenFailed(nsresult aRv);
// Request to pair with a HttpBackgroundChannelParent with the same channel
// id, a promise will be returned so the caller can append callbacks on it.
// If called multiple times before mBgParent is available, the same promise
// will be returned and the callbacks will be invoked in order.
already_AddRefed<GenericPromise> WaitForBgParent();
// Remove the association with background channel after main-thread IPC
// is about to be destroyed or no further event is going to be sent, i.e.,
// DocumentChannelCleanup.
void CleanupBackgroundChannel();
friend class HttpBackgroundChannelParent;
friend class DivertDataAvailableEvent;
friend class DivertStopRequestEvent;
friend class DivertCompleteEvent;
@ -238,7 +272,6 @@ private:
// since the information can be recontructed from ODA.
bool mIgnoreProgress : 1;
bool mSentRedirect1Begin : 1;
bool mSentRedirect1BeginFailed : 1;
bool mReceivedRedirect2Verify : 1;
@ -274,6 +307,20 @@ private:
dom::TabId mNestedFrameId;
RefPtr<ChannelEventQueue> mEventQ;
RefPtr<HttpBackgroundChannelParent> mBgParent;
// Number of events to wait before actually invoking AsyncOpen on the main
// channel. For each asynchronous step required before InvokeAsyncOpen, should
// increase 1 to mAsyncOpenBarrier and invoke TryInvokeAsyncOpen after
// finished. This attribute is main thread only.
uint8_t mAsyncOpenBarrier = 0;
// Corresponding redirect channel registrar Id. 0 means redirection is not started.
uint32_t mRedirectRegistrarId = 0;
MozPromiseHolder<GenericPromise> mPromise;
MozPromiseRequestHolder<GenericPromise> mRequest;
};
NS_DEFINE_STATIC_IID_ACCESSOR(HttpChannelParent,

Просмотреть файл

@ -8,6 +8,7 @@ with Files('**'):
BUG_COMPONENT = ('Core', 'Networking: HTTP')
XPIDL_SOURCES += [
'nsIBackgroundChannelRegistrar.idl',
'nsIHstsPrimingCallback.idl',
'nsIHttpActivityObserver.idl',
'nsIHttpAuthenticableChannel.idl',
@ -60,6 +61,7 @@ UNIFIED_SOURCES += [
'AltDataOutputStreamParent.cpp',
'AlternateServices.cpp',
'ASpdySession.cpp',
'BackgroundChannelRegistrar.cpp',
'CacheControlParser.cpp',
'ConnectionDiagnostics.cpp',
'HSTSPrimerListener.cpp',

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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/. */
#include "nsISupports.idl"
%{ C++
namespace mozilla {
namespace net {
class HttpBackgroundChannelParent;
class HttpChannelParent;
}
}
%}
[ptr] native HttpChannelParent(mozilla::net::HttpChannelParent);
[ptr] native HttpBackgroundChannelParent(mozilla::net::HttpBackgroundChannelParent);
/*
* Registrar for pairing HttpChannelParent and HttpBackgroundChannelParent via
* channel Id. HttpChannelParent::OnBackgroundParentReady and
* HttpBackgroundChannelParent::LinkToChannel will be invoked to notify the
* existence of associated channel object.
*/
[builtinclass, uuid(8acaa9b1-f0c4-4ade-baeb-39b0d4b96e5b)]
interface nsIBackgroundChannelRegistrar : nsISupports
{
/*
* Link the provided channel parent actor with the given channel Id.
* callbacks will be invoked immediately when the HttpBackgroundChannelParent
* associated with the same channel Id is found. Store the HttpChannelParent
* until a matched linkBackgroundChannel is invoked.
*
* @param aKey the channel Id
* @param aChannel the channel parent actor to be paired
*/
[noscript,notxpcom,nostdcall] void linkHttpChannel(in uint64_t aKey,
in HttpChannelParent aChannel);
/*
* Link the provided background channel with the given channel Id.
* callbacks will be invoked immediately when the HttpChannelParent associated
* with the same channel Id is found. Store the HttpBackgroundChannelParent
* until a matched linkHttpChannel is invoked.
*
* @param aKey the channel Id
* @param aBgChannel the background channel to be paired
*/
[noscript,notxpcom,nostdcall] void linkBackgroundChannel(in uint64_t aKey,
in HttpBackgroundChannelParent aBgChannel);
/*
* Delete previous stored HttpChannelParent or HttpBackgroundChannelParent
* if no need to wait for the paired channel object, e.g. background channel
* is destroyed before pairing is completed.
*
* @param aKey the channel Id
*/
[noscript,notxpcom,nostdcall] void deleteChannel(in uint64_t aKey);
};