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);
38 /* static */ void FontPreloader::BuildChannelFlags(
39 nsIURI
* aURI
, bool aIsPreload
,
40 nsContentSecurityManager::CORSSecurityMapping
& aCorsMapping
,
41 nsSecurityFlags
& aSecurityFlags
, nsContentPolicyType
& aContentPolicyType
) {
42 // aCORSMode is ignored. We always load as crossorigin=anonymous, but a
43 // preload started with anything other then "anonymous" will never be found.
45 aURI
->SchemeIs("file")
46 ? nsContentSecurityManager::CORSSecurityMapping::
47 CORS_NONE_MAPS_TO_INHERITED_CONTEXT
48 : nsContentSecurityManager::CORSSecurityMapping::REQUIRE_CORS_CHECKS
;
50 aSecurityFlags
= nsContentSecurityManager::ComputeSecurityFlags(
51 CORSMode::CORS_NONE
, aCorsMapping
);
53 aContentPolicyType
= aIsPreload
? nsIContentPolicy::TYPE_INTERNAL_FONT_PRELOAD
54 : nsIContentPolicy::TYPE_FONT
;
57 /* static */ nsresult
FontPreloader::BuildChannelSetup(
58 nsIChannel
* aChannel
, nsIHttpChannel
* aHttpChannel
,
59 nsIReferrerInfo
* aReferrerInfo
, const gfxFontFaceSrc
* aFontFaceSrc
) {
61 nsresult rv
= aHttpChannel
->SetRequestHeader(
63 "application/font-woff2;q=1.0,application/font-woff;q=0.9,*/*;q=0.8"_ns
,
65 NS_ENSURE_SUCCESS(rv
, rv
);
68 rv
= aHttpChannel
->SetReferrerInfoWithoutClone(aReferrerInfo
);
69 MOZ_ASSERT(NS_SUCCEEDED(rv
));
71 MOZ_ASSERT(aFontFaceSrc
);
73 rv
= aHttpChannel
->SetReferrerInfo(aFontFaceSrc
->mReferrerInfo
);
74 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
76 // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try
77 // and apply additional compression at the content-encoding layer
78 if (aFontFaceSrc
->mFormatHint
== StyleFontFaceSourceFormatKeyword::Woff
||
79 aFontFaceSrc
->mFormatHint
==
80 StyleFontFaceSourceFormatKeyword::Woff2
) {
81 rv
= aHttpChannel
->SetRequestHeader("Accept-Encoding"_ns
, "identity"_ns
,
83 NS_ENSURE_SUCCESS(rv
, rv
);
88 nsCOMPtr
<nsISupportsPriority
> priorityChannel(do_QueryInterface(aChannel
));
89 if (priorityChannel
) {
90 priorityChannel
->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH
);
92 nsCOMPtr
<nsIClassOfService
> cos(do_QueryInterface(aChannel
));
94 cos
->AddClassFlags(nsIClassOfService::TailForbidden
);
101 nsresult
FontPreloader::BuildChannel(
102 nsIChannel
** aChannel
, nsIURI
* aURI
, const CORSMode aCORSMode
,
103 const dom::ReferrerPolicy
& aReferrerPolicy
,
104 gfxUserFontEntry
* aUserFontEntry
, const gfxFontFaceSrc
* aFontFaceSrc
,
105 dom::Document
* aDocument
, nsILoadGroup
* aLoadGroup
,
106 nsIInterfaceRequestor
* aCallbacks
, bool aIsPreload
) {
109 nsIPrincipal
* principal
=
110 aUserFontEntry
? (aUserFontEntry
->GetPrincipal()
111 ? aUserFontEntry
->GetPrincipal()->NodePrincipal()
113 : aDocument
->NodePrincipal();
115 nsContentSecurityManager::CORSSecurityMapping corsMapping
;
116 nsSecurityFlags securityFlags
;
117 nsContentPolicyType contentPolicyType
;
118 BuildChannelFlags(aURI
, aIsPreload
, corsMapping
, securityFlags
,
121 nsCOMPtr
<nsIChannel
> channel
;
122 // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
123 // node and a principal. This is because the document where the font is
124 // being loaded might have a different origin from the principal of the
125 // stylesheet that initiated the font load.
126 rv
= NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel
), aURI
,
127 aDocument
, principal
, securityFlags
,
129 nullptr, // PerformanceStorage
131 NS_ENSURE_SUCCESS(rv
, rv
);
133 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
134 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
;
135 if (httpChannel
&& !aFontFaceSrc
) {
136 referrerInfo
= new dom::ReferrerInfo(aDocument
->GetDocumentURIAsReferrer(),
138 rv
= httpChannel
->SetReferrerInfoWithoutClone(referrerInfo
);
139 MOZ_ASSERT(NS_SUCCEEDED(rv
));
142 rv
= BuildChannelSetup(channel
, httpChannel
, referrerInfo
, aFontFaceSrc
);
143 NS_ENSURE_SUCCESS(rv
, rv
);
145 channel
.forget(aChannel
);
150 nsresult
FontPreloader::BuildChannel(
151 nsIChannel
** aChannel
, nsIURI
* aURI
, const CORSMode aCORSMode
,
152 const dom::ReferrerPolicy
& aReferrerPolicy
,
153 gfxUserFontEntry
* aUserFontEntry
, const gfxFontFaceSrc
* aFontFaceSrc
,
154 dom::WorkerPrivate
* aWorkerPrivate
, nsILoadGroup
* aLoadGroup
,
155 nsIInterfaceRequestor
* aCallbacks
, bool aIsPreload
) {
158 nsIPrincipal
* principal
=
159 aUserFontEntry
? (aUserFontEntry
->GetPrincipal()
160 ? aUserFontEntry
->GetPrincipal()->NodePrincipal()
162 : aWorkerPrivate
->GetPrincipal();
164 nsContentSecurityManager::CORSSecurityMapping corsMapping
;
165 nsSecurityFlags securityFlags
;
166 nsContentPolicyType contentPolicyType
;
167 BuildChannelFlags(aURI
, aIsPreload
, corsMapping
, securityFlags
,
170 nsCOMPtr
<nsIChannel
> channel
;
171 rv
= NS_NewChannelWithTriggeringPrincipal(
172 getter_AddRefs(channel
), aURI
, aWorkerPrivate
->GetLoadingPrincipal(),
173 principal
, securityFlags
, contentPolicyType
, nullptr, nullptr,
175 NS_ENSURE_SUCCESS(rv
, rv
);
177 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
179 nsCOMPtr
<nsIReferrerInfo
> referrerInfo
;
180 if (httpChannel
&& !aFontFaceSrc
) {
182 static_cast<dom::ReferrerInfo
*>(aWorkerPrivate
->GetReferrerInfo())
183 ->CloneWithNewPolicy(aReferrerPolicy
);
186 rv
= BuildChannelSetup(channel
, httpChannel
, referrerInfo
, aFontFaceSrc
);
187 NS_ENSURE_SUCCESS(rv
, rv
);
189 channel
.forget(aChannel
);
193 } // namespace mozilla