Bug 1646892 - Allow DocumentChannel process switches into the parent process. r=jya,nika
Differential Revision: https://phabricator.services.mozilla.com/D80327
This commit is contained in:
@@ -40,6 +40,12 @@ void ChildProcessChannelListener::OnChannelReady(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChildProcessChannelListener::~ChildProcessChannelListener() {
|
||||||
|
for (auto& args : mChannelArgs) {
|
||||||
|
args.GetData().mResolver(NS_ERROR_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<ChildProcessChannelListener>
|
already_AddRefed<ChildProcessChannelListener>
|
||||||
ChildProcessChannelListener::GetSingleton() {
|
ChildProcessChannelListener::GetSingleton() {
|
||||||
if (!sCPCLSingleton) {
|
if (!sCPCLSingleton) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class ChildProcessChannelListener final {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ChildProcessChannelListener() = default;
|
ChildProcessChannelListener() = default;
|
||||||
~ChildProcessChannelListener() = default;
|
~ChildProcessChannelListener();
|
||||||
struct CallbackArgs {
|
struct CallbackArgs {
|
||||||
RefPtr<nsDocShellLoadState> mLoadState;
|
RefPtr<nsDocShellLoadState> mLoadState;
|
||||||
nsTArray<Endpoint> mStreamFilterEndpoints;
|
nsTArray<Endpoint> mStreamFilterEndpoints;
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
#include "mozilla/dom/JSWindowActorChild.h"
|
#include "mozilla/dom/JSWindowActorChild.h"
|
||||||
#include "mozilla/ipc/ProtocolUtils.h"
|
#include "mozilla/ipc/ProtocolUtils.h"
|
||||||
#include "mozilla/net/DocumentChannel.h"
|
#include "mozilla/net/DocumentChannel.h"
|
||||||
|
#include "mozilla/net/ParentChannelWrapper.h"
|
||||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||||
#include "ReferrerInfo.h"
|
#include "ReferrerInfo.h"
|
||||||
|
|
||||||
@@ -206,6 +207,7 @@
|
|||||||
#include "nsSHEntry.h"
|
#include "nsSHEntry.h"
|
||||||
#include "nsStructuredCloneContainer.h"
|
#include "nsStructuredCloneContainer.h"
|
||||||
#include "nsSubDocumentFrame.h"
|
#include "nsSubDocumentFrame.h"
|
||||||
|
#include "nsURILoader.h"
|
||||||
#include "nsView.h"
|
#include "nsView.h"
|
||||||
#include "nsViewManager.h"
|
#include "nsViewManager.h"
|
||||||
#include "nsViewSourceHandler.h"
|
#include "nsViewSourceHandler.h"
|
||||||
@@ -9436,8 +9438,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
|||||||
outRequest.forget(aRequest);
|
outRequest.forget(aRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpenInitializedChannel(channel, uriLoader,
|
return OpenRedirectedChannel(aLoadState);
|
||||||
nsIURILoader::REDIRECTED_CHANNEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are two cases we care about:
|
// There are two cases we care about:
|
||||||
@@ -9723,15 +9724,10 @@ static nsresult AppendSegmentToString(nsIInputStream* aIn, void* aClosure,
|
|||||||
return openFlags;
|
return openFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
void nsDocShell::UpdateMixedContentChannelForNewLoad(nsIChannel* aChannel) {
|
||||||
nsIURILoader* aURILoader,
|
|
||||||
uint32_t aOpenFlags) {
|
|
||||||
nsresult rv = NS_OK;
|
|
||||||
|
|
||||||
if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
|
if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
|
||||||
mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
|
mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
|
||||||
rv = SetMixedContentChannel(aChannel);
|
SetMixedContentChannel(aChannel);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
} else if (mMixedContentChannel) {
|
} else if (mMixedContentChannel) {
|
||||||
/*
|
/*
|
||||||
* If the user "Disables Protection on This Page", we call
|
* If the user "Disables Protection on This Page", we call
|
||||||
@@ -9742,11 +9738,20 @@ nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
|||||||
* This way, the user does not have to click the disable protection button
|
* This way, the user does not have to click the disable protection button
|
||||||
* over and over for browsing the same site.
|
* over and over for browsing the same site.
|
||||||
*/
|
*/
|
||||||
rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, aChannel);
|
nsresult rv =
|
||||||
|
nsContentUtils::CheckSameOrigin(mMixedContentChannel, aChannel);
|
||||||
if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(aChannel))) {
|
if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(aChannel))) {
|
||||||
SetMixedContentChannel(nullptr);
|
SetMixedContentChannel(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
||||||
|
nsIURILoader* aURILoader,
|
||||||
|
uint32_t aOpenFlags) {
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
UpdateMixedContentChannelForNewLoad(aChannel);
|
||||||
|
|
||||||
// If anything fails here, make sure to clear our initial ClientSource.
|
// If anything fails here, make sure to clear our initial ClientSource.
|
||||||
auto cleanupInitialClient =
|
auto cleanupInitialClient =
|
||||||
@@ -9757,21 +9762,6 @@ nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
|||||||
|
|
||||||
MaybeCreateInitialClientSource();
|
MaybeCreateInitialClientSource();
|
||||||
|
|
||||||
if (aOpenFlags & nsIURILoader::REDIRECTED_CHANNEL) {
|
|
||||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
|
||||||
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
|
||||||
|
|
||||||
LoadInfo* li = static_cast<LoadInfo*>(loadInfo.get());
|
|
||||||
if (loadInfo->GetExternalContentPolicyType() ==
|
|
||||||
nsIContentPolicy::TYPE_DOCUMENT) {
|
|
||||||
li->UpdateBrowsingContextID(mBrowsingContext->Id());
|
|
||||||
} else if (loadInfo->GetExternalContentPolicyType() ==
|
|
||||||
nsIContentPolicy::TYPE_SUBDOCUMENT) {
|
|
||||||
li->UpdateFrameBrowsingContextID(mBrowsingContext->Id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: more attributes need to be updated on the LoadInfo (bug 1561706)
|
|
||||||
|
|
||||||
// Let the client channel helper know if we are using DocumentChannel,
|
// Let the client channel helper know if we are using DocumentChannel,
|
||||||
// since redirects get handled in the parent process in that case.
|
// since redirects get handled in the parent process in that case.
|
||||||
RefPtr<net::DocumentChannel> docChannel = do_QueryObject(aChannel);
|
RefPtr<net::DocumentChannel> docChannel = do_QueryObject(aChannel);
|
||||||
@@ -9794,12 +9784,6 @@ nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
|||||||
rv = AddClientChannelHelperInChild(
|
rv = AddClientChannelHelperInChild(
|
||||||
aChannel, win->EventTargetFor(TaskCategory::Other));
|
aChannel, win->EventTargetFor(TaskCategory::Other));
|
||||||
docChannel->SetInitialClientInfo(GetInitialClientInfo());
|
docChannel->SetInitialClientInfo(GetInitialClientInfo());
|
||||||
} else if (aOpenFlags & nsIURILoader::REDIRECTED_CHANNEL) {
|
|
||||||
// If we did a process switch, then we should have an existing allocated
|
|
||||||
// ClientInfo, so we just need to allocate a corresponding ClientSource.
|
|
||||||
CreateReservedSourceIfNeeded(aChannel,
|
|
||||||
win->EventTargetFor(TaskCategory::Other));
|
|
||||||
rv = NS_OK;
|
|
||||||
} else {
|
} else {
|
||||||
rv = AddClientChannelHelper(aChannel, std::move(noReservedClient),
|
rv = AddClientChannelHelper(aChannel, std::move(noReservedClient),
|
||||||
GetInitialClientInfo(),
|
GetInitialClientInfo(),
|
||||||
@@ -9821,6 +9805,81 @@ nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult nsDocShell::OpenRedirectedChannel(nsDocShellLoadState* aLoadState) {
|
||||||
|
nsCOMPtr<nsIChannel> channel = aLoadState->GetPendingRedirectedChannel();
|
||||||
|
MOZ_ASSERT(channel);
|
||||||
|
|
||||||
|
UpdateMixedContentChannelForNewLoad(channel);
|
||||||
|
|
||||||
|
// If anything fails here, make sure to clear our initial ClientSource.
|
||||||
|
auto cleanupInitialClient =
|
||||||
|
MakeScopeExit([&] { mInitialClientSource.reset(); });
|
||||||
|
|
||||||
|
nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
|
||||||
|
NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
MaybeCreateInitialClientSource();
|
||||||
|
|
||||||
|
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||||
|
channel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||||
|
|
||||||
|
LoadInfo* li = static_cast<LoadInfo*>(loadInfo.get());
|
||||||
|
if (loadInfo->GetExternalContentPolicyType() ==
|
||||||
|
nsIContentPolicy::TYPE_DOCUMENT) {
|
||||||
|
li->UpdateBrowsingContextID(mBrowsingContext->Id());
|
||||||
|
} else if (loadInfo->GetExternalContentPolicyType() ==
|
||||||
|
nsIContentPolicy::TYPE_SUBDOCUMENT) {
|
||||||
|
li->UpdateFrameBrowsingContextID(mBrowsingContext->Id());
|
||||||
|
}
|
||||||
|
// TODO: more attributes need to be updated on the LoadInfo (bug 1561706)
|
||||||
|
|
||||||
|
// If we did a process switch, then we should have an existing allocated
|
||||||
|
// ClientInfo, so we just need to allocate a corresponding ClientSource.
|
||||||
|
CreateReservedSourceIfNeeded(channel,
|
||||||
|
win->EventTargetFor(TaskCategory::Other));
|
||||||
|
|
||||||
|
RefPtr<nsDocumentOpenInfo> loader =
|
||||||
|
new nsDocumentOpenInfo(this, nsIURILoader::DONT_RETARGET, nullptr);
|
||||||
|
channel->SetLoadGroup(mLoadGroup);
|
||||||
|
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(loader->Prepare());
|
||||||
|
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
if (XRE_IsParentProcess()) {
|
||||||
|
// If we're in the parent, the we don't have an nsIChildChannel, just
|
||||||
|
// the original channel, which is already open in this process.
|
||||||
|
|
||||||
|
// DocumentLoadListener expects to get an nsIParentChannel, so
|
||||||
|
// we create a wrapper around the channel and nsIStreamListener
|
||||||
|
// that forwards functionality as needed, and then we register
|
||||||
|
// it under the provided identifier.
|
||||||
|
RefPtr<ParentChannelWrapper> wrapper =
|
||||||
|
new ParentChannelWrapper(channel, loader);
|
||||||
|
wrapper->Register(aLoadState->GetPendingRedirectChannelRegistrarId());
|
||||||
|
|
||||||
|
mLoadGroup->AddRequest(channel, nullptr);
|
||||||
|
} else if (nsCOMPtr<nsIChildChannel> childChannel =
|
||||||
|
do_QueryInterface(channel)) {
|
||||||
|
// Our channel was redirected from another process, so doesn't need to
|
||||||
|
// be opened again. However, it does need its listener hooked up
|
||||||
|
// correctly.
|
||||||
|
rv = childChannel->CompleteRedirectSetup(loader);
|
||||||
|
} else {
|
||||||
|
// It's possible for the redirected channel to not implement
|
||||||
|
// nsIChildChannel and be entirely local (like srcdoc). In that case we
|
||||||
|
// can just open the local instance and it will work.
|
||||||
|
rv = channel->AsyncOpen(loader);
|
||||||
|
}
|
||||||
|
if (rv == NS_ERROR_NO_CONTENT) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Success. Keep the initial ClientSource if it exists.
|
||||||
|
cleanupInitialClient.release();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
||||||
nsACString& aNewHash, uint32_t aLoadType) {
|
nsACString& aNewHash, uint32_t aLoadType) {
|
||||||
if (!mCurrentURI) {
|
if (!mCurrentURI) {
|
||||||
|
|||||||
@@ -653,6 +653,9 @@ class nsDocShell final : public nsDocLoader,
|
|||||||
nsresult OpenInitializedChannel(nsIChannel* aChannel,
|
nsresult OpenInitializedChannel(nsIChannel* aChannel,
|
||||||
nsIURILoader* aURILoader,
|
nsIURILoader* aURILoader,
|
||||||
uint32_t aOpenFlags);
|
uint32_t aOpenFlags);
|
||||||
|
nsresult OpenRedirectedChannel(nsDocShellLoadState* aLoadState);
|
||||||
|
|
||||||
|
void UpdateMixedContentChannelForNewLoad(nsIChannel* aChannel);
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
nsresult ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
nsresult ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ nsDocShellLoadState::~nsDocShellLoadState() {}
|
|||||||
|
|
||||||
nsresult nsDocShellLoadState::CreateFromPendingChannel(
|
nsresult nsDocShellLoadState::CreateFromPendingChannel(
|
||||||
nsIChannel* aPendingChannel, uint64_t aLoadIdentifier,
|
nsIChannel* aPendingChannel, uint64_t aLoadIdentifier,
|
||||||
nsDocShellLoadState** aResult) {
|
uint64_t aRegistrarId, nsDocShellLoadState** aResult) {
|
||||||
// Create the nsDocShellLoadState object with default state pulled from the
|
// Create the nsDocShellLoadState object with default state pulled from the
|
||||||
// passed-in channel.
|
// passed-in channel.
|
||||||
nsCOMPtr<nsIURI> uri;
|
nsCOMPtr<nsIURI> uri;
|
||||||
@@ -195,6 +195,7 @@ nsresult nsDocShellLoadState::CreateFromPendingChannel(
|
|||||||
RefPtr<nsDocShellLoadState> loadState =
|
RefPtr<nsDocShellLoadState> loadState =
|
||||||
new nsDocShellLoadState(uri, aLoadIdentifier);
|
new nsDocShellLoadState(uri, aLoadIdentifier);
|
||||||
loadState->mPendingRedirectedChannel = aPendingChannel;
|
loadState->mPendingRedirectedChannel = aPendingChannel;
|
||||||
|
loadState->mChannelRegistrarId = aRegistrarId;
|
||||||
|
|
||||||
// Pull relevant state from the channel, and store it on the
|
// Pull relevant state from the channel, and store it on the
|
||||||
// nsDocShellLoadState.
|
// nsDocShellLoadState.
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class nsDocShellLoadState final {
|
|||||||
|
|
||||||
static nsresult CreateFromPendingChannel(nsIChannel* aPendingChannel,
|
static nsresult CreateFromPendingChannel(nsIChannel* aPendingChannel,
|
||||||
uint64_t aLoadIdentifier,
|
uint64_t aLoadIdentifier,
|
||||||
|
uint64_t aRegistarId,
|
||||||
nsDocShellLoadState** aResult);
|
nsDocShellLoadState** aResult);
|
||||||
|
|
||||||
static nsresult CreateFromLoadURIOptions(
|
static nsresult CreateFromLoadURIOptions(
|
||||||
@@ -230,6 +231,10 @@ class nsDocShellLoadState final {
|
|||||||
return mPendingRedirectedChannel;
|
return mPendingRedirectedChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t GetPendingRedirectChannelRegistrarId() const {
|
||||||
|
return mChannelRegistrarId;
|
||||||
|
}
|
||||||
|
|
||||||
void SetOriginalURIString(const nsCString& aOriginalURI) {
|
void SetOriginalURIString(const nsCString& aOriginalURI) {
|
||||||
mOriginalURIString.emplace(aOriginalURI);
|
mOriginalURIString.emplace(aOriginalURI);
|
||||||
}
|
}
|
||||||
@@ -426,6 +431,11 @@ class nsDocShellLoadState final {
|
|||||||
// when initiating the load.
|
// when initiating the load.
|
||||||
mozilla::Maybe<int32_t> mCancelContentJSEpoch;
|
mozilla::Maybe<int32_t> mCancelContentJSEpoch;
|
||||||
|
|
||||||
|
// If mPendingRedirectChannel is set, then this is the identifier
|
||||||
|
// that the parent-process equivalent channel has been registered
|
||||||
|
// with using RedirectChannelRegistrar.
|
||||||
|
uint64_t mChannelRegistrarId;
|
||||||
|
|
||||||
// An identifier to make it possible to examine if two loads are
|
// An identifier to make it possible to examine if two loads are
|
||||||
// equal, and which browsing context they belong to (see
|
// equal, and which browsing context they belong to (see
|
||||||
// BrowsingContext::{Get, Set}CurrentLoadIdentifier)
|
// BrowsingContext::{Get, Set}CurrentLoadIdentifier)
|
||||||
|
|||||||
@@ -3447,7 +3447,8 @@ mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
|
|||||||
|
|
||||||
RefPtr<nsDocShellLoadState> loadState;
|
RefPtr<nsDocShellLoadState> loadState;
|
||||||
rv = nsDocShellLoadState::CreateFromPendingChannel(
|
rv = nsDocShellLoadState::CreateFromPendingChannel(
|
||||||
newChannel, aArgs.loadIdentifier(), getter_AddRefs(loadState));
|
newChannel, aArgs.loadIdentifier(), aArgs.registrarId(),
|
||||||
|
getter_AddRefs(loadState));
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "mozilla/StaticPrefs_security.h"
|
#include "mozilla/StaticPrefs_security.h"
|
||||||
#include "mozilla/dom/BrowsingContextGroup.h"
|
#include "mozilla/dom/BrowsingContextGroup.h"
|
||||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||||
|
#include "mozilla/dom/ChildProcessChannelListener.h"
|
||||||
#include "mozilla/dom/ClientChannelHelper.h"
|
#include "mozilla/dom/ClientChannelHelper.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
#include "mozilla/dom/ContentProcessManager.h"
|
#include "mozilla/dom/ContentProcessManager.h"
|
||||||
@@ -1312,8 +1313,9 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||||||
NS_ConvertUTF16toUTF8(remoteType).get()));
|
NS_ConvertUTF16toUTF8(remoteType).get()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (NS_WARN_IF(remoteType.IsEmpty())) {
|
|
||||||
LOG(("Process Switch Abort: non-remote target process"));
|
if (NS_WARN_IF(!browsingContext->IsTop() && remoteType.IsEmpty())) {
|
||||||
|
LOG(("Process Switch Abort: non-remote target process for subframe"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1335,14 +1337,10 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||||||
->Then(
|
->Then(
|
||||||
GetMainThreadSerialEventTarget(), __func__,
|
GetMainThreadSerialEventTarget(), __func__,
|
||||||
[self = RefPtr{this}](BrowserParent* aBrowserParent) {
|
[self = RefPtr{this}](BrowserParent* aBrowserParent) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(
|
|
||||||
aBrowserParent,
|
|
||||||
"Shouldn't have switched into the parent process, as we check "
|
|
||||||
"!remoteType.IsEmpty() earlier in MaybeTriggerProcessSwitch");
|
|
||||||
MOZ_ASSERT(self->mChannel,
|
MOZ_ASSERT(self->mChannel,
|
||||||
"Something went wrong, channel got cancelled");
|
"Something went wrong, channel got cancelled");
|
||||||
self->TriggerRedirectToRealChannel(
|
self->TriggerRedirectToRealChannel(Some(
|
||||||
Some(aBrowserParent->Manager()->ChildID()));
|
aBrowserParent ? aBrowserParent->Manager()->ChildID() : 0));
|
||||||
},
|
},
|
||||||
[self = RefPtr{this}](nsresult aStatusCode) {
|
[self = RefPtr{this}](nsresult aStatusCode) {
|
||||||
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
MOZ_ASSERT(NS_FAILED(aStatusCode), "Status should be error");
|
||||||
@@ -1351,6 +1349,42 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||||
|
DocumentLoadListener::RedirectToParentProcess(uint32_t aRedirectFlags,
|
||||||
|
uint32_t aLoadFlags) {
|
||||||
|
// This is largely the same as ContentChild::RecvCrossProcessRedirect,
|
||||||
|
// except without needing to deserialize or create an nsIChildChannel.
|
||||||
|
|
||||||
|
RefPtr<nsDocShellLoadState> loadState;
|
||||||
|
nsDocShellLoadState::CreateFromPendingChannel(
|
||||||
|
mChannel, mLoadIdentifier, mRedirectChannelId, getter_AddRefs(loadState));
|
||||||
|
|
||||||
|
loadState->SetLoadFlags(mLoadStateLoadFlags);
|
||||||
|
loadState->SetLoadType(mLoadStateLoadType);
|
||||||
|
if (mSessionHistoryInfo) {
|
||||||
|
loadState->SetSessionHistoryInfo(*mSessionHistoryInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is poorly named now.
|
||||||
|
RefPtr<ChildProcessChannelListener> processListener =
|
||||||
|
ChildProcessChannelListener::GetSingleton();
|
||||||
|
|
||||||
|
auto promise =
|
||||||
|
MakeRefPtr<PDocumentChannelParent::RedirectToRealChannelPromise::Private>(
|
||||||
|
__func__);
|
||||||
|
promise->UseDirectTaskDispatch(__func__);
|
||||||
|
auto resolve = [promise](nsresult aResult) {
|
||||||
|
promise->Resolve(aResult, __func__);
|
||||||
|
};
|
||||||
|
|
||||||
|
nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>> endpoints;
|
||||||
|
processListener->OnChannelReady(loadState, mCrossProcessRedirectIdentifier,
|
||||||
|
std::move(endpoints), mTiming,
|
||||||
|
std::move(resolve));
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||||
DocumentLoadListener::RedirectToRealChannel(
|
DocumentLoadListener::RedirectToRealChannel(
|
||||||
uint32_t aRedirectFlags, uint32_t aLoadFlags,
|
uint32_t aRedirectFlags, uint32_t aLoadFlags,
|
||||||
@@ -1379,6 +1413,10 @@ DocumentLoadListener::RedirectToRealChannel(
|
|||||||
MOZ_ALWAYS_SUCCEEDS(registrar->RegisterChannel(mChannel, mRedirectChannelId));
|
MOZ_ALWAYS_SUCCEEDS(registrar->RegisterChannel(mChannel, mRedirectChannelId));
|
||||||
|
|
||||||
if (aDestinationProcess) {
|
if (aDestinationProcess) {
|
||||||
|
if (!*aDestinationProcess) {
|
||||||
|
MOZ_ASSERT(aStreamFilterEndpoints.IsEmpty());
|
||||||
|
return RedirectToParentProcess(aRedirectFlags, aLoadFlags);
|
||||||
|
}
|
||||||
dom::ContentParent* cp =
|
dom::ContentParent* cp =
|
||||||
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
|
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
|
||||||
ContentParentId{*aDestinationProcess});
|
ContentParentId{*aDestinationProcess});
|
||||||
@@ -1466,15 +1504,24 @@ void DocumentLoadListener::TriggerRedirectToRealChannel(
|
|||||||
if (!mStreamFilterRequests.IsEmpty()) {
|
if (!mStreamFilterRequests.IsEmpty()) {
|
||||||
base::ProcessId pid = OtherPid();
|
base::ProcessId pid = OtherPid();
|
||||||
if (aDestinationProcess) {
|
if (aDestinationProcess) {
|
||||||
dom::ContentParent* cp =
|
if (*aDestinationProcess) {
|
||||||
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
|
dom::ContentParent* cp =
|
||||||
ContentParentId(*aDestinationProcess));
|
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
|
||||||
if (cp) {
|
ContentParentId(*aDestinationProcess));
|
||||||
pid = cp->OtherPid();
|
if (cp) {
|
||||||
|
pid = cp->OtherPid();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pid = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (StreamFilterRequest& request : mStreamFilterRequests) {
|
for (StreamFilterRequest& request : mStreamFilterRequests) {
|
||||||
|
if (!pid) {
|
||||||
|
request.mPromise->Reject(false, __func__);
|
||||||
|
request.mPromise = nullptr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ParentEndpoint parent;
|
ParentEndpoint parent;
|
||||||
nsresult rv = extensions::PStreamFilter::CreateEndpoints(
|
nsresult rv = extensions::PStreamFilter::CreateEndpoints(
|
||||||
pid, request.mChildProcessId, &parent, &request.mChildEndpoint);
|
pid, request.mChildProcessId, &parent, &request.mChildEndpoint);
|
||||||
|
|||||||
@@ -271,6 +271,11 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||||||
const Maybe<uint64_t>& aDestinationProcess,
|
const Maybe<uint64_t>& aDestinationProcess,
|
||||||
nsTArray<ParentEndpoint>&& aStreamFilterEndpoints);
|
nsTArray<ParentEndpoint>&& aStreamFilterEndpoints);
|
||||||
|
|
||||||
|
// A helper for RedirectToRealChannel that handles the case where we started
|
||||||
|
// from a content process and are process switching into the parent process.
|
||||||
|
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||||
|
RedirectToParentProcess(uint32_t aRedirectFlags, uint32_t aLoadFlags);
|
||||||
|
|
||||||
// Construct a LoadInfo object to use for the internal channel.
|
// Construct a LoadInfo object to use for the internal channel.
|
||||||
already_AddRefed<LoadInfo> CreateLoadInfo(
|
already_AddRefed<LoadInfo> CreateLoadInfo(
|
||||||
dom::CanonicalBrowsingContext* aBrowsingContext,
|
dom::CanonicalBrowsingContext* aBrowsingContext,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "ParentChannelWrapper.h"
|
#include "ParentChannelWrapper.h"
|
||||||
#include "mozilla/net/UrlClassifierCommon.h"
|
#include "mozilla/net/UrlClassifierCommon.h"
|
||||||
|
#include "nsIRedirectChannelRegistrar.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace net {
|
namespace net {
|
||||||
@@ -14,6 +15,15 @@ namespace net {
|
|||||||
NS_IMPL_ISUPPORTS(ParentChannelWrapper, nsIParentChannel, nsIStreamListener,
|
NS_IMPL_ISUPPORTS(ParentChannelWrapper, nsIParentChannel, nsIStreamListener,
|
||||||
nsIRequestObserver);
|
nsIRequestObserver);
|
||||||
|
|
||||||
|
void ParentChannelWrapper::Register(uint64_t aRegistrarId) {
|
||||||
|
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||||
|
RedirectChannelRegistrar::GetOrCreate();
|
||||||
|
nsCOMPtr<nsIChannel> dummy;
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(
|
||||||
|
NS_LinkRedirectChannels(aRegistrarId, this, getter_AddRefs(dummy)));
|
||||||
|
MOZ_ASSERT(dummy == mChannel);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// nsIParentChannel
|
// nsIParentChannel
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ class ParentChannelWrapper : public nsIParentChannel {
|
|||||||
ParentChannelWrapper(nsIChannel* aChannel, nsIStreamListener* aListener)
|
ParentChannelWrapper(nsIChannel* aChannel, nsIStreamListener* aListener)
|
||||||
: mChannel(aChannel), mListener(aListener) {}
|
: mChannel(aChannel), mListener(aListener) {}
|
||||||
|
|
||||||
|
// Registers this nsIParentChannel wrapper with the RedirectChannelRegistrar
|
||||||
|
// and holds a reference.
|
||||||
|
void Register(uint64_t aRegistrarId);
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIPARENTCHANNEL
|
NS_DECL_NSIPARENTCHANNEL
|
||||||
NS_FORWARD_NSISTREAMLISTENER(mListener->)
|
NS_FORWARD_NSISTREAMLISTENER(mListener->)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "nsDocShell.h"
|
#include "nsDocShell.h"
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
#include "nsIClassifiedChannel.h"
|
#include "nsIClassifiedChannel.h"
|
||||||
#include "nsIRedirectChannelRegistrar.h"
|
|
||||||
|
|
||||||
extern mozilla::LazyLogModule gDocumentChannelLog;
|
extern mozilla::LazyLogModule gDocumentChannelLog;
|
||||||
#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
|
#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
|
||||||
@@ -118,13 +117,7 @@ ParentProcessDocumentChannel::OnRedirectVerifyCallback(nsresult aResult) {
|
|||||||
RefPtr<ParentChannelWrapper> wrapper =
|
RefPtr<ParentChannelWrapper> wrapper =
|
||||||
new ParentChannelWrapper(channel, mListener);
|
new ParentChannelWrapper(channel, mListener);
|
||||||
|
|
||||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
wrapper->Register(mDocumentLoadListener->GetRedirectChannelId());
|
||||||
RedirectChannelRegistrar::GetOrCreate();
|
|
||||||
nsCOMPtr<nsIChannel> dummy;
|
|
||||||
MOZ_ALWAYS_SUCCEEDS(
|
|
||||||
NS_LinkRedirectChannels(mDocumentLoadListener->GetRedirectChannelId(),
|
|
||||||
wrapper, getter_AddRefs(dummy)));
|
|
||||||
MOZ_ASSERT(dummy == channel);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -824,7 +824,6 @@ var E10SUtils = {
|
|||||||
// handled using DocumentChannel, then we can skip switching
|
// handled using DocumentChannel, then we can skip switching
|
||||||
// for now, and let DocumentChannel do it during the response.
|
// for now, and let DocumentChannel do it during the response.
|
||||||
if (
|
if (
|
||||||
requiredRemoteType != NOT_REMOTE &&
|
|
||||||
uriObject &&
|
uriObject &&
|
||||||
(remoteSubframes || documentChannel) &&
|
(remoteSubframes || documentChannel) &&
|
||||||
documentChannelPermittedForURI(uriObject)
|
documentChannelPermittedForURI(uriObject)
|
||||||
@@ -855,7 +854,6 @@ var E10SUtils = {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
(aRemoteSubframes || documentChannel) &&
|
(aRemoteSubframes || documentChannel) &&
|
||||||
wantRemoteType != NOT_REMOTE &&
|
|
||||||
documentChannelPermittedForURI(aURI)
|
documentChannelPermittedForURI(aURI)
|
||||||
) {
|
) {
|
||||||
// We can switch later with documentchannel.
|
// We can switch later with documentchannel.
|
||||||
@@ -893,7 +891,6 @@ var E10SUtils = {
|
|||||||
if (
|
if (
|
||||||
AppConstants.MOZ_WIDGET_TOOLKIT != "android" &&
|
AppConstants.MOZ_WIDGET_TOOLKIT != "android" &&
|
||||||
(useRemoteSubframes || documentChannel) &&
|
(useRemoteSubframes || documentChannel) &&
|
||||||
wantRemoteType != NOT_REMOTE &&
|
|
||||||
documentChannelPermittedForURI(aURI)
|
documentChannelPermittedForURI(aURI)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -53,12 +53,6 @@ interface nsIURILoader : nsISupports
|
|||||||
* be indicated.
|
* be indicated.
|
||||||
*/
|
*/
|
||||||
const unsigned long DONT_RETARGET = 1 << 1;
|
const unsigned long DONT_RETARGET = 1 << 1;
|
||||||
/**
|
|
||||||
* If this flag is set, it means that aChannel has been redirected from
|
|
||||||
* another process, and should be reopened using CompleteRedirectSetup rather
|
|
||||||
* than AsyncOpen.
|
|
||||||
*/
|
|
||||||
const unsigned long REDIRECTED_CHANNEL = 1 << 2;
|
|
||||||
/* @} */
|
/* @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -687,19 +687,6 @@ NS_IMETHODIMP nsURILoader::OpenURI(nsIChannel* channel, uint32_t aFlags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aFlags & nsIURILoader::REDIRECTED_CHANNEL) {
|
|
||||||
// Our channel was redirected from another process, so doesn't need to
|
|
||||||
// be opened again. However, it does need its listener hooked up
|
|
||||||
// correctly.
|
|
||||||
if (nsCOMPtr<nsIChildChannel> childChannel = do_QueryInterface(channel)) {
|
|
||||||
return childChannel->CompleteRedirectSetup(loader);
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's possible for the redirected channel to not implement
|
|
||||||
// nsIChildChannel and be entirely local (like srcdoc). In that case we
|
|
||||||
// can just open the local instance and it will work.
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is not complete. Eventually, we should first go
|
// This method is not complete. Eventually, we should first go
|
||||||
// to the content listener and ask them for a protocol handler...
|
// to the content listener and ask them for a protocol handler...
|
||||||
// if they don't give us one, we need to go to the registry and get
|
// if they don't give us one, we need to go to the registry and get
|
||||||
|
|||||||
Reference in New Issue
Block a user