diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 7698271bc569..75bf0d79a001 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -3636,7 +3636,7 @@ mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect( const ReplacementChannelConfigInit& aConfig, const Maybe& aLoadInfo, const uint64_t& aChannelId, nsIURI* aOriginalURI, const uint64_t& aIdentifier, - const uint32_t& aRedirectMode) { + const uint32_t& aRedirectMode, CrossProcessRedirectResolver&& aResolve) { nsCOMPtr 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 loadInfo; + MOZ_ALWAYS_SUCCEEDS(newChannel->GetLoadInfo(getter_AddRefs(loadInfo))); + Maybe loadInfoArgs; + MOZ_ALWAYS_SUCCEEDS( + mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs)); + aResolve( + Tuple&>(rv, loadInfoArgs)); + }); rv = httpChild->SetChannelId(aChannelId); if (NS_FAILED(rv)) { diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 46d008959f88..d21ea7f969b2 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -662,7 +662,7 @@ class ContentChild final : public PContentChild, const ReplacementChannelConfigInit& aConfig, const Maybe& 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); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 32984b383a9c..7cdb8c84d235 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -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 diff --git a/netwerk/base/nsICrossProcessSwitchChannel.idl b/netwerk/base/nsICrossProcessSwitchChannel.idl index 12e53ccc23ef..e2740a69a3a1 100644 --- a/netwerk/base/nsICrossProcessSwitchChannel.idl +++ b/netwerk/base/nsICrossProcessSwitchChannel.idl @@ -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 diff --git a/netwerk/ipc/DocumentChannelParent.cpp b/netwerk/ipc/DocumentChannelParent.cpp index 30fb75cc4caf..0e3b13248817 100644 --- a/netwerk/ipc/DocumentChannelParent.cpp +++ b/netwerk/ipc/DocumentChannelParent.cpp @@ -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 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>&& aResponse) { + if (NS_SUCCEEDED(Get<0>(aResponse))) { + nsCOMPtr 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 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); }); } } diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 99143599568e..6f66a04b7ddc 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -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 loadInfo; - MOZ_ALWAYS_SUCCEEDS(GetLoadInfo(getter_AddRefs(loadInfo))); - Maybe loadInfoArgs; - MOZ_ALWAYS_SUCCEEDS( - mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs)); - Unused << SendCrossProcessRedirectDone(mStatus, loadInfoArgs); - return NS_OK; + return mStatus; } } // namespace net diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 0558aafd5289..5ae5885569ce 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1257,48 +1257,36 @@ void HttpChannelParent::MaybeFlushPendingDiversion() { } } -static void FinishCrossProcessSwitchHelper(nsHttpChannel* aChannel, - nsresult aStatus) { - nsCOMPtr 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 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& aLoadInfoArgs) { RefPtr 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 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>&& aResponse) { + // We need to continue on the new HttpChannelParent. + MOZ_ASSERT(self->mRedirectChannelId); + nsCOMPtr redirectReg = + RedirectChannelRegistrar::GetOrCreate(); + MOZ_ASSERT(redirectReg); - MOZ_ASSERT(result, "SendCrossProcessRedirect failed"); - - return result ? NS_OK : NS_ERROR_UNEXPECTED; + nsCOMPtr redirectParentChannel; + redirectReg->GetParentChannel( + self->mRedirectChannelId, + getter_AddRefs(redirectParentChannel)); + MOZ_ASSERT(redirectParentChannel); + RefPtr 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"); diff --git a/netwerk/protocol/http/HttpChannelParent.h b/netwerk/protocol/http/HttpChannelParent.h index 4a67f59e5b71..f64fa74c427d 100644 --- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -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& 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& 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 diff --git a/netwerk/protocol/http/PHttpChannel.ipdl b/netwerk/protocol/http/PHttpChannel.ipdl index 3ecc1daf7822..d48eb5c490dc 100644 --- a/netwerk/protocol/http/PHttpChannel.ipdl +++ b/netwerk/protocol/http/PHttpChannel.ipdl @@ -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.