FontLoaderUtils.cpp (7410B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/FontLoaderUtils.h" 8 9 #include "gfxUserFontSet.h" 10 #include "mozilla/dom/Document.h" 11 #include "mozilla/dom/ReferrerInfo.h" 12 #include "mozilla/dom/WorkerPrivate.h" 13 #include "nsCOMPtr.h" 14 #include "nsIChannel.h" 15 #include "nsIClassOfService.h" 16 #include "nsIContentPolicy.h" 17 #include "nsIHttpChannel.h" 18 #include "nsILoadInfo.h" 19 #include "nsIReferrerInfo.h" 20 #include "nsISupportsPriority.h" 21 #include "nsIURI.h" 22 #include "nsNetUtil.h" 23 24 namespace mozilla { 25 26 /* static */ void FontLoaderUtils::BuildChannelFlags( 27 nsIURI* aURI, bool aIsPreload, 28 nsContentSecurityManager::CORSSecurityMapping& aCorsMapping, 29 nsSecurityFlags& aSecurityFlags, nsContentPolicyType& aContentPolicyType) { 30 // aCORSMode is ignored. We always load as crossorigin=anonymous, but a 31 // preload started with anything other then "anonymous" will never be found. 32 aCorsMapping = 33 aURI->SchemeIs("file") || aURI->SchemeIs("resource") || 34 aURI->SchemeIs("chrome") 35 ? nsContentSecurityManager::CORSSecurityMapping:: 36 CORS_NONE_MAPS_TO_INHERITED_CONTEXT 37 : nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS; 38 39 // Besides the CORS flags, include SEC_ALLOW_CHROME to allow a font to come 40 // from a resource:// or chrome:// URL (as long as it is marked 41 // contentaccessible) 42 aSecurityFlags = nsContentSecurityManager::ComputeSecurityFlags( 43 CORSMode::CORS_NONE, aCorsMapping) | 44 nsILoadInfo::SEC_ALLOW_CHROME; 45 46 aContentPolicyType = aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD 47 : nsIContentPolicy::TYPE_FONT; 48 } 49 50 /* static */ nsresult FontLoaderUtils::BuildChannelSetup( 51 nsIChannel* aChannel, nsIHttpChannel* aHttpChannel, 52 nsIReferrerInfo* aReferrerInfo, const gfxFontFaceSrc* aFontFaceSrc, 53 int32_t aSupportsPriorityValue) { 54 if (aHttpChannel) { 55 nsresult rv = aHttpChannel->SetRequestHeader( 56 "Accept"_ns, 57 "application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8"_ns, 58 false); 59 NS_ENSURE_SUCCESS(rv, rv); 60 61 if (aReferrerInfo) { 62 rv = aHttpChannel->SetReferrerInfoWithoutClone(aReferrerInfo); 63 MOZ_ASSERT(NS_SUCCEEDED(rv)); 64 } else { 65 MOZ_ASSERT(aFontFaceSrc); 66 67 rv = aHttpChannel->SetReferrerInfo(aFontFaceSrc->mReferrerInfo); 68 (void)NS_WARN_IF(NS_FAILED(rv)); 69 70 // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try 71 // and apply additional compression at the content-encoding layer 72 if (aFontFaceSrc->mFormatHint == StyleFontFaceSourceFormatKeyword::Woff || 73 aFontFaceSrc->mFormatHint == 74 StyleFontFaceSourceFormatKeyword::Woff2) { 75 rv = aHttpChannel->SetRequestHeader("Accept-Encoding"_ns, "identity"_ns, 76 false); 77 NS_ENSURE_SUCCESS(rv, rv); 78 } 79 } 80 } 81 82 nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(aChannel)); 83 if (priorityChannel) { 84 priorityChannel->SetPriority(aSupportsPriorityValue); 85 } 86 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(aChannel)); 87 if (cos) { 88 cos->AddClassFlags(nsIClassOfService::TailForbidden); 89 } 90 91 return NS_OK; 92 } 93 94 // static 95 nsresult FontLoaderUtils::BuildChannel( 96 nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode, 97 const dom::ReferrerPolicy& aReferrerPolicy, 98 gfxUserFontEntry* aUserFontEntry, const gfxFontFaceSrc* aFontFaceSrc, 99 dom::Document* aDocument, nsILoadGroup* aLoadGroup, 100 nsIInterfaceRequestor* aCallbacks, bool aIsPreload, 101 int32_t aSupportsPriorityValue) { 102 nsresult rv; 103 104 nsIPrincipal* principal = 105 aUserFontEntry ? (aUserFontEntry->GetPrincipal() 106 ? aUserFontEntry->GetPrincipal()->NodePrincipal() 107 : nullptr) 108 : aDocument->NodePrincipal(); 109 110 nsContentSecurityManager::CORSSecurityMapping corsMapping; 111 nsSecurityFlags securityFlags; 112 nsContentPolicyType contentPolicyType; 113 BuildChannelFlags(aURI, aIsPreload, corsMapping, securityFlags, 114 contentPolicyType); 115 116 nsCOMPtr<nsIChannel> channel; 117 // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a 118 // node and a principal. This is because the document where the font is 119 // being loaded might have a different origin from the principal of the 120 // stylesheet that initiated the font load. 121 rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel), aURI, 122 aDocument, principal, securityFlags, 123 contentPolicyType, 124 nullptr, // PerformanceStorage 125 aLoadGroup); 126 NS_ENSURE_SUCCESS(rv, rv); 127 128 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); 129 nsCOMPtr<nsIReferrerInfo> referrerInfo; 130 if (httpChannel && !aFontFaceSrc) { 131 referrerInfo = new dom::ReferrerInfo(aDocument->GetDocumentURIAsReferrer(), 132 aReferrerPolicy); 133 rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo); 134 MOZ_ASSERT(NS_SUCCEEDED(rv)); 135 } 136 137 rv = BuildChannelSetup(channel, httpChannel, referrerInfo, aFontFaceSrc, 138 aSupportsPriorityValue); 139 NS_ENSURE_SUCCESS(rv, rv); 140 141 channel.forget(aChannel); 142 return NS_OK; 143 } 144 145 // static 146 nsresult FontLoaderUtils::BuildChannel( 147 nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode, 148 const dom::ReferrerPolicy& aReferrerPolicy, 149 gfxUserFontEntry* aUserFontEntry, const gfxFontFaceSrc* aFontFaceSrc, 150 dom::WorkerPrivate* aWorkerPrivate, nsILoadGroup* aLoadGroup, 151 nsIInterfaceRequestor* aCallbacks) { 152 nsresult rv; 153 154 nsIPrincipal* principal = 155 aUserFontEntry ? (aUserFontEntry->GetPrincipal() 156 ? aUserFontEntry->GetPrincipal()->NodePrincipal() 157 : nullptr) 158 : aWorkerPrivate->GetPrincipal(); 159 160 nsContentSecurityManager::CORSSecurityMapping corsMapping; 161 nsSecurityFlags securityFlags; 162 nsContentPolicyType contentPolicyType; 163 BuildChannelFlags(aURI, /* aIsPreload */ false, corsMapping, securityFlags, 164 contentPolicyType); 165 166 nsCOMPtr<nsIChannel> channel; 167 rv = NS_NewChannelWithTriggeringPrincipal( 168 getter_AddRefs(channel), aURI, aWorkerPrivate->GetLoadingPrincipal(), 169 principal, securityFlags, contentPolicyType, nullptr, nullptr, 170 aLoadGroup); 171 NS_ENSURE_SUCCESS(rv, rv); 172 173 nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); 174 175 nsCOMPtr<nsIReferrerInfo> referrerInfo; 176 if (httpChannel && !aFontFaceSrc) { 177 referrerInfo = 178 static_cast<dom::ReferrerInfo*>(aWorkerPrivate->GetReferrerInfo()) 179 ->CloneWithNewPolicy(aReferrerPolicy); 180 } 181 182 rv = BuildChannelSetup(channel, httpChannel, referrerInfo, aFontFaceSrc, 183 nsISupportsPriority::PRIORITY_HIGH); 184 NS_ENSURE_SUCCESS(rv, rv); 185 186 channel.forget(aChannel); 187 return NS_OK; 188 } 189 190 } // namespace mozilla