зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1574372 - Add parent-process version of nsDocumentOpenInfo, and use it in DocumentLoadListener. r=bzbarsky
Differential Revision: https://phabricator.services.mozilla.com/D56137 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
3f6ef264a3
Коммит
898cc13c90
|
@ -10244,6 +10244,15 @@ nsresult nsDocShell::OpenInitializedChannel(nsIChannel* aChannel,
|
|||
// Let the client channel helper know if we are using DocumentChannel,
|
||||
// since redirects get handled in the parent process in that case.
|
||||
RefPtr<net::DocumentChannelChild> docChannel = do_QueryObject(aChannel);
|
||||
if (docChannel) {
|
||||
bool pluginsAllowed = true;
|
||||
GetAllowPlugins(&pluginsAllowed);
|
||||
docChannel->SetDocumentOpenFlags(aOpenFlags, pluginsAllowed);
|
||||
// Now that we've sent the real flags across to be run on the parent,
|
||||
// tell the content process nsDocumentOpenInfo to not try to do
|
||||
// any sort of targeting.
|
||||
aOpenFlags |= nsIURILoader::DONT_RETARGET;
|
||||
}
|
||||
|
||||
// Since we are loading a document we need to make sure the proper reserved
|
||||
// and initial client data is stored on the nsILoadInfo. The
|
||||
|
|
|
@ -26,7 +26,13 @@ class ADocumentChannelBridge {
|
|||
// process).
|
||||
// This should remove the nsIChannel from the loadgroup, and
|
||||
// fire OnStart/StopRequest with aStatus.
|
||||
virtual void DisconnectChildListeners(nsresult aStatus) = 0;
|
||||
// aLoadGroupStatus is used as mStatus when we remove the child channel
|
||||
// from the loadgroup (but aStatus is passed as the parameter to
|
||||
// RemoveRequest).
|
||||
// We do this so we can remove using NS_BINDING_RETARGETED, but still have
|
||||
// the channel not be in an error state.
|
||||
virtual void DisconnectChildListeners(nsresult aStatus,
|
||||
nsresult aLoadGroupStatus) = 0;
|
||||
|
||||
// Delete the bridge, and drop any refs to the DocumentLoadListener
|
||||
virtual void Delete() = 0;
|
||||
|
|
|
@ -190,6 +190,8 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
|
|||
args.hasNonEmptySandboxingFlags() = mHasNonEmptySandboxingFlags;
|
||||
args.channelId() = mChannelId;
|
||||
args.asyncOpenTime() = mAsyncOpenTime;
|
||||
args.documentOpenFlags() = mDocumentOpenFlags;
|
||||
args.pluginsAllowed() = mPluginsAllowed;
|
||||
|
||||
nsDocShell* docshell = GetDocShell();
|
||||
if (docshell) {
|
||||
|
@ -201,7 +203,7 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
|
|||
NS_GET_TEMPLATE_IID(nsIBrowserChild),
|
||||
getter_AddRefs(iBrowserChild));
|
||||
BrowserChild* browserChild = static_cast<BrowserChild*>(iBrowserChild.get());
|
||||
if (MissingRequiredBrowserChild(browserChild, "ftp")) {
|
||||
if (MissingRequiredBrowserChild(browserChild, "documentchannel")) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
|
@ -270,8 +272,9 @@ void DocumentChannelChild::ShutdownListeners(nsresult aStatusCode) {
|
|||
}
|
||||
|
||||
IPCResult DocumentChannelChild::RecvDisconnectChildListeners(
|
||||
const nsresult& aStatus) {
|
||||
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.
|
||||
|
|
|
@ -46,7 +46,8 @@ class DocumentChannelChild final : public nsIIdentChannel,
|
|||
|
||||
mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& aStatusCode);
|
||||
|
||||
mozilla::ipc::IPCResult RecvDisconnectChildListeners(const nsresult& aStatus);
|
||||
mozilla::ipc::IPCResult RecvDisconnectChildListeners(
|
||||
const nsresult& aStatus, const nsresult& aLoadGroupStatus);
|
||||
|
||||
mozilla::ipc::IPCResult RecvDeleteSelf();
|
||||
|
||||
|
@ -70,6 +71,11 @@ class DocumentChannelChild final : public nsIIdentChannel,
|
|||
*aChannelRedirectFlags = mLastVisitInfo.previousFlags();
|
||||
}
|
||||
|
||||
void SetDocumentOpenFlags(uint32_t aFlags, bool aPluginsAllowed) {
|
||||
mDocumentOpenFlags = Some(aFlags);
|
||||
mPluginsAllowed = aPluginsAllowed;
|
||||
}
|
||||
|
||||
private:
|
||||
void ShutdownListeners(nsresult aStatusCode);
|
||||
nsDocShell* GetDocShell();
|
||||
|
@ -93,6 +99,7 @@ class DocumentChannelChild final : public nsIIdentChannel,
|
|||
|
||||
nsresult mStatus = NS_OK;
|
||||
bool mCanceled = false;
|
||||
Maybe<uint32_t> mDocumentOpenFlags;
|
||||
bool mIsPending = false;
|
||||
bool mWasOpened = false;
|
||||
uint64_t mChannelId;
|
||||
|
@ -103,6 +110,7 @@ class DocumentChannelChild final : public nsIIdentChannel,
|
|||
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
bool mPluginsAllowed = false;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DocumentChannelChild, DOCUMENT_CHANNEL_CHILD_IID)
|
||||
|
|
|
@ -13,19 +13,20 @@ extern mozilla::LazyLogModule gDocumentChannelLog;
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
DocumentChannelParent::DocumentChannelParent(
|
||||
const dom::PBrowserOrId& aIframeEmbedding, nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus) {
|
||||
DocumentChannelParent::DocumentChannelParent(BrowserParent* aBrowser,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus) {
|
||||
LOG(("DocumentChannelParent ctor [this=%p]", this));
|
||||
mParent = new DocumentLoadListener(aIframeEmbedding, aLoadContext,
|
||||
aOverrideStatus, this);
|
||||
mParent =
|
||||
new DocumentLoadListener(aBrowser, aLoadContext, aOverrideStatus, this);
|
||||
}
|
||||
|
||||
DocumentChannelParent::~DocumentChannelParent() {
|
||||
LOG(("DocumentChannelParent dtor [this=%p]", this));
|
||||
}
|
||||
|
||||
bool DocumentChannelParent::Init(const DocumentChannelCreationArgs& aArgs) {
|
||||
bool DocumentChannelParent::Init(BrowserParent* aBrowser,
|
||||
const DocumentChannelCreationArgs& aArgs) {
|
||||
RefPtr<nsDocShellLoadState> loadState =
|
||||
new nsDocShellLoadState(aArgs.loadState());
|
||||
LOG(("DocumentChannelParent Init [this=%p, uri=%s]", this,
|
||||
|
@ -37,13 +38,14 @@ bool DocumentChannelParent::Init(const DocumentChannelCreationArgs& aArgs) {
|
|||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
if (!mParent->Open(loadState, loadInfo, aArgs.initiatorType().ptrOr(nullptr),
|
||||
aArgs.loadFlags(), aArgs.loadType(), aArgs.cacheKey(),
|
||||
aArgs.isActive(), aArgs.isTopLevelDoc(),
|
||||
aArgs.hasNonEmptySandboxingFlags(), aArgs.topWindowURI(),
|
||||
aArgs.contentBlockingAllowListPrincipal(),
|
||||
aArgs.customUserAgent(), aArgs.channelId(),
|
||||
aArgs.asyncOpenTime(), &rv)) {
|
||||
if (!mParent->Open(
|
||||
aBrowser, loadState, loadInfo, aArgs.initiatorType().ptrOr(nullptr),
|
||||
aArgs.loadFlags(), aArgs.loadType(), aArgs.cacheKey(),
|
||||
aArgs.isActive(), aArgs.isTopLevelDoc(),
|
||||
aArgs.hasNonEmptySandboxingFlags(), aArgs.topWindowURI(),
|
||||
aArgs.contentBlockingAllowListPrincipal(), aArgs.customUserAgent(),
|
||||
aArgs.channelId(), aArgs.asyncOpenTime(), aArgs.documentOpenFlags(),
|
||||
aArgs.pluginsAllowed(), &rv)) {
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,12 @@ class DocumentChannelParent final : public ADocumentChannelBridge,
|
|||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(DocumentChannelParent, override);
|
||||
|
||||
explicit DocumentChannelParent(const dom::PBrowserOrId& aIframeEmbedding,
|
||||
explicit DocumentChannelParent(dom::BrowserParent* aBrowser,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus);
|
||||
|
||||
bool Init(const DocumentChannelCreationArgs& aArgs);
|
||||
bool Init(dom::BrowserParent* aBrowser,
|
||||
const DocumentChannelCreationArgs& aArgs);
|
||||
|
||||
// PDocumentChannelParent
|
||||
bool RecvCancel(const nsresult& aStatus) {
|
||||
|
@ -41,9 +42,10 @@ class DocumentChannelParent final : public ADocumentChannelBridge,
|
|||
|
||||
private:
|
||||
// DocumentChannelListener
|
||||
void DisconnectChildListeners(nsresult aStatus) override {
|
||||
void DisconnectChildListeners(nsresult aStatus,
|
||||
nsresult aLoadGroupStatus) override {
|
||||
if (CanSend()) {
|
||||
Unused << SendDisconnectChildListeners(aStatus);
|
||||
Unused << SendDisconnectChildListeners(aStatus, aLoadGroupStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/MozPromiseInlines.h" // For MozPromise::FromDomPromise
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
||||
#include "mozilla/dom/ClientChannelHelper.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentProcessManager.h"
|
||||
|
@ -25,6 +26,13 @@
|
|||
#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"
|
||||
|
||||
mozilla::LazyLogModule gDocumentChannelLog("DocumentChannel");
|
||||
#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
|
||||
|
@ -34,6 +42,179 @@ using namespace mozilla::dom;
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
/**
|
||||
* An extension to nsDocumentOpenInfo that we run in the parent process, so
|
||||
* that we can make the decision to retarget to content handlers or the external
|
||||
* helper app, before we make process switching decisions.
|
||||
*
|
||||
* This modifies the behaviour of nsDocumentOpenInfo so that it can do
|
||||
* retargeting, but doesn't do stream conversion (but confirms that we will be
|
||||
* able to do so later).
|
||||
*
|
||||
* We still run nsDocumentOpenInfo in the content process, but disable
|
||||
* retargeting, so that it can only apply stream conversion, and then send data
|
||||
* to the docshell.
|
||||
*/
|
||||
class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
|
||||
public nsIMultiPartChannelListener {
|
||||
public:
|
||||
ParentProcessDocumentOpenInfo(ParentChannelListener* aListener,
|
||||
bool aPluginsAllowed, uint32_t aFlags,
|
||||
mozilla::dom::BrowsingContext* aBrowsingContext)
|
||||
: nsDocumentOpenInfo(aFlags, false),
|
||||
mBrowsingContext(aBrowsingContext),
|
||||
mListener(aListener),
|
||||
mPluginsAllowed(aPluginsAllowed) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// The default content listener is always a docshell, so this manually
|
||||
// implements the same checks, and if it succeeds, uses the parent
|
||||
// channel listener so that we forward onto DocumentLoadListener.
|
||||
bool TryDefaultContentListener(nsIChannel* aChannel,
|
||||
const nsCString& aContentType) {
|
||||
uint32_t canHandle =
|
||||
nsWebNavigationInfo::IsTypeSupported(aContentType, mPluginsAllowed);
|
||||
if (canHandle != nsIWebNavigationInfo::UNSUPPORTED) {
|
||||
m_targetStreamListener = mListener;
|
||||
nsLoadFlags loadFlags = 0;
|
||||
aChannel->GetLoadFlags(&loadFlags);
|
||||
aChannel->SetLoadFlags(loadFlags | nsIChannel::LOAD_TARGETED);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryDefaultContentListener(nsIChannel* aChannel) override {
|
||||
return TryDefaultContentListener(aChannel, mContentType);
|
||||
}
|
||||
|
||||
// Generally we only support stream converters that can tell
|
||||
// use exactly what type they'll output. If we find one, then
|
||||
// we just target to our default listener directly (without
|
||||
// conversion), and the content process nsDocumentOpenInfo will
|
||||
// run and do the actual conversion.
|
||||
bool TryStreamConversion(nsIChannel* aChannel) override {
|
||||
// The one exception is nsUnknownDecoder, which works in the parent
|
||||
// (and we need to know what the content type is before we can
|
||||
// decide if it will be handled in the parent), so we run that here.
|
||||
if (mContentType.LowerCaseEqualsASCII(UNKNOWN_CONTENT_TYPE)) {
|
||||
return nsDocumentOpenInfo::TryStreamConversion(aChannel);
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStreamConverterService> streamConvService =
|
||||
do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
|
||||
nsAutoCString str;
|
||||
if (NS_SUCCEEDED(streamConvService->ConvertedType(mContentType, str))) {
|
||||
// We only support passing data to the default content listener
|
||||
// (docshell), and we don't supported chaining converters.
|
||||
if (TryDefaultContentListener(aChannel, str)) {
|
||||
mContentType = str;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryExternalHelperApp(nsIExternalHelperAppService* aHelperAppService,
|
||||
nsIChannel* aChannel) override {
|
||||
RefPtr<nsExternalAppHandler> handler;
|
||||
nsresult rv = aHelperAppService->CreateListener(
|
||||
mContentType, aChannel, mBrowsingContext, false, nullptr,
|
||||
getter_AddRefs(handler));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
m_targetStreamListener = handler;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDocumentOpenInfo* Clone() override {
|
||||
mCloned = true;
|
||||
return new ParentProcessDocumentOpenInfo(mListener, mPluginsAllowed, mFlags,
|
||||
mBrowsingContext);
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIRequest* request) override {
|
||||
nsCOMPtr<nsIMultiPartChannel> multiPartChannel = do_QueryInterface(request);
|
||||
if (multiPartChannel) {
|
||||
mExpectingOnAfterLastPart = true;
|
||||
}
|
||||
|
||||
nsresult rv = nsDocumentOpenInfo::OnStartRequest(request);
|
||||
|
||||
// If we didn't find a content handler,
|
||||
// and we don't have a listener, then just forward to our
|
||||
// default listener. This happens when the channel is in
|
||||
// an error state, and we want to just forward that on to be
|
||||
// handled in the content process.
|
||||
if (!mUsedContentHandler && !m_targetStreamListener) {
|
||||
m_targetStreamListener = mListener;
|
||||
return m_targetStreamListener->OnStartRequest(request);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIRequest* request, nsresult aStatus) override {
|
||||
// If we're not a multipart stream (and thus not expecting OnAfterLastPart),
|
||||
// then this is the final OnStopRequest we'll get. If we haven't been
|
||||
// targeting our default listener, then we need to manually notify it that
|
||||
// we're done, and nothing further will be arriving. If we got cloned, then
|
||||
// we don't need to do this, as only the last link needs to do it.
|
||||
bool needToNotifyListener = false;
|
||||
if (!mExpectingOnAfterLastPart && m_targetStreamListener != mListener &&
|
||||
!mCloned) {
|
||||
needToNotifyListener = true;
|
||||
}
|
||||
|
||||
nsresult rv = nsDocumentOpenInfo::OnStopRequest(request, aStatus);
|
||||
|
||||
if (needToNotifyListener) {
|
||||
// Tell the DocumentLoadListener to notify the content process that it's
|
||||
// been entirely retargeted, and to stop waiting.
|
||||
// Clear mListener's pointer to the DocumentLoadListener to break the
|
||||
// reference cycle.
|
||||
RefPtr<DocumentLoadListener> doc = do_GetInterface(ToSupports(mListener));
|
||||
MOZ_ASSERT(doc);
|
||||
doc->DisconnectChildListeners(NS_BINDING_RETARGETED, NS_OK);
|
||||
mListener->SetListenerAfterRedirect(nullptr);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnAfterLastPart(nsresult aStatus) override {
|
||||
mListener->OnAfterLastPart(aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~ParentProcessDocumentOpenInfo() = default;
|
||||
|
||||
RefPtr<mozilla::dom::BrowsingContext> mBrowsingContext;
|
||||
RefPtr<ParentChannelListener> mListener;
|
||||
bool mPluginsAllowed;
|
||||
|
||||
/**
|
||||
* Set to true if we got OnStartRequest called with a multipart
|
||||
* channel, and thus expect OnAfterLastPart to be called when
|
||||
* the channel is complete.
|
||||
*/
|
||||
bool mExpectingOnAfterLastPart = false;
|
||||
|
||||
/**
|
||||
* Set to true if we got cloned to create a chained listener.
|
||||
*/
|
||||
bool mCloned = false;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ParentProcessDocumentOpenInfo, nsDocumentOpenInfo)
|
||||
NS_IMPL_RELEASE_INHERITED(ParentProcessDocumentOpenInfo, nsDocumentOpenInfo)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ParentProcessDocumentOpenInfo)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMultiPartChannelListener)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDocumentOpenInfo)
|
||||
|
||||
NS_IMPL_ADDREF(DocumentLoadListener)
|
||||
NS_IMPL_RELEASE(DocumentLoadListener)
|
||||
|
||||
|
@ -50,18 +231,13 @@ NS_INTERFACE_MAP_BEGIN(DocumentLoadListener)
|
|||
NS_INTERFACE_MAP_ENTRY_CONCRETE(DocumentLoadListener)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
DocumentLoadListener::DocumentLoadListener(const PBrowserOrId& aIframeEmbedding,
|
||||
DocumentLoadListener::DocumentLoadListener(BrowserParent* aBrowser,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus,
|
||||
ADocumentChannelBridge* aBridge)
|
||||
: mLoadContext(aLoadContext), mPBOverride(aOverrideStatus) {
|
||||
LOG(("DocumentLoadListener ctor [this=%p]", this));
|
||||
RefPtr<dom::BrowserParent> parent;
|
||||
if (aIframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
|
||||
parent =
|
||||
static_cast<dom::BrowserParent*>(aIframeEmbedding.get_PBrowserParent());
|
||||
}
|
||||
mParentChannelListener = new ParentChannelListener(this, parent);
|
||||
mParentChannelListener = new ParentChannelListener(this, aBrowser);
|
||||
mDocumentChannelBridge = aBridge;
|
||||
}
|
||||
|
||||
|
@ -70,13 +246,15 @@ DocumentLoadListener::~DocumentLoadListener() {
|
|||
}
|
||||
|
||||
bool DocumentLoadListener::Open(
|
||||
nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
const nsString* aInitiatorType, nsLoadFlags aLoadFlags, uint32_t aLoadType,
|
||||
uint32_t aCacheKey, bool aIsActive, bool aIsTopLevelDoc,
|
||||
bool aHasNonEmptySandboxingFlags, const Maybe<URIParams>& aTopWindowURI,
|
||||
BrowserParent* aBrowser, nsDocShellLoadState* aLoadState,
|
||||
class LoadInfo* aLoadInfo, const nsString* aInitiatorType,
|
||||
nsLoadFlags aLoadFlags, uint32_t aLoadType, uint32_t aCacheKey,
|
||||
bool aIsActive, bool aIsTopLevelDoc, bool aHasNonEmptySandboxingFlags,
|
||||
const Maybe<URIParams>& aTopWindowURI,
|
||||
const Maybe<PrincipalInfo>& aContentBlockingAllowListPrincipal,
|
||||
const nsString& aCustomUserAgent, const uint64_t& aChannelId,
|
||||
const TimeStamp& aAsyncOpenTime, nsresult* aRv) {
|
||||
const TimeStamp& aAsyncOpenTime, const Maybe<uint32_t>& aDocumentOpenFlags,
|
||||
bool aPluginsAllowed, nsresult* aRv) {
|
||||
LOG(("DocumentLoadListener Open [this=%p, uri=%s]", this,
|
||||
aLoadState->URI()->GetSpecOrDefault().get()));
|
||||
if (!nsDocShell::CreateChannelForLoadState(
|
||||
|
@ -142,7 +320,17 @@ bool DocumentLoadListener::Open(
|
|||
// across any serviceworker related data between channels as needed.
|
||||
AddClientChannelHelperInParent(mChannel, GetMainThreadSerialEventTarget());
|
||||
|
||||
*aRv = mChannel->AsyncOpen(mParentChannelListener);
|
||||
if (aDocumentOpenFlags) {
|
||||
RefPtr<ParentProcessDocumentOpenInfo> openInfo =
|
||||
new ParentProcessDocumentOpenInfo(mParentChannelListener,
|
||||
aPluginsAllowed, *aDocumentOpenFlags,
|
||||
aBrowser->GetBrowsingContext());
|
||||
openInfo->Prepare();
|
||||
|
||||
*aRv = mChannel->AsyncOpen(openInfo);
|
||||
} else {
|
||||
*aRv = mChannel->AsyncOpen(mParentChannelListener);
|
||||
}
|
||||
if (NS_FAILED(*aRv)) {
|
||||
mParentChannelListener = nullptr;
|
||||
return false;
|
||||
|
@ -230,7 +418,8 @@ void DocumentLoadListener::FinishReplacementChannelSetup(bool aSucceeded) {
|
|||
nsresult rv;
|
||||
|
||||
if (mDoingProcessSwitch && mDocumentChannelBridge) {
|
||||
mDocumentChannelBridge->DisconnectChildListeners(NS_BINDING_ABORTED);
|
||||
mDocumentChannelBridge->DisconnectChildListeners(NS_BINDING_ABORTED,
|
||||
NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIParentChannel> redirectChannel;
|
||||
|
@ -687,7 +876,7 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) {
|
|||
nsresult status = NS_OK;
|
||||
aRequest->GetStatus(&status);
|
||||
if (status == NS_ERROR_NO_CONTENT) {
|
||||
mDocumentChannelBridge->DisconnectChildListeners(NS_ERROR_NO_CONTENT);
|
||||
mDocumentChannelBridge->DisconnectChildListeners(status, status);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -779,6 +968,15 @@ DocumentLoadListener::OnDataAvailable(nsIRequest* aRequest,
|
|||
|
||||
NS_IMETHODIMP
|
||||
DocumentLoadListener::OnAfterLastPart(nsresult aStatus) {
|
||||
LOG(("DocumentLoadListener OnAfterLastPart [this=%p]", this));
|
||||
if (!mInitiatedRedirectToRealChannel) {
|
||||
// if we get here, and we haven't initiated a redirect to a real
|
||||
// channel, then it means we never got OnStartRequest (maybe a problem?)
|
||||
// and we retargeted everything.
|
||||
LOG(("DocumentLoadListener Disconnecting child"));
|
||||
DisconnectChildListeners(NS_BINDING_RETARGETED, NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
mStreamListenerFunctions.AppendElement(StreamListenerFunction{
|
||||
VariantIndex<3>{}, OnAfterLastPartParams{aStatus}});
|
||||
mIsFinished = true;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/net/PDocumentChannelParent.h"
|
||||
#include "mozilla/net/ParentChannelListener.h"
|
||||
#include "mozilla/net/ADocumentChannelBridge.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIParentChannel.h"
|
||||
|
@ -59,20 +60,26 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
public nsIProcessSwitchRequestor,
|
||||
public nsIMultiPartChannelListener {
|
||||
public:
|
||||
explicit DocumentLoadListener(const dom::PBrowserOrId& aIframeEmbedding,
|
||||
explicit DocumentLoadListener(dom::BrowserParent* aBrowser,
|
||||
nsILoadContext* aLoadContext,
|
||||
PBOverrideStatus aOverrideStatus,
|
||||
ADocumentChannelBridge* aBridge);
|
||||
|
||||
// Creates the channel, and then calls AsyncOpen on it.
|
||||
bool Open(nsDocShellLoadState* aLoadState, class LoadInfo* aLoadInfo,
|
||||
const nsString* aInitiatorType, nsLoadFlags aLoadFlags,
|
||||
uint32_t aLoadType, uint32_t aCacheKey, bool aIsActive,
|
||||
bool aIsTopLevelDoc, bool aHasNonEmptySandboxingFlags,
|
||||
// Must be the same BrowserParent as was passed to the constructor, we
|
||||
// expect Necko to pass it again so that we don't need a member var for
|
||||
// it.
|
||||
bool Open(dom::BrowserParent* aBrowser, nsDocShellLoadState* aLoadState,
|
||||
class LoadInfo* aLoadInfo, const nsString* aInitiatorType,
|
||||
nsLoadFlags aLoadFlags, uint32_t aLoadType, uint32_t aCacheKey,
|
||||
bool aIsActive, bool aIsTopLevelDoc,
|
||||
bool aHasNonEmptySandboxingFlags,
|
||||
const Maybe<ipc::URIParams>& aTopWindowURI,
|
||||
const Maybe<ipc::PrincipalInfo>& aContentBlockingAllowListPrincipal,
|
||||
const nsString& aCustomUserAgent, const uint64_t& aChannelId,
|
||||
const TimeStamp& aAsyncOpenTime, nsresult* aRv);
|
||||
const TimeStamp& aAsyncOpenTime,
|
||||
const Maybe<uint32_t>& aDocumentOpenFlags, bool aPluginsAllowed,
|
||||
nsresult* aRv);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
@ -134,6 +141,13 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||
// our reference to it.
|
||||
void DocumentChannelBridgeDisconnected();
|
||||
|
||||
void DisconnectChildListeners(nsresult aStatus, nsresult aLoadGroupStatus) {
|
||||
if (mDocumentChannelBridge) {
|
||||
mDocumentChannelBridge->DisconnectChildListeners(aStatus,
|
||||
aLoadGroupStatus);
|
||||
}
|
||||
}
|
||||
|
||||
base::ProcessId OtherPid() const {
|
||||
if (mDocumentChannelBridge) {
|
||||
return mDocumentChannelBridge->OtherPid();
|
||||
|
|
|
@ -405,9 +405,11 @@ struct DocumentChannelCreationArgs {
|
|||
uint32_t loadFlags;
|
||||
uint32_t loadType;
|
||||
uint32_t cacheKey;
|
||||
uint32_t? documentOpenFlags;
|
||||
bool isActive;
|
||||
bool isTopLevelDoc;
|
||||
bool hasNonEmptySandboxingFlags;
|
||||
bool pluginsAllowed;
|
||||
};
|
||||
|
||||
struct DocumentChannelRedirect {
|
||||
|
|
|
@ -409,7 +409,7 @@ mozilla::ipc::IPCResult NeckoParent::RecvPFTPChannelConstructor(
|
|||
|
||||
already_AddRefed<PDocumentChannelParent>
|
||||
NeckoParent::AllocPDocumentChannelParent(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
PBrowserParent* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& args) {
|
||||
nsCOMPtr<nsIPrincipal> requestingPrincipal =
|
||||
GetRequestingPrincipal(Some(args.loadInfo()));
|
||||
|
@ -422,17 +422,21 @@ NeckoParent::AllocPDocumentChannelParent(
|
|||
}
|
||||
PBOverrideStatus overrideStatus =
|
||||
PBOverrideStatusFromLoadContext(aSerialized);
|
||||
RefPtr<dom::BrowserParent> browser =
|
||||
static_cast<dom::BrowserParent*>(aBrowser);
|
||||
RefPtr<DocumentChannelParent> p =
|
||||
new DocumentChannelParent(aBrowser, loadContext, overrideStatus);
|
||||
new DocumentChannelParent(browser, loadContext, overrideStatus);
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult NeckoParent::RecvPDocumentChannelConstructor(
|
||||
PDocumentChannelParent* aActor, const PBrowserOrId& aBrowser,
|
||||
PDocumentChannelParent* aActor, PBrowserParent* aBrowser,
|
||||
const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& aArgs) {
|
||||
DocumentChannelParent* p = static_cast<DocumentChannelParent*>(aActor);
|
||||
if (!p->Init(aArgs)) {
|
||||
RefPtr<dom::BrowserParent> browser =
|
||||
static_cast<dom::BrowserParent*>(aBrowser);
|
||||
if (!p->Init(browser, aArgs)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
|
|
|
@ -128,10 +128,10 @@ class NeckoParent : public PNeckoParent {
|
|||
const uint16_t& port);
|
||||
|
||||
already_AddRefed<PDocumentChannelParent> AllocPDocumentChannelParent(
|
||||
const PBrowserOrId& aBrowser, const SerializedLoadContext& aSerialized,
|
||||
PBrowserParent* aBrowser, const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& args);
|
||||
virtual mozilla::ipc::IPCResult RecvPDocumentChannelConstructor(
|
||||
PDocumentChannelParent* aActor, const PBrowserOrId& aBrowser,
|
||||
PDocumentChannelParent* aActor, PBrowserParent* aBrowser,
|
||||
const SerializedLoadContext& aSerialized,
|
||||
const DocumentChannelCreationArgs& aArgs) override;
|
||||
bool DeallocPDocumentChannelParent(PDocumentChannelParent* channel);
|
||||
|
|
|
@ -45,7 +45,11 @@ child:
|
|||
// As a consequence, it should cleanup the channel listeners and remove the
|
||||
// request from the loadGroup.
|
||||
// aStatus must be an error result.
|
||||
async DisconnectChildListeners(nsresult aStatus);
|
||||
// aLoadGroupReason is used as mStatus when we remove the child channel from
|
||||
// the loadgroup (but aStatus is passed as the parameter to RemoveRequest).
|
||||
// We do this so we can remove using NS_BINDING_RETARGETED, but still have the
|
||||
// channel not be in an error state.
|
||||
async DisconnectChildListeners(nsresult aStatus, nsresult aLoadGroupReason);
|
||||
|
||||
// Triggers replacing this DocumentChannel with a 'real' channel (like PHttpChannel),
|
||||
// and notifies the listener via a redirect to the new channel.
|
||||
|
|
|
@ -88,7 +88,7 @@ parent:
|
|||
async PDNSRequest(nsCString hostName, OriginAttributes originAttributes,
|
||||
uint32_t flags);
|
||||
|
||||
async PDocumentChannel(PBrowserOrId browser,
|
||||
async PDocumentChannel(PBrowser browser,
|
||||
SerializedLoadContext loadContext,
|
||||
DocumentChannelCreationArgs args);
|
||||
|
||||
|
|
|
@ -98,6 +98,10 @@ class ParentChannelListener final : public nsIInterfaceRequestor,
|
|||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ParentChannelListener, PARENT_CHANNEL_LISTENER)
|
||||
|
||||
inline nsISupports* ToSupports(ParentChannelListener* aDoc) {
|
||||
return static_cast<nsIInterfaceRequestor*>(aDoc);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[a-download-click-404.html]
|
||||
[Do not navigate to 404 for anchor with download]
|
||||
expected: FAIL
|
||||
|
Загрузка…
Ссылка в новой задаче