Bug 1948596 - Implement #can-have-its-url-rewritten. r=dom-core,edgar
This extracts common code from nsDocShell::AddState. Differential Revision: https://phabricator.services.mozilla.com/D243069
This commit is contained in:
@@ -11179,7 +11179,8 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
|
|||||||
|
|
||||||
// Here's what we do, roughly in the order specified by HTML5. The specific
|
// Here's what we do, roughly in the order specified by HTML5. The specific
|
||||||
// steps we are executing are at
|
// steps we are executing are at
|
||||||
// <https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate>
|
// <https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate>,
|
||||||
|
// <https://html.spec.whatwg.org/#shared-history-push/replace-state-steps>,
|
||||||
// and
|
// and
|
||||||
// <https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps>.
|
// <https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps>.
|
||||||
// This function basically implements #dom-history-pushstate and
|
// This function basically implements #dom-history-pushstate and
|
||||||
@@ -11310,44 +11311,9 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
|
|||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7.4 and 7.5: Same-origin check.
|
if (!document->CanRewriteURL(newURI)) {
|
||||||
if (!nsContentUtils::URIIsLocalFile(newURI)) {
|
|
||||||
// In addition to checking that the security manager says that
|
|
||||||
// the new URI has the same origin as our current URI, we also
|
|
||||||
// check that the two URIs have the same userpass. (The
|
|
||||||
// security manager says that |http://foo.com| and
|
|
||||||
// |http://me@foo.com| have the same origin.) currentURI
|
|
||||||
// won't contain the password part of the userpass, so this
|
|
||||||
// means that it's never valid to specify a password in a
|
|
||||||
// pushState or replaceState URI.
|
|
||||||
|
|
||||||
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
|
||||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
|
|
||||||
NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
// It's very important that we check that newURI is of the same
|
|
||||||
// origin as currentURI, not docBaseURI, because a page can
|
|
||||||
// set docBaseURI arbitrarily to any domain.
|
|
||||||
nsAutoCString currentUserPass, newUserPass;
|
|
||||||
NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
|
|
||||||
NS_ERROR_FAILURE);
|
|
||||||
NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), NS_ERROR_FAILURE);
|
|
||||||
bool isPrivateWin =
|
|
||||||
document->NodePrincipal()->OriginAttributesRef().IsPrivateBrowsing();
|
|
||||||
if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, newURI, true,
|
|
||||||
isPrivateWin)) ||
|
|
||||||
!currentUserPass.Equals(newUserPass)) {
|
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// It's a file:// URI
|
|
||||||
nsCOMPtr<nsIPrincipal> principal = document->GetPrincipal();
|
|
||||||
|
|
||||||
if (!principal || NS_FAILED(principal->CheckMayLoadWithReporting(
|
|
||||||
newURI, false, document->InnerWindowID()))) {
|
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentURI) {
|
if (currentURI) {
|
||||||
currentURI->Equals(newURI, &equalURIs);
|
currentURI->Equals(newURI, &equalURIs);
|
||||||
|
|||||||
@@ -13284,6 +13284,47 @@ bool Document::HasBeenScrolled() const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Document::CanRewriteURL(nsIURI* aTargetURL) const {
|
||||||
|
if (nsContentUtils::URIIsLocalFile(aTargetURL)) {
|
||||||
|
// It's a file:// URI
|
||||||
|
nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
|
||||||
|
return NS_SUCCEEDED(principal->CheckMayLoadWithReporting(
|
||||||
|
mDocumentURI, false, InnerWindowID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
||||||
|
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
|
||||||
|
if (!secMan) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's very important that we check that aTargetURL is of the same
|
||||||
|
// origin as mDocumentURI, not docBaseURI, because a page can
|
||||||
|
// set docBaseURI arbitrarily to any domain.
|
||||||
|
bool isPrivateWin =
|
||||||
|
NodePrincipal()->OriginAttributesRef().IsPrivateBrowsing();
|
||||||
|
if (NS_FAILED(secMan->CheckSameOriginURI(mDocumentURI, aTargetURL, true,
|
||||||
|
isPrivateWin))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In addition to checking that the security manager says that
|
||||||
|
// the new URI has the same origin as our current URI, we also
|
||||||
|
// check that the two URIs have the same userpass. (The
|
||||||
|
// security manager says that |http://foo.com| and
|
||||||
|
// |http://me@foo.com| have the same origin.) mDocumentURI
|
||||||
|
// won't contain the password part of the userpass, so this
|
||||||
|
// means that it's never valid to specify a password in a
|
||||||
|
// pushState or replaceState URI.
|
||||||
|
nsAutoCString currentUserPass, newUserPass;
|
||||||
|
if (NS_FAILED(mDocumentURI->GetUserPass(currentUserPass)) ||
|
||||||
|
NS_FAILED(aTargetURL->GetUserPass(newUserPass))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentUserPass.Equals(newUserPass);
|
||||||
|
}
|
||||||
|
|
||||||
nsISupports* Document::GetCurrentContentSink() {
|
nsISupports* Document::GetCurrentContentSink() {
|
||||||
return mParser ? mParser->GetContentSink() : nullptr;
|
return mParser ? mParser->GetContentSink() : nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2696,6 +2696,12 @@ class Document : public nsINode,
|
|||||||
return inner && inner->IsCurrentInnerWindow() && inner->GetDoc() == this;
|
return inner && inner->IsCurrentInnerWindow() && inner->GetDoc() == this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if the documents current url can be re-written to `aTargetURL`.
|
||||||
|
* This implements https://html.spec.whatwg.org/#can-have-its-url-rewritten.
|
||||||
|
*/
|
||||||
|
bool CanRewriteURL(nsIURI* aTargetURL) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if this document is fully active as described by spec.
|
* Return true if this document is fully active as described by spec.
|
||||||
* https://html.spec.whatwg.org/multipage/document-sequences.html#fully-active
|
* https://html.spec.whatwg.org/multipage/document-sequences.html#fully-active
|
||||||
|
|||||||
@@ -423,10 +423,6 @@ bool Navigation::FireDownloadRequestNavigateEvent(
|
|||||||
/* aClassicHistoryAPIState */ nullptr, aFilename);
|
/* aClassicHistoryAPIState */ nullptr, aFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of this will be done in Bug 1948596.
|
|
||||||
// https://html.spec.whatwg.org/#can-have-its-url-rewritten
|
|
||||||
static bool CanBeRewritten(nsIURI* aURI, nsIURI* aOtherURI) { return false; }
|
|
||||||
|
|
||||||
static bool HasHistoryActionActivation(
|
static bool HasHistoryActionActivation(
|
||||||
Maybe<nsGlobalWindowInner&> aRelevantGlobalObject) {
|
Maybe<nsGlobalWindowInner&> aRelevantGlobalObject) {
|
||||||
return aRelevantGlobalObject
|
return aRelevantGlobalObject
|
||||||
@@ -551,9 +547,8 @@ bool Navigation::InnerFireNavigateEvent(
|
|||||||
.valueOr(nullptr);
|
.valueOr(nullptr);
|
||||||
|
|
||||||
// Step 9
|
// Step 9
|
||||||
init.mCanIntercept =
|
init.mCanIntercept = document &&
|
||||||
document &&
|
document->CanRewriteURL(aDestination->GetURI()) &&
|
||||||
CanBeRewritten(document->GetDocumentURI(), aDestination->GetURI()) &&
|
|
||||||
(aDestination->SameDocument() ||
|
(aDestination->SameDocument() ||
|
||||||
aNavigationType != NavigationType::Traverse);
|
aNavigationType != NavigationType::Traverse);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user