/* -*- 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/. */
// Implementation of ClassInfo is required to serialize/deserialize
NS_IMPL_CLASSINFO(ReferrerInfo, nullptr, nsIClassInfo::THREADSAFE,
REFERRERINFO_CID)
/* * Parse ReferrerPolicy from token. * The supported tokens are defined in ReferrerPolicy.webidl. * The legacy tokens are "never", "default", "always" and * "origin-when-crossorigin". The legacy tokens are only supported in meta * referrer content * * @param aContent content string to be transformed into * ReferrerPolicyEnum, e.g. "origin".
*/
ReferrerPolicy ReferrerPolicyFromToken(const nsAString& aContent, bool allowedLegacyToken) {
nsString lowerContent(aContent);
ToLowerCase(lowerContent);
uint8_t numStr = (sizeof(sLegacyReferrerPolicyToken) / sizeof(sLegacyReferrerPolicyToken[0])); for (uint8_t i = 0; i < numStr; i++) { if (lowerContent.EqualsASCII(sLegacyReferrerPolicyToken[i].mToken)) { return sLegacyReferrerPolicyToken[i].mPolicy;
}
}
}
// Return no referrer policy (empty string) if it's not a valid enum value. return StringToEnum<ReferrerPolicy>(lowerContent)
.valueOr(ReferrerPolicy::_empty);
}
// static
ReferrerPolicy ReferrerInfo::ReferrerPolicyFromMetaString( const nsAString& aContent) { // This is implemented as described in // https://html.spec.whatwg.org/multipage/semantics.html#meta-referrer // Meta referrer accepts both supported tokens in ReferrerPolicy.webidl and // legacy tokens. return ReferrerPolicyFromToken(aContent, true);
}
// static
ReferrerPolicy ReferrerInfo::ReferrerPolicyAttributeFromString( const nsAString& aContent) { // This is implemented as described in // https://html.spec.whatwg.org/multipage/infrastructure.html#referrer-policy-attribute // referrerpolicy attribute only accepts supported tokens in // ReferrerPolicy.webidl return ReferrerPolicyFromToken(aContent, false);
}
// static
ReferrerPolicy ReferrerInfo::ReferrerPolicyFromHeaderString( const nsAString& aContent) { // Multiple headers could be concatenated into one comma-separated // list of policies. Need to tokenize the multiple headers.
ReferrerPolicyEnum referrerPolicy = ReferrerPolicy::_empty; for (constauto& token : nsCharSeparatedTokenizer(aContent, ',').ToRange()) { if (token.IsEmpty()) { continue;
}
// Referrer-Policy header only accepts supported tokens in // ReferrerPolicy.webidl
ReferrerPolicyEnum policy = ReferrerPolicyFromToken(token, false); // If there are multiple policies available, the last valid policy should be // used. // https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values if (policy != ReferrerPolicy::_empty) {
referrerPolicy = policy;
}
} return referrerPolicy;
}
// We only check if the channel is isolated if it's in the parent process // with the rejection of third party contexts is enabled. We don't need to // check this in content processes since the tracking state of the channel // is unknown here and the referrer policy would be updated when the channel // starts connecting in the parent process. if (XRE_IsParentProcess() && cjs->GetRejectThirdPartyContexts()) {
uint32_t rejectedReason = 0;
thirdPartyTrackerIsolated =
!ShouldAllowAccessFor(aChannel, aURI, &rejectedReason) &&
rejectedReason != static_cast<uint32_t>(
nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN); // Here we intentionally do not notify about the rejection reason, if any // in order to avoid this check to have any visible side-effects (e.g. a // web console report.)
}
}
// Select the appropriate pref starting with // "network.http.referer.defaultPolicy" to use based on private-browsing // ("pbmode") AND third-party trackers ("trackers"). return DefaultReferrerPolicyToReferrerPolicy(
thirdPartyTrackerIsolated
? GetDefaultThirdPartyReferrerPolicyPref(aPrivateBrowsing)
: GetDefaultFirstPartyReferrerPolicyPref(aPrivateBrowsing));
}
// It's ok to send referrer for https-to-http scenarios if the referrer // policy is "unsafe-url", "origin", or "origin-when-cross-origin". // in other referrer policies, https->http is not allowed... bool uriIsHttpsScheme = aURI->SchemeIs("https"); if (aPolicy != ReferrerPolicy::Unsafe_url &&
aPolicy != ReferrerPolicy::Origin_when_cross_origin &&
aPolicy != ReferrerPolicy::Origin && !uriIsHttpsScheme) { return NS_OK;
}
nsresult rv = aURI->GetAsciiHost(uriHost); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
rv = aReferrer->GetAsciiHost(referrerHost); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// Send an empty referrer if xorigin and leaving a .onion domain. if (StaticPrefs::network_http_referer_hideOnionSource() &&
!uriHost.Equals(referrerHost) &&
StringEndsWith(referrerHost, ".onion"_ns)) { return NS_OK;
}
switch (GetUserXOriginSendingPolicy()) { // Check policy for sending referrer only when hosts match case XOriginSendingPolicy::ePolicySendWhenSameHost: { if (!uriHost.Equals(referrerHost)) { return NS_OK;
} break;
}
case XOriginSendingPolicy::ePolicySendWhenSameDomain: {
nsCOMPtr<nsIEffectiveTLDService> eTLDService =
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); if (!eTLDService) { // check policy for sending only when effective top level domain // matches. this falls back on using host if eTLDService does not work if (!uriHost.Equals(referrerHost)) { return NS_OK;
} break;
}
rv = eTLDService->GetBaseDomain(aURI, extraDomains, uriDomain); if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { // uri is either an IP address, an alias such as 'localhost', an eTLD // such as 'co.uk', or the empty string. Uses the normalized host in // such cases.
rv = aURI->GetAsciiHost(uriDomain);
}
if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
rv = eTLDService->GetBaseDomain(aReferrer, extraDomains, referrerDomain); if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { // referrer is either an IP address, an alias such as 'localhost', an // eTLD such as 'co.uk', or the empty string. Uses the normalized host // in such cases.
rv = aReferrer->GetAsciiHost(referrerDomain);
}
if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
if (!uriDomain.Equals(referrerDomain)) { return NS_OK;
} break;
}
default: break;
}
aAllowed = true; return NS_OK;
}
// This roughly implements Step 3.1. of // https://fetch.spec.whatwg.org/#append-a-request-origin-header /* static */ bool ReferrerInfo::ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel,
nsIURI* aOriginURI) {
MOZ_ASSERT(aChannel);
MOZ_ASSERT(aOriginURI);
// If request’s mode is not "cors", then switch on request’s referrer policy:
RequestMode requestMode = RequestMode::No_cors;
MOZ_ALWAYS_SUCCEEDS(aChannel->GetRequestMode(&requestMode)); if (requestMode == RequestMode::Cors) { returnfalse;
}
nsCOMPtr<nsIReferrerInfo> referrerInfo;
NS_ENSURE_SUCCESS(aChannel->GetReferrerInfo(getter_AddRefs(referrerInfo)), false); if (!referrerInfo) { returnfalse;
}
// "no-referrer": enum ReferrerPolicy policy = referrerInfo->ReferrerPolicy(); if (policy == ReferrerPolicy::No_referrer) { // Set serializedOrigin to `null`. // Note: Returning true is the same as setting the serializedOrigin to null // in this method. returntrue;
}
// "no-referrer-when-downgrade": // "strict-origin": // "strict-origin-when-cross-origin": // If request’s origin is a tuple origin, its scheme is "https", and // request’s current URL’s scheme is not "https", then set serializedOrigin // to `null`. bool allowed = false;
nsCOMPtr<nsIURI> uri;
NS_ENSURE_SUCCESS(aChannel->GetURI(getter_AddRefs(uri)), false); if (NS_SUCCEEDED(ReferrerInfo::HandleSecureToInsecureReferral(
aOriginURI, uri, policy, allowed)) &&
!allowed) { returntrue;
}
// "same-origin": if (policy == ReferrerPolicy::Same_origin) { // If request’s origin is not same origin with request’s current URL’s // origin, then set serializedOrigin to `null`. return ReferrerInfo::IsCrossOriginRequest(aChannel);
}
switch (mPolicy) { case ReferrerPolicy::Origin: case ReferrerPolicy::Strict_origin:
trimmingPolicy = TrimmingPolicy::ePolicySchemeHostPort; break;
case ReferrerPolicy::Origin_when_cross_origin: case ReferrerPolicy::Strict_origin_when_cross_origin: if (trimmingPolicy != TrimmingPolicy::ePolicySchemeHostPort &&
IsReferrerCrossOrigin(aChannel, aReferrer)) { // Ignore set trimmingPolicy if it is already the strictest // policy.
trimmingPolicy = TrimmingPolicy::ePolicySchemeHostPort;
} break;
// This function is called when a nonempty referrer value is allowed to // send. For the next 3 policies: same-origin, no-referrer-when-downgrade, // unsafe-url, without trimming we should have a full uri. And the trimming // policy only depends on user prefs. case ReferrerPolicy::Same_origin: case ReferrerPolicy::No_referrer_when_downgrade: case ReferrerPolicy::Unsafe_url: if (trimmingPolicy != TrimmingPolicy::ePolicySchemeHostPort) { // Ignore set trimmingPolicy if it is already the strictest // policy. Apply the user cross-origin trimming policy if it's more // restrictive than the general one. if (GetUserXOriginTrimmingPolicy() != TrimmingPolicy::ePolicyFullURI &&
IsCrossOriginRequest(aChannel)) {
trimmingPolicy =
std::max(trimmingPolicy, GetUserXOriginTrimmingPolicy());
}
} break;
case ReferrerPolicy::No_referrer: case ReferrerPolicy::_empty: default:
MOZ_ASSERT_UNREACHABLE("Unexpected value"); break;
}
if (aInAndOutTrimmedReferrer.Length() <=
StaticPrefs::network_http_referer_referrerLengthLimit()) { return NS_OK;
}
nsAutoString referrerLengthLimit;
referrerLengthLimit.AppendInt(
StaticPrefs::network_http_referer_referrerLengthLimit()); if (aTrimmingPolicy == ePolicyFullURI ||
aTrimmingPolicy == ePolicySchemeHostPortPath) { // If referrer header is over max Length, down to origin
nsresult rv = GetOriginFromReferrerURI(aReferrer, aInAndOutTrimmedReferrer); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// Step 6 within https://w3c.github.io/webappsec-referrer-policy/#strip-url // states that the trailing "/" does not need to get stripped. However, // GetOriginFromReferrerURI() also removes any trailing "/" hence we have to // add it back here.
aInAndOutTrimmedReferrer.AppendLiteral("/"); if (aInAndOutTrimmedReferrer.Length() <=
StaticPrefs::network_http_referer_referrerLengthLimit()) {
AutoTArray<nsString, 2> params = {
referrerLengthLimit, NS_ConvertUTF8toUTF16(aInAndOutTrimmedReferrer)};
LogMessageToConsole(aChannel, "ReferrerLengthOverLimitation", params); return NS_OK;
}
}
// If we end up here either the trimmingPolicy is equal to // 'ePolicySchemeHostPort' or the 'origin' of any other policy is still over // the length limit. If so, truncate the referrer entirely.
AutoTArray<nsString, 2> params = {
referrerLengthLimit, NS_ConvertUTF8toUTF16(aInAndOutTrimmedReferrer)};
LogMessageToConsole(aChannel, "ReferrerOriginLengthOverLimitation", params);
aInAndOutTrimmedReferrer.Truncate();
return NS_OK;
}
nsresult ReferrerInfo::GetOriginFromReferrerURI(nsIURI* aReferrer,
nsACString& aResult) const {
MOZ_ASSERT(aReferrer);
aResult.Truncate(); // We want the IDN-normalized PrePath. That's not something currently // available and there doesn't yet seem to be justification for adding it to // the interfaces, so just build it up from scheme+AsciiHostPort
nsAutoCString scheme, asciiHostPort;
nsresult rv = aReferrer->GetScheme(scheme); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
aResult = scheme;
aResult.AppendLiteral("://"); // Note we explicitly cleared UserPass above, so do not need to build it.
rv = aReferrer->GetAsciiHostPort(asciiHostPort); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
if (aTrimmingPolicy == TrimmingPolicy::ePolicySchemeHostPortPath) {
nsCOMPtr<nsIURL> url(do_QueryInterface(aReferrer)); if (url) {
nsAutoCString path;
rv = url->GetFilePath(path); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
aResult.Append(path); return NS_OK;
}
}
// Step 6 within https://w3c.github.io/webappsec-referrer-policy/#strip-url // states that the trailing "/" does not need to get stripped. However, // GetOriginFromReferrerURI() also removes any trailing "/" hence we have to // add it back here.
aResult.AppendLiteral("/"); return NS_OK;
}
// We only care about the less restricted policies. if (aPolicy != ReferrerPolicy::Unsafe_url &&
aPolicy != ReferrerPolicy::No_referrer_when_downgrade &&
aPolicy != ReferrerPolicy::Origin_when_cross_origin) { returnfalse;
}
// Return early if we don't want to ignore less restricted policies for the // top navigation. if (loadInfo->GetExternalContentPolicyType() ==
ExtContentPolicy::TYPE_DOCUMENT) { bool isEnabledForTopNavigation =
isPrivate
? StaticPrefs::
network_http_referer_disallowCrossSiteRelaxingDefault_pbmode_top_navigation()
: StaticPrefs::
network_http_referer_disallowCrossSiteRelaxingDefault_top_navigation(); if (!isEnabledForTopNavigation) { returnfalse;
}
// We have to get the value of the contentBlockingAllowList earlier because // the channel hasn't been opened yet here. Note that we only need to do // this for first-party navigation. For third-party loads, the value is // inherited from the parent. if (XRE_IsParentProcess()) {
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
Unused << loadInfo->GetCookieJarSettings(
getter_AddRefs(cookieJarSettings));
// We don't ignore less restricted referrer policies if ETP is toggled off. // This would affect iframe loads and top navigation. For iframes, it will // stop ignoring if the first-party site toggled ETP off. For top navigation, // it depends on the ETP toggle for the destination site. if (ContentBlockingAllowList::Check(aChannel)) { returnfalse;
}
if (!isEnabled) { // Log the warning message to console to inform that we will ignore // less restricted policies for cross-site requests in the future. if (isCrossSite) {
nsCOMPtr<nsIURI> uri;
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, false);
// Check if the channel is triggered by the system or the extension. auto* triggerBasePrincipal =
BasePrincipal::Cast(loadInfo->TriggeringPrincipal()); if (triggerBasePrincipal->IsSystemPrincipal() ||
triggerBasePrincipal->AddonPolicy()) { returnfalse;
}
if (isCrossSite) { // Log the console message to say that the less restricted policy was // ignored.
nsCOMPtr<nsIURI> uri;
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, true);
/** * Check whether the given node has referrerpolicy attribute and parse * referrer policy from the attribute. * Currently, referrerpolicy attribute is supported in a, area, img, iframe, * script, or link element.
*/ static ReferrerPolicy ReferrerPolicyFromAttribute(const Element& aElement) { if (!aElement.IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area,
nsGkAtoms::script, nsGkAtoms::iframe,
nsGkAtoms::link, nsGkAtoms::img)) { return ReferrerPolicy::_empty;
} return aElement.GetReferrerPolicyAsEnum();
}
staticbool HasRelNoReferrer(const Element& aElement) { // rel=noreferrer is only supported in <a>, <area>, and <form> if (!aElement.IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area,
nsGkAtoms::form) &&
!aElement.IsSVGElement(nsGkAtoms::a)) { returnfalse;
}
// Referrer policy from referrerpolicy attribute will have a higher priority // than referrer policy from <meta> tag and Referrer-Policy header.
mPolicy = ReferrerPolicyFromAttribute(*aElement); if (mPolicy == ReferrerPolicy::_empty) { // Fallback to use document's referrer poicy if we don't have referrer // policy from attribute.
mPolicy = aElement->OwnerDoc()->GetReferrerPolicy();
}
nsCOMPtr<nsIReferrerInfo> referrerInfo; if (!aPrincipal || aPrincipal->IsSystemPrincipal()) {
referrerInfo = new ReferrerInfo(nullptr); return referrerInfo.forget();
}
if (!aDoc) {
aPrincipal->CreateReferrerInfo(ReferrerPolicy::_empty,
getter_AddRefs(referrerInfo)); return referrerInfo.forget();
}
// If it weren't for history.push/replaceState, we could just use the // principal's URI here. But since we want changes to the URI effected // by push/replaceState to be reflected in the XHR referrer, we have to // be more clever. // // If the document's original URI (before any push/replaceStates) matches // our principal, then we use the document's current URI (after // push/replaceStates). Otherwise (if the document is, say, a data: // URI), we just use the principal's URI.
nsCOMPtr<nsIURI> docCurURI = aDoc->GetDocumentURI();
nsCOMPtr<nsIURI> docOrigURI = aDoc->GetOriginalURI();
if (docCurURI && docOrigURI) { bool equal = false;
aPrincipal->EqualsURI(docOrigURI, &equal); if (equal) {
referrerInfo = new ReferrerInfo(docCurURI, aDoc->GetReferrerPolicy()); return referrerInfo.forget();
}
}
aPrincipal->CreateReferrerInfo(aDoc->GetReferrerPolicy(),
getter_AddRefs(referrerInfo)); return referrerInfo.forget();
}
// Step 2 // https://w3c.github.io/webappsec-referrer-policy/#integration-with-css // Use empty policy at the beginning and update it later from Referrer-Policy // header.
referrerInfo = new ReferrerInfo(aExternalSheet->GetSheetURI(), aPolicy); return referrerInfo.forget();
}
// If the referrerInfo is passed around when redirect, just use the last // computedReferrer to recompute
nsCOMPtr<nsIURI> referrer;
nsresult rv = NS_OK;
mOverridePolicyByDefault = false;
if (mComputedReferrer.isSome()) { if (mComputedReferrer.value().IsEmpty()) { return NS_OK;
}
mComputedReferrer.reset(); // Emplace mComputedReferrer with an empty string, which means we have // computed the referrer and the result referrer value is empty (not send // referrer). So any early return later than this line will use that empty // referrer.
mComputedReferrer.emplace(""_ns);
// This is for the case where the ETP toggle is off. In this case, we need to // reset the referrer and the policy if the original policy is different from // the current policy in order to recompute the referrer policy with the // original policy. if (!mOverridePolicyByDefault && mOriginalPolicy != ReferrerPolicy::_empty &&
mPolicy != mOriginalPolicy) {
referrer = nullptr;
mPolicy = mOriginalPolicy;
}
if (mPolicy == ReferrerPolicy::No_referrer) { return NS_OK;
}
// Strip away any fragment per RFC 2616 section 14.36 // and Referrer Policy section 6.3.5. if (!referrer) {
rv = NS_GetURIWithoutRef(mOriginalReferrer, getter_AddRefs(referrer)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
}
// Handle user pref network.http.referer.spoofSource, send spoofed referrer if // desired if (StaticPrefs::network_http_referer_spoofSource()) {
nsCOMPtr<nsIURI> userSpoofReferrer;
rv = NS_GetURIWithoutRef(uri, getter_AddRefs(userSpoofReferrer)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
referrer = userSpoofReferrer;
}
// strip away any userpass; we don't want to be giving out passwords ;-) // This is required by Referrer Policy stripping algorithm.
nsCOMPtr<nsIURI> exposableURI = nsIOService::CreateExposableURI(referrer);
referrer = exposableURI;
// Don't send referrer when the request is cross-origin and policy is // "same-origin". if (mPolicy == ReferrerPolicy::Same_origin &&
IsReferrerCrossOrigin(aChannel, referrer)) { return NS_OK;
}
nsAutoCString trimmedReferrer; // We first trim the referrer according to the policy by calling // 'TrimReferrerWithPolicy' and right after we have to call // 'LimitReferrerLength' (using the same arguments) because the trimmed // referrer might exceed the allowed max referrer length.
rv = TrimReferrerWithPolicy(referrer, trimmingPolicy, trimmedReferrer); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// We need to create a new pipe in order to read the aData and the rest of // the input stream together in the old format. This would also help us with // handling big endian correctly.
NS_NewPipe(getter_AddRefs(reader), getter_AddRefs(writer));
// Write back the aData so that we can read bytes from it and handle big // endian correctly.
nsresult rv = binaryPipeWriter->Write32(aData); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// We need to handle the following string if isComputed is true. if (isComputed) { // Comsume the following 2 bytes from the input stream. They are the half // part of the length prefix of the following string.
uint16_t data;
rv = aInputStream->Read16(&data); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// Write the bytes to the pipe so that we can read the length of the string.
rv = binaryPipeWriter->Write16(data); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// Consume the string body from the input stream.
nsAutoCString computedReferrer;
rv = NS_ConsumeStream(aInputStream, length, computedReferrer); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
mComputedReferrer.emplace(computedReferrer);
// Read the remaining two bytes and write to the pipe.
uint16_t remain;
rv = aInputStream->Read16(&remain); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
rv = binaryPipeWriter->Write16(remain); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
}
rv = binaryPipeReader->ReadBoolean(&mInitialized); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
rv = binaryPipeReader->ReadBoolean(&mOverridePolicyByDefault); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
// ReferrerPolicy.webidl has different order with ReferrerPolicyIDL. We store // to disk using the order of ReferrerPolicyIDL, so we convert to // ReferrerPolicyIDL to make it be compatible to the old format.
uint32_t policy;
rv = aStream->Read32(&policy); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
}
mPolicy = ReferrerPolicyIDLToReferrerPolicy( static_cast<nsIReferrerInfo::ReferrerPolicyIDL>(policy));
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1784045#c6 for more // details. // // We need to differentiate the old format and the new format here in order // to be able to read both formats. The check here helps us with verifying // which format it is. if (MOZ_UNLIKELY(originalPolicy > 0xFF)) {
mOriginalPolicy = mPolicy;
// The telemetry probe has 18 buckets. The first 9 buckets are for same-site // requests and the rest 9 buckets are for cross-site requests.
uint32_t telemetryOffset =
IsCrossSiteRequest(aChannel)
? UnderlyingValue(
MaxContiguousEnumValue<dom::ReferrerPolicy>::value) +
1
: 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.