From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- dom/base/LocationBase.cpp | 278 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 dom/base/LocationBase.cpp (limited to 'dom/base/LocationBase.cpp') diff --git a/dom/base/LocationBase.cpp b/dom/base/LocationBase.cpp new file mode 100644 index 0000000000..bdf7edc134 --- /dev/null +++ b/dom/base/LocationBase.cpp @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/LocationBase.h" +#include "nsIScriptSecurityManager.h" +#include "nsIScriptContext.h" +#include "nsDocShellLoadState.h" +#include "nsIWebNavigation.h" +#include "nsNetUtil.h" +#include "nsCOMPtr.h" +#include "nsError.h" +#include "nsContentUtils.h" +#include "nsGlobalWindowInner.h" +#include "mozilla/NullPrincipal.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/ReferrerInfo.h" +#include "mozilla/dom/WindowContext.h" + +namespace mozilla::dom { + +already_AddRefed LocationBase::CheckURL( + nsIURI* aURI, nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { + RefPtr bc(GetBrowsingContext()); + if (NS_WARN_IF(!bc)) { + aRv.Throw(NS_ERROR_NOT_AVAILABLE); + return nullptr; + } + + nsCOMPtr triggeringPrincipal; + nsCOMPtr sourceURI; + ReferrerPolicy referrerPolicy = ReferrerPolicy::_empty; + nsCOMPtr referrerInfo; + + // Get security manager. + nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager(); + if (NS_WARN_IF(!ssm)) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + // Check to see if URI is allowed. We're not going to worry about a + // window ID here because it's not 100% clear which window's id we + // would want, and we're throwing a content-visible exception + // anyway. + nsresult rv = ssm->CheckLoadURIWithPrincipal( + &aSubjectPrincipal, aURI, nsIScriptSecurityManager::STANDARD, 0); + if (NS_WARN_IF(NS_FAILED(rv))) { + nsAutoCString spec; + aURI->GetSpec(spec); + aRv.ThrowTypeError(spec); + return nullptr; + } + + // Make the load's referrer reflect changes to the document's URI caused by + // push/replaceState, if possible. First, get the document corresponding to + // fp. If the document's original URI (i.e. its URI before + // push/replaceState) matches the principal's URI, use the document's + // current URI as the referrer. If they don't match, use the principal's + // URI. + // + // The triggering principal for this load should be the principal of the + // incumbent document (which matches where the referrer information is + // coming from) when there is an incumbent document, and the subject + // principal otherwise. Note that the URI in the triggering principal + // may not match the referrer URI in various cases, notably including + // the cases when the incumbent document's document URI was modified + // after the document was loaded. + + nsCOMPtr incumbent = + do_QueryInterface(mozilla::dom::GetIncumbentGlobal()); + nsCOMPtr doc = incumbent ? incumbent->GetDoc() : nullptr; + + // Create load info + RefPtr loadState = new nsDocShellLoadState(aURI); + + if (!doc) { + // No document; just use our subject principal as the triggering principal. + loadState->SetTriggeringPrincipal(&aSubjectPrincipal); + return loadState.forget(); + } + + nsCOMPtr docOriginalURI, docCurrentURI, principalURI; + docOriginalURI = doc->GetOriginalURI(); + docCurrentURI = doc->GetDocumentURI(); + nsCOMPtr principal = doc->NodePrincipal(); + + triggeringPrincipal = doc->NodePrincipal(); + referrerPolicy = doc->GetReferrerPolicy(); + + bool urisEqual = false; + if (docOriginalURI && docCurrentURI && principal) { + principal->EqualsURI(docOriginalURI, &urisEqual); + } + if (urisEqual) { + referrerInfo = new ReferrerInfo(docCurrentURI, referrerPolicy); + } else { + principal->CreateReferrerInfo(referrerPolicy, getter_AddRefs(referrerInfo)); + } + loadState->SetTriggeringPrincipal(triggeringPrincipal); + loadState->SetTriggeringSandboxFlags(doc->GetSandboxFlags()); + loadState->SetCsp(doc->GetCsp()); + if (referrerInfo) { + loadState->SetReferrerInfo(referrerInfo); + } + loadState->SetHasValidUserGestureActivation( + doc->HasValidTransientUserGestureActivation()); + + loadState->SetTriggeringWindowId(doc->InnerWindowID()); + loadState->SetTriggeringStorageAccess(doc->UsingStorageAccess()); + + return loadState.forget(); +} + +void LocationBase::SetURI(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal, + ErrorResult& aRv, bool aReplace) { + RefPtr bc = GetBrowsingContext(); + if (!bc || bc->IsDiscarded()) { + return; + } + + CallerType callerType = aSubjectPrincipal.IsSystemPrincipal() + ? CallerType::System + : CallerType::NonSystem; + + nsresult rv = bc->CheckLocationChangeRateLimit(callerType); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return; + } + + RefPtr loadState = + CheckURL(aURI, aSubjectPrincipal, aRv); + if (aRv.Failed()) { + return; + } + + if (aReplace) { + loadState->SetLoadType(LOAD_STOP_CONTENT_AND_REPLACE); + } else { + loadState->SetLoadType(LOAD_STOP_CONTENT); + } + + // Get the incumbent script's browsing context to set as source. + nsCOMPtr sourceWindow = + nsContentUtils::IncumbentInnerWindow(); + if (sourceWindow) { + WindowContext* context = sourceWindow->GetWindowContext(); + loadState->SetSourceBrowsingContext(sourceWindow->GetBrowsingContext()); + loadState->SetHasValidUserGestureActivation( + context && context->HasValidTransientUserGestureActivation()); + } + + loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE); + loadState->SetFirstParty(true); + + rv = bc->LoadURI(loadState); + if (NS_WARN_IF(NS_FAILED(rv))) { + if (rv == NS_ERROR_DOM_BAD_CROSS_ORIGIN_URI && + net::SchemeIsJavascript(loadState->URI())) { + // Per spec[1], attempting to load a javascript: URI into a cross-origin + // BrowsingContext is a no-op, and should not raise an exception. + // Technically, Location setters run with exceptions enabled should only + // throw an exception[2] when the caller is not allowed to navigate[3] the + // target browsing context due to sandboxing flags or not being + // closely-related enough, though in practice we currently throw for other + // reasons as well. + // + // [1]: + // https://html.spec.whatwg.org/multipage/browsing-the-web.html#javascript-protocol + // [2]: + // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate + // [3]: + // https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-navigate + return; + } + aRv.Throw(rv); + return; + } + + Document* doc = bc->GetDocument(); + if (doc && nsContentUtils::IsExternalProtocol(aURI)) { + doc->EnsureNotEnteringAndExitFullscreen(); + } +} + +void LocationBase::SetHref(const nsAString& aHref, + nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) { + DoSetHref(aHref, aSubjectPrincipal, false, aRv); +} + +void LocationBase::DoSetHref(const nsAString& aHref, + nsIPrincipal& aSubjectPrincipal, bool aReplace, + ErrorResult& aRv) { + // Get the source of the caller + nsCOMPtr base = GetSourceBaseURL(); + SetHrefWithBase(aHref, base, aSubjectPrincipal, aReplace, aRv); +} + +void LocationBase::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase, + nsIPrincipal& aSubjectPrincipal, + bool aReplace, ErrorResult& aRv) { + nsresult result; + nsCOMPtr newUri; + + if (Document* doc = GetEntryDocument()) { + result = NS_NewURI(getter_AddRefs(newUri), aHref, + doc->GetDocumentCharacterSet(), aBase); + } else { + result = NS_NewURI(getter_AddRefs(newUri), aHref, nullptr, aBase); + } + + if (NS_FAILED(result) || !newUri) { + aRv.ThrowSyntaxError("'"_ns + NS_ConvertUTF16toUTF8(aHref) + + "' is not a valid URL."_ns); + return; + } + + /* Check with the scriptContext if it is currently processing a script tag. + * If so, this must be a