/* -*- 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/FontLoaderUtils.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/ReferrerInfo.h" #include "mozilla/dom/WorkerPrivate.h" #include "gfxUserFontSet.h" #include "nsCOMPtr.h" #include "nsIChannel.h" #include "nsIClassOfService.h" #include "nsIContentPolicy.h" #include "nsIHttpChannel.h" #include "nsILoadInfo.h" #include "nsIReferrerInfo.h" #include "nsISupportsPriority.h" #include "nsIURI.h" #include "nsNetUtil.h" namespace mozilla { /* static */ void FontLoaderUtils::BuildChannelFlags( nsIURI* aURI, bool aIsPreload, nsContentSecurityManager::CORSSecurityMapping& aCorsMapping, nsSecurityFlags& aSecurityFlags, nsContentPolicyType& aContentPolicyType) { // aCORSMode is ignored. We always load as crossorigin=anonymous, but a // preload started with anything other then "anonymous" will never be found. aCorsMapping = aURI->SchemeIs("file") ? nsContentSecurityManager::CORSSecurityMapping:: CORS_NONE_MAPS_TO_INHERITED_CONTEXT : nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS; aSecurityFlags = nsContentSecurityManager::ComputeSecurityFlags( CORSMode::CORS_NONE, aCorsMapping); aContentPolicyType = aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD : nsIContentPolicy::TYPE_FONT; } /* static */ nsresult FontLoaderUtils::BuildChannelSetup( nsIChannel* aChannel, nsIHttpChannel* aHttpChannel, nsIReferrerInfo* aReferrerInfo, const gfxFontFaceSrc* aFontFaceSrc, int32_t aSupportsPriorityValue) { if (aHttpChannel) { nsresult rv = aHttpChannel->SetRequestHeader( "Accept"_ns, "application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8"_ns, false); NS_ENSURE_SUCCESS(rv, rv); if (aReferrerInfo) { rv = aHttpChannel->SetReferrerInfoWithoutClone(aReferrerInfo); MOZ_ASSERT(NS_SUCCEEDED(rv)); } else { MOZ_ASSERT(aFontFaceSrc); rv = aHttpChannel->SetReferrerInfo(aFontFaceSrc->mReferrerInfo); Unused << NS_WARN_IF(NS_FAILED(rv)); // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try // and apply additional compression at the content-encoding layer if (aFontFaceSrc->mFormatHint == StyleFontFaceSourceFormatKeyword::Woff || aFontFaceSrc->mFormatHint == StyleFontFaceSourceFormatKeyword::Woff2) { rv = aHttpChannel->SetRequestHeader("Accept-Encoding"_ns, "identity"_ns, false); NS_ENSURE_SUCCESS(rv, rv); } } } nsCOMPtr priorityChannel(do_QueryInterface(aChannel)); if (priorityChannel) { priorityChannel->SetPriority(aSupportsPriorityValue); } nsCOMPtr cos(do_QueryInterface(aChannel)); if (cos) { cos->AddClassFlags(nsIClassOfService::TailForbidden); } return NS_OK; } // static nsresult FontLoaderUtils::BuildChannel( nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode, const dom::ReferrerPolicy& aReferrerPolicy, gfxUserFontEntry* aUserFontEntry, const gfxFontFaceSrc* aFontFaceSrc, dom::Document* aDocument, nsILoadGroup* aLoadGroup, nsIInterfaceRequestor* aCallbacks, bool aIsPreload, int32_t aSupportsPriorityValue) { nsresult rv; nsIPrincipal* principal = aUserFontEntry ? (aUserFontEntry->GetPrincipal() ? aUserFontEntry->GetPrincipal()->NodePrincipal() : nullptr) : aDocument->NodePrincipal(); nsContentSecurityManager::CORSSecurityMapping corsMapping; nsSecurityFlags securityFlags; nsContentPolicyType contentPolicyType; BuildChannelFlags(aURI, aIsPreload, corsMapping, securityFlags, contentPolicyType); nsCOMPtr channel; // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a // node and a principal. This is because the document where the font is // being loaded might have a different origin from the principal of the // stylesheet that initiated the font load. rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel), aURI, aDocument, principal, securityFlags, contentPolicyType, nullptr, // PerformanceStorage aLoadGroup); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr httpChannel(do_QueryInterface(channel)); nsCOMPtr referrerInfo; if (httpChannel && !aFontFaceSrc) { referrerInfo = new dom::ReferrerInfo(aDocument->GetDocumentURIAsReferrer(), aReferrerPolicy); rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo); MOZ_ASSERT(NS_SUCCEEDED(rv)); } rv = BuildChannelSetup(channel, httpChannel, referrerInfo, aFontFaceSrc, aSupportsPriorityValue); NS_ENSURE_SUCCESS(rv, rv); channel.forget(aChannel); return NS_OK; } // static nsresult FontLoaderUtils::BuildChannel( nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode, const dom::ReferrerPolicy& aReferrerPolicy, gfxUserFontEntry* aUserFontEntry, const gfxFontFaceSrc* aFontFaceSrc, dom::WorkerPrivate* aWorkerPrivate, nsILoadGroup* aLoadGroup, nsIInterfaceRequestor* aCallbacks) { nsresult rv; nsIPrincipal* principal = aUserFontEntry ? (aUserFontEntry->GetPrincipal() ? aUserFontEntry->GetPrincipal()->NodePrincipal() : nullptr) : aWorkerPrivate->GetPrincipal(); nsContentSecurityManager::CORSSecurityMapping corsMapping; nsSecurityFlags securityFlags; nsContentPolicyType contentPolicyType; BuildChannelFlags(aURI, /* aIsPreload */ false, corsMapping, securityFlags, contentPolicyType); nsCOMPtr channel; rv = NS_NewChannelWithTriggeringPrincipal( getter_AddRefs(channel), aURI, aWorkerPrivate->GetLoadingPrincipal(), principal, securityFlags, contentPolicyType, nullptr, nullptr, aLoadGroup); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr httpChannel(do_QueryInterface(channel)); nsCOMPtr referrerInfo; if (httpChannel && !aFontFaceSrc) { referrerInfo = static_cast(aWorkerPrivate->GetReferrerInfo()) ->CloneWithNewPolicy(aReferrerPolicy); } rv = BuildChannelSetup(channel, httpChannel, referrerInfo, aFontFaceSrc, nsISupportsPriority::PRIORITY_HIGH); NS_ENSURE_SUCCESS(rv, rv); channel.forget(aChannel); return NS_OK; } } // namespace mozilla