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/. */
7 #include "FontPreloader.h"
9 #include "gfxUserFontSet.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/WorkerPrivate.h"
12 #include "mozilla/dom/ReferrerInfo.h"
13 #include "nsContentSecurityManager.h"
14 #include "nsIClassOfService.h"
15 #include "nsIHttpChannel.h"
16 #include "nsISupportsPriority.h"
17 #include "nsNetUtil.h"
21 FontPreloader::FontPreloader()
22 : FetchPreloader(nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD
) {}
24 nsresult
FontPreloader::CreateChannel(
25 nsIChannel
** aChannel
, nsIURI
* aURI
, const CORSMode aCORSMode
,
26 const dom::ReferrerPolicy
& aReferrerPolicy
, dom::Document
* aDocument
,
27 nsILoadGroup
* aLoadGroup
, nsIInterfaceRequestor
* aCallbacks
,
28 uint64_t aEarlyHintPreloaderId
) {
29 // Don't preload fonts if they've been preffed-off.
30 if (!gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
31 return NS_ERROR_NOT_AVAILABLE
;
34 return BuildChannel(aChannel
, aURI
, aCORSMode
, aReferrerPolicy
, nullptr,
35 nullptr, aDocument
, aLoadGroup
, aCallbacks
, true);
39 void FontPreloader::PrioritizeAsPreload(nsIChannel
* aChannel
) {
40 nsCOMPtr
<nsIClassOfService
> cos(do_QueryInterface(aChannel
));
42 cos
->AddClassFlags(nsIClassOfService::Unblocked
);
46 /* static */ void FontPreloader::BuildChannelFlags(
47 nsIURI
* aURI
, bool aIsPreload
,
48 nsContentSecurityManager::CORSSecurityMapping
& aCorsMapping
,
49 nsSecurityFlags
& aSecurityFlags
, nsContentPolicyType
& aContentPolicyType
) {
50 // aCORSMode is ignored. We always load as crossorigin=anonymous, but a
51 // preload started with anything other then "anonymous" will never be found.
53 aURI
->SchemeIs("file")
54 ? nsContentSecurityManager::CORSSecurityMapping::
55 CORS_NONE_MAPS_TO_INHERITED_CONTEXT
56 : nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS
;
58 aSecurityFlags
= nsContentSecurityManager::ComputeSecurityFlags(
59 CORSMode::CORS_NONE
, aCorsMapping
);
61 aContentPolicyType
= aIsPreload
? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD
62 : nsIContentPolicy::TYPE_FONT
;
65 /* static */ nsresult
FontPreloader::BuildChannelSetup(
66 nsIChannel
* aChannel
, nsIHttpChannel
* aHttpChannel
,
67 nsIReferrerInfo
* aReferrerInfo
, const gfxFontFaceSrc
* aFontFaceSrc
) {
69 nsresult rv
= aHttpChannel
->SetRequestHeader(
71 "application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8"_ns
,
73 NS_ENSURE_SUCCESS(rv
, rv
);
76 rv
= aHttpChannel
->SetReferrerInfoWithoutClone(aReferrerInfo
);
77 MOZ_ASSERT(NS_SUCCEEDED(rv
));
79 MOZ_ASSERT(aFontFaceSrc
);
81 rv
= aHttpChannel
->SetReferrerInfo(aFontFaceSrc
->mReferrerInfo
);
82 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
84 // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try
85 // and apply additional compression at the content-encoding layer
86 if (aFontFaceSrc
->mFormatHint
== StyleFontFaceSourceFormatKeyword::Woff
||
87 aFontFaceSrc
->mFormatHint
==
88 StyleFontFaceSourceFormatKeyword::Woff2
) {
89 rv
= aHttpChannel
->SetRequestHeader("Accept-Encoding"_ns
, "identity"_ns
,
91 NS_ENSURE_SUCCESS(rv
, rv
);
96 nsCOMPtr
<nsISupportsPriority
> priorityChannel(do_QueryInterface(aChannel
));
97 if (priorityChannel
) {
98 priorityChannel
->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH
);
100 nsCOMPtr
<nsIClassOfService
> cos(do_QueryInterface(aChannel
));
102 cos
->AddClassFlags(nsIClassOfService::TailForbidden
);
109 nsresult
FontPreloader::BuildChannel(
110 nsIChannel
** aChannel
, nsIURI
* aURI
, const CORSMode aCORSMode
,
111 const dom::ReferrerPolicy
& aReferrerPolicy
,
112 gfxUserFontEntry
* aUserFontEntry
, const gfxFontFaceSrc
* aFontFaceSrc
,
113 dom::Document
* aDocument
, nsILoadGroup
* aLoadGroup
,
114 nsIInterfaceRequestor
* aCallbacks
, bool aIsPreload
) {
117 nsIPrincipal
* principal
=
118 aUserFontEntry
? (aUserFontEntry
->GetPrincipal()
119 ? aUserFontEntry
->GetPrincipal()->NodePrincipal()
121 : aDocument
->NodePrincipal();
123 nsContentSecurityManager::CORSSecurityMapping corsMapping
;
124 nsSecurityFlags securityFlags
;
125 nsContentPolicyType contentPolicyType
;
126 BuildChannelFlags(aURI
, aIsPreload
, corsMapping
, securityFlags
,
129 nsCOMPtr
<nsIChannel
> channel
;
130 // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
131 // node and a principal. This is because the document where the font is
132 // being loaded might have a different origin from the principal of the
133 // stylesheet that initiated the font load.
134 rv
= NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel
), aURI
,
135 aDocument
, principal
, securityFlags
,
137 nullptr, // PerformanceStorage
139 NS_ENSURE_SUCCESS(rv
, rv
);
141 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
142 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
;
143 if (httpChannel
&& !aFontFaceSrc
) {
144 referrerInfo
= new dom::ReferrerInfo(aDocument
->GetDocumentURIAsReferrer(),
146 rv
= httpChannel
->SetReferrerInfoWithoutClone(referrerInfo
);
147 MOZ_ASSERT(NS_SUCCEEDED(rv
));
150 rv
= BuildChannelSetup(channel
, httpChannel
, referrerInfo
, aFontFaceSrc
);
151 NS_ENSURE_SUCCESS(rv
, rv
);
153 channel
.forget(aChannel
);
158 nsresult
FontPreloader::BuildChannel(
159 nsIChannel
** aChannel
, nsIURI
* aURI
, const CORSMode aCORSMode
,
160 const dom::ReferrerPolicy
& aReferrerPolicy
,
161 gfxUserFontEntry
* aUserFontEntry
, const gfxFontFaceSrc
* aFontFaceSrc
,
162 dom::WorkerPrivate
* aWorkerPrivate
, nsILoadGroup
* aLoadGroup
,
163 nsIInterfaceRequestor
* aCallbacks
, bool aIsPreload
) {
166 nsIPrincipal
* principal
=
167 aUserFontEntry
? (aUserFontEntry
->GetPrincipal()
168 ? aUserFontEntry
->GetPrincipal()->NodePrincipal()
170 : aWorkerPrivate
->GetPrincipal();
172 nsContentSecurityManager::CORSSecurityMapping corsMapping
;
173 nsSecurityFlags securityFlags
;
174 nsContentPolicyType contentPolicyType
;
175 BuildChannelFlags(aURI
, aIsPreload
, corsMapping
, securityFlags
,
178 nsCOMPtr
<nsIChannel
> channel
;
179 rv
= NS_NewChannelWithTriggeringPrincipal(
180 getter_AddRefs(channel
), aURI
, aWorkerPrivate
->GetLoadingPrincipal(),
181 principal
, securityFlags
, contentPolicyType
, nullptr, nullptr,
183 NS_ENSURE_SUCCESS(rv
, rv
);
185 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
187 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
;
188 if (httpChannel
&& !aFontFaceSrc
) {
190 static_cast<dom::ReferrerInfo
*>(aWorkerPrivate
->GetReferrerInfo())
191 ->CloneWithNewPolicy(aReferrerPolicy
);
194 rv
= BuildChannelSetup(channel
, httpChannel
, referrerInfo
, aFontFaceSrc
);
195 NS_ENSURE_SUCCESS(rv
, rv
);
197 channel
.forget(aChannel
);
201 } // namespace mozilla