From abec029eac01f4cf1c016bd54c97285a07476fdc Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 20 Sep 2019 04:09:47 +0000 Subject: [PATCH] Bug 1575744 - P5. Implement process switch from DocumentChannelParent. r=mayhemer Differential Revision: https://phabricator.services.mozilla.com/D46020 --HG-- extra : moz-landing-system : lando --- netwerk/ipc/DocumentChannelParent.cpp | 81 +++++++++++++++++++-------- netwerk/ipc/DocumentChannelParent.h | 22 ++++++-- 2 files changed, 75 insertions(+), 28 deletions(-) diff --git a/netwerk/ipc/DocumentChannelParent.cpp b/netwerk/ipc/DocumentChannelParent.cpp index f6e6fcce9eef..30fb75cc4caf 100644 --- a/netwerk/ipc/DocumentChannelParent.cpp +++ b/netwerk/ipc/DocumentChannelParent.cpp @@ -8,6 +8,7 @@ #include "DocumentChannelParent.h" #include "mozilla/DebugOnly.h" #include "mozilla/LoadInfo.h" +#include "mozilla/MozPromiseInlines.h" // For MozPromise::FromDomPromise #include "mozilla/dom/BrowserParent.h" #include "mozilla/dom/ClientChannelHelper.h" #include "mozilla/dom/ContentParent.h" @@ -40,6 +41,7 @@ NS_INTERFACE_MAP_BEGIN(DocumentChannelParent) NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectReadyCallback) NS_INTERFACE_MAP_ENTRY(nsICrossProcessSwitchChannel) NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) + NS_INTERFACE_MAP_ENTRY(nsIProcessSwitchRequestor) NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentChannelParent) NS_INTERFACE_MAP_END @@ -369,26 +371,22 @@ DocumentChannelParent::FinishCrossProcessSwitch( nsresult DocumentChannelParent::TriggerCrossProcessSwitch( nsIHttpChannel* aChannel, uint64_t aIdentifier) { - RefPtr httpChannel = do_QueryObject(aChannel); - MOZ_DIAGNOSTIC_ASSERT(httpChannel, - "Must be called with nsHttpChannel object"); - RefPtr p = - httpChannel->TakeRedirectContentProcessIdPromise(); - TriggerCrossProcessSwitch(p.forget(), aIdentifier, httpChannel); + MOZ_ASSERT_UNREACHABLE( + "We can no longer be called from nsHttpChannel, this interface will be " + "removed in a follow-up patch"); return NS_OK; } -void DocumentChannelParent::TriggerCrossProcessSwitch( - already_AddRefed aPromise, uint64_t aIdentifier, - nsHttpChannel* aChannel) { +void DocumentChannelParent::TriggerCrossProcessSwitch() { + MOZ_ASSERT(mRedirectContentProcessIdPromise); CancelChildForProcessSwitch(); RefPtr self = this; - RefPtr channel = aChannel; - RefPtr p = aPromise; - p->Then( + mRedirectContentProcessIdPromise->Then( GetMainThreadSerialEventTarget(), __func__, - [self, aIdentifier, channel](uint64_t aCpId) { - self->TriggerRedirectToRealChannel(channel, Some(aCpId), aIdentifier); + [self, this](uint64_t aCpId) { + MOZ_ASSERT(mChannel, "Something went wrong, channel got cancelled"); + TriggerRedirectToRealChannel(mChannel, Some(aCpId), + mCrossProcessRedirectIdentifier); }, [self](nsresult aStatusCode) { MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error"); @@ -606,14 +604,11 @@ DocumentChannelParent::OnStartRequest(nsIRequest* aRequest) { // notify "http-on-may-change-process" observers which is typically // SessionStore.jsm. This will determine if a new process needs to be - // spawned and if so channel->SwitchProcessTo() will be called which will - // set a ContentProcessIdPromise. - gHttpHandler->OnMayChangeProcess(channel); - RefPtr promise = - channel->TakeRedirectContentProcessIdPromise(); - if (promise) { - TriggerCrossProcessSwitch( - promise.forget(), channel->CrossProcessRedirectIdentifier(), channel); + // spawned and if so SwitchProcessTo() will be called which will set a + // ContentProcessIdPromise. + gHttpHandler->OnMayChangeProcess(this); + if (mRedirectContentProcessIdPromise) { + TriggerCrossProcessSwitch(); return NS_OK; } } @@ -839,5 +834,47 @@ DocumentChannelParent::AsyncOnChannelRedirect( return NS_OK; } +//----------------------------------------------------------------------------- +// DocumentChannelParent::nsIProcessSwitchRequestor +//----------------------------------------------------------------------------- + +NS_IMETHODIMP DocumentChannelParent::GetChannel(nsIChannel** aChannel) { + MOZ_ASSERT(mChannel); + nsCOMPtr channel(mChannel); + channel.forget(aChannel); + return NS_OK; +} + +NS_IMETHODIMP DocumentChannelParent::SwitchProcessTo( + dom::Promise* aContentProcessIdPromise, uint64_t aIdentifier) { + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_ARG(aContentProcessIdPromise); + + mRedirectContentProcessIdPromise = + ContentProcessIdPromise::FromDomPromise(aContentProcessIdPromise); + mCrossProcessRedirectIdentifier = aIdentifier; + return NS_OK; +} + +// This method returns the cached result of running the Cross-Origin-Opener +// policy compare algorithm by calling ComputeCrossOriginOpenerPolicyMismatch +NS_IMETHODIMP +DocumentChannelParent::HasCrossOriginOpenerPolicyMismatch(bool* aMismatch) { + MOZ_ASSERT(aMismatch); + + if (!aMismatch) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr channel = do_QueryInterface(mChannel); + if (!channel) { + // Not an nsHttpChannel assume it's okay to switch. + *aMismatch = false; + return NS_OK; + } + + return channel->HasCrossOriginOpenerPolicyMismatch(aMismatch); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/DocumentChannelParent.h b/netwerk/ipc/DocumentChannelParent.h index 53d9a78a1d35..0d91323cccef 100644 --- a/netwerk/ipc/DocumentChannelParent.h +++ b/netwerk/ipc/DocumentChannelParent.h @@ -38,7 +38,8 @@ class DocumentChannelParent : public nsIInterfaceRequestor, public nsIParentChannel, public nsIChannelEventSink, public nsICrossProcessSwitchChannel, - public HttpChannelSecurityWarningReporter { + public HttpChannelSecurityWarningReporter, + public nsIProcessSwitchRequestor { public: explicit DocumentChannelParent(const dom::PBrowserOrId& iframeEmbedding, nsILoadContext* aLoadContext, @@ -54,6 +55,7 @@ class DocumentChannelParent : public nsIInterfaceRequestor, NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICROSSPROCESSSWITCHCHANNEL + NS_DECL_NSIPROCESSSWITCHREQUESTOR NS_DECLARE_STATIC_IID_ACCESSOR(DOCUMENT_CHANNEL_PARENT_IID) @@ -111,11 +113,7 @@ class DocumentChannelParent : public nsIInterfaceRequestor, void FinishReplacementChannelSetup(bool aSucceeded); - typedef MozPromise - ContentProcessIdPromise; - void TriggerCrossProcessSwitch( - already_AddRefed aPromise, uint64_t aIdentifier, - nsHttpChannel* aChannel); + void TriggerCrossProcessSwitch(); // This defines a variant that describes all the attribute setters (and their // parameters) from nsIParentChannel @@ -216,6 +214,18 @@ class DocumentChannelParent : public nsIInterfaceRequestor, // helper from being installed, but we need to restore the value // later. bool mOldApplyConversion = false; + + typedef MozPromise + ContentProcessIdPromise; + // This promise is set following a on-may-change-process observer + // notification when the associated channel is getting relocated to another + // process. It will be resolved when that process is set up. + RefPtr mRedirectContentProcessIdPromise; + // This identifier is set at the same time as the + // mRedirectContentProcessIdPromise. + // This identifier is later passed to the childChannel in order to identify it + // once the promise is resolved. + uint64_t mCrossProcessRedirectIdentifier = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(DocumentChannelParent,