зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1607984 - P12. Start parent load via DocumentChannel. r=mayhemer,nika,mattwoodrow,necko-reviewers
Add ParentProcessDocumentChannel object. This object is a DocumentChannel that will start a channel load from the parent process via a DocumentChannel. The aim of this task is two-fold. 1- Be consistent on how we handle redirects before continuing the load on the final channel. 2- Prepare to initiate a process switch when needed without having to go via an intermediary content process, saving a process switch. This task will be done in a follow-up task. The behaviour of the ParentProcessDocumentChannel is similar in logic to the DocumentChannelChild/DocumentChannelParent pair. The ParentProcessDocumentChannel sets up a DocumentLoadListener, have it handle the redirects and upon completion continue the load on the final channel. Differential Revision: https://phabricator.services.mozilla.com/D70009
This commit is contained in:
Родитель
46e166596d
Коммит
fce4dd9e1f
|
@ -73,9 +73,8 @@
|
|||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/dom/LoadURIOptionsBinding.h"
|
||||
#include "mozilla/dom/JSWindowActorChild.h"
|
||||
#include "mozilla/net/DocumentChannel.h"
|
||||
#include "nsSHEntry.h"
|
||||
#include "mozilla/net/DocumentChannelChild.h"
|
||||
#include "mozilla/net/DocumentChannel.h"
|
||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||
#include "ReferrerInfo.h"
|
||||
|
||||
|
@ -5713,7 +5712,8 @@ void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
|||
// of redirects handled in the parent process.
|
||||
// Query the full redirect chain directly, so that we can add history
|
||||
// entries for them.
|
||||
if (RefPtr<DocumentChannel> docChannel = do_QueryObject(aOldChannel)) {
|
||||
RefPtr<DocumentChannel> docChannel = do_QueryObject(aOldChannel);
|
||||
if (docChannel) {
|
||||
nsCOMPtr<nsIURI> previousURI;
|
||||
uint32_t previousFlags = 0;
|
||||
docChannel->GetLastVisit(getter_AddRefs(previousURI), &previousFlags);
|
||||
|
@ -5761,7 +5761,7 @@ void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
|||
// check if the new load should go through the application cache.
|
||||
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
|
||||
do_QueryInterface(aNewChannel);
|
||||
if (appCacheChannel) {
|
||||
if (appCacheChannel && !docChannel) {
|
||||
if (GeckoProcessType_Default != XRE_GetProcessType()) {
|
||||
// Permission will be checked in the parent process.
|
||||
appCacheChannel->SetChooseApplicationCache(true);
|
||||
|
@ -9188,23 +9188,6 @@ static bool IsConsideredSameOriginForUIR(nsIPrincipal* aTriggeringPrincipal,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Changes here should also be made in
|
||||
// E10SUtils.documentChannelPermittedForURI().
|
||||
static bool URIUsesDocChannel(nsIURI* aURI) {
|
||||
if (SchemeIsJavascript(aURI) || NS_IsAboutBlank(aURI)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString spec = aURI->GetSpecOrDefault();
|
||||
|
||||
if (spec.EqualsLiteral("about:printpreview") ||
|
||||
spec.EqualsLiteral("about:crashcontent")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool nsDocShell::CreateAndConfigureRealChannelForLoadState(
|
||||
BrowsingContext* aBrowsingContext, nsDocShellLoadState* aLoadState,
|
||||
LoadInfo* aLoadInfo, nsIInterfaceRequestor* aCallbacks,
|
||||
|
@ -9605,8 +9588,9 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
|||
// If we have a pending channel, use the channel we've already created here.
|
||||
// We don't need to set up load flags for our channel, as it has already been
|
||||
// created.
|
||||
nsCOMPtr<nsIChannel> channel = aLoadState->GetPendingRedirectedChannel();
|
||||
if (channel) {
|
||||
|
||||
if (nsCOMPtr<nsIChannel> channel =
|
||||
aLoadState->GetPendingRedirectedChannel()) {
|
||||
MOZ_ASSERT(!aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC),
|
||||
"pending channel for srcdoc load?");
|
||||
|
||||
|
@ -9775,20 +9759,11 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
|
|||
cacheKey = mOSHE->GetCacheKey();
|
||||
}
|
||||
|
||||
// We want to use DocumentChannel if we're using a supported scheme. Sandboxed
|
||||
// srcdoc loads break due to failing assertions after changing processes, and
|
||||
// non-sandboxed srcdoc loads need to share the same principal object as their
|
||||
// outer document (and must load in the same process), which breaks if we
|
||||
// serialize to the parent process.
|
||||
bool canUseDocumentChannel =
|
||||
!aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_IS_SRCDOC) &&
|
||||
URIUsesDocChannel(aLoadState->URI());
|
||||
|
||||
if (StaticPrefs::browser_tabs_documentchannel() && XRE_IsContentProcess() &&
|
||||
canUseDocumentChannel) {
|
||||
channel =
|
||||
new DocumentChannelChild(aLoadState, loadInfo, loadFlags, cacheKey);
|
||||
channel->SetNotificationCallbacks(this);
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
if (DocumentChannel::CanUseDocumentChannel(aLoadState)) {
|
||||
channel = DocumentChannel::CreateDocumentChannel(aLoadState, loadInfo,
|
||||
loadFlags, this, cacheKey);
|
||||
MOZ_ASSERT(channel);
|
||||
} else if (!CreateAndConfigureRealChannelForLoadState(
|
||||
mBrowsingContext, aLoadState, loadInfo, this, this,
|
||||
GetOriginAttributes(), loadFlags, cacheKey, rv,
|
||||
|
|
|
@ -95,7 +95,7 @@ var RequestWatcher = {
|
|||
// We may also see, eg, chrome://global/skin/icons/resizer.svg, so
|
||||
// skip chrome:// URLs too.
|
||||
if (req.name.startsWith("about:") || req.name.startsWith("resource:") ||
|
||||
req.name.startsWith("chrome:")) {
|
||||
req.name.startsWith("chrome:") || req.name.startsWith("documentchannel:")) {
|
||||
return;
|
||||
}
|
||||
is(req.loadFlags & TEST_FLAGS, TEST_FLAGS, "request " + req.name + " has the expected flags");
|
||||
|
|
|
@ -47,6 +47,7 @@ class ADocumentChannelBridge {
|
|||
uint32_t aRedirectFlags, uint32_t aLoadFlags) = 0;
|
||||
|
||||
// Returns the process id that this bridge is connected to.
|
||||
// If 0 indicates that the load is started from the parent process.
|
||||
virtual base::ProcessId OtherPid() const = 0;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -10,20 +10,24 @@
|
|||
#include "SerializedLoadContext.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/dom/BrowserChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/nsCSPContext.h"
|
||||
#include "mozilla/extensions/StreamFilterParent.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/net/DocumentChannelChild.h"
|
||||
#include "mozilla/net/HttpChannelChild.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/net/ParentProcessDocumentChannel.h"
|
||||
#include "mozilla/net/UrlClassifierCommon.h"
|
||||
#include "nsContentSecurityManager.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsIInputStreamChannel.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
#include "nsStreamListenerWrapper.h"
|
||||
|
@ -77,6 +81,48 @@ DocumentChannel::AsyncOpen(nsIStreamListener* aListener) {
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void DocumentChannel::ShutdownListeners(nsresult aStatusCode) {
|
||||
LOG(("DocumentChannel ShutdownListeners [this=%p, status=%" PRIx32 "]", this,
|
||||
static_cast<uint32_t>(aStatusCode)));
|
||||
mStatus = aStatusCode;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = mListener;
|
||||
if (listener) {
|
||||
listener->OnStartRequest(this);
|
||||
}
|
||||
|
||||
mIsPending = false;
|
||||
|
||||
listener = mListener; // it might have changed!
|
||||
if (listener) {
|
||||
listener->OnStopRequest(this, aStatusCode);
|
||||
}
|
||||
mListener = nullptr;
|
||||
mCallbacks = nullptr;
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aStatusCode);
|
||||
mLoadGroup = nullptr;
|
||||
}
|
||||
|
||||
DeleteIPDL();
|
||||
}
|
||||
|
||||
void DocumentChannel::DisconnectChildListeners(
|
||||
const nsresult& aStatus, const nsresult& aLoadGroupStatus) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
mStatus = aLoadGroupStatus;
|
||||
// Make sure we remove from the load group before
|
||||
// setting mStatus, as existing tests expect the
|
||||
// status to be successful when we disconnect.
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aStatus);
|
||||
mLoadGroup = nullptr;
|
||||
}
|
||||
|
||||
ShutdownListeners(aStatus);
|
||||
}
|
||||
|
||||
nsDocShell* DocumentChannel::GetDocShell() {
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(this, loadContext);
|
||||
|
@ -93,6 +139,47 @@ nsDocShell* DocumentChannel::GetDocShell() {
|
|||
return nsDocShell::Cast(docshell);
|
||||
}
|
||||
|
||||
// Changes here should also be made in
|
||||
// E10SUtils.documentChannelPermittedForURI().
|
||||
static bool URIUsesDocChannel(nsIURI* aURI) {
|
||||
if (SchemeIsJavascript(aURI) || NS_IsAboutBlank(aURI)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString spec = aURI->GetSpecOrDefault();
|
||||
return !spec.EqualsLiteral("about:printpreview") &&
|
||||
!spec.EqualsLiteral("about:crashcontent");
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<DocumentChannel> DocumentChannel::CreateDocumentChannel(
|
||||
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
|
||||
uint32_t aCacheKey) {
|
||||
RefPtr<DocumentChannel> channel;
|
||||
if (XRE_IsContentProcess()) {
|
||||
channel =
|
||||
new DocumentChannelChild(aLoadState, aLoadInfo, aLoadFlags, aCacheKey);
|
||||
} else {
|
||||
channel = new ParentProcessDocumentChannel(aLoadState, aLoadInfo,
|
||||
aLoadFlags, aCacheKey);
|
||||
}
|
||||
channel->SetNotificationCallbacks(aNotificationCallbacks);
|
||||
return channel.forget();
|
||||
}
|
||||
|
||||
bool DocumentChannel::CanUseDocumentChannel(nsDocShellLoadState* aLoadState) {
|
||||
MOZ_ASSERT(aLoadState);
|
||||
// We want to use DocumentChannel if we're using a supported scheme. Sandboxed
|
||||
// srcdoc loads break due to failing assertions after changing processes, and
|
||||
// non-sandboxed srcdoc loads need to share the same principal object as their
|
||||
// outer document (and must load in the same process), which breaks if we
|
||||
// serialize to the parent process.
|
||||
return StaticPrefs::browser_tabs_documentchannel() &&
|
||||
!aLoadState->HasLoadFlags(nsDocShell::INTERNAL_LOAD_FLAGS_IS_SRCDOC) &&
|
||||
URIUsesDocChannel(aLoadState->URI());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DocumentChannel::nsITraceableChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -100,6 +187,8 @@ nsDocShell* DocumentChannel::GetDocShell() {
|
|||
NS_IMETHODIMP
|
||||
DocumentChannel::SetNewListener(nsIStreamListener* aListener,
|
||||
nsIStreamListener** _retval) {
|
||||
LOG(("DocumentChannel SetNewListener [this=%p, aListener=%p]", this,
|
||||
aListener));
|
||||
NS_ENSURE_ARG_POINTER(aListener);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener);
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
#ifndef mozilla_net_DocumentChannel_h
|
||||
#define mozilla_net_DocumentChannel_h
|
||||
|
||||
#include "mozilla/net/PDocumentChannelChild.h"
|
||||
#include "mozilla/dom/ClientInfo.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "nsDOMNavigationTiming.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChildChannel.h"
|
||||
#include "nsITraceableChannel.h"
|
||||
#include "mozilla/dom/ClientInfo.h"
|
||||
|
||||
#define DOCUMENT_CHANNEL_IID \
|
||||
{ \
|
||||
|
@ -45,9 +45,6 @@ class DocumentChannel : public nsIIdentChannel, public nsITraceableChannel {
|
|||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOCUMENT_CHANNEL_IID)
|
||||
|
||||
DocumentChannel(nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
nsLoadFlags aLoadFlags, uint32_t aCacheKey);
|
||||
|
||||
const nsTArray<DocumentChannelRedirect>& GetRedirectChain() const {
|
||||
return mRedirects;
|
||||
}
|
||||
|
@ -65,7 +62,28 @@ class DocumentChannel : public nsIIdentChannel, public nsITraceableChannel {
|
|||
mInitialClientInfo = aInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will create the appropriate document channel:
|
||||
* Either a DocumentChannelChild if called from the content process or
|
||||
* a ParentProcessDocumentChannel if called from the parent process.
|
||||
* This operation is infallible.
|
||||
*/
|
||||
static already_AddRefed<DocumentChannel> CreateDocumentChannel(
|
||||
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
nsLoadFlags aLoadFlags, nsIInterfaceRequestor* aNotificationCallbacks,
|
||||
uint32_t aCacheKey);
|
||||
|
||||
static bool CanUseDocumentChannel(nsDocShellLoadState* aLoadState);
|
||||
|
||||
protected:
|
||||
DocumentChannel(nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
nsLoadFlags aLoadFlags, uint32_t aCacheKey);
|
||||
|
||||
void ShutdownListeners(nsresult aStatusCode);
|
||||
void DisconnectChildListeners(const nsresult& aStatus,
|
||||
const nsresult& aLoadGroupStatus);
|
||||
virtual void DeleteIPDL() {}
|
||||
|
||||
nsDocShell* GetDocShell();
|
||||
|
||||
virtual ~DocumentChannel() = default;
|
||||
|
|
|
@ -128,48 +128,9 @@ IPCResult DocumentChannelChild::RecvFailedAsyncOpen(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
void DocumentChannelChild::ShutdownListeners(nsresult aStatusCode) {
|
||||
LOG(("DocumentChannelChild ShutdownListeners [this=%p, status=%" PRIx32 "]",
|
||||
this, static_cast<uint32_t>(aStatusCode)));
|
||||
mStatus = aStatusCode;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> l = mListener;
|
||||
if (l) {
|
||||
l->OnStartRequest(this);
|
||||
}
|
||||
|
||||
mIsPending = false;
|
||||
|
||||
l = mListener; // it might have changed!
|
||||
if (l) {
|
||||
l->OnStopRequest(this, aStatusCode);
|
||||
}
|
||||
mListener = nullptr;
|
||||
mCallbacks = nullptr;
|
||||
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aStatusCode);
|
||||
mLoadGroup = nullptr;
|
||||
}
|
||||
|
||||
if (CanSend()) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvDisconnectChildListeners(
|
||||
const nsresult& aStatus, const nsresult& aLoadGroupStatus) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatus));
|
||||
mStatus = aLoadGroupStatus;
|
||||
// Make sure we remove from the load group before
|
||||
// setting mStatus, as existing tests expect the
|
||||
// status to be successful when we disconnect.
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, aStatus);
|
||||
mLoadGroup = nullptr;
|
||||
}
|
||||
|
||||
ShutdownListeners(aStatus);
|
||||
DisconnectChildListeners(aStatus, aLoadGroupStatus);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,11 @@ class DocumentChannelChild final : public DocumentChannel,
|
|||
RedirectToRealChannelResolver&& aResolve);
|
||||
|
||||
private:
|
||||
void ShutdownListeners(nsresult aStatusCode);
|
||||
void DeleteIPDL() override {
|
||||
if (CanSend()) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
~DocumentChannelChild();
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
class CanonicalBrowsingContext;
|
||||
}
|
||||
class BrowserParent;
|
||||
} // namespace dom
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
|
@ -61,7 +62,7 @@ class DocumentChannelParent final : public ADocumentChannelBridge,
|
|||
}
|
||||
}
|
||||
|
||||
virtual ProcessId OtherPid() const override { return IProtocol::OtherPid(); }
|
||||
ProcessId OtherPid() const override { return IProtocol::OtherPid(); }
|
||||
|
||||
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||
RedirectToRealChannel(
|
||||
|
@ -69,7 +70,7 @@ class DocumentChannelParent final : public ADocumentChannelBridge,
|
|||
aStreamFilterEndpoints,
|
||||
uint32_t aRedirectFlags, uint32_t aLoadFlags) override;
|
||||
|
||||
~DocumentChannelParent();
|
||||
virtual ~DocumentChannelParent();
|
||||
|
||||
RefPtr<DocumentLoadListener> mParent;
|
||||
};
|
||||
|
|
|
@ -6,44 +6,36 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DocumentLoadListener.h"
|
||||
|
||||
#include "mozilla/AntiTrackingUtils.h"
|
||||
#include "mozilla/ContentBlockingAllowList.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/MozPromiseInlines.h" // For MozPromise::FromDomPromise
|
||||
#include "mozilla/StaticPrefs_security.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/ClientChannelHelper.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/dom/ipc/IdType.h"
|
||||
#include "mozilla/dom/ServiceWorkerManager.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/net/HttpChannelParent.h"
|
||||
#include "mozilla/net/RedirectChannelRegistrar.h"
|
||||
#include "mozilla/net/UrlClassifierCommon.h"
|
||||
#include "nsContentSecurityUtils.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsDocShellLoadState.h"
|
||||
#include "nsContentSecurityUtils.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsISecureBrowserUI.h"
|
||||
#include "nsRedirectHistoryEntry.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
#include "nsIPrompt.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIURIContentListener.h"
|
||||
#include "nsWebNavigationInfo.h"
|
||||
#include "nsURILoader.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsExternalHelperAppService.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIViewSourceChannel.h"
|
||||
#include "nsIOService.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/StaticPrefs_security.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsIBrowser.h"
|
||||
#include "nsIE10SUtils.h"
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsIViewSourceChannel.h"
|
||||
#include "nsImportModule.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsRedirectHistoryEntry.h"
|
||||
#include "nsURILoader.h"
|
||||
#include "nsWebNavigationInfo.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
# include "mozilla/widget/nsWindow.h"
|
||||
|
@ -248,11 +240,10 @@ NS_INTERFACE_MAP_END
|
|||
DocumentLoadListener::DocumentLoadListener(
|
||||
CanonicalBrowsingContext* aBrowsingContext, nsILoadContext* aLoadContext,
|
||||
ADocumentChannelBridge* aBridge)
|
||||
: mLoadContext(aLoadContext) {
|
||||
: mDocumentChannelBridge(aBridge), mLoadContext(aLoadContext) {
|
||||
LOG(("DocumentLoadListener ctor [this=%p]", this));
|
||||
mParentChannelListener = new ParentChannelListener(
|
||||
this, aBrowsingContext, aLoadContext->UsePrivateBrowsing());
|
||||
mDocumentChannelBridge = aBridge;
|
||||
}
|
||||
|
||||
DocumentLoadListener::~DocumentLoadListener() {
|
||||
|
@ -440,8 +431,8 @@ bool DocumentLoadListener::Open(
|
|||
// OnStart/StopRequest with itself. We don't need this, and instead
|
||||
// we want the original request so that we get different ones for
|
||||
// each part of a multipart channel.
|
||||
if (nsCOMPtr<nsIViewSourceChannel> viewSourceChannel =
|
||||
do_QueryInterface(mChannel)) {
|
||||
nsCOMPtr<nsIViewSourceChannel> viewSourceChannel;
|
||||
if (OtherPid() && (viewSourceChannel = do_QueryInterface(mChannel))) {
|
||||
viewSourceChannel->SetReplaceRequest(false);
|
||||
}
|
||||
|
||||
|
@ -570,6 +561,11 @@ void DocumentLoadListener::RedirectToRealChannelFinished(nsresult aRv) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mRedirectChannelId) {
|
||||
FinishReplacementChannelSetup(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for background channel ready on target channel
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> redirectReg =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
|
@ -608,42 +604,48 @@ void DocumentLoadListener::FinishReplacementChannelSetup(bool aSucceeded) {
|
|||
("DocumentLoadListener FinishReplacementChannelSetup [this=%p, "
|
||||
"aSucceeded=%d]",
|
||||
this, aSucceeded));
|
||||
nsresult rv;
|
||||
|
||||
if (mDoingProcessSwitch) {
|
||||
DisconnectChildListeners(NS_BINDING_ABORTED, NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIParentChannel> redirectChannel;
|
||||
if (mRedirectChannelId) {
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
MOZ_ASSERT(registrar);
|
||||
|
||||
rv = registrar->GetParentChannel(mRedirectChannelId,
|
||||
getter_AddRefs(redirectChannel));
|
||||
if (NS_FAILED(rv) || !redirectChannel) {
|
||||
// Redirect might get canceled before we got AsyncOnChannelRedirect
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = registrar->GetRegisteredChannel(mRedirectChannelId,
|
||||
getter_AddRefs(newChannel));
|
||||
MOZ_ASSERT(newChannel, "Already registered channel not found");
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
newChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
if (!mRedirectChannelId) {
|
||||
if (!aSucceeded) {
|
||||
mChannel->Resume();
|
||||
return;
|
||||
}
|
||||
// Release all previously registered channels, they are no longer needed to
|
||||
// be kept in the registrar from this moment.
|
||||
registrar->DeregisterChannels(mRedirectChannelId);
|
||||
|
||||
mRedirectChannelId = 0;
|
||||
ApplyPendingFunctions(mChannel);
|
||||
// ResumeSuspendedChannel will be called later as RedirectToRealChannel
|
||||
// continues, so we can return early.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!redirectChannel) {
|
||||
aSucceeded = false;
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
MOZ_ASSERT(registrar);
|
||||
|
||||
nsCOMPtr<nsIParentChannel> redirectChannel;
|
||||
nsresult rv = registrar->GetParentChannel(mRedirectChannelId,
|
||||
getter_AddRefs(redirectChannel));
|
||||
if (NS_FAILED(rv) || !redirectChannel) {
|
||||
// Redirect might get canceled before we got AsyncOnChannelRedirect
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
rv = registrar->GetRegisteredChannel(mRedirectChannelId,
|
||||
getter_AddRefs(newChannel));
|
||||
MOZ_ASSERT(newChannel, "Already registered channel not found");
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
newChannel->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
if (!redirectChannel) {
|
||||
aSucceeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Release all previously registered channels, they are no longer needed to
|
||||
// be kept in the registrar from this moment.
|
||||
registrar->DeregisterChannels(mRedirectChannelId);
|
||||
mRedirectChannelId = 0;
|
||||
if (!aSucceeded) {
|
||||
if (redirectChannel) {
|
||||
redirectChannel->Delete();
|
||||
|
@ -656,36 +658,85 @@ void DocumentLoadListener::FinishReplacementChannelSetup(bool aSucceeded) {
|
|||
!SameCOMIdentity(redirectChannel, static_cast<nsIParentChannel*>(this)));
|
||||
|
||||
Delete();
|
||||
if (!mIsFinished) {
|
||||
mParentChannelListener->SetListenerAfterRedirect(redirectChannel);
|
||||
}
|
||||
redirectChannel->SetParentListener(mParentChannelListener);
|
||||
|
||||
ApplyPendingFunctions(redirectChannel);
|
||||
|
||||
ResumeSuspendedChannel(redirectChannel);
|
||||
}
|
||||
|
||||
void DocumentLoadListener::ApplyPendingFunctions(nsISupports* aChannel) const {
|
||||
// We stored the values from all nsIParentChannel functions called since we
|
||||
// couldn't handle them. Copy them across to the real channel since it should
|
||||
// know what to do.
|
||||
for (auto& variant : mIParentChannelFunctions) {
|
||||
variant.match(
|
||||
[redirectChannel](const nsIHttpChannel::FlashPluginState& aState) {
|
||||
redirectChannel->NotifyFlashPluginStateChanged(aState);
|
||||
},
|
||||
[redirectChannel](const ClassifierMatchedInfoParams& aParams) {
|
||||
redirectChannel->SetClassifierMatchedInfo(
|
||||
aParams.mList, aParams.mProvider, aParams.mFullHash);
|
||||
},
|
||||
[redirectChannel](const ClassifierMatchedTrackingInfoParams& aParams) {
|
||||
redirectChannel->SetClassifierMatchedTrackingInfo(
|
||||
aParams.mLists, aParams.mFullHashes);
|
||||
},
|
||||
[redirectChannel](const ClassificationFlagsParams& aParams) {
|
||||
redirectChannel->NotifyClassificationFlags(
|
||||
aParams.mClassificationFlags, aParams.mIsThirdParty);
|
||||
});
|
||||
// couldn't handle them. Copy them across to the real channel since it
|
||||
// should know what to do.
|
||||
|
||||
nsCOMPtr<nsIParentChannel> parentChannel = do_QueryInterface(aChannel);
|
||||
if (parentChannel) {
|
||||
for (auto& variant : mIParentChannelFunctions) {
|
||||
variant.match(
|
||||
[parentChannel](const nsIHttpChannel::FlashPluginState& aState) {
|
||||
parentChannel->NotifyFlashPluginStateChanged(aState);
|
||||
},
|
||||
[parentChannel](const ClassifierMatchedInfoParams& aParams) {
|
||||
parentChannel->SetClassifierMatchedInfo(
|
||||
aParams.mList, aParams.mProvider, aParams.mFullHash);
|
||||
},
|
||||
[parentChannel](const ClassifierMatchedTrackingInfoParams& aParams) {
|
||||
parentChannel->SetClassifierMatchedTrackingInfo(
|
||||
aParams.mLists, aParams.mFullHashes);
|
||||
},
|
||||
[parentChannel](const ClassificationFlagsParams& aParams) {
|
||||
parentChannel->NotifyClassificationFlags(
|
||||
aParams.mClassificationFlags, aParams.mIsThirdParty);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (auto& variant : mIParentChannelFunctions) {
|
||||
variant.match(
|
||||
[&](const nsIHttpChannel::FlashPluginState& aState) {
|
||||
// For now, only HttpChannel use this attribute.
|
||||
RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(aChannel);
|
||||
if (httpChannel) {
|
||||
httpChannel->SetFlashPluginState(aState);
|
||||
}
|
||||
},
|
||||
[&](const ClassifierMatchedInfoParams& aParams) {
|
||||
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (classifiedChannel) {
|
||||
classifiedChannel->SetMatchedInfo(
|
||||
aParams.mList, aParams.mProvider, aParams.mFullHash);
|
||||
}
|
||||
},
|
||||
[&](const ClassifierMatchedTrackingInfoParams& aParams) {
|
||||
nsCOMPtr<nsIClassifiedChannel> classifiedChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (classifiedChannel) {
|
||||
nsTArray<nsCString> lists, fullhashes;
|
||||
for (const nsACString& token : aParams.mLists.Split(',')) {
|
||||
lists.AppendElement(token);
|
||||
}
|
||||
for (const nsACString& token : aParams.mFullHashes.Split(',')) {
|
||||
fullhashes.AppendElement(token);
|
||||
}
|
||||
classifiedChannel->SetMatchedTrackingInfo(lists, fullhashes);
|
||||
}
|
||||
},
|
||||
[&](const ClassificationFlagsParams& aParams) {
|
||||
UrlClassifierCommon::SetClassificationFlagsHelper(
|
||||
static_cast<nsIChannel*>(aChannel),
|
||||
aParams.mClassificationFlags, aParams.mIsThirdParty);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<HttpChannelParent> httpParent = do_QueryObject(redirectChannel);
|
||||
if (httpParent) {
|
||||
RefPtr<HttpChannelSecurityWarningReporter> reporter = httpParent;
|
||||
RefPtr<HttpChannelSecurityWarningReporter> reporter;
|
||||
if (RefPtr<HttpChannelParent> httpParent = do_QueryObject(aChannel)) {
|
||||
reporter = httpParent;
|
||||
} else if (RefPtr<nsHttpChannel> httpChannel = do_QueryObject(aChannel)) {
|
||||
reporter = httpChannel->GetWarningReporter();
|
||||
}
|
||||
if (reporter) {
|
||||
for (auto& variant : mSecurityWarningFunctions) {
|
||||
variant.match(
|
||||
[reporter](const ReportSecurityMessageParams& aParams) {
|
||||
|
@ -703,11 +754,9 @@ void DocumentLoadListener::FinishReplacementChannelSetup(bool aSucceeded) {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
ResumeSuspendedChannel(redirectChannel);
|
||||
}
|
||||
|
||||
void DocumentLoadListener::ResumeSuspendedChannel(
|
||||
bool DocumentLoadListener::ResumeSuspendedChannel(
|
||||
nsIStreamListener* aListener) {
|
||||
LOG(("DocumentLoadListener ResumeSuspendedChannel [this=%p]", this));
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel);
|
||||
|
@ -715,11 +764,18 @@ void DocumentLoadListener::ResumeSuspendedChannel(
|
|||
httpChannel->SetApplyConversion(mOldApplyConversion);
|
||||
}
|
||||
|
||||
if (!mIsFinished) {
|
||||
mParentChannelListener->SetListenerAfterRedirect(aListener);
|
||||
}
|
||||
|
||||
// If we failed to suspend the channel, then we might have received
|
||||
// some messages while the redirected was being handled.
|
||||
// Manually send them on now.
|
||||
nsTArray<StreamListenerFunction> streamListenerFunctions =
|
||||
std::move(mStreamListenerFunctions);
|
||||
if (!aListener) {
|
||||
streamListenerFunctions.Clear();
|
||||
}
|
||||
nsresult rv = NS_OK;
|
||||
for (auto& variant : streamListenerFunctions) {
|
||||
variant.match(
|
||||
|
@ -775,6 +831,7 @@ void DocumentLoadListener::ResumeSuspendedChannel(
|
|||
"Should not have added new stream listener function!");
|
||||
|
||||
mChannel->Resume();
|
||||
return !mIsFinished;
|
||||
}
|
||||
|
||||
void DocumentLoadListener::SerializeRedirectData(
|
||||
|
@ -1089,6 +1146,15 @@ DocumentLoadListener::RedirectToRealChannel(
|
|||
MOZ_ALWAYS_SUCCEEDS(
|
||||
registrar->RegisterChannel(mChannel, &mRedirectChannelId));
|
||||
|
||||
if (aDestinationProcess || OtherPid()) {
|
||||
// Register the new channel and obtain id for it
|
||||
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
|
||||
RedirectChannelRegistrar::GetOrCreate();
|
||||
MOZ_ASSERT(registrar);
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
registrar->RegisterChannel(mChannel, &mRedirectChannelId));
|
||||
}
|
||||
|
||||
if (aDestinationProcess) {
|
||||
dom::ContentParent* cp =
|
||||
dom::ContentProcessManager::GetSingleton()->GetContentProcessById(
|
||||
|
@ -1426,16 +1492,13 @@ NS_IMETHODIMP
|
|||
DocumentLoadListener::AsyncOnChannelRedirect(
|
||||
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
|
||||
nsIAsyncVerifyRedirectCallback* aCallback) {
|
||||
LOG(("DocumentLoadListener AsyncOnChannelRedirect [this=%p, aFlags=%" PRIx32
|
||||
"]",
|
||||
this, aFlags));
|
||||
// We generally don't want to notify the content process about redirects,
|
||||
// so just update our channel and tell the callback that we're good to go.
|
||||
mChannel = aNewChannel;
|
||||
|
||||
// We need the original URI of the current channel to use to open the real
|
||||
// channel in the content process. Unfortunately we overwrite the original
|
||||
// uri of the new channel with the original pre-redirect URI, so grab
|
||||
// a copy of it now.
|
||||
aNewChannel->GetOriginalURI(getter_AddRefs(mChannelCreationURI));
|
||||
|
||||
// Since we're redirecting away from aOldChannel, we should check if it
|
||||
// had a COOP mismatch, since we want the final result for this to
|
||||
// include the state of all channels we redirected through.
|
||||
|
@ -1448,6 +1511,10 @@ DocumentLoadListener::AsyncOnChannelRedirect(
|
|||
// We don't need to confirm internal redirects or record any
|
||||
// history for them, so just immediately verify and return.
|
||||
if (aFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
|
||||
LOG(
|
||||
("DocumentLoadListener AsyncOnChannelRedirect [this=%p] "
|
||||
"flags=REDIRECT_INTERNAL",
|
||||
this));
|
||||
aCallback->OnRedirectVerifyCallback(NS_OK);
|
||||
return NS_OK;
|
||||
} else {
|
||||
|
@ -1460,11 +1527,21 @@ DocumentLoadListener::AsyncOnChannelRedirect(
|
|||
mRedirects.AppendElement(DocumentChannelRedirect{
|
||||
oldURI, aFlags, responseStatus, net::ChannelIsPost(aOldChannel)});
|
||||
}
|
||||
LOG(
|
||||
("DocumentLoadListener AsyncOnChannelRedirect [this=%p] "
|
||||
"mRedirects=%" PRIx32,
|
||||
this, uint32_t(mRedirects.Length())));
|
||||
|
||||
if (!mDocumentChannelBridge) {
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
|
||||
// We need the original URI of the current channel to use to open the real
|
||||
// channel in the content process. Unfortunately we overwrite the original
|
||||
// uri of the new channel with the original pre-redirect URI, so grab
|
||||
// a copy of it now.
|
||||
aNewChannel->GetOriginalURI(getter_AddRefs(mChannelCreationURI));
|
||||
|
||||
// Clear out our nsIParentChannel functions, since a normal parent
|
||||
// channel would actually redirect and not have those values on the new one.
|
||||
// We expect the URI classifier to run on the redirected channel with
|
||||
|
@ -1535,14 +1612,14 @@ DocumentLoadListener::AsyncOnChannelRedirect(
|
|||
|
||||
// This method returns the cached result of running the Cross-Origin-Opener
|
||||
// policy compare algorithm by calling ComputeCrossOriginOpenerPolicyMismatch
|
||||
bool DocumentLoadListener::HasCrossOriginOpenerPolicyMismatch() {
|
||||
bool DocumentLoadListener::HasCrossOriginOpenerPolicyMismatch() const {
|
||||
// If we found a COOP mismatch on an earlier channel and then
|
||||
// redirected away from that, we should use that result.
|
||||
if (mHasCrossOriginOpenerPolicyMismatch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel);
|
||||
RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel.get());
|
||||
if (!httpChannel) {
|
||||
// Not an nsHttpChannel assume it's okay to switch.
|
||||
return false;
|
||||
|
|
|
@ -114,12 +114,15 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
// This helper resumes the underlying channel again, and manually
|
||||
// forwards any nsIStreamListener messages that arrived while we
|
||||
// were suspended (which might have failed).
|
||||
void ResumeSuspendedChannel(nsIStreamListener* aListener);
|
||||
// Returns true if the channel was finished before we could resume it.
|
||||
bool ResumeSuspendedChannel(nsIStreamListener* aListener);
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOCUMENT_LOAD_LISTENER_IID)
|
||||
|
||||
void Cancel(const nsresult& status);
|
||||
|
||||
nsIChannel* GetChannel() const { return mChannel; }
|
||||
|
||||
nsresult ReportSecurityMessage(const nsAString& aMessageTag,
|
||||
const nsAString& aMessageCategory) override {
|
||||
ReportSecurityMessageParams params;
|
||||
|
@ -221,7 +224,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
dom::CanonicalBrowsingContext* aBrowsingContext,
|
||||
nsDocShellLoadState* aLoadState, uint64_t aOuterWindowId);
|
||||
|
||||
bool HasCrossOriginOpenerPolicyMismatch();
|
||||
bool HasCrossOriginOpenerPolicyMismatch() const;
|
||||
void ApplyPendingFunctions(nsISupports* aChannel) const;
|
||||
|
||||
// This defines a variant that describes all the attribute setters (and their
|
||||
// parameters) from nsIParentChannel
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ParentProcessDocumentChannel.h"
|
||||
|
||||
extern mozilla::LazyLogModule gDocumentChannelLog;
|
||||
#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(ParentProcessDocumentChannel, DocumentChannel,
|
||||
nsIAsyncVerifyRedirectCallback)
|
||||
|
||||
ParentProcessDocumentChannel::ParentProcessDocumentChannel(
|
||||
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
nsLoadFlags aLoadFlags, uint32_t aCacheKey)
|
||||
: DocumentChannel(aLoadState, aLoadInfo, aLoadFlags, aCacheKey) {
|
||||
LOG(("ParentProcessDocumentChannel ctor [this=%p]", this));
|
||||
}
|
||||
|
||||
ParentProcessDocumentChannel::~ParentProcessDocumentChannel() {
|
||||
LOG(("ParentProcessDocumentChannel dtor [this=%p]", this));
|
||||
}
|
||||
|
||||
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||
ParentProcessDocumentChannel::RedirectToRealChannel(
|
||||
nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>>&&
|
||||
aStreamFilterEndpoints,
|
||||
uint32_t aRedirectFlags, uint32_t aLoadFlags) {
|
||||
LOG(("ParentProcessDocumentChannel RedirectToRealChannel [this=%p]", this));
|
||||
nsCOMPtr<nsIChannel> channel = mDocumentLoadListener->GetChannel();
|
||||
channel->SetLoadFlags(aLoadFlags);
|
||||
channel->SetNotificationCallbacks(mCallbacks);
|
||||
|
||||
if (mLoadGroup) {
|
||||
channel->SetLoadGroup(mLoadGroup);
|
||||
}
|
||||
|
||||
mLastVisitInfo = mDocumentLoadListener->LastVisitInfo();
|
||||
mRedirects = mDocumentLoadListener->Redirects();
|
||||
mStreamFilterEndpoints = std::move(aStreamFilterEndpoints);
|
||||
|
||||
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise> p =
|
||||
mPromise.Ensure(__func__);
|
||||
|
||||
nsresult rv =
|
||||
gHttpHandler->AsyncOnChannelRedirect(this, channel, aRedirectFlags);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnRedirectVerifyCallback(rv);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ParentProcessDocumentChannel::OnRedirectVerifyCallback(nsresult aResult) {
|
||||
LOG(
|
||||
("ParentProcessDocumentChannel OnRedirectVerifyCallback [this=%p "
|
||||
"aResult=%d]",
|
||||
this, int(aResult)));
|
||||
MOZ_ASSERT(mDocumentLoadListener);
|
||||
|
||||
if (NS_FAILED(aResult)) {
|
||||
Cancel(aResult);
|
||||
} else if (mCanceled && NS_SUCCEEDED(aResult)) {
|
||||
aResult = NS_BINDING_ABORTED;
|
||||
} else {
|
||||
const nsCOMPtr<nsIChannel> channel = mDocumentLoadListener->GetChannel();
|
||||
mLoadGroup->AddRequest(channel, nullptr);
|
||||
// Adding the channel to the loadgroup could have triggered a status
|
||||
// change with an observer being called destroying the docShell, resulting
|
||||
// in the PPDC to be canceled.
|
||||
if (!mCanceled) {
|
||||
mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_REDIRECTED);
|
||||
for (auto& endpoint : mStreamFilterEndpoints) {
|
||||
extensions::StreamFilterParent::Attach(channel, std::move(endpoint));
|
||||
}
|
||||
if (!mDocumentLoadListener->ResumeSuspendedChannel(mListener)) {
|
||||
// We added ourselves to the load group, but attempting
|
||||
// to resume has notified us that the channel is already
|
||||
// finished. Better remove ourselves from the loadgroup
|
||||
// again.
|
||||
nsresult status = NS_OK;
|
||||
channel->GetStatus(&status);
|
||||
mLoadGroup->RemoveRequest(channel, nullptr, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLoadGroup = nullptr;
|
||||
mListener = nullptr;
|
||||
mCallbacks = nullptr;
|
||||
mDocumentLoadListener->DocumentChannelBridgeDisconnected();
|
||||
mDocumentLoadListener = nullptr;
|
||||
|
||||
mPromise.ResolveIfExists(aResult, __func__);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen(
|
||||
nsIStreamListener* aListener) {
|
||||
LOG(("ParentProcessDocumentChannel AsyncOpen [this=%p]", this));
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(this, loadContext);
|
||||
|
||||
mDocumentLoadListener = new DocumentLoadListener(
|
||||
GetDocShell()->GetBrowsingContext()->Canonical(), loadContext, this);
|
||||
LOG(("Created PPDocumentChannel with listener=%p",
|
||||
mDocumentLoadListener.get()));
|
||||
|
||||
gHttpHandler->OnOpeningDocumentRequest(this);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
Maybe<dom::ClientInfo> initialClientInfo = mInitialClientInfo;
|
||||
if (!mDocumentLoadListener->Open(
|
||||
mLoadState, mLoadFlags, mCacheKey, mChannelId, mAsyncOpenTime,
|
||||
mTiming, std::move(initialClientInfo), mLoadInfo->GetOuterWindowID(),
|
||||
GetDocShell()
|
||||
->GetBrowsingContext()
|
||||
->HasValidTransientUserGestureActivation(),
|
||||
&rv)) {
|
||||
MOZ_ASSERT(NS_FAILED(rv));
|
||||
mDocumentLoadListener->DocumentChannelBridgeDisconnected();
|
||||
mDocumentLoadListener = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
mListener = aListener;
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->AddRequest(this, nullptr);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP ParentProcessDocumentChannel::Cancel(nsresult aStatus) {
|
||||
LOG(("ParentProcessDocumentChannel Cancel [this=%p]", this));
|
||||
if (mCanceled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCanceled = true;
|
||||
mDocumentLoadListener->Cancel(aStatus);
|
||||
|
||||
ShutdownListeners(aStatus);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#undef LOG
|
|
@ -0,0 +1,62 @@
|
|||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_ParentProcessDocumentChannel_h
|
||||
#define mozilla_net_ParentProcessDocumentChannel_h
|
||||
|
||||
#include "ProtocolUtils.h"
|
||||
#include "mozilla/net/ADocumentChannelBridge.h"
|
||||
#include "mozilla/net/DocumentChannel.h"
|
||||
#include "mozilla/net/DocumentLoadListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class ParentProcessDocumentChannel : public DocumentChannel,
|
||||
public nsIAsyncVerifyRedirectCallback,
|
||||
public ADocumentChannelBridge {
|
||||
public:
|
||||
ParentProcessDocumentChannel(nsDocShellLoadState* aLoadState,
|
||||
class LoadInfo* aLoadInfo,
|
||||
nsLoadFlags aLoadFlags, uint32_t aCacheKey);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
|
||||
|
||||
NS_IMETHOD AsyncOpen(nsIStreamListener* aListener) override;
|
||||
NS_IMETHOD Cancel(nsresult aStatusCode) override;
|
||||
|
||||
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||
RedirectToRealChannel(
|
||||
nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>>&&
|
||||
aStreamFilterEndpoints,
|
||||
uint32_t aRedirectFlags, uint32_t aLoadFlags) override;
|
||||
|
||||
void DisconnectChildListeners(nsresult aStatus,
|
||||
nsresult aLoadGroupStatus) override {
|
||||
DocumentChannel::DisconnectChildListeners(aStatus, aLoadGroupStatus);
|
||||
mDocumentLoadListener = nullptr;
|
||||
}
|
||||
void Delete() override {}
|
||||
void DeleteIPDL() override {
|
||||
mPromise.ResolveIfExists(NS_BINDING_ABORTED, __func__);
|
||||
}
|
||||
base::ProcessId OtherPid() const override { return 0; }
|
||||
|
||||
private:
|
||||
virtual ~ParentProcessDocumentChannel();
|
||||
|
||||
RefPtr<DocumentLoadListener> mDocumentLoadListener;
|
||||
nsTArray<ipc::Endpoint<extensions::PStreamFilterParent>>
|
||||
mStreamFilterEndpoints;
|
||||
MozPromiseHolder<PDocumentChannelParent::RedirectToRealChannelPromise>
|
||||
mPromise;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_ParentProcessDocumentChannel_h
|
|
@ -18,6 +18,7 @@ EXPORTS.mozilla.net += [
|
|||
'NeckoMessageUtils.h',
|
||||
'NeckoParent.h',
|
||||
'NeckoTargetHolder.h',
|
||||
'ParentProcessDocumentChannel.h',
|
||||
'SocketProcessBridgeChild.h',
|
||||
'SocketProcessBridgeParent.h',
|
||||
'SocketProcessChild.h',
|
||||
|
@ -38,6 +39,7 @@ UNIFIED_SOURCES += [
|
|||
'NeckoCommon.cpp',
|
||||
'NeckoParent.cpp',
|
||||
'NeckoTargetHolder.cpp',
|
||||
'ParentProcessDocumentChannel.cpp',
|
||||
'SocketProcessBridgeChild.cpp',
|
||||
'SocketProcessBridgeParent.cpp',
|
||||
'SocketProcessChild.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче