Bug 1590762 - Part 3: Keep track of current loads in BrowsingContext. r=mattwoodrow

Differential Revision: https://phabricator.services.mozilla.com/D75110
This commit is contained in:
Andreas Farre 2020-06-23 13:01:37 +00:00
parent ca5db92916
commit 78dfb0a991
20 changed files with 263 additions and 287 deletions

View File

@ -1586,8 +1586,10 @@ nsresult BrowsingContext::LoadURI(nsDocShellLoadState* aLoadState,
// Attempt to initiate this load immediately in the parent, if it succeeds // Attempt to initiate this load immediately in the parent, if it succeeds
// it'll return a unique identifier so that we can find it later. // it'll return a unique identifier so that we can find it later.
uint64_t loadIdentifier = 0; uint64_t loadIdentifier = 0;
if (Canonical()->AttemptLoadURIInParent(aLoadState, &loadIdentifier)) { if (Canonical()->AttemptLoadURIInParent(aLoadState)) {
aLoadState->SetLoadIdentifier(loadIdentifier); MOZ_DIAGNOSTIC_ASSERT(GetCurrentLoadIdentifier().isSome());
loadIdentifier = GetCurrentLoadIdentifier().value();
aLoadState->SetChannelInitialized(true);
} }
cp->TransmitBlobDataIfBlobURL(aLoadState->URI(), cp->TransmitBlobDataIfBlobURL(aLoadState->URI(),
@ -1612,9 +1614,7 @@ nsresult BrowsingContext::LoadURI(nsDocShellLoadState* aLoadState,
return NS_OK; return NS_OK;
} }
nsresult BrowsingContext::InternalLoad(nsDocShellLoadState* aLoadState, nsresult BrowsingContext::InternalLoad(nsDocShellLoadState* aLoadState) {
nsIDocShell** aDocShell,
nsIRequest** aRequest) {
if (IsDiscarded()) { if (IsDiscarded()) {
return NS_OK; return NS_OK;
} }
@ -1624,8 +1624,7 @@ nsresult BrowsingContext::InternalLoad(nsDocShellLoadState* aLoadState,
sourceBC && sourceBC->GetIsActive() && !GetIsActive() && sourceBC && sourceBC->GetIsActive() && !GetIsActive() &&
!Preferences::GetBool("browser.tabs.loadDivertedInBackground", false); !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false);
if (mDocShell) { if (mDocShell) {
nsresult rv = nsDocShell::Cast(mDocShell)->InternalLoad( nsresult rv = nsDocShell::Cast(mDocShell)->InternalLoad(aLoadState);
aLoadState, aDocShell, aRequest);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Switch to target tab if we're currently focused window. // Switch to target tab if we're currently focused window.
@ -1650,6 +1649,8 @@ nsresult BrowsingContext::InternalLoad(nsDocShellLoadState* aLoadState,
MOZ_TRY(CheckSandboxFlags(aLoadState)); MOZ_TRY(CheckSandboxFlags(aLoadState));
if (XRE_IsParentProcess()) { if (XRE_IsParentProcess()) {
SetCurrentLoadIdentifier(Some(aLoadState->GetLoadIdentifier()));
if (ContentParent* cp = Canonical()->GetContentParent()) { if (ContentParent* cp = Canonical()->GetContentParent()) {
Unused << cp->SendInternalLoad(this, aLoadState, isActive); Unused << cp->SendInternalLoad(this, aLoadState, isActive);
} }
@ -1661,12 +1662,15 @@ nsresult BrowsingContext::InternalLoad(nsDocShellLoadState* aLoadState,
return NS_ERROR_DOM_PROP_ACCESS_DENIED; return NS_ERROR_DOM_PROP_ACCESS_DENIED;
} }
SetCurrentLoadIdentifier(Some(aLoadState->GetLoadIdentifier()));
nsCOMPtr<nsPIDOMWindowOuter> win(sourceBC->GetDOMWindow()); nsCOMPtr<nsPIDOMWindowOuter> win(sourceBC->GetDOMWindow());
if (WindowGlobalChild* wgc = if (WindowGlobalChild* wgc =
win->GetCurrentInnerWindow()->GetWindowGlobalChild()) { win->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
wgc->SendInternalLoad(this, aLoadState); wgc->SendInternalLoad(this, aLoadState);
} }
} }
return NS_OK; return NS_OK;
} }

View File

@ -140,6 +140,8 @@ class WindowProxyHolder;
FIELD(FullZoom, float) \ FIELD(FullZoom, float) \
FIELD(WatchedByDevToolsInternal, bool) \ FIELD(WatchedByDevToolsInternal, bool) \
FIELD(TextZoom, float) \ FIELD(TextZoom, float) \
/* The current in-progress load. */ \
FIELD(CurrentLoadIdentifier, Maybe<uint64_t>) \
/* See nsIRequest for possible flags. */ \ /* See nsIRequest for possible flags. */ \
FIELD(DefaultLoadFlags, uint32_t) \ FIELD(DefaultLoadFlags, uint32_t) \
/* Signals that session history is enabled for this browsing context tree. \ /* Signals that session history is enabled for this browsing context tree. \
@ -280,8 +282,7 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
nsresult LoadURI(nsDocShellLoadState* aLoadState, nsresult LoadURI(nsDocShellLoadState* aLoadState,
bool aSetNavigating = false); bool aSetNavigating = false);
nsresult InternalLoad(nsDocShellLoadState* aLoadState, nsresult InternalLoad(nsDocShellLoadState* aLoadState);
nsIDocShell** aDocShell, nsIRequest** aRequest);
// If the load state includes a source BrowsingContext has been passed, check // If the load state includes a source BrowsingContext has been passed, check
// to see if we are sandboxed from it as the result of an iframe or CSP // to see if we are sandboxed from it as the result of an iframe or CSP
@ -408,6 +409,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool IsLoading(); bool IsLoading();
bool IsLoadingIdentifier(uint64_t aLoadIdentifer) {
if (GetCurrentLoadIdentifier() &&
*GetCurrentLoadIdentifier() == aLoadIdentifer) {
return true;
}
return false;
}
// ScreenOrientation related APIs // ScreenOrientation related APIs
void SetCurrentOrientation(OrientationType aType, float aAngle) { void SetCurrentOrientation(OrientationType aType, float aAngle) {
SetCurrentOrientationType(aType); SetCurrentOrientationType(aType);

View File

@ -813,7 +813,7 @@ MediaController* CanonicalBrowsingContext::GetMediaController() {
} }
bool CanonicalBrowsingContext::AttemptLoadURIInParent( bool CanonicalBrowsingContext::AttemptLoadURIInParent(
nsDocShellLoadState* aLoadState, uint64_t* aLoadIdentifier) { nsDocShellLoadState* aLoadState) {
// We currently only support starting loads directly from the // We currently only support starting loads directly from the
// CanonicalBrowsingContext for top-level BCs. // CanonicalBrowsingContext for top-level BCs.
if (!IsTopContent() || !GetContentParent() || if (!IsTopContent() || !GetContentParent() ||
@ -866,18 +866,21 @@ bool CanonicalBrowsingContext::AttemptLoadURIInParent(
// If we successfully open the DocumentChannel, then it'll register // If we successfully open the DocumentChannel, then it'll register
// itself using aLoadIdentifier and be kept alive until it completes // itself using aLoadIdentifier and be kept alive until it completes
// loading. // loading.
return net::DocumentLoadListener::OpenFromParent( return net::DocumentLoadListener::OpenFromParent(this, aLoadState,
this, aLoadState, outerWindowId, aLoadIdentifier); outerWindowId);
} }
void CanonicalBrowsingContext::StartDocumentLoad( void CanonicalBrowsingContext::StartDocumentLoad(
net::DocumentLoadListener* aLoad) { net::DocumentLoadListener* aLoad) {
mCurrentLoad = aLoad; mCurrentLoad = aLoad;
SetCurrentLoadIdentifier(Some(aLoad->GetLoadIdentifier()));
} }
void CanonicalBrowsingContext::EndDocumentLoad(
net::DocumentLoadListener* aLoad) { void CanonicalBrowsingContext::EndDocumentLoad(bool aForProcessSwitch) {
if (mCurrentLoad == aLoad) { mCurrentLoad = nullptr;
mCurrentLoad = nullptr;
if (!aForProcessSwitch) {
SetCurrentLoadIdentifier(Nothing());
} }
} }

View File

@ -150,8 +150,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// if the top-level browsing context has been discarded. // if the top-level browsing context has been discarded.
MediaController* GetMediaController(); MediaController* GetMediaController();
bool AttemptLoadURIInParent(nsDocShellLoadState* aLoadState, bool AttemptLoadURIInParent(nsDocShellLoadState* aLoadState);
uint64_t* aLoadIdentifier);
// Get or create a secure browser UI for this BrowsingContext // Get or create a secure browser UI for this BrowsingContext
nsISecureBrowserUI* GetSecureBrowserUI(); nsISecureBrowserUI* GetSecureBrowserUI();
@ -225,7 +224,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
// Called once DocumentLoadListener completes handling a load, and it // Called once DocumentLoadListener completes handling a load, and it
// is either complete, or handed off to the final channel to deliver // is either complete, or handed off to the final channel to deliver
// data to the destination docshell. // data to the destination docshell.
void EndDocumentLoad(net::DocumentLoadListener* aLoad); void EndDocumentLoad(bool aForProcessSwitch);
// XXX(farre): Store a ContentParent pointer here rather than mProcessId? // XXX(farre): Store a ContentParent pointer here rather than mProcessId?
// Indicates which process owns the docshell. // Indicates which process owns the docshell.

View File

@ -807,9 +807,7 @@ nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
MOZ_ASSERT(aLoadState->SHEntry() == nullptr, MOZ_ASSERT(aLoadState->SHEntry() == nullptr,
"SHEntry should be null when calling InternalLoad from LoadURI"); "SHEntry should be null when calling InternalLoad from LoadURI");
return InternalLoad(aLoadState, return InternalLoad(aLoadState); // no nsIRequest
nullptr, // no nsIDocShell
nullptr); // no nsIRequest
} }
void nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState) { void nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState) {
@ -3742,7 +3740,7 @@ nsresult nsDocShell::LoadErrorPage(nsIURI* aErrorURI, nsIURI* aFailedURI,
mBrowsingContext && mBrowsingContext &&
mBrowsingContext->HasValidTransientUserGestureActivation()); mBrowsingContext->HasValidTransientUserGestureActivation());
return InternalLoad(loadState, nullptr, nullptr); return InternalLoad(loadState);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -3850,7 +3848,7 @@ nsDocShell::Reload(uint32_t aReloadFlags) {
loadState->SetHasValidUserGestureActivation( loadState->SetHasValidUserGestureActivation(
mBrowsingContext && mBrowsingContext &&
mBrowsingContext->HasValidTransientUserGestureActivation()); mBrowsingContext->HasValidTransientUserGestureActivation());
rv = InternalLoad(loadState, nullptr, nullptr); rv = InternalLoad(loadState);
} }
return rv; return rv;
@ -7864,7 +7862,7 @@ class InternalLoadEvent : public Runnable {
MOZ_ASSERT(mLoadState->TriggeringPrincipal(), MOZ_ASSERT(mLoadState->TriggeringPrincipal(),
"InternalLoadEvent: Should always have a principal here"); "InternalLoadEvent: Should always have a principal here");
#endif #endif
return mDocShell->InternalLoad(mLoadState, nullptr, nullptr); return mDocShell->InternalLoad(mLoadState);
} }
private: private:
@ -7909,9 +7907,7 @@ uint32_t nsDocShell::DetermineContentType() {
return nsIContentPolicy::TYPE_INTERNAL_IFRAME; return nsIContentPolicy::TYPE_INTERNAL_IFRAME;
} }
nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState, nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
nsIDocShell** aDocShell,
nsIRequest** aRequest) {
MOZ_ASSERT(aLoadState, "need a load state!"); MOZ_ASSERT(aLoadState, "need a load state!");
MOZ_ASSERT(!aLoadState->Target().IsEmpty(), "should have a target here!"); MOZ_ASSERT(!aLoadState->Target().IsEmpty(), "should have a target here!");
@ -8101,6 +8097,8 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(targetContext, rv); NS_ENSURE_TRUE(targetContext, rv);
aLoadState->SetTargetBrowsingContext(targetContext);
// //
// Transfer the load to the target BrowsingContext... Pass empty string as the // Transfer the load to the target BrowsingContext... Pass empty string as the
// window target name from to prevent recursive retargeting! // window target name from to prevent recursive retargeting!
@ -8109,7 +8107,7 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
aLoadState->SetTarget(EmptyString()); aLoadState->SetTarget(EmptyString());
// No forced download // No forced download
aLoadState->SetFileName(VoidString()); aLoadState->SetFileName(VoidString());
return targetContext->InternalLoad(aLoadState, aDocShell, aRequest); return targetContext->InternalLoad(aLoadState);
} }
bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState, bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
@ -8416,9 +8414,7 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
return NS_OK; return NS_OK;
} }
nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState, nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState) {
nsIDocShell** aDocShell,
nsIRequest** aRequest) {
MOZ_ASSERT(aLoadState, "need a load state!"); MOZ_ASSERT(aLoadState, "need a load state!");
MOZ_ASSERT(aLoadState->TriggeringPrincipal(), MOZ_ASSERT(aLoadState->TriggeringPrincipal(),
"need a valid TriggeringPrincipal"); "need a valid TriggeringPrincipal");
@ -8437,14 +8433,6 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
("DOCSHELL %p InternalLoad %s\n", this, ("DOCSHELL %p InternalLoad %s\n", this,
aLoadState->URI()->GetSpecOrDefault().get())); aLoadState->URI()->GetSpecOrDefault().get()));
// Initialize aDocShell/aRequest
if (aDocShell) {
*aDocShell = nullptr;
}
if (aRequest) {
*aRequest = nullptr;
}
NS_ENSURE_TRUE(IsValidLoadType(aLoadState->LoadType()), NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(IsValidLoadType(aLoadState->LoadType()), NS_ERROR_INVALID_ARG);
// Cancel loads coming from Docshells that are being destroyed. // Cancel loads coming from Docshells that are being destroyed.
@ -8459,7 +8447,7 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
// If we have a target to move to, do that now. // If we have a target to move to, do that now.
if (!aLoadState->Target().IsEmpty()) { if (!aLoadState->Target().IsEmpty()) {
return PerformRetargeting(aLoadState, aDocShell, aRequest); return PerformRetargeting(aLoadState);
} }
// If we don't have a target, we're loading into ourselves, and our load // If we don't have a target, we're loading into ourselves, and our load
@ -8777,10 +8765,7 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr); nsINetworkPredictor::PREDICT_LOAD, attrs, nullptr);
nsCOMPtr<nsIRequest> req; nsCOMPtr<nsIRequest> req;
rv = DoURILoad(aLoadState, aDocShell, getter_AddRefs(req)); rv = DoURILoad(aLoadState, getter_AddRefs(req));
if (req && aRequest) {
NS_ADDREF(*aRequest = req);
}
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
nsCOMPtr<nsIChannel> chan(do_QueryInterface(req)); nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
@ -9276,7 +9261,7 @@ nsIPrincipal* nsDocShell::GetInheritedPrincipal(
} }
nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState, nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
nsIDocShell** aDocShell, nsIRequest** aRequest) { nsIRequest** aRequest) {
// Double-check that we're still around to load this URI. // Double-check that we're still around to load this URI.
if (mIsBeingDestroyed) { if (mIsBeingDestroyed) {
// Return NS_OK despite not doing anything to avoid throwing exceptions // Return NS_OK despite not doing anything to avoid throwing exceptions
@ -9381,16 +9366,8 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
outRequest.forget(aRequest); outRequest.forget(aRequest);
} }
rv = OpenInitializedChannel(channel, uriLoader, return OpenInitializedChannel(channel, uriLoader,
nsIURILoader::REDIRECTED_CHANNEL); nsIURILoader::REDIRECTED_CHANNEL);
// If the channel load failed, we failed and nsIWebProgress just ain't
// gonna happen.
if (NS_SUCCEEDED(rv) && aDocShell) {
nsCOMPtr<nsIDocShell> self = this;
self.forget(aDocShell);
}
return rv;
} }
// There are two cases we care about: // There are two cases we care about:
@ -9588,20 +9565,7 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState,
uint32_t openFlags = uint32_t openFlags =
nsDocShell::ComputeURILoaderFlags(mBrowsingContext, mLoadType); nsDocShell::ComputeURILoaderFlags(mBrowsingContext, mLoadType);
rv = OpenInitializedChannel(channel, uriLoader, openFlags); return OpenInitializedChannel(channel, uriLoader, openFlags);
//
// If the channel load failed, we failed and nsIWebProgress just ain't
// gonna happen.
//
if (NS_SUCCEEDED(rv)) {
if (aDocShell) {
*aDocShell = this;
NS_ADDREF(*aDocShell);
}
}
return rv;
} }
static nsresult AppendSegmentToString(nsIInputStream* aIn, void* aClosure, static nsresult AppendSegmentToString(nsIInputStream* aIn, void* aClosure,
@ -10839,9 +10803,7 @@ nsresult nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
rv = InternalLoad(loadState, rv = InternalLoad(loadState);
nullptr, // No nsIDocShell
nullptr); // No nsIRequest
return rv; return rv;
} }
@ -11567,13 +11529,9 @@ nsresult nsDocShell::EnsureCommandHandler() {
class OnLinkClickEvent : public Runnable { class OnLinkClickEvent : public Runnable {
public: public:
OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, nsIURI* aURI, OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
const nsAString& aTargetSpec, const nsAString& aFileName, nsDocShellLoadState* aLoadState, bool aNoOpenerImplied,
nsIInputStream* aPostDataStream, bool aIsTrusted, nsIPrincipal* aTriggeringPrincipal);
nsIInputStream* aHeadersDataStream, bool aNoOpenerImplied,
bool aIsUserTriggered, bool aIsTrusted,
nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp);
NS_IMETHOD Run() override { NS_IMETHOD Run() override {
AutoPopupStatePusher popupStatePusher(mPopupState); AutoPopupStatePusher popupStatePusher(mPopupState);
@ -11586,50 +11544,34 @@ class OnLinkClickEvent : public Runnable {
// concerned. // concerned.
AutoJSAPI jsapi; AutoJSAPI jsapi;
if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) { if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
mHandler->OnLinkClickSync(mContent, mURI, mTargetSpec, mFileName, mHandler->OnLinkClickSync(mContent, mLoadState, mNoOpenerImplied,
mPostDataStream, mHeadersDataStream, mTriggeringPrincipal);
mNoOpenerImplied, nullptr, nullptr,
mIsUserTriggered, mTriggeringPrincipal, mCsp);
} }
return NS_OK; return NS_OK;
} }
private: private:
RefPtr<nsDocShell> mHandler; RefPtr<nsDocShell> mHandler;
nsCOMPtr<nsIURI> mURI;
nsString mTargetSpec;
nsString mFileName;
nsCOMPtr<nsIInputStream> mPostDataStream;
nsCOMPtr<nsIInputStream> mHeadersDataStream;
nsCOMPtr<nsIContent> mContent; nsCOMPtr<nsIContent> mContent;
RefPtr<nsDocShellLoadState> mLoadState;
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
PopupBlocker::PopupControlState mPopupState; PopupBlocker::PopupControlState mPopupState;
bool mNoOpenerImplied; bool mNoOpenerImplied;
bool mIsUserTriggered;
bool mIsTrusted; bool mIsTrusted;
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
nsCOMPtr<nsIContentSecurityPolicy> mCsp;
}; };
OnLinkClickEvent::OnLinkClickEvent( OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
nsDocShell* aHandler, nsIContent* aContent, nsIURI* aURI, nsDocShellLoadState* aLoadState,
const nsAString& aTargetSpec, const nsAString& aFileName, bool aNoOpenerImplied, bool aIsTrusted,
nsIInputStream* aPostDataStream, nsIInputStream* aHeadersDataStream, nsIPrincipal* aTriggeringPrincipal)
bool aNoOpenerImplied, bool aIsUserTriggered, bool aIsTrusted,
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp)
: mozilla::Runnable("OnLinkClickEvent"), : mozilla::Runnable("OnLinkClickEvent"),
mHandler(aHandler), mHandler(aHandler),
mURI(aURI),
mTargetSpec(aTargetSpec),
mFileName(aFileName),
mPostDataStream(aPostDataStream),
mHeadersDataStream(aHeadersDataStream),
mContent(aContent), mContent(aContent),
mLoadState(aLoadState),
mTriggeringPrincipal(aTriggeringPrincipal),
mPopupState(PopupBlocker::GetPopupControlState()), mPopupState(PopupBlocker::GetPopupControlState()),
mNoOpenerImplied(aNoOpenerImplied), mNoOpenerImplied(aNoOpenerImplied),
mIsUserTriggered(aIsUserTriggered), mIsTrusted(aIsTrusted) {}
mIsTrusted(aIsTrusted),
mTriggeringPrincipal(aTriggeringPrincipal),
mCsp(aCsp) {}
nsresult nsDocShell::OnLinkClick( nsresult nsDocShell::OnLinkClick(
nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec, nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec,
@ -11676,10 +11618,20 @@ nsresult nsDocShell::OnLinkClick(
target = aTargetSpec; target = aTargetSpec;
} }
nsCOMPtr<nsIRunnable> ev = new OnLinkClickEvent( RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aURI);
this, aContent, aURI, target, aFileName, aPostDataStream, loadState->SetTarget(target);
aHeadersDataStream, noOpenerImplied, aIsUserTriggered, aIsTrusted, loadState->SetFileName(aFileName);
aTriggeringPrincipal, aCsp); loadState->SetPostDataStream(aPostDataStream);
loadState->SetHeadersStream(aHeadersDataStream);
loadState->SetFirstParty(true);
loadState->SetTriggeringPrincipal(
aTriggeringPrincipal ? aTriggeringPrincipal : aContent->NodePrincipal());
loadState->SetPrincipalToInherit(aContent->NodePrincipal());
loadState->SetCsp(aCsp ? aCsp : aContent->GetCsp());
nsCOMPtr<nsIRunnable> ev =
new OnLinkClickEvent(this, aContent, loadState, noOpenerImplied,
aIsTrusted, aTriggeringPrincipal);
return Dispatch(TaskCategory::UI, ev.forget()); return Dispatch(TaskCategory::UI, ev.forget());
} }
@ -11689,21 +11641,11 @@ static bool IsElementAnchorOrArea(nsIContent* aContent) {
return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area); return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area);
} }
nsresult nsDocShell::OnLinkClickSync( nsresult nsDocShell::OnLinkClickSync(nsIContent* aContent,
nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec, nsDocShellLoadState* aLoadState,
const nsAString& aFileName, nsIInputStream* aPostDataStream, bool aNoOpenerImplied,
nsIInputStream* aHeadersDataStream, bool aNoOpenerImplied, nsIPrincipal* aTriggeringPrincipal) {
nsIDocShell** aDocShell, nsIRequest** aRequest, bool aIsUserTriggered, if (!IsNavigationAllowed() || !IsOKToLoadURI(aLoadState->URI())) {
nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp) {
// Initialize the DocShell / Request
if (aDocShell) {
*aDocShell = nullptr;
}
if (aRequest) {
*aRequest = nullptr;
}
if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
return NS_OK; return NS_OK;
} }
@ -11730,7 +11672,7 @@ nsresult nsDocShell::OnLinkClickSync(
do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID); do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
if (extProtService) { if (extProtService) {
nsAutoCString scheme; nsAutoCString scheme;
aURI->GetScheme(scheme); aLoadState->URI()->GetScheme(scheme);
if (!scheme.IsEmpty()) { if (!scheme.IsEmpty()) {
// if the URL scheme does not correspond to an exposed protocol, then // if the URL scheme does not correspond to an exposed protocol, then
// we need to hand this link click over to the external protocol // we need to hand this link click over to the external protocol
@ -11739,22 +11681,17 @@ nsresult nsDocShell::OnLinkClickSync(
nsresult rv = nsresult rv =
extProtService->IsExposedProtocol(scheme.get(), &isExposed); extProtService->IsExposedProtocol(scheme.get(), &isExposed);
if (NS_SUCCEEDED(rv) && !isExposed) { if (NS_SUCCEEDED(rv) && !isExposed) {
return extProtService->LoadURI(aURI, triggeringPrincipal, return extProtService->LoadURI(aLoadState->URI(), triggeringPrincipal,
mBrowsingContext); mBrowsingContext);
} }
} }
} }
} }
nsCOMPtr<nsIContentSecurityPolicy> csp = aCsp;
if (!csp) {
// Currently, if no csp is passed explicitly we fall back to querying the
// CSP from the document.
csp = aContent->GetCsp();
}
uint32_t flags = INTERNAL_LOAD_FLAGS_NONE; uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
bool isElementAnchorOrArea = IsElementAnchorOrArea(aContent); bool isElementAnchorOrArea = IsElementAnchorOrArea(aContent);
bool triggeringPrincipalIsSystemPrincipal =
aLoadState->TriggeringPrincipal()->IsSystemPrincipal();
if (isElementAnchorOrArea) { if (isElementAnchorOrArea) {
MOZ_ASSERT(aContent->IsHTMLElement()); MOZ_ASSERT(aContent->IsHTMLElement());
nsAutoString relString; nsAutoString relString;
@ -11763,7 +11700,7 @@ nsresult nsDocShell::OnLinkClickSync(
nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok( nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
relString); relString);
bool targetBlank = aTargetSpec.LowerCaseEqualsLiteral("_blank"); bool targetBlank = aLoadState->Target().LowerCaseEqualsLiteral("_blank");
bool explicitOpenerSet = false; bool explicitOpenerSet = false;
// The opener behaviour follows a hierarchy, such that if a higher // The opener behaviour follows a hierarchy, such that if a higher
@ -11792,7 +11729,7 @@ nsresult nsDocShell::OnLinkClickSync(
} }
if (targetBlank && StaticPrefs::dom_targetBlankNoOpener_enabled() && if (targetBlank && StaticPrefs::dom_targetBlankNoOpener_enabled() &&
!explicitOpenerSet && !triggeringPrincipal->IsSystemPrincipal()) { !explicitOpenerSet && !triggeringPrincipalIsSystemPrincipal) {
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER; flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
} }
@ -11843,29 +11780,22 @@ nsresult nsDocShell::OnLinkClickSync(
isElementAnchorOrArea ? new ReferrerInfo(*aContent->AsElement()) isElementAnchorOrArea ? new ReferrerInfo(*aContent->AsElement())
: new ReferrerInfo(*referrerDoc); : new ReferrerInfo(*referrerDoc);
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aURI); aLoadState->SetReferrerInfo(referrerInfo);
loadState->SetReferrerInfo(referrerInfo); aLoadState->SetLoadFlags(flags);
loadState->SetTriggeringPrincipal(triggeringPrincipal); aLoadState->SetTypeHint(NS_ConvertUTF16toUTF8(typeHint));
loadState->SetPrincipalToInherit(aContent->NodePrincipal()); aLoadState->SetLoadType(loadType);
loadState->SetCsp(csp); aLoadState->SetSourceBrowsingContext(mBrowsingContext);
loadState->SetLoadFlags(flags); aLoadState->SetHasValidUserGestureActivation(
loadState->SetTarget(aTargetSpec);
loadState->SetTypeHint(NS_ConvertUTF16toUTF8(typeHint));
loadState->SetFileName(aFileName);
loadState->SetPostDataStream(aPostDataStream);
loadState->SetHeadersStream(aHeadersDataStream);
loadState->SetLoadType(loadType);
loadState->SetFirstParty(true);
loadState->SetSourceBrowsingContext(mBrowsingContext);
loadState->SetIsFormSubmission(aContent->IsHTMLElement(nsGkAtoms::form));
loadState->SetHasValidUserGestureActivation(
mBrowsingContext && mBrowsingContext &&
mBrowsingContext->HasValidTransientUserGestureActivation()); mBrowsingContext->HasValidTransientUserGestureActivation());
nsresult rv = InternalLoad(loadState, aDocShell, aRequest);
nsresult rv = InternalLoad(aLoadState);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
nsPingListener::DispatchPings(this, aContent, aURI, referrerInfo); nsPingListener::DispatchPings(this, aContent, aLoadState->URI(),
referrerInfo);
} }
return rv; return rv;
} }
@ -12136,7 +12066,7 @@ nsDocShell::ResumeRedirectedLoad(uint64_t aIdentifier, int32_t aHistoryIndex) {
} }
} }
self->InternalLoad(aLoadState, nullptr, nullptr); self->InternalLoad(aLoadState);
for (auto& endpoint : aStreamFilterEndpoints) { for (auto& endpoint : aStreamFilterEndpoints) {
extensions::StreamFilterParent::Attach( extensions::StreamFilterParent::Attach(

View File

@ -261,32 +261,16 @@ class nsDocShell final : public nsDocLoader,
* through an event. * through an event.
* *
* @param aContent the content object used for triggering the link. * @param aContent the content object used for triggering the link.
* @param aURI a URI obect that defines the destination for the link * @param aDocShellLoadState the extended load info for this load.
* @param aTargetSpec indicates where the link is targeted (may be an empty
* string)
* @param aFileName non-null when the link should be downloaded as the given
* file
* @param aPostDataStream the POST data to send
* @param aHeadersDataStream ??? (only used for plugins)
* @param aNoOpenerImplied if the link implies "noopener" * @param aNoOpenerImplied if the link implies "noopener"
* @param aDocShell (out-param) the DocShell that the request was opened on
* @param aRequest the request that was opened
* @param aTriggeringPrincipal, if not passed explicitly we fall back to * @param aTriggeringPrincipal, if not passed explicitly we fall back to
* the document's principal. * the document's principal.
* @param aCsp, the CSP to be used for the load, that is the CSP of the
* entity responsible for causing the load to occur. Most likely
* this is the CSP of the document that started the load. In case
* aCsp was not passed explicitly we fall back to using
* aContent's document's CSP if that document holds any.
*/ */
nsresult OnLinkClickSync( nsresult OnLinkClickSync(nsIContent* aContent,
nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec, nsDocShellLoadState* aLoadState,
const nsAString& aFileName, nsIInputStream* aPostDataStream = nullptr, bool aNoOpenerImplied,
nsIInputStream* aHeadersDataStream = nullptr, nsIPrincipal* aTriggeringPrincipal);
bool aNoOpenerImplied = false, nsIDocShell** aDocShell = nullptr,
nsIRequest** aRequest = nullptr, bool aIsUserTriggered = false,
nsIPrincipal* aTriggeringPrincipal = nullptr,
nsIContentSecurityPolicy* aCsp = nullptr);
/** /**
* Process a mouse-over a link. * Process a mouse-over a link.
* *
@ -418,8 +402,7 @@ class nsDocShell final : public nsDocLoader,
* onLinkClickSync, which is triggered during form submission. * onLinkClickSync, which is triggered during form submission.
*/ */
MOZ_CAN_RUN_SCRIPT_BOUNDARY MOZ_CAN_RUN_SCRIPT_BOUNDARY
nsresult InternalLoad(nsDocShellLoadState* aLoadState, nsresult InternalLoad(nsDocShellLoadState* aLoadState);
nsIDocShell** aDocShell, nsIRequest** aRequest);
// Clear the document's storage access flag if needed. // Clear the document's storage access flag if needed.
void MaybeClearStorageAccessFlag(); void MaybeClearStorageAccessFlag();
@ -632,8 +615,7 @@ class nsDocShell final : public nsDocLoader,
// originalURI on the channel that does the load. If OriginalURI is null, URI // originalURI on the channel that does the load. If OriginalURI is null, URI
// will be set as the originalURI. If LoadReplace is true, LOAD_REPLACE flag // will be set as the originalURI. If LoadReplace is true, LOAD_REPLACE flag
// will be set on the nsIChannel. // will be set on the nsIChannel.
nsresult DoURILoad(nsDocShellLoadState* aLoadState, nsIDocShell** aDocShell, nsresult DoURILoad(nsDocShellLoadState* aLoadState, nsIRequest** aRequest);
nsIRequest** aRequest);
static nsresult AddHeadersToChannel(nsIInputStream* aHeadersData, static nsresult AddHeadersToChannel(nsIInputStream* aHeadersData,
nsIChannel* aChannel); nsIChannel* aChannel);
@ -977,8 +959,7 @@ class nsDocShell final : public nsDocLoader,
// If we are passed a named target during InternalLoad, this method handles // If we are passed a named target during InternalLoad, this method handles
// moving the load to the browsing context the target name resolves to. // moving the load to the browsing context the target name resolves to.
nsresult PerformRetargeting(nsDocShellLoadState* aLoadState, nsresult PerformRetargeting(nsDocShellLoadState* aLoadState);
nsIDocShell** aDocShell, nsIRequest** aRequest);
// Returns one of nsIContentPolicy::TYPE_DOCUMENT, // Returns one of nsIContentPolicy::TYPE_DOCUMENT,
// nsIContentPolicy::TYPE_INTERNAL_IFRAME, or // nsIContentPolicy::TYPE_INTERNAL_IFRAME, or

View File

@ -75,30 +75,11 @@ already_AddRefed<nsIURIFixupInfo> GetFixupURIInfo(const nsACString& aStringURI,
} // anonymous namespace } // anonymous namespace
nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI) nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI)
: mURI(aURI), : nsDocShellLoadState(aURI, nsContentUtils::GenerateLoadIdentifier()) {}
mResultPrincipalURIIsSome(false),
mKeepResultPrincipalURIIfSet(false),
mLoadReplace(false),
mInheritPrincipal(false),
mPrincipalIsExplicit(false),
mForceAllowDataURI(false),
mOriginalFrameSrc(false),
mIsFormSubmission(false),
mLoadType(LOAD_NORMAL),
mTarget(),
mSrcdocData(VoidString()),
mLoadFlags(0),
mFirstParty(false),
mHasValidUserGestureActivation(false),
mTypeHint(VoidCString()),
mFileName(VoidString()),
mIsFromProcessingFrameAttributes(false),
mLoadIdentifier(0) {
MOZ_ASSERT(aURI, "Cannot create a LoadState with a null URI!");
}
nsDocShellLoadState::nsDocShellLoadState( nsDocShellLoadState::nsDocShellLoadState(
const DocShellLoadStateInit& aLoadState) { const DocShellLoadStateInit& aLoadState)
: mLoadIdentifier(aLoadState.LoadIdentifier()) {
MOZ_ASSERT(aLoadState.URI(), "Cannot create a LoadState with a null URI!"); MOZ_ASSERT(aLoadState.URI(), "Cannot create a LoadState with a null URI!");
mResultPrincipalURI = aLoadState.ResultPrincipalURI(); mResultPrincipalURI = aLoadState.ResultPrincipalURI();
mResultPrincipalURIIsSome = aLoadState.ResultPrincipalURIIsSome(); mResultPrincipalURIIsSome = aLoadState.ResultPrincipalURIIsSome();
@ -111,6 +92,7 @@ nsDocShellLoadState::nsDocShellLoadState(
mIsFormSubmission = aLoadState.IsFormSubmission(); mIsFormSubmission = aLoadState.IsFormSubmission();
mLoadType = aLoadState.LoadType(); mLoadType = aLoadState.LoadType();
mTarget = aLoadState.Target(); mTarget = aLoadState.Target();
mTargetBrowsingContext = aLoadState.SourceBrowsingContext();
mLoadFlags = aLoadState.LoadFlags(); mLoadFlags = aLoadState.LoadFlags();
mFirstParty = aLoadState.FirstParty(); mFirstParty = aLoadState.FirstParty();
mHasValidUserGestureActivation = aLoadState.HasValidUserGestureActivation(); mHasValidUserGestureActivation = aLoadState.HasValidUserGestureActivation();
@ -132,7 +114,7 @@ nsDocShellLoadState::nsDocShellLoadState(
mPostDataStream = aLoadState.PostDataStream(); mPostDataStream = aLoadState.PostDataStream();
mHeadersStream = aLoadState.HeadersStream(); mHeadersStream = aLoadState.HeadersStream();
mSrcdocData = aLoadState.SrcdocData(); mSrcdocData = aLoadState.SrcdocData();
mLoadIdentifier = aLoadState.LoadIdentifier(); mChannelInitialized = aLoadState.ChannelInitialized();
} }
nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther) nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
@ -155,6 +137,7 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
mLoadType(aOther.mLoadType), mLoadType(aOther.mLoadType),
mSHEntry(aOther.mSHEntry), mSHEntry(aOther.mSHEntry),
mTarget(aOther.mTarget), mTarget(aOther.mTarget),
mTargetBrowsingContext(aOther.mTargetBrowsingContext),
mPostDataStream(aOther.mPostDataStream), mPostDataStream(aOther.mPostDataStream),
mHeadersStream(aOther.mHeadersStream), mHeadersStream(aOther.mHeadersStream),
mSrcdocData(aOther.mSrcdocData), mSrcdocData(aOther.mSrcdocData),
@ -169,12 +152,38 @@ nsDocShellLoadState::nsDocShellLoadState(const nsDocShellLoadState& aOther)
mPendingRedirectedChannel(aOther.mPendingRedirectedChannel), mPendingRedirectedChannel(aOther.mPendingRedirectedChannel),
mOriginalURIString(aOther.mOriginalURIString), mOriginalURIString(aOther.mOriginalURIString),
mCancelContentJSEpoch(aOther.mCancelContentJSEpoch), mCancelContentJSEpoch(aOther.mCancelContentJSEpoch),
mLoadIdentifier(aOther.mLoadIdentifier) {} mLoadIdentifier(aOther.mLoadIdentifier),
mChannelInitialized(aOther.mChannelInitialized) {}
nsDocShellLoadState::nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier)
: mURI(aURI),
mResultPrincipalURIIsSome(false),
mKeepResultPrincipalURIIfSet(false),
mLoadReplace(false),
mInheritPrincipal(false),
mPrincipalIsExplicit(false),
mForceAllowDataURI(false),
mOriginalFrameSrc(false),
mIsFormSubmission(false),
mLoadType(LOAD_NORMAL),
mTarget(),
mSrcdocData(VoidString()),
mLoadFlags(0),
mFirstParty(false),
mHasValidUserGestureActivation(false),
mTypeHint(VoidCString()),
mFileName(VoidString()),
mIsFromProcessingFrameAttributes(false),
mLoadIdentifier(aLoadIdentifier),
mChannelInitialized(false) {
MOZ_ASSERT(aURI, "Cannot create a LoadState with a null URI!");
}
nsDocShellLoadState::~nsDocShellLoadState() {} nsDocShellLoadState::~nsDocShellLoadState() {}
nsresult nsDocShellLoadState::CreateFromPendingChannel( nsresult nsDocShellLoadState::CreateFromPendingChannel(
nsIChannel* aPendingChannel, nsDocShellLoadState** aResult) { nsIChannel* aPendingChannel, uint64_t aLoadIdentifier,
nsDocShellLoadState** aResult) {
// Create the nsDocShellLoadState object with default state pulled from the // Create the nsDocShellLoadState object with default state pulled from the
// passed-in channel. // passed-in channel.
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
@ -183,7 +192,8 @@ nsresult nsDocShellLoadState::CreateFromPendingChannel(
return rv; return rv;
} }
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(uri); RefPtr<nsDocShellLoadState> loadState =
new nsDocShellLoadState(uri, aLoadIdentifier);
loadState->mPendingRedirectedChannel = aPendingChannel; loadState->mPendingRedirectedChannel = aPendingChannel;
// Pull relevant state from the channel, and store it on the // Pull relevant state from the channel, and store it on the
@ -535,6 +545,11 @@ void nsDocShellLoadState::SetSourceBrowsingContext(
mSourceBrowsingContext = aSourceBrowsingContext; mSourceBrowsingContext = aSourceBrowsingContext;
} }
void nsDocShellLoadState::SetTargetBrowsingContext(
BrowsingContext* aTargetBrowsingContext) {
mTargetBrowsingContext = aTargetBrowsingContext;
}
nsIURI* nsDocShellLoadState::BaseURI() const { return mBaseURI; } nsIURI* nsDocShellLoadState::BaseURI() const { return mBaseURI; }
void nsDocShellLoadState::SetBaseURI(nsIURI* aBaseURI) { mBaseURI = aBaseURI; } void nsDocShellLoadState::SetBaseURI(nsIURI* aBaseURI) { mBaseURI = aBaseURI; }
@ -858,6 +873,7 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize() {
loadState.IsFormSubmission() = mIsFormSubmission; loadState.IsFormSubmission() = mIsFormSubmission;
loadState.LoadType() = mLoadType; loadState.LoadType() = mLoadType;
loadState.Target() = mTarget; loadState.Target() = mTarget;
loadState.TargetBrowsingContext() = mTargetBrowsingContext;
loadState.LoadFlags() = mLoadFlags; loadState.LoadFlags() = mLoadFlags;
loadState.FirstParty() = mFirstParty; loadState.FirstParty() = mFirstParty;
loadState.HasValidUserGestureActivation() = mHasValidUserGestureActivation; loadState.HasValidUserGestureActivation() = mHasValidUserGestureActivation;
@ -881,5 +897,6 @@ DocShellLoadStateInit nsDocShellLoadState::Serialize() {
loadState.SrcdocData() = mSrcdocData; loadState.SrcdocData() = mSrcdocData;
loadState.ResultPrincipalURI() = mResultPrincipalURI; loadState.ResultPrincipalURI() = mResultPrincipalURI;
loadState.LoadIdentifier() = mLoadIdentifier; loadState.LoadIdentifier() = mLoadIdentifier;
loadState.ChannelInitialized() = mChannelInitialized;
return loadState; return loadState;
} }

View File

@ -46,8 +46,10 @@ class nsDocShellLoadState final {
explicit nsDocShellLoadState( explicit nsDocShellLoadState(
const mozilla::dom::DocShellLoadStateInit& aLoadState); const mozilla::dom::DocShellLoadStateInit& aLoadState);
explicit nsDocShellLoadState(const nsDocShellLoadState& aOther); explicit nsDocShellLoadState(const nsDocShellLoadState& aOther);
nsDocShellLoadState(nsIURI* aURI, uint64_t aLoadIdentifier);
static nsresult CreateFromPendingChannel(nsIChannel* aPendingChannel, static nsresult CreateFromPendingChannel(nsIChannel* aPendingChannel,
uint64_t aLoadIdentifier,
nsDocShellLoadState** aResult); nsDocShellLoadState** aResult);
static nsresult CreateFromLoadURIOptions( static nsresult CreateFromLoadURIOptions(
@ -160,6 +162,12 @@ class nsDocShellLoadState final {
void SetSourceBrowsingContext(BrowsingContext* aSourceBrowsingContext); void SetSourceBrowsingContext(BrowsingContext* aSourceBrowsingContext);
const MaybeDiscarded<BrowsingContext>& TargetBrowsingContext() const {
return mTargetBrowsingContext;
}
void SetTargetBrowsingContext(BrowsingContext* aTargetBrowsingContext);
nsIURI* BaseURI() const; nsIURI* BaseURI() const;
void SetBaseURI(nsIURI* aBaseURI); void SetBaseURI(nsIURI* aBaseURI);
@ -238,9 +246,14 @@ class nsDocShellLoadState final {
return mCancelContentJSEpoch; return mCancelContentJSEpoch;
} }
void SetLoadIdentifier(uint64_t aIdent) { mLoadIdentifier = aIdent; }
uint64_t GetLoadIdentifier() const { return mLoadIdentifier; } uint64_t GetLoadIdentifier() const { return mLoadIdentifier; }
void SetChannelInitialized(bool aInitilized) {
mChannelInitialized = aInitilized;
}
bool GetChannelInitialized() const { return mChannelInitialized; }
// When loading a document through nsDocShell::LoadURI(), a special set of // When loading a document through nsDocShell::LoadURI(), a special set of
// flags needs to be set based on other values in nsDocShellLoadState. This // flags needs to be set based on other values in nsDocShellLoadState. This
// function calculates those flags, before the LoadState is passed to // function calculates those flags, before the LoadState is passed to
@ -357,6 +370,10 @@ class nsDocShellLoadState final {
// Target for load, like _content, _blank etc. // Target for load, like _content, _blank etc.
nsString mTarget; nsString mTarget;
// When set, this is the Target Browsing Context for the navigation
// after retargeting.
MaybeDiscarded<BrowsingContext> mTargetBrowsingContext;
// Post data stream (if POSTing) // Post data stream (if POSTing)
nsCOMPtr<nsIInputStream> mPostDataStream; nsCOMPtr<nsIInputStream> mPostDataStream;
@ -411,11 +428,14 @@ class nsDocShellLoadState final {
// when initiating the load. // when initiating the load.
mozilla::Maybe<int32_t> mCancelContentJSEpoch; mozilla::Maybe<int32_t> mCancelContentJSEpoch;
// An optional identifier that refers to a DocumentLoadListener // An identifier to make it possible to examine if two loads are
// created in the parent process for this loads. DocumentChannels // equal, and which browsing context they belong to (see
// created in the content process can use this to find and attach // BrowsingContext::{Get, Set}CurrentLoadIdentifier)
// to the in progress load. const uint64_t mLoadIdentifier;
uint64_t mLoadIdentifier;
// Optional value to indicate that a channel has been
// pre-initialized in the parent process.
bool mChannelInitialized;
}; };
#endif /* nsDocShellLoadState_h__ */ #endif /* nsDocShellLoadState_h__ */

View File

@ -16,6 +16,7 @@
#include "mozilla/EventStates.h" #include "mozilla/EventStates.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/dom/BindContext.h" #include "mozilla/dom/BindContext.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/CustomEvent.h" #include "mozilla/dom/CustomEvent.h"
#include "mozilla/dom/Document.h" #include "mozilla/dom/Document.h"
#include "mozilla/dom/HTMLFormControlsCollection.h" #include "mozilla/dom/HTMLFormControlsCollection.h"
@ -27,6 +28,7 @@
#include "nsContentList.h" #include "nsContentList.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDocShell.h" #include "nsDocShell.h"
#include "nsDocShellLoadState.h"
#include "nsError.h" #include "nsError.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
#include "nsHTMLDocument.h" #include "nsHTMLDocument.h"
@ -102,7 +104,6 @@ HTMLFormElement::HTMLFormElement(
mRequiredRadioButtonCounts(2), mRequiredRadioButtonCounts(2),
mValueMissingRadioGroups(2), mValueMissingRadioGroups(2),
mPendingSubmission(nullptr), mPendingSubmission(nullptr),
mSubmittingRequest(nullptr),
mDefaultSubmitElement(nullptr), mDefaultSubmitElement(nullptr),
mFirstSubmitInElements(nullptr), mFirstSubmitInElements(nullptr),
mFirstSubmitNotInElements(nullptr), mFirstSubmitNotInElements(nullptr),
@ -113,7 +114,6 @@ HTMLFormElement::HTMLFormElement(
mFormNumber(-1), mFormNumber(-1),
mGeneratingSubmit(false), mGeneratingSubmit(false),
mGeneratingReset(false), mGeneratingReset(false),
mIsSubmitting(false),
mDeferSubmission(false), mDeferSubmission(false),
mNotifiedObservers(false), mNotifiedObservers(false),
mNotifiedObserversResult(false), mNotifiedObserversResult(false),
@ -142,10 +142,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLFormElement,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageNameLookupTable) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageNameLookupTable)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPastNameLookupTable) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPastNameLookupTable)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedRadioButtons) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedRadioButtons)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTargetContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLFormElement, NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLFormElement,
nsGenericHTMLElement) nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTargetContext)
tmp->Clear(); tmp->Clear();
tmp->mExpandoAndGeneration.OwnerUnlinked(); tmp->mExpandoAndGeneration.OwnerUnlinked();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -634,16 +636,14 @@ nsresult HTMLFormElement::DoSubmit(Event* aEvent) {
return NS_OK; return NS_OK;
} }
if (mIsSubmitting) { if (IsSubmitting()) {
NS_WARNING("Preventing double form submission"); NS_WARNING("Preventing double form submission");
// XXX Should this return an error? // XXX Should this return an error?
return NS_OK; return NS_OK;
} }
// Mark us as submitting so that we don't try to submit again mTargetContext = nullptr;
mIsSubmitting = true; mCurrentLoadId = Nothing();
NS_ASSERTION(!mWebProgress && !mSubmittingRequest,
"Web progress / submitting request should not exist here!");
UniquePtr<HTMLFormSubmission> submission; UniquePtr<HTMLFormSubmission> submission;
@ -655,14 +655,10 @@ nsresult HTMLFormElement::DoSubmit(Event* aEvent) {
// Don't raise an error if form cannot navigate. // Don't raise an error if form cannot navigate.
if (StaticPrefs::dom_formdata_event_enabled() && if (StaticPrefs::dom_formdata_event_enabled() &&
rv == NS_ERROR_NOT_AVAILABLE) { rv == NS_ERROR_NOT_AVAILABLE) {
mIsSubmitting = false;
return NS_OK; return NS_OK;
} }
if (NS_FAILED(rv)) { NS_ENSURE_SUCCESS(rv, rv);
mIsSubmitting = false;
return rv;
}
// XXXbz if the script global is that for an sXBL/XBL2 doc, it won't // XXXbz if the script global is that for an sXBL/XBL2 doc, it won't
// be a window... // be a window...
@ -678,8 +674,6 @@ nsresult HTMLFormElement::DoSubmit(Event* aEvent) {
// defer this submission. let's remember it and return // defer this submission. let's remember it and return
// without submitting // without submitting
mPendingSubmission = std::move(submission); mPendingSubmission = std::move(submission);
// ensure reentrancy
mIsSubmitting = false;
return NS_OK; return NS_OK;
} }
@ -687,7 +681,6 @@ nsresult HTMLFormElement::DoSubmit(Event* aEvent) {
// perform the submission // perform the submission
// //
if (!submission) { if (!submission) {
mIsSubmitting = false;
#ifdef DEBUG #ifdef DEBUG
HTMLDialogElement* dialog = nullptr; HTMLDialogElement* dialog = nullptr;
for (nsIContent* parent = GetParent(); parent; for (nsIContent* parent = GetParent(); parent;
@ -764,7 +757,6 @@ nsresult HTMLFormElement::SubmitSubmission(
nsCOMPtr<nsIURI> actionURI = aFormSubmission->GetActionURL(); nsCOMPtr<nsIURI> actionURI = aFormSubmission->GetActionURL();
if (!actionURI) { if (!actionURI) {
mIsSubmitting = false;
return NS_OK; return NS_OK;
} }
@ -772,7 +764,6 @@ nsresult HTMLFormElement::SubmitSubmission(
Document* doc = GetComposedDoc(); Document* doc = GetComposedDoc();
nsCOMPtr<nsIDocShell> container = doc ? doc->GetDocShell() : nullptr; nsCOMPtr<nsIDocShell> container = doc ? doc->GetDocShell() : nullptr;
if (!container || IsEditable()) { if (!container || IsEditable()) {
mIsSubmitting = false;
return NS_OK; return NS_OK;
} }
@ -788,9 +779,6 @@ nsresult HTMLFormElement::SubmitSubmission(
// we're not submitting when submitting to a JS URL. That's kinda bogus, but // we're not submitting when submitting to a JS URL. That's kinda bogus, but
// there we are. // there we are.
bool schemeIsJavaScript = actionURI->SchemeIs("javascript"); bool schemeIsJavaScript = actionURI->SchemeIs("javascript");
if (schemeIsJavaScript) {
mIsSubmitting = false;
}
// //
// Notify observers of submit // Notify observers of submit
@ -804,7 +792,6 @@ nsresult HTMLFormElement::SubmitSubmission(
} }
if (cancelSubmit) { if (cancelSubmit) {
mIsSubmitting = false;
return NS_OK; return NS_OK;
} }
@ -813,7 +800,6 @@ nsresult HTMLFormElement::SubmitSubmission(
NS_ENSURE_SUBMIT_SUCCESS(rv); NS_ENSURE_SUBMIT_SUCCESS(rv);
if (cancelSubmit) { if (cancelSubmit) {
mIsSubmitting = false;
return NS_OK; return NS_OK;
} }
@ -821,6 +807,7 @@ nsresult HTMLFormElement::SubmitSubmission(
// Submit // Submit
// //
nsCOMPtr<nsIDocShell> docShell; nsCOMPtr<nsIDocShell> docShell;
uint64_t currentLoadId = 0;
{ {
AutoPopupStatePusher popupStatePusher(mSubmitPopupState); AutoPopupStatePusher popupStatePusher(mSubmitPopupState);
@ -835,31 +822,29 @@ nsresult HTMLFormElement::SubmitSubmission(
nsAutoString target; nsAutoString target;
aFormSubmission->GetTarget(target); aFormSubmission->GetTarget(target);
rv = nsDocShell::Cast(container)->OnLinkClickSync(
this, actionURI, target, VoidString(), postDataStream, nullptr, false, RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(actionURI);
getter_AddRefs(docShell), getter_AddRefs(mSubmittingRequest), loadState->SetTarget(target);
aFormSubmission->IsInitiatedFromUserInput()); loadState->SetPostDataStream(postDataStream);
loadState->SetFirstParty(true);
loadState->SetIsFormSubmission(true);
loadState->SetTriggeringPrincipal(NodePrincipal());
loadState->SetPrincipalToInherit(NodePrincipal());
loadState->SetCsp(GetCsp());
rv = nsDocShell::Cast(container)->OnLinkClickSync(this, loadState, false,
NodePrincipal());
NS_ENSURE_SUBMIT_SUCCESS(rv); NS_ENSURE_SUBMIT_SUCCESS(rv);
mTargetContext = loadState->TargetBrowsingContext().GetMaybeDiscarded();
currentLoadId = loadState->GetLoadIdentifier();
} }
// Even if the submit succeeds, it's possible for there to be no docshell // Even if the submit succeeds, it's possible for there to be no
// or request; for example, if it's to a named anchor within the same page // browsing context; for example, if it's to a named anchor within
// the submit will not really do anything. // the same page the submit will not really do anything.
if (docShell) { if (mTargetContext && !mTargetContext->IsDiscarded() && !schemeIsJavaScript) {
// If the channel is pending, we have to listen for web progress. mCurrentLoadId = Some(currentLoadId);
bool pending = false;
mSubmittingRequest->IsPending(&pending);
if (pending && !schemeIsJavaScript) {
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
NS_ASSERTION(webProgress, "nsIDocShell not converted to nsIWebProgress!");
rv = webProgress->AddProgressListener(this,
nsIWebProgress::NOTIFY_STATE_ALL);
NS_ENSURE_SUBMIT_SUCCESS(rv);
mWebProgress = do_GetWeakReference(webProgress);
NS_ASSERTION(mWebProgress, "can't hold weak ref to webprogress!");
} else {
ForgetCurrentSubmission();
}
} else { } else {
ForgetCurrentSubmission(); ForgetCurrentSubmission();
} }
@ -869,8 +854,6 @@ nsresult HTMLFormElement::SubmitSubmission(
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-dialog // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-dialog
nsresult HTMLFormElement::SubmitDialog(DialogFormSubmission* aFormSubmission) { nsresult HTMLFormElement::SubmitDialog(DialogFormSubmission* aFormSubmission) {
mIsSubmitting = false;
// Close the dialog subject. If there is a result, let that be the return // Close the dialog subject. If there is a result, let that be the return
// value. // value.
HTMLDialogElement* dialog = aFormSubmission->DialogElement(); HTMLDialogElement* dialog = aFormSubmission->DialogElement();
@ -1824,13 +1807,10 @@ int32_t HTMLFormElement::Length() { return mControls->Length(); }
void HTMLFormElement::ForgetCurrentSubmission() { void HTMLFormElement::ForgetCurrentSubmission() {
mNotifiedObservers = false; mNotifiedObservers = false;
mIsSubmitting = false;
mSubmittingRequest = nullptr; mSubmittingRequest = nullptr;
nsCOMPtr<nsIWebProgress> webProgress = do_QueryReferent(mWebProgress);
if (webProgress) { mTargetContext = nullptr;
webProgress->RemoveProgressListener(this); mCurrentLoadId = Nothing();
}
mWebProgress = nullptr;
} }
bool HTMLFormElement::CheckFormValidity( bool HTMLFormElement::CheckFormValidity(
@ -2497,5 +2477,12 @@ void HTMLFormElement::NodeInfoChanged(Document* aOldDoc) {
mFormNumber = -1; mFormNumber = -1;
} }
bool HTMLFormElement::IsSubmitting() const {
bool loading = mTargetContext && !mTargetContext->IsDiscarded() &&
mCurrentLoadId &&
mTargetContext->IsLoadingIdentifier(*mCurrentLoadId);
return loading;
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -10,6 +10,7 @@
#include "mozilla/AsyncEventDispatcher.h" #include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/dom/BrowsingContext.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIForm.h" #include "nsIForm.h"
#include "nsIFormControl.h" #include "nsIFormControl.h"
@ -574,6 +575,12 @@ class HTMLFormElement final : public nsGenericHTMLElement,
/** The web progress object we are currently listening to */ /** The web progress object we are currently listening to */
nsWeakPtr mWebProgress; nsWeakPtr mWebProgress;
/** The target browsing context, if any. */
RefPtr<BrowsingContext> mTargetContext;
/** The load identifier for the pending request created for a
* submit, used to be able to block double submits. */
Maybe<uint64_t> mCurrentLoadId;
/** The default submit element -- WEAK */ /** The default submit element -- WEAK */
nsGenericHTMLFormElement* mDefaultSubmitElement; nsGenericHTMLFormElement* mDefaultSubmitElement;
@ -619,8 +626,6 @@ class HTMLFormElement final : public nsGenericHTMLElement,
bool mGeneratingSubmit; bool mGeneratingSubmit;
/** Whether we are currently processing a reset event or not */ /** Whether we are currently processing a reset event or not */
bool mGeneratingReset; bool mGeneratingReset;
/** Whether we are submitting currently */
bool mIsSubmitting;
/** Whether the submission is to be deferred in case a script triggers it */ /** Whether the submission is to be deferred in case a script triggers it */
bool mDeferSubmission; bool mDeferSubmission;
/** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */ /** Whether we notified NS_FORMSUBMIT_SUBJECT listeners already */
@ -638,6 +643,8 @@ class HTMLFormElement final : public nsGenericHTMLElement,
bool mIsFiringSubmissionEvents; bool mIsFiringSubmissionEvents;
private: private:
bool IsSubmitting() const;
NotNull<const Encoding*> GetSubmitEncoding(); NotNull<const Encoding*> GetSubmitEncoding();
~HTMLFormElement(); ~HTMLFormElement();
}; };

View File

@ -3433,8 +3433,8 @@ mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
} }
RefPtr<nsDocShellLoadState> loadState; RefPtr<nsDocShellLoadState> loadState;
rv = nsDocShellLoadState::CreateFromPendingChannel(newChannel, rv = nsDocShellLoadState::CreateFromPendingChannel(
getter_AddRefs(loadState)); newChannel, aArgs.loadIdentifier(), getter_AddRefs(loadState));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_OK(); return IPC_OK();
} }
@ -4073,7 +4073,7 @@ mozilla::ipc::IPCResult ContentChild::RecvInternalLoad(
} }
BrowsingContext* context = aContext.get(); BrowsingContext* context = aContext.get();
context->InternalLoad(aLoadState, nullptr, nullptr); context->InternalLoad(aLoadState);
if (aTakeFocus) { if (aTakeFocus) {
if (nsCOMPtr<nsPIDOMWindowOuter> domWin = context->GetDOMWindow()) { if (nsCOMPtr<nsPIDOMWindowOuter> domWin = context->GetDOMWindow()) {

View File

@ -263,6 +263,7 @@ struct DocShellLoadStateInit
nsIContentSecurityPolicy Csp; nsIContentSecurityPolicy Csp;
MaybeDiscardedBrowsingContext SourceBrowsingContext; MaybeDiscardedBrowsingContext SourceBrowsingContext;
MaybeDiscardedBrowsingContext TargetBrowsingContext;
nsCString? OriginalURIString; nsCString? OriginalURIString;
int32_t? CancelContentJSEpoch; int32_t? CancelContentJSEpoch;
@ -278,6 +279,8 @@ struct DocShellLoadStateInit
// nsIChannel pendingRedirectedChannel; // sent through other mechanism // nsIChannel pendingRedirectedChannel; // sent through other mechanism
uint64_t LoadIdentifier; uint64_t LoadIdentifier;
bool ChannelInitialized;
}; };
struct TimedChannelInfo struct TimedChannelInfo

View File

@ -305,7 +305,7 @@ mozilla::ipc::IPCResult WindowGlobalParent::RecvInternalLoad(
// FIXME: We should really initiate the load in the parent before bouncing // FIXME: We should really initiate the load in the parent before bouncing
// back down to the child. // back down to the child.
targetBC->InternalLoad(aLoadState, nullptr, nullptr); targetBC->InternalLoad(aLoadState);
return IPC_OK(); return IPC_OK();
} }

View File

@ -103,6 +103,9 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
->GetBrowsingContext() ->GetBrowsingContext()
->HasValidTransientUserGestureActivation(); ->HasValidTransientUserGestureActivation();
GetDocShell()->GetBrowsingContext()->SetCurrentLoadIdentifier(
Some(mLoadState->GetLoadIdentifier()));
gNeckoChild->SendPDocumentChannelConstructor( gNeckoChild->SendPDocumentChannelConstructor(
this, GetDocShell()->GetBrowsingContext(), args); this, GetDocShell()->GetBrowsingContext(), args);

View File

@ -36,7 +36,7 @@ bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext,
loadState->URI()->GetSpecOrDefault().get())); loadState->URI()->GetSpecOrDefault().get()));
RefPtr<DocumentLoadListener::OpenPromise> promise; RefPtr<DocumentLoadListener::OpenPromise> promise;
if (loadState->GetLoadIdentifier()) { if (loadState->GetChannelInitialized()) {
promise = DocumentLoadListener::ClaimParentLoad( promise = DocumentLoadListener::ClaimParentLoad(
getter_AddRefs(mDocumentLoadListener), loadState->GetLoadIdentifier()); getter_AddRefs(mDocumentLoadListener), loadState->GetLoadIdentifier());
if (!promise) { if (!promise) {

View File

@ -377,6 +377,7 @@ auto DocumentLoadListener::Open(
OriginAttributes attrs; OriginAttributes attrs;
browsingContext->GetOriginAttributes(attrs); browsingContext->GetOriginAttributes(attrs);
mLoadIdentifier = aLoadState->GetLoadIdentifier();
MOZ_DIAGNOSTIC_ASSERT_IF(browsingContext->GetParent(), MOZ_DIAGNOSTIC_ASSERT_IF(browsingContext->GetParent(),
browsingContext->GetParentWindowContext()); browsingContext->GetParentWindowContext());
@ -525,9 +526,7 @@ auto DocumentLoadListener::Open(
browsingContext->CreateSessionHistoryEntryForLoad(aLoadState, mChannel); browsingContext->CreateSessionHistoryEntryForLoad(aLoadState, mChannel);
} }
if (auto* ctx = GetBrowsingContext()) { browsingContext->StartDocumentLoad(this);
ctx->StartDocumentLoad(this);
}
*aRv = NS_OK; *aRv = NS_OK;
mOpenPromise = new OpenPromise::Private(__func__); mOpenPromise = new OpenPromise::Private(__func__);
@ -540,7 +539,7 @@ auto DocumentLoadListener::Open(
/* static */ /* static */
bool DocumentLoadListener::OpenFromParent( bool DocumentLoadListener::OpenFromParent(
dom::CanonicalBrowsingContext* aBrowsingContext, dom::CanonicalBrowsingContext* aBrowsingContext,
nsDocShellLoadState* aLoadState, uint64_t aOuterWindowId, uint64_t* aOutIdent) { nsDocShellLoadState* aLoadState, uint64_t aOuterWindowId) {
LOG(("DocumentLoadListener::OpenFromParent")); LOG(("DocumentLoadListener::OpenFromParent"));
// We currently only support passing nullptr for aLoadInfo for // We currently only support passing nullptr for aLoadInfo for
@ -616,7 +615,6 @@ bool DocumentLoadListener::OpenFromParent(
nsCOMPtr<nsIRedirectChannelRegistrar> registrar = nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
RedirectChannelRegistrar::GetOrCreate(); RedirectChannelRegistrar::GetOrCreate();
uint64_t loadIdentifier = aLoadState->GetLoadIdentifier(); uint64_t loadIdentifier = aLoadState->GetLoadIdentifier();
*aOutIdent = loadIdentifier;
rv = registrar->RegisterChannel(nullptr, loadIdentifier); rv = registrar->RegisterChannel(nullptr, loadIdentifier);
MOZ_ASSERT(NS_SUCCEEDED(rv)); MOZ_ASSERT(NS_SUCCEEDED(rv));
// Register listener (as an nsIParentChannel) under our new identifier. // Register listener (as an nsIParentChannel) under our new identifier.
@ -684,7 +682,7 @@ void DocumentLoadListener::Disconnect() {
} }
if (auto* ctx = GetBrowsingContext()) { if (auto* ctx = GetBrowsingContext()) {
ctx->EndDocumentLoad(this); ctx->EndDocumentLoad(mDoingProcessSwitch);
} }
} }
@ -777,6 +775,12 @@ void DocumentLoadListener::FinishReplacementChannelSetup(nsresult aResult) {
"aResult=%x]", "aResult=%x]",
this, int(aResult))); this, int(aResult)));
auto endDocumentLoad = MakeScopeExit([&]() {
if (auto* ctx = GetBrowsingContext()) {
ctx->EndDocumentLoad(false);
}
});
if (mDoingProcessSwitch) { if (mDoingProcessSwitch) {
DisconnectListeners(NS_BINDING_ABORTED, NS_BINDING_ABORTED); DisconnectListeners(NS_BINDING_ABORTED, NS_BINDING_ABORTED);
} }
@ -802,9 +806,6 @@ void DocumentLoadListener::FinishReplacementChannelSetup(nsresult aResult) {
} }
mChannel->Cancel(aResult); mChannel->Cancel(aResult);
mChannel->Resume(); mChannel->Resume();
if (auto* ctx = GetBrowsingContext()) {
ctx->EndDocumentLoad(this);
}
return; return;
} }
@ -960,7 +961,7 @@ bool DocumentLoadListener::ResumeSuspendedChannel(
mChannel->Resume(); mChannel->Resume();
if (auto* ctx = GetBrowsingContext()) { if (auto* ctx = GetBrowsingContext()) {
ctx->EndDocumentLoad(this); ctx->EndDocumentLoad(mDoingProcessSwitch);
} }
return !mIsFinished; return !mIsFinished;
@ -977,6 +978,8 @@ void DocumentLoadListener::SerializeRedirectData(
mChannel->GetOriginalURI(getter_AddRefs(aArgs.uri())); mChannel->GetOriginalURI(getter_AddRefs(aArgs.uri()));
} }
aArgs.loadIdentifier() = mLoadIdentifier;
// I previously used HttpBaseChannel::CloneLoadInfoForRedirect, but that // I previously used HttpBaseChannel::CloneLoadInfoForRedirect, but that
// clears the principal to inherit, which fails tests (probably because this // clears the principal to inherit, which fails tests (probably because this
// 'redirect' is usually just an implementation detail). It's also http // 'redirect' is usually just an implementation detail). It's also http

View File

@ -137,7 +137,7 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// and clean up. // and clean up.
static bool OpenFromParent(dom::CanonicalBrowsingContext* aBrowsingContext, static bool OpenFromParent(dom::CanonicalBrowsingContext* aBrowsingContext,
nsDocShellLoadState* aLoadState, nsDocShellLoadState* aLoadState,
uint64_t aOuterWindowId, uint64_t* aOutIdent); uint64_t aOuterWindowId);
// Ensures that a load identifier allocated by OpenFromParent has // Ensures that a load identifier allocated by OpenFromParent has
// been deregistered if it hasn't already been claimed. // been deregistered if it hasn't already been claimed.
@ -228,6 +228,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
uint32_t aLoadFlags, uint32_t aLoadFlags,
dom::ContentParent* aParent) const; dom::ContentParent* aParent) const;
uint64_t GetLoadIdentifier() const { return mLoadIdentifier; }
protected: protected:
virtual ~DocumentLoadListener(); virtual ~DocumentLoadListener();
@ -440,6 +442,9 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// passed to the childChannel in order to identify it in the new process. // passed to the childChannel in order to identify it in the new process.
uint64_t mCrossProcessRedirectIdentifier = 0; uint64_t mCrossProcessRedirectIdentifier = 0;
// The id of the currently pending load.
uint64_t mLoadIdentifier = 0;
// True if cancelled. // True if cancelled.
bool mCancelled = false; bool mCancelled = false;

View File

@ -468,6 +468,7 @@ struct RedirectToRealChannelArgs {
nsString srcdocData; nsString srcdocData;
nsIURI baseUri; nsIURI baseUri;
SessionHistoryInfoAndId? sessionHistoryInfo; SessionHistoryInfoAndId? sessionHistoryInfo;
uint64_t loadIdentifier;
}; };
struct TimingStructArgs { struct TimingStructArgs {

View File

@ -337,8 +337,9 @@ mozilla::ipc::IPCResult NeckoParent::RecvPDocumentChannelConstructor(
} }
if (!p->Init(aContext.get_canonical(), aArgs)) { if (!p->Init(aContext.get_canonical(), aArgs)) {
return IPC_FAIL_NO_REASON(this); return IPC_FAIL(this, "Couldn't initialize DocumentChannel");
} }
return IPC_OK(); return IPC_OK();
} }

View File

@ -169,6 +169,9 @@ NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen(
gHttpHandler->OnOpeningDocumentRequest(this); gHttpHandler->OnOpeningDocumentRequest(this);
GetDocShell()->GetBrowsingContext()->SetCurrentLoadIdentifier(
Some(mLoadState->GetLoadIdentifier()));
nsresult rv = NS_OK; nsresult rv = NS_OK;
Maybe<dom::ClientInfo> initialClientInfo = mInitialClientInfo; Maybe<dom::ClientInfo> initialClientInfo = mInitialClientInfo;
auto promise = mDocumentLoadListener->Open( auto promise = mDocumentLoadListener->Open(