Bug Summary

File:Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/LinkLoader.cpp
Warning:line 429, column 9
Call argument for 'this' parameter is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -O3 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource282.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource282.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/11721353671419897710/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I PAL -I ForwardingHeaders -I /usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/libxml2 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release-iphonesimulator/PAL.build/DerivedSources -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release-iphonesimulator/WebCore.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource282.plist -x c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebCore/unified-sources/UnifiedSource282.cpp
1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2016-2025 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33#include "config.h"
34#include "LinkLoader.h"
35
36#include "CSSStyleSheet.h"
37#include "CachedCSSStyleSheet.h"
38#include "CachedResourceLoader.h"
39#include "CachedResourceRequest.h"
40#include "ContainerNode.h"
41#include "CrossOriginAccessControl.h"
42#include "DefaultResourceLoadPriority.h"
43#include "DocumentLoader.h"
44#include "DocumentPage.h"
45#include "FetchRequestDestination.h"
46#include "FrameDestructionObserverInlines.h"
47#include "FrameLoader.h"
48#include "HTMLSrcsetParser.h"
49#include <JavaScriptCore/ConsoleTypes.h>
50#include "JSFetchRequestDestination.h"
51#include "LinkHeader.h"
52#include "LinkPreloadResourceClients.h"
53#include "LinkRelAttribute.h"
54#include "LoaderStrategy.h"
55#include "LocalFrame.h"
56#include "LocalFrameLoaderClient.h"
57#include "LocalFrameView.h"
58#include "MIMETypeRegistry.h"
59#include "MediaQueryEvaluator.h"
60#include "MediaQueryParser.h"
61#include "NodeRenderStyle.h"
62#include "PlatformStrategies.h"
63#include "RenderElement.h"
64#include "ResourceError.h"
65#include "Settings.h"
66#include "SizesAttributeParser.h"
67#include "StyleResolver.h"
68#include "UserContentProvider.h"
69#include <JavaScriptCore/ConsoleTypes.h>
70#include <wtf/text/MakeString.h>
71
72namespace WebCore {
73
74Ref<LinkLoader> LinkLoader::create(LinkLoaderClient& client)
75{
76 return adoptRef(*new LinkLoader(client));
77}
78
79LinkLoader::LinkLoader(LinkLoaderClient& client)
80 : m_client(client)
81{
82}
83
84LinkLoader::~LinkLoader()
85{
86 if (RefPtr cachedLinkResource = m_cachedLinkResource.get())
87 cachedLinkResource->removeClient(*this);
88 if (RefPtr client = m_preloadResourceClient)
89 client->clear();
90}
91
92void LinkLoader::triggerEvents(const CachedResource& resource)
93{
94 RefPtr client = m_client.get();
95 if (!client)
96 return;
97
98 if (resource.errorOccurred())
99 client->linkLoadingErrored();
100 else
101 client->linkLoaded();
102}
103
104void LinkLoader::triggerError()
105{
106 if (RefPtr client = m_client.get())
107 client->linkLoadingErrored();
108}
109
110void LinkLoader::notifyFinished(CachedResource& resource, const NetworkLoadMetrics&, LoadWillContinueInAnotherProcess)
111{
112 ASSERT_UNUSED(resource, m_cachedLinkResource.get() == &resource)((void)resource);
113
114 RefPtr cachedLinkResource = m_cachedLinkResource.get();
115 triggerEvents(*cachedLinkResource);
116
117 cachedLinkResource->removeClient(*this);
118 m_cachedLinkResource = nullptr;
119}
120
121void LinkLoader::loadLinksFromHeader(const String& headerValue, const URL& baseURL, Document& document, MediaAttributeCheck mediaAttributeCheck)
122{
123 if (headerValue.isEmpty())
124 return;
125 LinkHeaderSet headerSet(headerValue);
126 for (auto& header : headerSet) {
127 if (!header.valid() || header.url().isEmpty() || header.rel().isEmpty())
128 continue;
129 if ((mediaAttributeCheck == MediaAttributeCheck::MediaAttributeNotEmpty && !header.isViewportDependent())
130 || (mediaAttributeCheck == MediaAttributeCheck::MediaAttributeEmpty && header.isViewportDependent())) {
131 continue;
132 }
133
134 LinkRelAttribute relAttribute(document, header.rel());
135 URL url(baseURL, header.url());
136 // Sanity check to avoid re-entrancy here.
137 if (equalIgnoringFragmentIdentifier(url, baseURL))
138 continue;
139
140 auto fetchPriority = parseEnumerationFromString<RequestPriority>(header.fetchPriority()).value_or(RequestPriority::Auto);
141 LinkLoadParameters params { relAttribute, url, header.as(), header.media(), header.mimeType(), header.crossOrigin(), header.imageSrcSet(), header.imageSizes(), header.nonce(),
142 parseReferrerPolicy(header.referrerPolicy(), ReferrerPolicySource::ReferrerPolicyAttribute).value_or(ReferrerPolicy::EmptyString), fetchPriority };
143
144 preconnectIfNeeded(params, document);
145 preloadIfNeeded(params, document, nullptr);
146 }
147}
148
149std::optional<CachedResource::Type> LinkLoader::resourceTypeFromAsAttribute(const String& as, Document& document, ShouldLog shouldLogError)
150{
151 if (equalLettersIgnoringASCIICase(as, "fetch"_s))
152 return CachedResource::Type::RawResource;
153 auto destination = parseEnumerationFromString<FetchRequestDestination>(as);
154 if (!destination) {
155 if (shouldLogError == ShouldLog::Yes)
156 document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> must have a valid `as` value"_s);
157 return std::nullopt;
158 }
159 switch (*destination) {
160 case FetchRequestDestination::EmptyString:
161 if (shouldLogError == ShouldLog::Yes)
162 document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> cannot have the empty string as `as` value"_s);
163 return std::nullopt;
164 case FetchRequestDestination::Audio:
165 if (document.settings().mediaPreloadingEnabled())
166 return CachedResource::Type::MediaResource;
167 return std::nullopt;
168 case FetchRequestDestination::Audioworklet:
169 return CachedResource::Type::Script;
170 case FetchRequestDestination::Document:
171 return std::nullopt;
172 case FetchRequestDestination::Embed:
173 return std::nullopt;
174 case FetchRequestDestination::Environmentmap:
175 return std::nullopt;
176 case FetchRequestDestination::Font:
177 return CachedResource::Type::FontResource;
178 case FetchRequestDestination::Image:
179 return CachedResource::Type::ImageResource;
180 case FetchRequestDestination::Iframe:
181 return std::nullopt;
182 case FetchRequestDestination::Json:
183 return CachedResource::Type::JSON;
184 case FetchRequestDestination::Manifest:
185 return std::nullopt;
186 case FetchRequestDestination::Model:
187 return std::nullopt;
188 case FetchRequestDestination::Object:
189 return std::nullopt;
190 case FetchRequestDestination::Paintworklet:
191 return CachedResource::Type::Script;
192 case FetchRequestDestination::Report:
193 return std::nullopt;
194 case FetchRequestDestination::Script:
195 return CachedResource::Type::Script;
196 case FetchRequestDestination::Serviceworker:
197 return CachedResource::Type::Script;
198 case FetchRequestDestination::Sharedworker:
199 return CachedResource::Type::Script;
200 case FetchRequestDestination::Speculationrules:
201 return CachedResource::Type::Script;
202 case FetchRequestDestination::Style:
203 return CachedResource::Type::CSSStyleSheet;
204 case FetchRequestDestination::Track:
205#if ENABLE(VIDEO)(defined 1 && 1)
206 return CachedResource::Type::TextTrackResource;
207#else
208 return std::nullopt;
209#endif
210 case FetchRequestDestination::Video:
211 if (document.settings().mediaPreloadingEnabled())
212 return CachedResource::Type::MediaResource;
213 return std::nullopt;
214 case FetchRequestDestination::Worker:
215 return CachedResource::Type::Script;
216 case FetchRequestDestination::Xslt:
217 return std::nullopt;
218 }
219 return std::nullopt;
220}
221
222static RefPtr<LinkPreloadResourceClient> createLinkPreloadResourceClient(CachedResource& resource, LinkLoader& loader, Document& document)
223{
224 switch (resource.type()) {
225 case CachedResource::Type::ImageResource:
226 return LinkPreloadImageResourceClient::create(loader, downcast<CachedImage>(resource));
227 case CachedResource::Type::JSON:
228 case CachedResource::Type::Script:
229 return LinkPreloadDefaultResourceClient::create(loader, downcast<CachedScript>(resource));
230 case CachedResource::Type::CSSStyleSheet:
231 return LinkPreloadStyleResourceClient::create(loader, downcast<CachedCSSStyleSheet>(resource));
232 case CachedResource::Type::FontResource:
233 return LinkPreloadFontResourceClient::create(loader, downcast<CachedFont>(resource));
234#if ENABLE(VIDEO)(defined 1 && 1)
235 case CachedResource::Type::TextTrackResource:
236 return LinkPreloadDefaultResourceClient::create(loader, downcast<CachedTextTrack>(resource));
237#endif
238 case CachedResource::Type::MediaResource:
239 ASSERT_UNUSED(document, document.settings().mediaPreloadingEnabled())((void)document);
240 [[fallthrough]];
241 case CachedResource::Type::RawResource:
242 return LinkPreloadRawResourceClient::create(loader, downcast<CachedRawResource>(resource));
243 case CachedResource::Type::MainResource:
244 case CachedResource::Type::Icon:
245 case CachedResource::Type::SVGFontResource:
246 case CachedResource::Type::SVGDocumentResource:
247#if ENABLE(XSLT)(defined 1 && 1)
248 case CachedResource::Type::XSLStyleSheet:
249#endif
250 case CachedResource::Type::Beacon:
251 case CachedResource::Type::Ping:
252 case CachedResource::Type::LinkPrefetch:
253#if ENABLE(APPLICATION_MANIFEST)(defined 1 && 1)
254 case CachedResource::Type::ApplicationManifest:
255#endif
256#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
257 case CachedResource::Type::EnvironmentMapResource:
258 case CachedResource::Type::ModelResource:
259#endif
260 // None of these values is currently supported as an `as` value.
261 ASSERT_NOT_REACHED()((void)0);
262 }
263 return nullptr;
264}
265
266bool LinkLoader::isSupportedType(CachedResource::Type resourceType, const String& mimeType, Document& document)
267{
268 if (mimeType.isEmpty())
269 return true;
270 switch (resourceType) {
271 case CachedResource::Type::ImageResource:
272 return MIMETypeRegistry::isSupportedImageVideoOrSVGMIMEType(mimeType);
273 case CachedResource::Type::JSON:
274 return MIMETypeRegistry::isSupportedJSONMIMEType(mimeType);
275 case CachedResource::Type::Script:
276 return MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType);
277 case CachedResource::Type::CSSStyleSheet:
278 return MIMETypeRegistry::isSupportedStyleSheetMIMEType(mimeType);
279 case CachedResource::Type::FontResource:
280 return MIMETypeRegistry::isSupportedFontMIMEType(mimeType);
281 case CachedResource::Type::MediaResource:
282 if (!document.settings().mediaPreloadingEnabled())
283 ASSERT_NOT_REACHED()((void)0);
284 return MIMETypeRegistry::isSupportedMediaMIMEType(mimeType);
285#if ENABLE(VIDEO)(defined 1 && 1)
286 case CachedResource::Type::TextTrackResource:
287 return MIMETypeRegistry::isSupportedTextTrackMIMEType(mimeType);
288#endif
289 case CachedResource::Type::RawResource:
290#if ENABLE(APPLICATION_MANIFEST)(defined 1 && 1)
291 case CachedResource::Type::ApplicationManifest:
292#endif
293 return true;
294 default:
295 ASSERT_NOT_REACHED()((void)0);
296 }
297 return false;
298}
299
300void LinkLoader::preconnectIfNeeded(const LinkLoadParameters& params, Document& document)
301{
302 if (!params.relAttribute.isLinkPreconnect || !params.href.isValid() || !params.href.protocolIsInHTTPFamily() || !document.frame())
303 return;
304
305 ResourceRequest request { URL { params.href } };
306#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
307 RefPtr page = document.page();
308 RefPtr documentLoader = document.loader();
309 RefPtr frame = document.frame();
310 RefPtr userContentProvider = frame ? frame->userContentProvider() : nullptr;
311 if (page && documentLoader && userContentProvider) {
312 auto results = userContentProvider->processContentRuleListsForLoad(*page, params.href, ContentExtensions::ResourceType::Ping, *documentLoader);
313 if (results.shouldBlock())
314 return;
315 ContentExtensions::applyResultsToRequest(WTF::move(results), page.get(), request);
316 }
317#endif
318
319 ASSERT(document.settings().linkPreconnectEnabled())((void)0);
320 StoredCredentialsPolicy storageCredentialsPolicy = StoredCredentialsPolicy::Use;
321 if (equalLettersIgnoringASCIICase(params.crossOrigin, "anonymous"_s) && !protect(document.securityOrigin())->isSameOriginDomain(SecurityOrigin::create(params.href)))
322 storageCredentialsPolicy = StoredCredentialsPolicy::DoNotUse;
323 ASSERT(document.frame()->loader().networkingContext())((void)0);
324 platformStrategies()->loaderStrategy()->preconnectTo(protect(document.frame())->loader(), WTF::move(request), storageCredentialsPolicy, LoaderStrategy::ShouldPreconnectAsFirstParty::No, [weakDocument = WeakPtr { document }, href = params.href](ResourceError error) {
325 RefPtr document = weakDocument.get();
326 if (!document)
327 return;
328
329 if (!error.isNull())
330 document->addConsoleMessage(MessageSource::Network, MessageLevel::Error, makeString("Failed to preconnect to "_s, href.string(), ". Error: "_s, error.localizedDescription()));
331 else
332 document->addConsoleMessage(MessageSource::Network, MessageLevel::Info, makeString("Successfully preconnected to "_s, href.string()));
333 });
334}
335
336RefPtr<LinkPreloadResourceClient> LinkLoader::preloadIfNeeded(const LinkLoadParameters& params, Document& document, LinkLoader* loader)
337{
338 std::optional<CachedResource::Type> type;
339 if (!document.loader())
340 return nullptr;
341
342 if (params.relAttribute.isLinkModulePreload) {
343 type = LinkLoader::resourceTypeFromAsAttribute(params.as, document, ShouldLog::No);
344 if (!type)
345 type = CachedResource::Type::Script;
346 if (type && type != CachedResource::Type::Script && type != CachedResource::Type::JSON) {
347 if (loader)
348 loader->triggerError();
349 return nullptr;
350 }
351 } else if (params.relAttribute.isLinkPreload) {
352 ASSERT(document.settings().linkPreloadEnabled())((void)0);
353 type = LinkLoader::resourceTypeFromAsAttribute(params.as, document, ShouldLog::Yes);
354 }
355
356 if (!type)
357 return nullptr;
358
359 URL url;
360 if (type == CachedResource::Type::ImageResource && !params.imageSrcSet.isEmpty()) {
361 auto sourceSize = SizesAttributeParser(params.imageSizes, document).effectiveSize();
362 auto candidate = bestFitSourceForImageAttributes(document.deviceScaleFactor(), AtomString { params.href.string() }, params.imageSrcSet, sourceSize);
363 url = document.completeURL(URL({ }, candidate.string.toString()).string());
364 } else
365 url = document.completeURL(params.href.string());
366
367 if (!url.isValid()) {
368 if (params.relAttribute.isLinkModulePreload)
369 document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=modulepreload> has an invalid `href` value"_s);
370 else if (params.imageSrcSet.isEmpty())
371 document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> has an invalid `href` value"_s);
372 else
373 document.addConsoleMessage(MessageSource::Other, MessageLevel::Error, "<link rel=preload> has an invalid `imagesrcset` value"_s);
374 return nullptr;
375 }
376 auto queries = MQ::MediaQueryParser::parse(params.media, document.cssParserContext());
377 if (!MQ::MediaQueryEvaluator { screenAtom(), document, document.renderStyle() }.evaluate(queries))
378 return nullptr;
379 if (!isSupportedType(type.value(), params.mimeType, document))
380 return nullptr;
381
382 auto options = CachedResourceLoader::defaultCachedResourceOptions();
383 options.referrerPolicy = params.referrerPolicy;
384 options.fetchPriority = params.fetchPriority;
385 options.nonce = params.nonce;
386
387 auto linkRequest = [&]() {
388 if (params.relAttribute.isLinkModulePreload) {
389 options.mode = FetchOptions::Mode::Cors;
390 options.credentials = equalLettersIgnoringASCIICase(params.crossOrigin, "use-credentials"_s) ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin;
391 CachedResourceRequest cachedRequest { ResourceRequest { WTF::move(url) }, WTF::move(options) };
392 Ref securityOrigin = document.securityOrigin();
393 cachedRequest.setOrigin(securityOrigin.get());
394 updateRequestForAccessControl(cachedRequest.resourceRequest(), securityOrigin.get(), options.storedCredentialsPolicy);
395 return cachedRequest;
396 }
397 return createPotentialAccessControlRequest(WTF::move(url), WTF::move(options), document, params.crossOrigin);
398 }();
399 linkRequest.setPriority(DefaultResourceLoadPriority::forResourceType(type.value()));
400 linkRequest.setInitiatorType("link"_s);
401 linkRequest.setIgnoreForRequestCount(true);
402 linkRequest.setIsLinkPreload();
403
404 RefPtr<CachedResource> cachedLinkResource;
405 if (auto result = protect(document.cachedResourceLoader())->preload(type.value(), WTF::move(linkRequest)))
406 cachedLinkResource = WTF::move(result.value());
407
408 if (cachedLinkResource && cachedLinkResource->type() != *type)
409 return nullptr;
410
411 if (cachedLinkResource && loader)
412 return createLinkPreloadResourceClient(*cachedLinkResource, *loader, document);
413
414 if (loader)
415 loader->triggerError();
416 return nullptr;
417}
418
419void LinkLoader::prefetchIfNeeded(const LinkLoadParameters& params, Document& document)
420{
421 if (!params.href.isValid() || !document.frame())
422 return;
423
424 ASSERT(document.settings().linkPrefetchEnabled())((void)0);
425 std::optional<ResourceLoadPriority> priority;
426 CachedResource::Type type = CachedResource::Type::LinkPrefetch;
427
428 if (m_cachedLinkResource) {
429 m_cachedLinkResource->removeClient(*this);
Call argument for 'this' parameter is uncounted and unsafe
430 m_cachedLinkResource = nullptr;
431 }
432 // FIXME: Add further prefetch restrictions/limitations:
433 // - third-party iframes cannot trigger prefetches
434 // - Number of prefetches of a given page is limited (to 1 maybe?)
435 ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
436 options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::DoPolicyCheck;
437 options.certificateInfoPolicy = CertificateInfoPolicy::IncludeCertificateInfo;
438 options.credentials = FetchOptions::Credentials::SameOrigin;
439 options.redirect = FetchOptions::Redirect::Manual;
440 options.mode = FetchOptions::Mode::Navigate;
441 options.serviceWorkersMode = ServiceWorkersMode::None;
442 options.cachingPolicy = CachingPolicy::DisallowCaching;
443 options.referrerPolicy = params.referrerPolicy;
444 options.nonce = params.nonce;
445 m_cachedLinkResource = nullptr;
446 if (auto result = protect(document.cachedResourceLoader())->requestLinkResource(type, CachedResourceRequest(ResourceRequest { document.completeURL(params.href.string()) }, options, priority)))
447 m_cachedLinkResource = WTF::move(result.value());
448 if (RefPtr cachedLinkResource = m_cachedLinkResource.get())
449 cachedLinkResource->addClient(*this);
450}
451
452void LinkLoader::cancelLoad()
453{
454 if (RefPtr client = m_preloadResourceClient)
455 client->clear();
456}
457
458void LinkLoader::loadLink(const LinkLoadParameters& params, Document& document)
459{
460 if (params.relAttribute.isDNSPrefetch) {
461 if (RefPtr frame = document.frame())
462 frame->loader().prefetchDNSIfNeeded(params.href);
463 } else if (params.relAttribute.isLinkPreconnect)
464 preconnectIfNeeded(params, document);
465 else if (params.relAttribute.isLinkPrefetch) {
466 prefetchIfNeeded(params, document);
467 return;
468 }
469
470 if (RefPtr client = m_client.get(); client && client->shouldLoadLink()) {
471 auto resourceClient = preloadIfNeeded(params, document, this);
472 if (RefPtr client = m_preloadResourceClient)
473 client->clear();
474 if (resourceClient)
475 m_preloadResourceClient = WTF::move(resourceClient);
476 }
477}
478
479}