зеркало из https://github.com/mozilla/gecko-dev.git
618 строки
25 KiB
C++
618 строки
25 KiB
C++
/* 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_DocumentLoadListener_h
|
|
#define mozilla_net_DocumentLoadListener_h
|
|
|
|
#include "mozilla/MozPromise.h"
|
|
#include "mozilla/Variant.h"
|
|
#include "mozilla/WeakPtr.h"
|
|
#include "mozilla/ipc/Endpoint.h"
|
|
#include "mozilla/dom/SessionHistoryEntry.h"
|
|
#include "EarlyHintsService.h"
|
|
#include "mozilla/net/NeckoCommon.h"
|
|
#include "mozilla/net/NeckoParent.h"
|
|
#include "mozilla/net/PDocumentChannelParent.h"
|
|
#include "mozilla/net/ParentChannelListener.h"
|
|
#include "nsDOMNavigationTiming.h"
|
|
#include "nsIBrowser.h"
|
|
#include "nsIChannelEventSink.h"
|
|
#include "nsIEarlyHintObserver.h"
|
|
#include "nsIInterfaceRequestor.h"
|
|
#include "nsIMultiPartChannel.h"
|
|
#include "nsIParentChannel.h"
|
|
#include "nsIParentRedirectingChannel.h"
|
|
#include "nsIProgressEventSink.h"
|
|
#include "nsIRedirectResultListener.h"
|
|
|
|
#define DOCUMENT_LOAD_LISTENER_IID \
|
|
{ \
|
|
0x3b393c56, 0x9e01, 0x11e9, { \
|
|
0xa2, 0xa3, 0x2a, 0x2a, 0xe2, 0xdb, 0xcc, 0xe4 \
|
|
} \
|
|
}
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
class CanonicalBrowsingContext;
|
|
struct NavigationIsolationOptions;
|
|
} // namespace dom
|
|
namespace net {
|
|
using ChildEndpointPromise =
|
|
MozPromise<mozilla::ipc::Endpoint<extensions::PStreamFilterChild>, bool,
|
|
true>;
|
|
|
|
// If we've been asked to attach a stream filter to our channel,
|
|
// then we return this promise and defer until we know the final
|
|
// content process. At that point we setup Endpoints between
|
|
// mStramFilterProcessId and the new content process, and send
|
|
// the parent Endpoint to the new process.
|
|
// Once we have confirmation of that being bound in the content
|
|
// process, we resolve the promise the child Endpoint.
|
|
struct StreamFilterRequest {
|
|
StreamFilterRequest() = default;
|
|
StreamFilterRequest(StreamFilterRequest&&) = default;
|
|
~StreamFilterRequest() {
|
|
if (mPromise) {
|
|
mPromise->Reject(false, __func__);
|
|
}
|
|
}
|
|
RefPtr<ChildEndpointPromise::Private> mPromise;
|
|
mozilla::ipc::Endpoint<extensions::PStreamFilterChild> mChildEndpoint;
|
|
};
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR(mozilla::net::StreamFilterRequest)
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
class LoadInfo;
|
|
|
|
/**
|
|
* DocumentLoadListener represents a connecting document load for a
|
|
* CanonicalBrowsingContext (in the parent process).
|
|
*
|
|
* It creates a network channel for the document load and then waits for it to
|
|
* receive a response (after all redirects are resolved). It then decides where
|
|
* to handle that load (could be in a different process from the initiator),
|
|
* and then sets up a real network nsIChannel to deliver the data to the final
|
|
* destination docshell, maybe through an nsIParentChannel/nsIChildChannel IPDL
|
|
* layer.
|
|
*
|
|
* In the case where this was initiated from an nsDocShell, we also create an
|
|
* nsIChannel to act as a placeholder within the docshell while this process
|
|
* completes, and then notify the docshell of a 'redirect' when we replace this
|
|
* channel with the real one.
|
|
*/
|
|
|
|
// TODO: We currently don't implement nsIProgressEventSink and forward those
|
|
// to the child. Should we? We get the interface requested.
|
|
class DocumentLoadListener : public nsIInterfaceRequestor,
|
|
public nsIAsyncVerifyRedirectReadyCallback,
|
|
public nsIParentChannel,
|
|
public nsIChannelEventSink,
|
|
public HttpChannelSecurityWarningReporter,
|
|
public nsIMultiPartChannelListener,
|
|
public nsIProgressEventSink,
|
|
public nsIEarlyHintObserver {
|
|
public:
|
|
// See the comment on GetLoadingBrowsingContext for explanation of
|
|
// aLoadingBrowsingContext.
|
|
DocumentLoadListener(dom::CanonicalBrowsingContext* aLoadingBrowsingContext,
|
|
bool aIsDocumentLoad);
|
|
|
|
struct OpenPromiseSucceededType {
|
|
nsTArray<mozilla::ipc::Endpoint<extensions::PStreamFilterParent>>
|
|
mStreamFilterEndpoints;
|
|
uint32_t mRedirectFlags;
|
|
uint32_t mLoadFlags;
|
|
nsTArray<EarlyHintConnectArgs> mEarlyHints;
|
|
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise::Private>
|
|
mPromise;
|
|
};
|
|
struct OpenPromiseFailedType {
|
|
nsresult mStatus;
|
|
nsresult mLoadGroupStatus;
|
|
// This is set to true if the navigation in the content process should not
|
|
// be cancelled, as the load is logically continuing within the current
|
|
// browsing session, just within a different process or browsing context.
|
|
bool mContinueNavigating = false;
|
|
};
|
|
|
|
using OpenPromise =
|
|
MozPromise<OpenPromiseSucceededType, OpenPromiseFailedType, true>;
|
|
|
|
// Interface which may be provided when performing an <object> or <embed> load
|
|
// with `DocumentLoadListener`, to allow upgrading the Object load to a proper
|
|
// Document load.
|
|
struct ObjectUpgradeHandler : public SupportsWeakPtr {
|
|
using ObjectUpgradePromise =
|
|
MozPromise<RefPtr<dom::CanonicalBrowsingContext>, nsresult,
|
|
true /* isExclusive */>;
|
|
|
|
// Upgrade an object load to be a potentially remote document.
|
|
//
|
|
// The returned promise will resolve with the BrowsingContext which has been
|
|
// created in the <object> or <embed> element to finish the load with.
|
|
virtual RefPtr<ObjectUpgradePromise> UpgradeObjectLoad() = 0;
|
|
};
|
|
|
|
private:
|
|
// Creates the channel, and then calls AsyncOpen on it.
|
|
// The DocumentLoadListener will require additional process from the consumer
|
|
// in order to complete the redirect to the end channel. This is done by
|
|
// returning a RedirectToRealChannelPromise and then waiting for it to be
|
|
// resolved or rejected accordingly.
|
|
// Once that promise is resolved; the consumer no longer needs to hold a
|
|
// reference to the DocumentLoadListener nor will the consumer required to be
|
|
// used again.
|
|
RefPtr<OpenPromise> Open(nsDocShellLoadState* aLoadState, LoadInfo* aLoadInfo,
|
|
nsLoadFlags aLoadFlags, uint32_t aCacheKey,
|
|
const Maybe<uint64_t>& aChannelId,
|
|
const TimeStamp& aAsyncOpenTime,
|
|
nsDOMNavigationTiming* aTiming,
|
|
Maybe<dom::ClientInfo>&& aInfo, bool aUrgentStart,
|
|
dom::ContentParent* aContentParent, nsresult* aRv);
|
|
|
|
public:
|
|
RefPtr<OpenPromise> OpenDocument(
|
|
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
|
|
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
|
|
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
|
|
Maybe<bool> aUriModified, Maybe<bool> aIsXFOError,
|
|
dom::ContentParent* aContentParent, nsresult* aRv);
|
|
|
|
RefPtr<OpenPromise> OpenObject(
|
|
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
|
|
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
|
|
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
|
|
uint64_t aInnerWindowId, nsLoadFlags aLoadFlags,
|
|
nsContentPolicyType aContentPolicyType, bool aUrgentStart,
|
|
dom::ContentParent* aContentParent,
|
|
ObjectUpgradeHandler* aObjectUpgradeHandler, nsresult* aRv);
|
|
|
|
// Creates a DocumentLoadListener entirely in the parent process and opens it,
|
|
// and never needs a DocumentChannel to connect to an existing docshell.
|
|
// Once we get a response it takes the 'process switch' path to find the right
|
|
// process and docshell, and delivers the response there directly.
|
|
static bool LoadInParent(dom::CanonicalBrowsingContext* aBrowsingContext,
|
|
nsDocShellLoadState* aLoadState,
|
|
bool aSetNavigating);
|
|
|
|
// Creates a DocumentLoadListener directly in the parent process and opens it,
|
|
// without needing an existing DocumentChannel.
|
|
// If successful it registers a unique identifier (return in aOutIdent) to
|
|
// keep it alive until a future DocumentChannel can attach to it, or we fail
|
|
// and clean up.
|
|
static bool SpeculativeLoadInParent(
|
|
dom::CanonicalBrowsingContext* aBrowsingContext,
|
|
nsDocShellLoadState* aLoadState);
|
|
|
|
// Ensures that a load identifier allocated by OpenFromParent has
|
|
// been deregistered if it hasn't already been claimed.
|
|
// This also cancels the load.
|
|
static void CleanupParentLoadAttempt(uint64_t aLoadIdent);
|
|
|
|
// Looks up aLoadIdent to find the associated, cleans up the registration
|
|
static RefPtr<OpenPromise> ClaimParentLoad(DocumentLoadListener** aListener,
|
|
uint64_t aLoadIdent,
|
|
Maybe<uint64_t> aChannelId);
|
|
|
|
// Called by the DocumentChannelParent if actor got destroyed or the parent
|
|
// channel got deleted.
|
|
void Abort();
|
|
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIREQUESTOBSERVER
|
|
NS_DECL_NSISTREAMLISTENER
|
|
NS_DECL_NSIPARENTCHANNEL
|
|
NS_DECL_NSIINTERFACEREQUESTOR
|
|
NS_DECL_NSIASYNCVERIFYREDIRECTREADYCALLBACK
|
|
NS_DECL_NSICHANNELEVENTSINK
|
|
NS_DECL_NSIMULTIPARTCHANNELLISTENER
|
|
NS_DECL_NSIPROGRESSEVENTSINK
|
|
NS_DECL_NSIEARLYHINTOBSERVER
|
|
|
|
// We suspend the underlying channel when replacing ourselves with
|
|
// the real listener channel.
|
|
// This helper resumes the underlying channel again, and manually
|
|
// forwards any nsIStreamListener messages that arrived while we
|
|
// were suspended (which might have failed).
|
|
// 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)
|
|
|
|
// Called by the DocumentChannel if cancelled.
|
|
void Cancel(const nsresult& aStatusCode, const nsACString& aReason);
|
|
|
|
nsIChannel* GetChannel() const { return mChannel; }
|
|
|
|
uint32_t GetRedirectChannelId() const { return mRedirectChannelId; }
|
|
|
|
nsresult ReportSecurityMessage(const nsAString& aMessageTag,
|
|
const nsAString& aMessageCategory) override {
|
|
ReportSecurityMessageParams params;
|
|
params.mMessageTag = aMessageTag;
|
|
params.mMessageCategory = aMessageCategory;
|
|
mSecurityWarningFunctions.AppendElement(
|
|
SecurityWarningFunction{VariantIndex<0>{}, std::move(params)});
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult LogBlockedCORSRequest(const nsAString& aMessage,
|
|
const nsACString& aCategory) override {
|
|
LogBlockedCORSRequestParams params;
|
|
params.mMessage = aMessage;
|
|
params.mCategory = aCategory;
|
|
mSecurityWarningFunctions.AppendElement(
|
|
SecurityWarningFunction{VariantIndex<1>{}, std::move(params)});
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult LogMimeTypeMismatch(const nsACString& aMessageName, bool aWarning,
|
|
const nsAString& aURL,
|
|
const nsAString& aContentType) override {
|
|
LogMimeTypeMismatchParams params;
|
|
params.mMessageName = aMessageName;
|
|
params.mWarning = aWarning;
|
|
params.mURL = aURL;
|
|
params.mContentType = aContentType;
|
|
mSecurityWarningFunctions.AppendElement(
|
|
SecurityWarningFunction{VariantIndex<2>{}, std::move(params)});
|
|
return NS_OK;
|
|
}
|
|
|
|
// The content process corresponding to this DocumentLoadListener, or nullptr
|
|
// if connected to the parent process.
|
|
dom::ContentParent* GetContentParent() const { return mContentParent; }
|
|
|
|
// The process id of the content process that we are being called from
|
|
// or 0 initiated from a parent process load.
|
|
base::ProcessId OtherPid() const;
|
|
|
|
[[nodiscard]] RefPtr<ChildEndpointPromise> AttachStreamFilter();
|
|
|
|
// Serializes all data needed to setup the new replacement channel
|
|
// in the content process into the RedirectToRealChannelArgs struct.
|
|
void SerializeRedirectData(
|
|
RedirectToRealChannelArgs& aArgs, bool aIsCrossProcess,
|
|
uint32_t aRedirectFlags, uint32_t aLoadFlags, dom::ContentParent* aParent,
|
|
nsTArray<EarlyHintConnectArgs>&& aEarlyHints) const;
|
|
|
|
uint64_t GetLoadIdentifier() const { return mLoadIdentifier; }
|
|
uint32_t GetLoadType() const { return mLoadStateLoadType; }
|
|
bool IsDownload() const { return mIsDownload; }
|
|
bool IsLoadingJSURI() const { return mIsLoadingJSURI; }
|
|
|
|
mozilla::dom::LoadingSessionHistoryInfo* GetLoadingSessionHistoryInfo() {
|
|
return mLoadingSessionHistoryInfo.get();
|
|
}
|
|
|
|
bool IsDocumentLoad() const { return mIsDocumentLoad; }
|
|
|
|
// Determine what process switching behavior a browser element should have.
|
|
enum ProcessBehavior : uint8_t {
|
|
// Gecko won't automatically change which process this frame, or it's
|
|
// subframes, are loaded in.
|
|
PROCESS_BEHAVIOR_DISABLED,
|
|
|
|
// If `useRemoteTabs` is enabled, Gecko will change which process this frame
|
|
// is loaded in automatically, without calling `performProcessSwitch`.
|
|
// When `useRemoteSubframes` is enabled, subframes will change processes.
|
|
PROCESS_BEHAVIOR_STANDARD,
|
|
|
|
// Gecko won't automatically change which process this frame is loaded, but
|
|
// when `useRemoteSubframes` is enabled, subframes will change processes.
|
|
//
|
|
// NOTE: This configuration is included only for backwards compatibility,
|
|
// and will be removed, as it can easily lead to invalid behavior.
|
|
PROCESS_BEHAVIOR_SUBFRAME_ONLY,
|
|
};
|
|
|
|
protected:
|
|
virtual ~DocumentLoadListener();
|
|
|
|
private:
|
|
RefPtr<OpenPromise> OpenInParent(nsDocShellLoadState* aLoadState,
|
|
bool aSupportsRedirectToRealChannel);
|
|
|
|
friend class ParentProcessDocumentOpenInfo;
|
|
|
|
// Will reject the promise to notify the DLL consumer that we are done.
|
|
//
|
|
// If `aContinueNavigating` is true, the navigation in the content process
|
|
// will not be aborted, as navigation is logically continuing in the existing
|
|
// browsing session (e.g. due to a process switch or entering the bfcache).
|
|
void DisconnectListeners(nsresult aStatus, nsresult aLoadGroupStatus,
|
|
bool aContinueNavigating = false);
|
|
|
|
// Called when we were created without a document channel, and creation has
|
|
// failed, and won't ever be attached.
|
|
void NotifyDocumentChannelFailed();
|
|
|
|
// Initiates the switch from DocumentChannel to the real protocol-specific
|
|
// channel, and ensures that RedirectToRealChannelFinished is called when
|
|
// this is complete.
|
|
void TriggerRedirectToRealChannel(
|
|
const Maybe<dom::ContentParent*>& aDestinationProcess,
|
|
nsTArray<StreamFilterRequest> aStreamFilterRequests);
|
|
|
|
// Called once the content-process side on setting up a replacement
|
|
// channel is complete. May wait for the new parent channel to
|
|
// finish, and then calls into FinishReplacementChannelSetup.
|
|
void RedirectToRealChannelFinished(nsresult aRv);
|
|
|
|
// Completes the replacement of the new channel.
|
|
// This redirects the ParentChannelListener to forward any future
|
|
// messages to the new channel, manually forwards any being held
|
|
// by us, and resumes the underlying source channel.
|
|
void FinishReplacementChannelSetup(nsresult aResult);
|
|
|
|
// Called from `OnStartRequest` to make the decision about whether or not to
|
|
// change process. This method will return `nullptr` if the current target
|
|
// process is appropriate.
|
|
// aWillSwitchToRemote is set to true if we initiate a process switch,
|
|
// and that the new remote type will be something other than NOT_REMOTE
|
|
bool MaybeTriggerProcessSwitch(bool* aWillSwitchToRemote);
|
|
|
|
// Called when the process switch is going to happen, potentially
|
|
// asynchronously, from `MaybeTriggerProcessSwitch`.
|
|
//
|
|
// aContext should be the target context for the navigation. This will either
|
|
// be the loading BrowsingContext, the newly created BrowsingContext for an
|
|
// object or embed element load, or a newly created tab for new tab load.
|
|
//
|
|
// If `aIsNewTab` is specified, the navigation in the original process will be
|
|
// aborted immediately, rather than waiting for a process switch to happen and
|
|
// the previous page to be unloaded or hidden.
|
|
void TriggerProcessSwitch(dom::CanonicalBrowsingContext* aContext,
|
|
const dom::NavigationIsolationOptions& aOptions,
|
|
bool aIsNewTab = false);
|
|
|
|
// A helper for TriggerRedirectToRealChannel that abstracts over
|
|
// the same-process and cross-process switch cases and returns
|
|
// a single promise to wait on.
|
|
using ParentEndpoint =
|
|
mozilla::ipc::Endpoint<extensions::PStreamFilterParent>;
|
|
RefPtr<PDocumentChannelParent::RedirectToRealChannelPromise>
|
|
RedirectToRealChannel(uint32_t aRedirectFlags, uint32_t aLoadFlags,
|
|
const Maybe<dom::ContentParent*>& aDestinationProcess,
|
|
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);
|
|
|
|
// Return the Browsing Context that is performing the load.
|
|
// For document loads, the BC is the one that the (sub)doc
|
|
// will load into. For <object>/<embed>, it's the embedder document's BC.
|
|
dom::CanonicalBrowsingContext* GetLoadingBrowsingContext() const;
|
|
|
|
// Return the Browsing Context that document is being loaded into. For
|
|
// non-document loads, this will return nullptr.
|
|
dom::CanonicalBrowsingContext* GetDocumentBrowsingContext() const;
|
|
dom::CanonicalBrowsingContext* GetTopBrowsingContext() const;
|
|
|
|
// Return the Window Context which which contains the element which the load
|
|
// is being performed in. For toplevel loads, this will return `nullptr`.
|
|
dom::WindowGlobalParent* GetParentWindowContext() const;
|
|
|
|
void AddURIVisit(nsIChannel* aChannel, uint32_t aLoadFlags);
|
|
bool HasCrossOriginOpenerPolicyMismatch() const;
|
|
void ApplyPendingFunctions(nsIParentChannel* aChannel) const;
|
|
|
|
void Disconnect(bool aContinueNavigating);
|
|
|
|
void MaybeReportBlockedByURLClassifier(nsresult aStatus);
|
|
|
|
// Returns true if a channel with aStatus will display
|
|
// some sort of content (could be the actual channel data,
|
|
// attempt a uri fixup and new load, or an error page).
|
|
// Returns false if the docshell will ignore the load entirely.
|
|
bool DocShellWillDisplayContent(nsresult aStatus);
|
|
|
|
void FireStateChange(uint32_t aStateFlags, nsresult aStatus);
|
|
|
|
// Returns true if this is a failed load, where we have successfully
|
|
// created a fixed URI to attempt loading instead.
|
|
// If successful, this calls DisconnectListeners to completely finish
|
|
// the current load, and calls BrowsingContext::LoadURI to start the new one.
|
|
bool MaybeHandleLoadErrorWithURIFixup(nsresult aStatus);
|
|
|
|
// This defines a variant that describes all the attribute setters (and their
|
|
// parameters) from nsIParentChannel
|
|
//
|
|
// SetClassifierMatchedInfo(const nsACString& aList, const nsACString&
|
|
// aProvider, const nsACString& aFullHash) = 0;
|
|
// SetClassifierMatchedTrackingInfo(const nsACString& aLists, const
|
|
// nsACString& aFullHashes) = 0; NotifyClassificationFlags(uint32_t
|
|
// aClassificationFlags, bool aIsThirdParty) = 0;
|
|
struct ClassifierMatchedInfoParams {
|
|
nsCString mList;
|
|
nsCString mProvider;
|
|
nsCString mFullHash;
|
|
};
|
|
|
|
struct ClassifierMatchedTrackingInfoParams {
|
|
nsCString mLists;
|
|
nsCString mFullHashes;
|
|
};
|
|
|
|
struct ClassificationFlagsParams {
|
|
uint32_t mClassificationFlags;
|
|
bool mIsThirdParty;
|
|
};
|
|
|
|
using IParentChannelFunction =
|
|
mozilla::Variant<ClassifierMatchedInfoParams,
|
|
ClassifierMatchedTrackingInfoParams,
|
|
ClassificationFlagsParams>;
|
|
|
|
// Store a list of all the attribute setters that have been called on this
|
|
// channel, so that we can repeat them on the real channel that we redirect
|
|
// to.
|
|
nsTArray<IParentChannelFunction> mIParentChannelFunctions;
|
|
|
|
// This defines a variant this describes all the functions
|
|
// from HttpChannelSecurityWarningReporter so that we can forward
|
|
// them on to the real channel.
|
|
|
|
struct ReportSecurityMessageParams {
|
|
nsString mMessageTag;
|
|
nsString mMessageCategory;
|
|
};
|
|
|
|
struct LogBlockedCORSRequestParams {
|
|
nsString mMessage;
|
|
nsCString mCategory;
|
|
};
|
|
|
|
struct LogMimeTypeMismatchParams {
|
|
nsCString mMessageName;
|
|
bool mWarning = false;
|
|
nsString mURL;
|
|
nsString mContentType;
|
|
};
|
|
|
|
using SecurityWarningFunction =
|
|
mozilla::Variant<ReportSecurityMessageParams, LogBlockedCORSRequestParams,
|
|
LogMimeTypeMismatchParams>;
|
|
nsTArray<SecurityWarningFunction> mSecurityWarningFunctions;
|
|
|
|
// TODO Backtrack this.
|
|
// The set of nsIStreamListener functions that got called on this
|
|
// listener, so that we can replay them onto the replacement channel's
|
|
// listener. This should generally only be OnStartRequest, since we
|
|
// Suspend() the channel at that point, but it can fail sometimes
|
|
// so we have to support holding a list.
|
|
nsTArray<StreamListenerFunction> mStreamListenerFunctions;
|
|
|
|
nsCOMPtr<nsIChannel> mChannel;
|
|
|
|
Maybe<uint64_t> mDocumentChannelId;
|
|
|
|
// An instance of ParentChannelListener that we use as a listener
|
|
// between mChannel (and any future redirected mChannels) and us.
|
|
// This handles service worker interception, and retargetting
|
|
// OnDataAvailable/OnStopRequest messages onto the listener that
|
|
// replaces us.
|
|
RefPtr<ParentChannelListener> mParentChannelListener;
|
|
|
|
// Get the channel creation URI for constructing the channel in the content
|
|
// process. See the function for more details.
|
|
nsIURI* GetChannelCreationURI() const;
|
|
|
|
// The original navigation timing information containing various timestamps
|
|
// such as when the original load started.
|
|
// This will be passed back to the new content process should a process
|
|
// switch occurs.
|
|
RefPtr<nsDOMNavigationTiming> mTiming;
|
|
|
|
net::EarlyHintsService mEarlyHintsService;
|
|
|
|
// An optional ObjectUpgradeHandler which can be used to upgrade an <object>
|
|
// or <embed> element to contain a nsFrameLoader, allowing us to switch them
|
|
// into a different process.
|
|
//
|
|
// A weak pointer is held in order to avoid reference cycles.
|
|
WeakPtr<ObjectUpgradeHandler> mObjectUpgradeHandler;
|
|
|
|
// Used to identify an internal redirect in redirect chain.
|
|
// True when we have seen at least one non-interal redirect.
|
|
bool mHaveVisibleRedirect = false;
|
|
|
|
// Pending stream filter requests which should be attached when redirecting to
|
|
// the real channel. Moved into `TriggerRedirectToRealChannel` when the
|
|
// connection is ready.
|
|
nsTArray<StreamFilterRequest> mStreamFilterRequests;
|
|
|
|
nsString mSrcdocData;
|
|
nsCOMPtr<nsIURI> mBaseURI;
|
|
|
|
mozilla::UniquePtr<mozilla::dom::LoadingSessionHistoryInfo>
|
|
mLoadingSessionHistoryInfo;
|
|
|
|
RefPtr<dom::WindowGlobalParent> mParentWindowContext;
|
|
|
|
// Flags from nsDocShellLoadState::LoadFlags/Type that we want to make
|
|
// available to the new docshell if we switch processes.
|
|
uint32_t mLoadStateExternalLoadFlags = 0;
|
|
uint32_t mLoadStateInternalLoadFlags = 0;
|
|
uint32_t mLoadStateLoadType = 0;
|
|
|
|
// Indicates if this load is a download.
|
|
bool mIsDownload = false;
|
|
|
|
// Indicates if we are loading a javascript URI.
|
|
bool mIsLoadingJSURI = false;
|
|
|
|
// Corresponding redirect channel registrar Id for the final channel that
|
|
// we want to use when redirecting the child, or doing a process switch.
|
|
// 0 means redirection is not started.
|
|
uint64_t mRedirectChannelId = 0;
|
|
// Set to true once we initiate the redirect to a real channel (either
|
|
// via a process switch or a same-process redirect, and Suspend the
|
|
// underlying channel.
|
|
bool mInitiatedRedirectToRealChannel = false;
|
|
// The value of GetApplyConversion on mChannel when OnStartRequest
|
|
// was called. We override it to false to prevent a conversion
|
|
// helper from being installed, but we need to restore the value
|
|
// later.
|
|
bool mOldApplyConversion = false;
|
|
// Set to true if any previous channel that we redirected away
|
|
// from had a COOP mismatch.
|
|
bool mHasCrossOriginOpenerPolicyMismatch = false;
|
|
// Set to true if we've received OnStopRequest, and shouldn't
|
|
// setup a reference from the ParentChannelListener to the replacement
|
|
// channel.
|
|
bool mIsFinished = false;
|
|
|
|
// The id of the currently pending load which is
|
|
// passed to the childChannel in order to identify it in the new process.
|
|
uint64_t mLoadIdentifier = 0;
|
|
|
|
Maybe<nsCString> mOriginalUriString;
|
|
|
|
// Parent-initiated loads do not support redirects to real channels.
|
|
bool mSupportsRedirectToRealChannel = true;
|
|
|
|
Maybe<nsCString> mRemoteTypeOverride;
|
|
|
|
// The ContentParent which this channel is currently connected to, or nullptr
|
|
// if connected to the parent process.
|
|
RefPtr<dom::ContentParent> mContentParent;
|
|
|
|
void RejectOpenPromise(nsresult aStatus, nsresult aLoadGroupStatus,
|
|
bool aContinueNavigating, const char* aLocation) {
|
|
// It is possible for mOpenPromise to not be set if AsyncOpen failed and
|
|
// the DocumentChannel got canceled.
|
|
if (!mOpenPromiseResolved && mOpenPromise) {
|
|
mOpenPromise->Reject(OpenPromiseFailedType({aStatus, aLoadGroupStatus,
|
|
aContinueNavigating}),
|
|
aLocation);
|
|
mOpenPromiseResolved = true;
|
|
}
|
|
}
|
|
RefPtr<OpenPromise::Private> mOpenPromise;
|
|
bool mOpenPromiseResolved = false;
|
|
|
|
const bool mIsDocumentLoad;
|
|
};
|
|
|
|
NS_DEFINE_STATIC_IID_ACCESSOR(DocumentLoadListener, DOCUMENT_LOAD_LISTENER_IID)
|
|
|
|
inline nsISupports* ToSupports(DocumentLoadListener* aObj) {
|
|
return static_cast<nsIInterfaceRequestor*>(aObj);
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_net_DocumentChannelParent_h
|