Bug 1575744 - P7. Promisify SendCrossProcessRedirect to avoid needing PHttpChannel to get a response. r=mayhemer

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jean-Yves Avenard 2019-09-21 11:14:49 +00:00
parent 9d8eadbabe
commit 7cdc8e0a68
9 changed files with 88 additions and 94 deletions

View File

@ -3636,7 +3636,7 @@ mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
const ReplacementChannelConfigInit& aConfig,
const Maybe<LoadInfoArgs>& aLoadInfo, const uint64_t& aChannelId,
nsIURI* aOriginalURI, const uint64_t& aIdentifier,
const uint32_t& aRedirectMode) {
const uint32_t& aRedirectMode, CrossProcessRedirectResolver&& aResolve) {
nsCOMPtr<nsILoadInfo> loadInfo;
nsresult rv =
mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfo, getter_AddRefs(loadInfo));
@ -3658,8 +3658,16 @@ mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
// This is used to report any errors back to the parent by calling
// CrossProcessRedirectFinished.
auto scopeExit =
MakeScopeExit([&]() { httpChild->CrossProcessRedirectFinished(rv); });
auto scopeExit = MakeScopeExit([&]() {
rv = httpChild->CrossProcessRedirectFinished(rv);
nsCOMPtr<nsILoadInfo> loadInfo;
MOZ_ALWAYS_SUCCEEDS(newChannel->GetLoadInfo(getter_AddRefs(loadInfo)));
Maybe<LoadInfoArgs> loadInfoArgs;
MOZ_ALWAYS_SUCCEEDS(
mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs));
aResolve(
Tuple<const nsresult&, const Maybe<LoadInfoArgs>&>(rv, loadInfoArgs));
});
rv = httpChild->SetChannelId(aChannelId);
if (NS_FAILED(rv)) {

View File

@ -662,7 +662,7 @@ class ContentChild final : public PContentChild,
const ReplacementChannelConfigInit& aConfig,
const Maybe<LoadInfoArgs>& aLoadInfoForwarder, const uint64_t& aChannelId,
nsIURI* aOriginalURI, const uint64_t& aIdentifier,
const uint32_t& aRedirectMode);
const uint32_t& aRedirectMode, CrossProcessRedirectResolver&& aResolve);
mozilla::ipc::IPCResult RecvStartDelayedAutoplayMediaComponents(
BrowsingContext* aContext);

View File

@ -791,6 +791,9 @@ child:
// new HttpChannelChild that will be connected to the parent channel
// represented by registrarId.
// This is on PContent not PNecko, as PNecko may not be initialized yet.
// The returned loadInfo needs to be set on the channel - since the channel
// moved to a new process it now has different properties.
async CrossProcessRedirect(uint32_t aRegistrarId,
nsIURI aURI,
ReplacementChannelConfigInit config,
@ -798,7 +801,8 @@ child:
uint64_t aChannelId,
nsIURI aOriginalURI,
uint64_t aIdentifier,
uint32_t aRedirectMode);
uint32_t aRedirectMode)
returns (nsresult rv, LoadInfoArgs? arg);
/**
* This method is used to notifty content process to start delayed autoplay

View File

@ -11,19 +11,6 @@
[scriptable, uuid(d2471b64-0292-4cb5-b801-914e34b31af0)]
interface nsICrossProcessSwitchChannel : nsISupports
{
/**
* When a process switch has been processed (either successfully or not),
* HttpChannelParent will call this method on the DocumentChannelParent or
* HttpChannelParent.
*
* @param callback
* Object to inform about the async result of this method.
* @param status
* The error that caused the process switch to fail.
* NS_OK means the process switch was processed successfully.
*/
void finishCrossProcessSwitch(in nsIAsyncVerifyRedirectCallback callback, in nsresult status);
/**
* When a process switch is about to start,
* nsHttpChannel will call this method on DocumentChannelParent or

View File

@ -359,16 +359,6 @@ void DocumentChannelParent::FinishReplacementChannelSetup(bool aSucceeded) {
}
}
NS_IMETHODIMP
DocumentChannelParent::FinishCrossProcessSwitch(
nsIAsyncVerifyRedirectCallback* aCallback, nsresult aStatusCode) {
// This updates ParentChannelListener to point to this parent and at
// the same time cancels the old channel.
FinishReplacementChannelSetup(NS_SUCCEEDED(aStatusCode));
return NS_OK;
}
nsresult DocumentChannelParent::TriggerCrossProcessSwitch(
nsIHttpChannel* aChannel, uint64_t aIdentifier) {
MOZ_ASSERT_UNREACHABLE(
@ -534,6 +524,7 @@ void DocumentChannelParent::TriggerRedirectToRealChannel(
contentDispositionFilename = Some(contentDispositionFilenameTemp);
}
RefPtr<DocumentChannelParent> self = this;
if (aDestinationProcess) {
dom::ContentParent* cp =
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
@ -544,24 +535,36 @@ void DocumentChannelParent::TriggerRedirectToRealChannel(
MOZ_ASSERT(config);
auto result = cp->SendCrossProcessRedirect(
mRedirectChannelId, uri, *config, loadInfoArgs, channelId, originalURI,
aIdentifier, redirectMode);
MOZ_ASSERT(result, "SendCrossProcessRedirect failed");
Unused << result;
cp->SendCrossProcessRedirect(mRedirectChannelId, uri, *config, loadInfoArgs,
channelId, originalURI, aIdentifier,
redirectMode)
->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[self](Tuple<nsresult, Maybe<LoadInfoArgs>>&& aResponse) {
if (NS_SUCCEEDED(Get<0>(aResponse))) {
nsCOMPtr<nsILoadInfo> newLoadInfo;
MOZ_ALWAYS_SUCCEEDS(LoadInfoArgsToLoadInfo(
Get<1>(aResponse), getter_AddRefs(newLoadInfo)));
if (newLoadInfo) {
self->mChannel->SetLoadInfo(newLoadInfo);
}
}
self->RedirectToRealChannelFinished(Get<0>(aResponse));
},
[self](const mozilla::ipc::ResponseRejectReason) {
self->RedirectToRealChannelFinished(NS_ERROR_FAILURE);
});
} else {
RefPtr<DocumentChannelParent> channel = this;
SendRedirectToRealChannel(mRedirectChannelId, uri, newLoadFlags, config,
loadInfoArgs, mRedirects, channelId, originalURI,
redirectMode, redirectFlags, contentDisposition,
contentDispositionFilename)
->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[channel](nsresult aRv) {
channel->RedirectToRealChannelFinished(aRv);
},
[channel](const mozilla::ipc::ResponseRejectReason) {
channel->RedirectToRealChannelFinished(NS_ERROR_FAILURE);
[self](nsresult aRv) { self->RedirectToRealChannelFinished(aRv); },
[self](const mozilla::ipc::ResponseRejectReason) {
self->RedirectToRealChannelFinished(NS_ERROR_FAILURE);
});
}
}

View File

@ -4085,16 +4085,7 @@ nsresult HttpChannelChild::CrossProcessRedirectFinished(nsresult aStatus) {
mStatus = aStatus;
}
// The loadInfo is updated in nsDocShell::OpenInitializedChannel to have the
// correct attributes (such as browsingContextID).
// We need to send it to the parent channel so the two match, which is done
nsCOMPtr<nsILoadInfo> loadInfo;
MOZ_ALWAYS_SUCCEEDS(GetLoadInfo(getter_AddRefs(loadInfo)));
Maybe<LoadInfoArgs> loadInfoArgs;
MOZ_ALWAYS_SUCCEEDS(
mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs));
Unused << SendCrossProcessRedirectDone(mStatus, loadInfoArgs);
return NS_OK;
return mStatus;
}
} // namespace net

View File

@ -1257,48 +1257,36 @@ void HttpChannelParent::MaybeFlushPendingDiversion() {
}
}
static void FinishCrossProcessSwitchHelper(nsHttpChannel* aChannel,
nsresult aStatus) {
nsCOMPtr<nsICrossProcessSwitchChannel> switchListener;
NS_QueryNotificationCallbacks(aChannel, switchListener);
if (!switchListener) {
// This can happen if the channel got aborted before the switch completed
// and OnStopRequest got called in between which cleared the callback.
return;
}
switchListener->FinishCrossProcessSwitch(aChannel, aStatus);
}
NS_IMETHODIMP
HttpChannelParent::FinishCrossProcessSwitch(
nsIAsyncVerifyRedirectCallback* aCallback, nsresult aStatus) {
void HttpChannelParent::FinishCrossProcessSwitch(nsHttpChannel* aChannel,
nsresult aStatus) {
if (NS_SUCCEEDED(aStatus)) {
nsCOMPtr<nsIRedirectResultListener> redirectListener;
NS_QueryNotificationCallbacks(aChannel, redirectListener);
MOZ_ASSERT(redirectListener);
// This updates ParentChannelListener to point to this parent and at
// the same time cancels the old channel.
OnRedirectResult(true);
redirectListener->OnRedirectResult(true);
}
aCallback->OnRedirectVerifyCallback(aStatus);
return NS_OK;
aChannel->OnRedirectVerifyCallback(aStatus);
}
mozilla::ipc::IPCResult HttpChannelParent::RecvCrossProcessRedirectDone(
void HttpChannelParent::CrossProcessRedirectDone(
const nsresult& aResult,
const mozilla::Maybe<LoadInfoArgs>& aLoadInfoArgs) {
RefPtr<nsHttpChannel> chan = do_QueryObject(mChannel);
nsresult rv = aResult;
auto sendReply =
MakeScopeExit([&]() { FinishCrossProcessSwitchHelper(chan, rv); });
auto sendReply = MakeScopeExit([&]() { FinishCrossProcessSwitch(chan, rv); });
if (NS_FAILED(rv)) {
return IPC_OK();
return;
}
nsCOMPtr<nsILoadInfo> newLoadInfo;
rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(newLoadInfo));
if (NS_FAILED(rv)) {
return IPC_OK();
return;
}
if (newLoadInfo) {
@ -1311,15 +1299,13 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvCrossProcessRedirectDone(
WaitForBgParent()->Then(
GetMainThreadSerialEventTarget(), __func__,
[self, chan, aResult]() {
FinishCrossProcessSwitchHelper(chan, aResult);
self->FinishCrossProcessSwitch(chan, aResult);
},
[self, chan](const nsresult& aRejectionRv) {
MOZ_ASSERT(NS_FAILED(aRejectionRv), "This should be an error code");
FinishCrossProcessSwitchHelper(chan, aRejectionRv);
self->FinishCrossProcessSwitch(chan, aRejectionRv);
});
}
return IPC_OK();
}
void HttpChannelParent::ResponseSynthesized() {
@ -2683,7 +2669,7 @@ nsresult HttpChannelParent::TriggerCrossProcessSwitch(nsIHttpChannel* aChannel,
RedirectChannelRegistrar::GetOrCreate();
MOZ_ASSERT(registrar);
rv = registrar->RegisterChannel(channel, &self->mRedirectChannelId);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS_VOID(rv);
LOG(("Registered %p channel under id=%d", channel.get(),
self->mRedirectChannelId));
@ -2714,15 +2700,34 @@ nsresult HttpChannelParent::TriggerCrossProcessSwitch(nsIHttpChannel* aChannel,
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
ContentParentId{cpId});
if (!cp) {
return NS_ERROR_UNEXPECTED;
return;
}
auto result = cp->SendCrossProcessRedirect(
self->mRedirectChannelId, uri, config, loadInfoArgs, channelId,
originalURI, aIdentifier, redirectMode);
cp->SendCrossProcessRedirect(self->mRedirectChannelId, uri, config,
loadInfoArgs, channelId, originalURI,
aIdentifier, redirectMode)
->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[self](Tuple<nsresult, Maybe<LoadInfoArgs>>&& aResponse) {
// We need to continue on the new HttpChannelParent.
MOZ_ASSERT(self->mRedirectChannelId);
nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
RedirectChannelRegistrar::GetOrCreate();
MOZ_ASSERT(redirectReg);
MOZ_ASSERT(result, "SendCrossProcessRedirect failed");
return result ? NS_OK : NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIParentChannel> redirectParentChannel;
redirectReg->GetParentChannel(
self->mRedirectChannelId,
getter_AddRefs(redirectParentChannel));
MOZ_ASSERT(redirectParentChannel);
RefPtr<HttpChannelParent> newParent =
do_QueryObject(redirectParentChannel);
MOZ_ASSERT(newParent);
newParent->CrossProcessRedirectDone(Get<0>(aResponse),
Get<1>(aResponse));
},
[self](const mozilla::ipc::ResponseRejectReason) {
self->CrossProcessRedirectDone(NS_ERROR_FAILURE, Nothing());
});
},
[httpChannel](nsresult aStatus) {
MOZ_ASSERT(NS_FAILED(aStatus), "Status should be error");

View File

@ -209,9 +209,6 @@ class HttpChannelParent final : public nsIInterfaceRequestor,
virtual mozilla::ipc::IPCResult RecvDivertOnStopRequest(
const nsresult& statusCode) override;
virtual mozilla::ipc::IPCResult RecvDivertComplete() override;
virtual mozilla::ipc::IPCResult RecvCrossProcessRedirectDone(
const nsresult& aResult,
const mozilla::Maybe<LoadInfoArgs>& aLoadInfoArgs) override;
virtual mozilla::ipc::IPCResult RecvRemoveCorsPreflightCacheEntry(
const URIParams& uri,
const mozilla::ipc::PrincipalInfo& requestingPrincipal) override;
@ -255,6 +252,11 @@ class HttpChannelParent final : public nsIInterfaceRequestor,
void MaybeFlushPendingDiversion();
void ResponseSynthesized();
void CrossProcessRedirectDone(
const nsresult& aResult,
const mozilla::Maybe<LoadInfoArgs>& aLoadInfoArgs);
void FinishCrossProcessSwitch(nsHttpChannel* aChannel, nsresult aStatus);
// 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

View File

@ -50,12 +50,6 @@ parent:
CorsPreflightArgs? corsPreflightArgs,
bool chooseAppcache);
// Sent to the parent in order signal that the child side listeners have been
// set up and the parent side of the channel can be opened.
// The passed loadInfo needs to be set on the channel - since the channel
// moved to a new process it now has different properties.
async CrossProcessRedirectDone(nsresult result, LoadInfoArgs? loadInfo);
// For document loads we keep this protocol open after child's
// OnStopRequest, and send this msg (instead of __delete__) to allow
// partial cleanup on parent.