Bug 1260527 - Change HttpChannelChild to open IPDL earlier than AsyncOpen r=kershaw,dragana

Since we need the loadInfo to set up the IPDL connection, we move the logic to
do so from HttpChannelChild::AsyncOpen to HttpChannelChild::SetLoadInfo
via InitIPCChannel.
It would have been nicer to do so in HttpChannelChild::Init, but
I ran into issues with view-source channels, which required an ugly hack.

Also note that RemoteChannelExists() preserves the existing contract - it is
true between asyncOpen and onStopRequest - but the name is slightly off, as
the channel has already been open by the time we call asyncOpen. We will fix
this in a follow-up.

Differential Revision: https://phabricator.services.mozilla.com/D12419

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Valentin Gosu 2018-11-26 17:38:42 +00:00
Родитель 0b4013a03e
Коммит a6efc6d0af
10 изменённых файлов: 150 добавлений и 108 удалений

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

@ -74,9 +74,7 @@ void NeckoChild::InitNeckoChild()
}
PHttpChannelChild*
NeckoChild::AllocPHttpChannelChild(const PBrowserOrId& browser,
const SerializedLoadContext& loadContext,
const HttpChannelCreationArgs& aOpenArgs)
NeckoChild::AllocPHttpChannelChild()
{
// We don't allocate here: instead we always use IPDL constructor that takes
// an existing HttpChildChannel

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

@ -25,9 +25,7 @@ public:
static void InitNeckoChild();
protected:
virtual PHttpChannelChild*
AllocPHttpChannelChild(const PBrowserOrId&, const SerializedLoadContext&,
const HttpChannelCreationArgs& aOpenArgs) override;
virtual PHttpChannelChild* AllocPHttpChannelChild() override;
virtual bool DeallocPHttpChannelChild(PHttpChannelChild*) override;
virtual PStunAddrsRequestChild* AllocPStunAddrsRequestChild() override;

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

@ -92,8 +92,9 @@ NeckoParent::NeckoParent()
}
}
static PBOverrideStatus
PBOverrideStatusFromLoadContext(const SerializedLoadContext& aSerialized)
/* static */ PBOverrideStatus
NeckoParent::PBOverrideStatusFromLoadContext(
const SerializedLoadContext& aSerialized)
{
if (!aSerialized.IsNotNull() && aSerialized.IsPrivateBitValid()) {
return (aSerialized.mOriginAttributes.mPrivateBrowsingId > 0) ?
@ -103,8 +104,9 @@ PBOverrideStatusFromLoadContext(const SerializedLoadContext& aSerialized)
return kPBOverride_Unset;
}
static already_AddRefed<nsIPrincipal>
GetRequestingPrincipal(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs)
/* static */ already_AddRefed<nsIPrincipal>
NeckoParent::GetRequestingPrincipal(
const OptionalLoadInfoArgs& aOptionalLoadInfoArgs)
{
if (aOptionalLoadInfoArgs.type() != OptionalLoadInfoArgs::TLoadInfoArgs) {
return nullptr;
@ -124,8 +126,8 @@ GetRequestingPrincipal(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs)
return PrincipalInfoToPrincipal(principalInfo);
}
static already_AddRefed<nsIPrincipal>
GetRequestingPrincipal(const HttpChannelCreationArgs& aArgs)
/* static */ already_AddRefed<nsIPrincipal>
NeckoParent::GetRequestingPrincipal(const HttpChannelCreationArgs& aArgs)
{
if (aArgs.type() != HttpChannelCreationArgs::THttpChannelOpenArgs) {
return nullptr;
@ -135,8 +137,8 @@ GetRequestingPrincipal(const HttpChannelCreationArgs& aArgs)
return GetRequestingPrincipal(args.loadInfo());
}
static already_AddRefed<nsIPrincipal>
GetRequestingPrincipal(const FTPChannelCreationArgs& aArgs)
/* static */ already_AddRefed<nsIPrincipal>
NeckoParent::GetRequestingPrincipal(const FTPChannelCreationArgs& aArgs)
{
if (aArgs.type() != FTPChannelCreationArgs::TFTPChannelOpenArgs) {
return nullptr;
@ -157,7 +159,7 @@ void CrashWithReason(const char * reason)
#endif
}
const char*
/* static */ const char*
NeckoParent::GetValidatedOriginAttributes(const SerializedLoadContext& aSerialized,
PContentParent* aContent,
nsIPrincipal* aRequestingPrincipal,
@ -233,7 +235,7 @@ NeckoParent::GetValidatedOriginAttributes(const SerializedLoadContext& aSerializ
return "App does not have permission";
}
const char *
/* static */ const char *
NeckoParent::CreateChannelLoadContext(const PBrowserOrId& aBrowser,
PContentParent* aContent,
const SerializedLoadContext& aSerialized,
@ -284,25 +286,9 @@ NeckoParent::ActorDestroy(ActorDestroyReason aWhy)
}
PHttpChannelParent*
NeckoParent::AllocPHttpChannelParent(const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs)
NeckoParent::AllocPHttpChannelParent()
{
nsCOMPtr<nsIPrincipal> requestingPrincipal =
GetRequestingPrincipal(aOpenArgs);
nsCOMPtr<nsILoadContext> loadContext;
const char *error = CreateChannelLoadContext(aBrowser, Manager(),
aSerialized, requestingPrincipal,
loadContext);
if (error) {
printf_stderr("NeckoParent::AllocPHttpChannelParent: "
"FATAL error: %s: KILLING CHILD PROCESS\n",
error);
return nullptr;
}
PBOverrideStatus overrideStatus = PBOverrideStatusFromLoadContext(aSerialized);
HttpChannelParent *p = new HttpChannelParent(aBrowser, loadContext, overrideStatus);
HttpChannelParent* p = new HttpChannelParent();
p->AddRef();
return p;
}
@ -315,20 +301,6 @@ NeckoParent::DeallocPHttpChannelParent(PHttpChannelParent* channel)
return true;
}
mozilla::ipc::IPCResult
NeckoParent::RecvPHttpChannelConstructor(
PHttpChannelParent* aActor,
const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs)
{
HttpChannelParent* p = static_cast<HttpChannelParent*>(aActor);
if (!p->Init(aOpenArgs)) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
PStunAddrsRequestParent*
NeckoParent::AllocPStunAddrsRequestParent()
{

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

@ -33,6 +33,15 @@ public:
NeckoParent();
virtual ~NeckoParent() = default;
static PBOverrideStatus PBOverrideStatusFromLoadContext(
const SerializedLoadContext& aSerialized);
static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
const OptionalLoadInfoArgs& aOptionalLoadInfoArgs);
static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
const FTPChannelCreationArgs& aArgs);
static already_AddRefed<nsIPrincipal> GetRequestingPrincipal(
const HttpChannelCreationArgs& aArgs);
MOZ_MUST_USE
static const char *
GetValidatedOriginAttributes(const SerializedLoadContext& aSerialized,
@ -93,15 +102,7 @@ public:
};
protected:
virtual PHttpChannelParent*
AllocPHttpChannelParent(const PBrowserOrId&, const SerializedLoadContext&,
const HttpChannelCreationArgs& aOpenArgs) override;
virtual mozilla::ipc::IPCResult
RecvPHttpChannelConstructor(
PHttpChannelParent* aActor,
const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs) override;
virtual PHttpChannelParent* AllocPHttpChannelParent() override;
virtual bool DeallocPHttpChannelParent(PHttpChannelParent*) override;
virtual PStunAddrsRequestParent* AllocPStunAddrsRequestParent() override;

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

@ -72,9 +72,7 @@ parent:
async __delete__();
nested(inside_cpow) async PCookieService();
async PHttpChannel(PBrowserOrId browser,
SerializedLoadContext loadContext,
HttpChannelCreationArgs args);
async PHttpChannel();
async PWyciwygChannel();
async PFTPChannel(PBrowserOrId browser, SerializedLoadContext loadContext,
FTPChannelCreationArgs args);

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

@ -193,6 +193,7 @@ HttpChannelChild::HttpChannelChild()
, mSuspendParentAfterSynthesizeResponse(false)
, mCacheNeedToReportBytesReadInitialized(false)
, mNeedToReportBytesRead(true)
, mSentAsyncOpen(false)
{
LOG(("Creating HttpChannelChild @%p\n", this));
@ -266,7 +267,7 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release()
// remote channel for security info IPDL itself holds 1 reference, so we
// Send_delete when refCnt==1. But if !mIPCOpen, then there's nobody to send
// to, so we fall through.
if (mKeptAlive && count == 1 && mIPCOpen) {
if ((mKeptAlive || !mSentAsyncOpen) && count == 1 && mIPCOpen) {
mKeptAlive = false;
// We send a message to the parent, which calls SendDelete, and then the
// child calling Send__delete__() to finally drop the refcount to 0.
@ -1707,7 +1708,8 @@ HttpChannelChild::DeleteSelf()
void HttpChannelChild::FinishInterceptedRedirect()
{
nsresult rv;
nsresult rv = InitIPCChannel(); // reinitializes IPC channel
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
MOZ_ASSERT(!mInterceptedRedirectContext, "the context should be null!");
rv = AsyncOpen2(mInterceptedRedirectListener);
@ -2264,24 +2266,13 @@ HttpChannelChild::ConnectParent(uint32_t registrarId)
HttpBaseChannel::SetDocshellUserAgentOverride();
// The socket transport in the chrome process now holds a logical ref to us
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
AddIPDLReference();
// This must happen before the constructor message is sent. Otherwise messages
// from the parent could arrive quickly and be delivered to the wrong event
// target.
SetEventTarget();
HttpChannelConnectArgs connectArgs(registrarId, mShouldParentIntercept);
PBrowserOrId browser = static_cast<ContentChild*>(gNeckoChild->Manager())
->GetBrowserOrId(tabChild);
if (!gNeckoChild->
SendPHttpChannelConstructor(this, browser,
IPC::SerializedLoadContext(this),
connectArgs)) {
if (!SendAsyncOpen(browser, IPC::SerializedLoadContext(this), connectArgs)) {
return NS_ERROR_FAILURE;
}
mSentAsyncOpen = true;
{
MutexAutoLock lock(mBgChildMutex);
@ -2788,6 +2779,42 @@ HttpChannelChild::AsyncOpen2(nsIStreamListener *aListener)
return AsyncOpen(listener, nullptr);
}
NS_IMETHODIMP
HttpChannelChild::SetLoadInfo(nsILoadInfo* aLoadInfo)
{
LOG(("HttpChannelChild::SetLoadInfo [this=%p, aLoadInfo=%p]",
this, aLoadInfo));
MOZ_ALWAYS_SUCCEEDS(HttpBaseChannel::SetLoadInfo(aLoadInfo));
// IPC channel already open
if (NS_WARN_IF(mIPCOpen)) {
return NS_OK;
}
return InitIPCChannel();
}
nsresult
HttpChannelChild::InitIPCChannel()
{
MOZ_ASSERT(!mIPCOpen);
// This must happen before the constructor message is sent. Otherwise messages
// from the parent could arrive quickly and be delivered to the wrong event
// target.
SetEventTarget();
LOG((" Calling SendPHttpChannelConstructor"));
if (!gNeckoChild->SendPHttpChannelConstructor(this)) {
return NS_ERROR_FAILURE;
}
// The socket transport in the chrome process now holds a logical ref to us
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
AddIPDLReference();
return NS_OK;
}
// Assigns an nsIEventTarget to our IPDL actor so that IPC messages are sent to
// the correct DocGroup/TabGroup.
void
@ -3001,21 +3028,12 @@ HttpChannelChild::ContinueAsyncOpen()
openArgs.navigationStartTimeStamp() = navigationStartTimeStamp;
// This must happen before the constructor message is sent. Otherwise messages
// from the parent could arrive quickly and be delivered to the wrong event
// target.
SetEventTarget();
// The socket transport in the chrome process now holds a logical ref to us
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
AddIPDLReference();
LOG(("HttpChannelChild::ContinueAsyncOpen - SendAsyncOpen [this=%p]", this));
PBrowserOrId browser = cc->GetBrowserOrId(tabChild);
if (!gNeckoChild->SendPHttpChannelConstructor(this, browser,
IPC::SerializedLoadContext(this),
openArgs)) {
if (!SendAsyncOpen(browser, IPC::SerializedLoadContext(this), openArgs)) {
return NS_ERROR_FAILURE;
}
mSentAsyncOpen = true;
{
MutexAutoLock lock(mBgChildMutex);
@ -3792,6 +3810,14 @@ HttpChannelChild::ResetInterception()
return;
}
if (!mIPCOpen) {
// The IPC channel was closed. See RecvFinishInterceptedRedirect.
// We now want to reuse it, so we call InitIPCChannel again.
DebugOnly<nsresult> rv = InitIPCChannel();
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
MOZ_ASSERT(mLoadInfo && mIPCOpen);
// Continue with the original cross-process request
nsresult rv = ContinueAsyncOpen();
if (NS_WARN_IF(NS_FAILED(rv))) {

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

@ -91,6 +91,7 @@ public:
NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo) override;
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
NS_IMETHOD SetLoadInfo(nsILoadInfo* aLoadInfo) override;
// HttpBaseChannel::nsIHttpChannel
NS_IMETHOD SetReferrerWithPolicy(nsIURI *referrer, uint32_t referrerPolicy) override;
@ -206,6 +207,7 @@ protected:
virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest(const nsString& aMessage, const nsCString& aCategory) override;
NS_IMETHOD LogBlockedCORSRequest(const nsAString & aMessage, const nsACString& aCategory) override;
nsresult InitIPCChannel();
private:
nsresult
AsyncCallImpl(void (HttpChannelChild::*funcPtr)(),
@ -432,11 +434,22 @@ private:
// True if we need to tell the parent the size of unreported received data
uint8_t mNeedToReportBytesRead : 1;
// True after SendAsyncOpen is called.
uint8_t mSentAsyncOpen : 1;
void FinishInterceptedRedirect();
void CleanupRedirectingChannel(nsresult rv);
// true after successful AsyncOpen until OnStopRequest completes.
bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; }
// XXX valentin: technically the channel exists after SetLoadInfo, but it
// used to be created at AsyncOpen, and before that the parent actually
// doesn't have all the info for it to be safe to call any method.
// We should rename it in the future and allow some methods to be called
// before asyncOpen.
bool RemoteChannelExists()
{
return mIPCOpen && !mKeptAlive && mSentAsyncOpen;
}
void AssociateApplicationCache(const nsCString &groupID,
const nsCString &clientID);

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

@ -62,13 +62,11 @@ using namespace mozilla::ipc;
namespace mozilla {
namespace net {
HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
nsILoadContext* aLoadContext,
PBOverrideStatus aOverrideStatus)
: mLoadContext(aLoadContext)
HttpChannelParent::HttpChannelParent()
: mLoadContext(nullptr)
, mNestedFrameId(0)
, mIPCClosed(false)
, mPBOverride(aOverrideStatus)
, mPBOverride(kPBOverride_Unset)
, mStatus(NS_OK)
, mIgnoreProgress(false)
, mSentRedirect1BeginFailed(false)
@ -94,14 +92,6 @@ HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
MOZ_ASSERT(gHttpHandler);
mHttpHandler = gHttpHandler;
if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent());
} else {
mNestedFrameId = iframeEmbedding.get_TabId();
}
mSendWindowSize = gHttpHandler->SendWindowSize();
mEventQ = new ChannelEventQueue(static_cast<nsIParentRedirectingChannel*>(this));
}
@ -175,6 +165,43 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
}
}
mozilla::ipc::IPCResult
HttpChannelParent::RecvAsyncOpen(const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs)
{
LOG(("HttpChannelParent::RecvAsyncOpen [this=%p]\n", this));
nsCOMPtr<nsIPrincipal> requestingPrincipal =
NeckoParent::GetRequestingPrincipal(aOpenArgs);
nsCOMPtr<nsILoadContext> loadContext;
const char* error =
NeckoParent::CreateChannelLoadContext(aBrowser,
Manager()->Manager(),
aSerialized,
requestingPrincipal,
loadContext);
if (error) {
return IPC_FAIL(this, "Error in NeckoParent::CreateChannelLoadContext");
}
mPBOverride = NeckoParent::PBOverrideStatusFromLoadContext(aSerialized);
mLoadContext = loadContext;
if (aBrowser.type() == PBrowserOrId::TPBrowserParent) {
mTabParent = static_cast<dom::TabParent*>(aBrowser.get_PBrowserParent());
} else {
mNestedFrameId = aBrowser.get_TabId();
}
mSendWindowSize = gHttpHandler->SendWindowSize();
if (!Init(aOpenArgs)) {
return IPC_FAIL(this, "Error in HttpChannelParent::Init");
}
return IPC_OK();
}
void
HttpChannelParent::TryInvokeAsyncOpen(nsresult aRv)
{
@ -478,8 +505,12 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
nsCOMPtr<nsIURI> topWindowUri = DeserializeURI(aTopWindowURI);
LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s, gid=%" PRIu64 " topwinid=%" PRIx64 "]\n",
this, uri->GetSpecOrDefault().get(), aChannelId, aTopLevelOuterContentWindowId));
LOG(("HttpChannelParent DoAsyncOpen [this=%p uri=%s, gid=%" PRIu64
" topwinid=%" PRIx64 "]\n",
this,
uri->GetSpecOrDefault().get(),
aChannelId,
aTopLevelOuterContentWindowId));
nsresult rv;

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

@ -71,9 +71,7 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_CHANNEL_PARENT_IID)
HttpChannelParent(const dom::PBrowserOrId& iframeEmbedding,
nsILoadContext* aLoadContext,
PBOverrideStatus aStatus);
HttpChannelParent();
MOZ_MUST_USE bool Init(const HttpChannelCreationArgs& aOpenArgs);
@ -233,6 +231,10 @@ protected:
// Called to notify the parent channel to not send any more IPC messages.
virtual mozilla::ipc::IPCResult RecvDeletingChannel() override;
virtual mozilla::ipc::IPCResult RecvFinishInterceptedRedirect() override;
virtual mozilla::ipc::IPCResult RecvAsyncOpen(
const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs) override;
private:
void UpdateAndSerializeSecurityInfo(nsACString& aSerializedSecurityInfoOut);

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

@ -13,12 +13,14 @@ include PBackgroundSharedTypes;
include NeckoChannelParams;
include IPCServiceWorkerDescriptor;
include IPCStream;
include PBrowserOrId;
include "mozilla/net/NeckoMessageUtils.h";
using class nsHttpHeaderArray from "nsHttpHeaderArray.h";
using mozilla::net::NetAddr from "mozilla/net/DNS.h";
using struct mozilla::net::ResourceTimingStruct from "mozilla/net/TimingStruct.h";
using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
namespace mozilla {
namespace net {
@ -29,8 +31,9 @@ protocol PHttpChannel
manager PNecko;
parent:
// Note: channels are opened during construction, so no open method here:
// see PNecko.ipdl
async AsyncOpen(PBrowserOrId browser,
SerializedLoadContext loadContext,
HttpChannelCreationArgs args);
async SetClassOfService(uint32_t cos);