Bug Summary

File:Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/loader/SubresourceLoader.cpp
Warning:line 944, column 90
Call argument is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx15.5.0 -O2 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource286.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=15.5 -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/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1167.5 -fcoverage-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21 -dependency-file /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource286.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/12902642326230122134/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D CLANG_WEBKIT_BRANCH=1 -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/include -I PAL -I ForwardingHeaders -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxml2 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/macosx15.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webm -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources -F/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -internal-isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.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/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource286.plist -x c++ /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore/unified-sources/UnifiedSource286.cpp
1/*
2 * Copyright (C) 2006-2025 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "SubresourceLoader.h"
31
32#include "CachedRawResource.h"
33#include "CrossOriginAccessControl.h"
34#include "DiagnosticLoggingClient.h"
35#include "DiagnosticLoggingKeys.h"
36#include "DiagnosticLoggingResultType.h"
37#include "DocumentLoader.h"
38#include "DocumentPage.h"
39#include "DocumentPrefetcher.h"
40#include "DocumentResourceLoader.h"
41#include "FrameLoader.h"
42#include "HTTPParsers.h"
43#include "HTTPStatusCodes.h"
44#include "InspectorNetworkAgent.h"
45#include "LinkLoader.h"
46#include "LocalFrame.h"
47#include "Logging.h"
48#include "MemoryCache.h"
49#include "OriginAccessPatterns.h"
50#include "ResourceLoadObserver.h"
51#include "ResourceTiming.h"
52#include "SecurityOrigin.h"
53#include "Settings.h"
54#include <wtf/CompletionHandler.h>
55#include <wtf/Ref.h>
56#include <wtf/StdLibExtras.h>
57#include <wtf/SystemTracing.h>
58#include <wtf/text/CString.h>
59#include <wtf/text/MakeString.h>
60
61#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
62#include <wtf/cocoa/RuntimeApplicationChecksCocoa.h>
63#endif
64
65#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
66#include "ResourceLoadInfo.h"
67#endif
68
69#if USE(QUICK_LOOK)(defined USE_QUICK_LOOK && USE_QUICK_LOOK)
70#include "LegacyPreviewLoader.h"
71#include "PreviewConverter.h"
72#endif
73
74#undef SUBRESOURCELOADER_RELEASE_LOG
75#undef SUBRESOURCELOADER_RELEASE_LOG_ERROR
76#define PAGE_ID (this->frame() && this->frame()->pageID() ? this->frame()->pageID()->toUInt64() : 0)
77#define FRAME_ID (this->frame() ? this->frame()->frameID().toUInt64() : 0)
78#if RELEASE_LOG_DISABLED!((defined 1 && 1) || (defined ENABLE_JOURNALD_LOG &&
ENABLE_JOURNALD_LOG) || (defined WTF_OS_ANDROID && WTF_OS_ANDROID
))
79#define SUBRESOURCELOADER_RELEASE_LOG(fmt, ...) UNUSED_VARIABLE(this)(void)this
80#define SUBRESOURCELOADER_RELEASE_LOG_ERROR(fmt, ...) UNUSED_VARIABLE(this)(void)this
81#else
82#define SUBRESOURCELOADER_RELEASE_LOG(fmt, ...) RELEASE_LOG_FORWARDABLE(ResourceLoading, fmt, PAGE_ID, FRAME_ID, identifier() ? identifier()->toUInt64() : 0, ##__VA_ARGS__)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (LogResourceLoading
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
(MESSAGE_fmt), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG35"
) = MESSAGE_fmt; uint8_t _Alignas(16) __attribute__((uninitialized
)) _os_fmt_buf[__builtin_os_log_format_buffer_size(MESSAGE_fmt
, WTF::safePrintfType(PAGE_ID) , WTF::safePrintfType(FRAME_ID
) , WTF::safePrintfType(identifier() ? identifier()->toUInt64
() : 0) , WTF::safePrintfType(##__VA_ARGS__))]; _os_log_impl(
&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, MESSAGE_fmt, WTF::safePrintfType
(PAGE_ID) , WTF::safePrintfType(FRAME_ID) , WTF::safePrintfType
(identifier() ? identifier()->toUInt64() : 0) , WTF::safePrintfType
(##__VA_ARGS__)), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
83#define SUBRESOURCELOADER_RELEASE_LOG_ERROR(fmt, ...) RELEASE_LOG_ERROR(ResourceLoading, "%p - [pageID=%" PRIu64 ", frameID=%" PRIu64 ", frameLoader=%p, resourceID=%" PRIu64 "] SubresourceLoader::" fmt, this, PAGE_ID, FRAME_ID, frameLoader(), identifier() ? identifier()->toUInt64() : 0, ##__VA_ARGS__)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (LogResourceLoading
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%p - [pageID=%" "ll" "u" ", frameID=%" "ll" "u" ", frameLoader=%p, resourceID=%"
"ll" "u" "] SubresourceLoader::" fmt), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG36"
) = "%p - [pageID=%" "ll" "u" ", frameID=%" "ll" "u" ", frameLoader=%p, resourceID=%"
"ll" "u" "] SubresourceLoader::" fmt; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("%p - [pageID=%" "ll" "u" ", frameID=%" "ll" "u" ", frameLoader=%p, resourceID=%"
"ll" "u" "] SubresourceLoader::" fmt, this, PAGE_ID, FRAME_ID
, frameLoader(), identifier() ? identifier()->toUInt64() :
0, ##__VA_ARGS__)]; _os_log_error_impl(&__dso_handle, _log_tmp
, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format(
_os_fmt_buf, "%p - [pageID=%" "ll" "u" ", frameID=%" "ll" "u"
", frameLoader=%p, resourceID=%" "ll" "u" "] SubresourceLoader::"
fmt, this, PAGE_ID, FRAME_ID, frameLoader(), identifier() ? identifier
()->toUInt64() : 0, ##__VA_ARGS__), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
84#endif
85
86namespace WebCore {
87
88SubresourceLoader::RequestCountTracker::RequestCountTracker(CachedResourceLoader& cachedResourceLoader, const CachedResource& resource)
89 : m_cachedResourceLoader(&cachedResourceLoader)
90 , m_resource(resource)
91{
92 cachedResourceLoader.incrementRequestCount(resource);
93}
94
95SubresourceLoader::RequestCountTracker::RequestCountTracker(RequestCountTracker&& other)
96 : m_cachedResourceLoader(std::exchange(other.m_cachedResourceLoader, nullptr))
97 , m_resource(std::exchange(other.m_resource, nullptr))
98{
99}
100
101auto SubresourceLoader::RequestCountTracker::operator=(RequestCountTracker&& other) -> RequestCountTracker&
102{
103 m_cachedResourceLoader = std::exchange(other.m_cachedResourceLoader, nullptr);
104 m_resource = std::exchange(other.m_resource, nullptr);
105 return *this;
106}
107
108SubresourceLoader::RequestCountTracker::~RequestCountTracker()
109{
110 RefPtr cachedResourceLoader = m_cachedResourceLoader.get();
111 RefPtr resource = m_resource.get();
112 if (cachedResourceLoader && resource)
113 cachedResourceLoader->decrementRequestCount(*resource);
114}
115
116SubresourceLoader::SubresourceLoader(LocalFrame& frame, CachedResource& resource, const ResourceLoaderOptions& options)
117 : ResourceLoader(frame, options)
118 , m_resource(resource)
119 , m_state(Uninitialized)
120 , m_requestCountTracker(std::in_place, protect(frame.document())->cachedResourceLoader(), resource)
121{
122#if ENABLE(CONTENT_EXTENSIONS)(defined 1 && 1)
123 m_resourceType = ContentExtensions::toResourceType(resource.type(), resource.resourceRequest().requester(), frame.isMainFrame());
124#endif
125
126 m_site = CachedResourceLoader::computeFetchMetadataSite(resource.resourceRequest(), resource.type(), options.mode, frame, frame.isMainFrame() && m_documentLoader && m_documentLoader->isRequestFromClientOrUserInput());
127 ASSERT(!resource.resourceRequest().hasHTTPHeaderField(HTTPHeaderName::SecFetchSite) || resource.resourceRequest().httpHeaderField(HTTPHeaderName::SecFetchSite) == convertEnumerationToString(m_site))((void)0);
128}
129
130SubresourceLoader::~SubresourceLoader()
131{
132 ASSERT(m_state != Initialized)((void)0);
133 ASSERT(reachedTerminalState())((void)0);
134}
135
136void SubresourceLoader::create(LocalFrame& frame, CachedResource& resource, ResourceRequest&& request, const ResourceLoaderOptions& options, CompletionHandler<void(RefPtr<SubresourceLoader>&&)>&& completionHandler)
137{
138 Ref subloader = adoptRef(*new SubresourceLoader(frame, resource, options));
139#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
140 if (!WTF::IOSApplication::isWebProcess()) {
141 // On iOS, do not invoke synchronous resource load delegates while resource load scheduling
142 // is disabled to avoid re-entering style selection from a different thread (see <rdar://problem/9121719>).
143 // FIXME: This should be fixed for all ports in <https://bugs.webkit.org/show_bug.cgi?id=56647>.
144 subloader->m_iOSOriginalRequest = request;
145 return completionHandler(WTF::move(subloader));
146 }
147#endif
148 subloader->init(WTF::move(request), [subloader, completionHandler = WTF::move(completionHandler)] (bool initialized) mutable {
149 if (!initialized)
150 return completionHandler(nullptr);
151 completionHandler(WTF::move(subloader));
152 });
153}
154
155#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
156void SubresourceLoader::startLoading()
157{
158 // FIXME: this should probably be removed.
159 ASSERT(!WTF::IOSApplication::isWebProcess())((void)0);
160 init(ResourceRequest(m_iOSOriginalRequest), [this, protectedThis = Ref { *this }] (bool success) {
161 if (!success)
162 return;
163 m_iOSOriginalRequest = ResourceRequest();
164 start();
165 });
166}
167#endif
168
169void SubresourceLoader::cancelIfNotFinishing()
170{
171 if (m_state != Initialized)
172 return;
173
174 ResourceLoader::cancel();
175}
176
177void SubresourceLoader::init(ResourceRequest&& request, CompletionHandler<void(bool)>&& completionHandler)
178{
179 ResourceLoader::init(WTF::move(request), [this, protectedThis = Ref { *this }, completionHandler = WTF::move(completionHandler)] (bool initialized) mutable {
180 if (!initialized)
181 return completionHandler(false);
182 RefPtr documentLoader = this->documentLoader();
183 if (!documentLoader) {
184 ASSERT_NOT_REACHED()((void)0);
185 SUBRESOURCELOADER_RELEASE_LOG_ERROR("init: resource load canceled because document loader is null");
186 return completionHandler(false);
187 }
188 ASSERT(!reachedTerminalState())((void)0);
189 m_state = Initialized;
190 documentLoader->addSubresourceLoader(*this);
191 m_origin = m_resource->origin();
192 completionHandler(true);
193 });
194}
195
196bool SubresourceLoader::isSubresourceLoader() const
197{
198 return true;
199}
200
201void SubresourceLoader::willSendRequestInternal(ResourceRequest&& newRequest, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& completionHandler)
202{
203 Ref protectedThis { *this };
204
205 if (!newRequest.url().isValid()) {
206 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL);
207 cancel(cannotShowURLError());
208 return completionHandler(WTF::move(newRequest));
209 }
210
211 if (newRequest.requester() != ResourceRequestRequester::Main) {
212 ResourceLoadObserver::singleton().logSubresourceLoading(protect(frame()).get(), newRequest, redirectResponse,
213 (isScriptLikeDestination(options().destination) ? ResourceLoadObserver::FetchDestinationIsScriptLike::Yes : ResourceLoadObserver::FetchDestinationIsScriptLike::No));
214 }
215
216 auto continueWillSendRequest = [this, protectedThis = Ref { *this }, redirectResponse] (CompletionHandler<void(ResourceRequest&&)>&& completionHandler, ResourceRequest&& newRequest) mutable {
217 if (newRequest.isNull() || reachedTerminalState()) {
218 if (newRequest.isNull())
219 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_CANCELLED_INVALID_NEW_REQUEST);
220 else
221 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_CANCELLED_TERMINAL_STATE);
222 return completionHandler(WTF::move(newRequest));
223 }
224
225 ResourceLoader::willSendRequestInternal(WTF::move(newRequest), redirectResponse, [this, protectedThis = Ref { *this }, completionHandler = WTF::move(completionHandler), redirectResponse] (ResourceRequest&& request) mutable {
226 tracePoint(SubresourceLoadWillStart, identifier() ? identifier()->toUInt64() : 0, PAGE_ID, FRAME_ID);
227
228 if (reachedTerminalState()) {
229 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_TERMINAL_STATE_CALLING_COMPLETION_HANDLER);
230 return completionHandler(WTF::move(request));
231 }
232
233 if (request.isNull()) {
234 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_CANCELLED_INVALID_REQUEST);
235 cancel();
236 return completionHandler(WTF::move(request));
237 }
238
239 if (m_resource->type() == CachedResource::Type::MainResource && !redirectResponse.isNull())
240 protect(documentLoader())->willContinueMainResourceLoadAfterRedirect(request);
241
242 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCELOAD_FINISHED);
243 completionHandler(WTF::move(request));
244 });
245 };
246
247 ASSERT(!newRequest.isNull())((void)0);
248 if (!redirectResponse.isNull()) {
249 RefPtr resource = m_resource.get();
250 if (options().redirect != FetchOptions::Redirect::Follow) {
251 if (options().redirect == FetchOptions::Redirect::Error) {
252 ResourceError error { errorDomainWebKitInternal, 0, request().url(), makeString("Not allowed to follow a redirection while loading "_s, request().url().string()), ResourceError::Type::AccessControl };
253
254 if (RefPtr frame = m_frame.get(); frame && frame->document())
255 protect(frame->document())->addConsoleMessage(MessageSource::Security, MessageLevel::Error, error.localizedDescription());
256
257 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCELOAD_CANCELLED_REDIRECT_NOT_ALLOWED);
258
259 cancel(error);
260 return completionHandler(WTF::move(newRequest));
261 }
262
263 ResourceResponse opaqueRedirectedResponse = redirectResponse;
264 opaqueRedirectedResponse.setType(ResourceResponse::Type::Opaqueredirect);
265 opaqueRedirectedResponse.setTainting(ResourceResponse::Tainting::Opaqueredirect);
266 resource->responseReceived(WTF::move(opaqueRedirectedResponse));
267 if (reachedTerminalState()) {
268 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_REACHED_TERMINAL_STATE);
269 return completionHandler(WTF::move(newRequest));
270 }
271
272 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_LOAD_COMPLETED);
273
274 NetworkLoadMetrics emptyMetrics;
275 didFinishLoading(emptyMetrics);
276 return completionHandler(WTF::move(newRequest));
277 } else if (m_redirectCount++ >= options().maxRedirectCount) {
278 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_LOAD_CANCELLED_TOO_MANY_REDIRECTS);
279 cancel(ResourceError(String(), 0, request().url(), "Too many redirections"_s, ResourceError::Type::General));
280 return completionHandler(WTF::move(newRequest));
281 }
282
283 // CachedResources are keyed off their original request URL.
284 // Requesting the same original URL a second time can redirect to a unique second resource.
285 // Therefore, if a redirect to a different destination URL occurs, we should no longer consider this a revalidation of the first resource.
286 // Doing so would have us reusing the resource from the first request if the second request's revalidation succeeds.
287 RefPtr frame = m_frame.get();
288 if (newRequest.isConditional() && resource->resourceToRevalidate() && newRequest.url() != protect(resource->resourceToRevalidate())->response().url()) {
289 newRequest.makeUnconditional();
290 MemoryCache::singleton().revalidationFailed(*resource);
291 if (frame && frame->page())
292 protect(frame->page())->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
293 }
294
295 RefPtr documentLoader = this->documentLoader();
296 Ref originalOrigin = SecurityOrigin::create(redirectResponse.url());
297 Ref cachedResourceLoader = documentLoader->cachedResourceLoader();
298 m_site = CachedResourceLoader::computeFetchMetadataSiteAfterRedirection(newRequest, m_resource->type(), options().mode, originalOrigin.get(), m_site, frame && frame->isMainFrame() && documentLoader->isRequestFromClientOrUserInput());
299
300 if (!cachedResourceLoader->updateRequestAfterRedirection(resource->type(), newRequest, options(), m_site, originalRequest().url(), redirectResponse.url())) {
301 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_LOAD_CANCELLED_CANNOT_REQUEST_AFTER_REDIRECTION);
302 cancel(ResourceError { String(), 0, request().url(), "Redirect was not allowed"_s, ResourceError::Type::AccessControl });
303 return completionHandler(WTF::move(newRequest));
304 }
305
306 if (!isPortAllowed(newRequest.url())) {
307 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_LOAD_CANCELLED_AFTER_USING_BLOCKED_PORT);
308 if (RefPtr frame = m_frame.get())
309 FrameLoader::reportBlockedLoadFailed(*frame, newRequest.url());
310 if (frameLoader())
311 cancel(frameLoader()->blockedError(newRequest));
312 return completionHandler(WTF::move(newRequest));
313 }
314
315 auto accessControlCheckResult = checkRedirectionCrossOriginAccessControl(request(), redirectResponse, newRequest);
316 if (!accessControlCheckResult) {
317 auto errorMessage = makeString("Cross-origin redirection to "_s, newRequest.url().string(), " denied by Cross-Origin Resource Sharing policy: "_s, accessControlCheckResult.error());
318 if (RefPtr frame = m_frame.get(); frame && frame->document())
319 protect(frame->document())->addConsoleMessage(MessageSource::Security, MessageLevel::Error, errorMessage);
320 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_LOAD_CANCELLED_AFTER_REDIRECT_DENIED_BY_CORS_POLICY);
321 cancel(ResourceError(String(), 0, request().url(), errorMessage, ResourceError::Type::AccessControl));
322 return completionHandler(WTF::move(newRequest));
323 }
324
325 if (resource->isImage() && cachedResourceLoader->shouldDeferImageLoad(newRequest.url())) {
326 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_LOAD_CANCELLED_AFTER_IMAGE_BEING_DEFERRED);
327 cancel();
328 return completionHandler(WTF::move(newRequest));
329 }
330 resource->redirectReceived(WTF::move(newRequest), redirectResponse, [this, protectedThis = Ref { *this }, completionHandler = WTF::move(completionHandler), continueWillSendRequest = WTF::move(continueWillSendRequest)] (ResourceRequest&& request) mutable {
331 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLSENDREQUESTINTERNAL_RESOURCE_DONE_NOTIFYING_CLIENTS);
332 continueWillSendRequest(WTF::move(completionHandler), WTF::move(request));
333 });
334 return;
335 }
336
337 continueWillSendRequest(WTF::move(completionHandler), WTF::move(newRequest));
338}
339
340void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
341{
342 ASSERT(m_state == Initialized)((void)0);
343 Ref protectedThis { *this };
344 protect(cachedResource())->didSendData(bytesSent, totalBytesToBeSent);
345}
346
347#if USE(QUICK_LOOK)(defined USE_QUICK_LOOK && USE_QUICK_LOOK)
348
349bool SubresourceLoader::shouldCreatePreviewLoaderForResponse(const ResourceResponse& response) const
350{
351 if (m_resource->type() != CachedResource::Type::MainResource)
352 return false;
353
354 if (m_previewLoader)
355 return false;
356
357 return PreviewConverter::supportsMIMEType(response.mimeType());
358}
359
360void SubresourceLoader::didReceivePreviewResponse(ResourceResponse&& response)
361{
362 ASSERT(m_state == Initialized)((void)0);
363 ASSERT(!response.isNull())((void)0);
364 ASSERT(m_resource)((void)0);
365 ResourceLoader::didReceivePreviewResponse(ResourceResponse { response });
366 protect(cachedResource())->previewResponseReceived(WTF::move(response));
367}
368
369#endif
370
371static bool isLocationURLFailure(const ResourceResponse& response)
372{
373 auto locationString = response.httpHeaderField(HTTPHeaderName::Location);
374 return !locationString.isNull() && locationString.isEmpty();
375}
376
377void SubresourceLoader::didReceiveResponse(ResourceResponse&& response, CompletionHandler<void()>&& policyCompletionHandler)
378{
379 ASSERT(!response.isNull())((void)0);
380 ASSERT(m_state == Initialized)((void)0);
381
382 CompletionHandlerCallingScope completionHandlerCaller(WTF::move(policyCompletionHandler));
383
384 if (response.containsInvalidHTTPHeaders()) {
385 didFail(badResponseHeadersError(request().url()));
386 return;
387 }
388
389#if USE(QUICK_LOOK)(defined USE_QUICK_LOOK && USE_QUICK_LOOK)
390 if (shouldCreatePreviewLoaderForResponse(response)) {
391 lazyInitialize(m_previewLoader, LegacyPreviewLoader::create(*this, response));
392 if (m_previewLoader->didReceiveResponse(response))
393 return;
394 }
395#endif
396 // Implementing step 10 of https://fetch.spec.whatwg.org/#main-fetch for service worker responses.
397 if (response.source() == ResourceResponse::Source::ServiceWorker && response.url() != request().url()) {
398 Ref loader = documentLoader()->cachedResourceLoader();
399 if (!loader->allowedByContentSecurityPolicy(m_resource->type(), response.url(), options(), ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
400 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDRECEIVERESPONSE_CANCELING_LOAD_BLOCKED_BY_CONTENT_POLICY);
401 cancel(ResourceError({ }, 0, response.url(), { }, ResourceError::Type::General));
402 return;
403 }
404 }
405
406 if (auto error = validateRangeRequestedFlag(request(), response)) {
407 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDRECEIVERESPONSE_CANCELING_LOAD_RECEIVED_UNEXPECTED_RANGE_RESPONSE);
408 cancel(WTF::move(*error));
409 return;
410 }
411
412 // We want redirect responses to be processed through willSendRequestInternal. Exceptions are
413 // redirection with no or empty Location headers and fetch in manual redirect mode. Or in rare circumstances,
414 // cases of too many redirects from CFNetwork (<rdar://problem/30610988>).
415#if !PLATFORM(COCOA)(defined 1 && 1)
416 ASSERT(response.httpStatusCode() < httpStatus300MultipleChoices || response.httpStatusCode() >= httpStatus400BadRequest || response.httpStatusCode() == httpStatus304NotModified || response.httpHeaderField(HTTPHeaderName::Location).isEmpty() || response.type() == ResourceResponse::Type::Opaqueredirect)((void)0);
417#endif
418
419 // Reference the object in this method since the additional processing can do
420 // anything including removing the last reference to this object; one example of this is 3266216.
421 Ref protectedThis { *this };
422
423 if (shouldIncludeCertificateInfo())
424 response.includeCertificateInfo();
425
426 RefPtr resource = m_resource.get();
427 if (!resource) {
428 ASSERT_NOT_REACHED()((void)0);
429 RELEASE_LOG_FAULT(Loading, "Resource was unexpectedly null in SubresourceLoader::didReceiveResponse")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (LogLoading.
osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_FAULT; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Resource was unexpectedly null in SubresourceLoader::didReceiveResponse"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG37"
) = "Resource was unexpectedly null in SubresourceLoader::didReceiveResponse"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Resource was unexpectedly null in SubresourceLoader::didReceiveResponse"
)]; _os_log_fault_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Resource was unexpectedly null in SubresourceLoader::didReceiveResponse"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
430 }
431
432 RefPtr frame = m_frame.get();
433 if (resource && resource->resourceToRevalidate()) {
434 if (response.httpStatusCode() == httpStatus304NotModified) {
435 // Existing resource is ok, just use it updating the expiration time.
436 ResourceResponse revalidationResponse = response;
437 revalidationResponse.setSource(ResourceResponse::Source::MemoryCacheAfterValidation);
438 resource->setResponse(ResourceResponse { revalidationResponse });
439 MemoryCache::singleton().revalidationSucceeded(*resource, resource->response());
440 if (frame && frame->page())
441 protect(frame->page())->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes);
442 if (!reachedTerminalState())
443 ResourceLoader::didReceiveResponse(WTF::move(revalidationResponse), [completionHandlerCaller = WTF::move(completionHandlerCaller)] { });
444 return;
445 }
446 // Did not get 304 response, continue as a regular resource load.
447 MemoryCache::singleton().revalidationFailed(*resource);
448 if (frame && frame->page())
449 protect(frame->page())->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes);
450 }
451
452 auto accessControlCheckResult = checkResponseCrossOriginAccessControl(response);
453 if (!accessControlCheckResult) {
454 if (frame && frame->document())
455 protect(frame->document())->addConsoleMessage(MessageSource::Security, MessageLevel::Error, accessControlCheckResult.error());
456 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDRECEIVERESPONSE_CANCELING_LOAD_BECAUSE_OF_CROSS_ORIGIN_ACCESS_CONTROL);
457 cancel(ResourceError(String(), 0, request().url(), accessControlCheckResult.error(), ResourceError::Type::AccessControl));
458 return;
459 }
460
461 if (response.isRedirection()) {
462 if (options().redirect == FetchOptions::Redirect::Follow && isLocationURLFailure(response)) {
463 // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 3
464 cancel();
465 return;
466 }
467 if (options().redirect == FetchOptions::Redirect::Manual) {
468 ResourceResponse opaqueRedirectedResponse = response;
469 opaqueRedirectedResponse.setType(ResourceResponse::Type::Opaqueredirect);
470 opaqueRedirectedResponse.setTainting(ResourceResponse::Tainting::Opaqueredirect);
471 if (resource)
472 resource->responseReceived(ResourceResponse { opaqueRedirectedResponse });
473 if (!reachedTerminalState())
474 ResourceLoader::didReceiveResponse(WTF::move(opaqueRedirectedResponse), [completionHandlerCaller = WTF::move(completionHandlerCaller)] { });
475 return;
476 }
477 }
478
479 if (m_loadingMultipartContent) {
480 if (!m_previousPartResponse.isNull()) {
481 if (resource) {
482 resource->responseReceived(WTF::move(m_previousPartResponse));
483 // The resource data will change as the next part is loaded, so we need to make a copy.
484 resource->finishLoading(protect(resourceData())->copy().ptr(), { });
485 }
486 }
487 clearResourceData();
488 m_previousPartResponse = response;
489 // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
490 // After the first multipart section is complete, signal to delegates that this load is "finished"
491 NetworkLoadMetrics emptyMetrics;
492 protect(documentLoader())->subresourceLoaderFinishedLoadingOnePart(*this);
493 didFinishLoadingOnePart(emptyMetrics);
494 } else {
495 if (resource)
496 resource->responseReceived(ResourceResponse { response });
497 }
498 if (reachedTerminalState())
499 return;
500
501 bool isResponseMultipart = response.isMultipart();
502 if (options().mode != FetchOptions::Mode::Navigate && frame && frame->document())
503 LinkLoader::loadLinksFromHeader(response.httpHeaderField(HTTPHeaderName::Link), protect(documentLoader())->url(), *protect(frame->document()), LinkLoader::MediaAttributeCheck::SkipMediaAttributeCheck);
504
505 // https://wicg.github.io/nav-speculation/prefetch.html#clear-prefetch-cache
506 if (frame && frame->settings().clearSiteDataHTTPHeaderEnabled()) {
507 auto clearSiteDataValues = parseClearSiteDataHeader(response);
508 if (clearSiteDataValues.containsAny({ ClearSiteDataValue::Cache, ClearSiteDataValue::PrefetchCache })) {
509 Ref origin = SecurityOrigin::create(response.url());
510 frame->loader().documentPrefetcher().clearPrefetchedResourcesForOrigin(origin);
511 }
512 }
513
514 ResourceLoader::didReceiveResponse(WTF::move(response), [this, protectedThis = Ref { *this }, isResponseMultipart, completionHandlerCaller = WTF::move(completionHandlerCaller)]() mutable {
515 if (reachedTerminalState())
516 return;
517
518 RefPtr resource = m_resource.get();
519 // FIXME: Main resources have a different set of rules for multipart than images do.
520 // Hopefully we can merge those 2 paths.
521 if (isResponseMultipart && resource && resource->type() != CachedResource::Type::MainResource) {
522 m_loadingMultipartContent = true;
523
524 // We don't count multiParts in a CachedResourceLoader's request count
525 m_requestCountTracker = std::nullopt;
526 if (!resource->isImage()) {
527 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDRECEIVERESPONSE_CANCELING_LOAD_BECAUSE_OF_MULTIPART_NON_IMAGE);
528 cancel();
529 return;
530 }
531 }
532
533 if (responseHasHTTPStatusCodeError()) {
534 m_loadTiming.markEndTime();
535 auto* metrics = this->response().deprecatedNetworkLoadMetricsOrNull();
536 reportResourceTiming(metrics ? *metrics : NetworkLoadMetrics::emptyMetrics());
537
538 m_state = Finishing;
539 resource->error(CachedResource::LoadError);
540 cancel();
541 }
542
543 if (m_inAsyncResponsePolicyCheck)
544 m_policyForResponseCompletionHandler = completionHandlerCaller.release();
545 });
546}
547
548void SubresourceLoader::didReceiveResponsePolicy()
549{
550 ASSERT(m_inAsyncResponsePolicyCheck)((void)0);
551 m_inAsyncResponsePolicyCheck = false;
552 if (auto completionHandler = WTF::move(m_policyForResponseCompletionHandler))
553 completionHandler();
554}
555
556void SubresourceLoader::didReceiveBuffer(const FragmentedSharedBuffer& buffer, long long encodedDataLength, DataPayloadType dataPayloadType)
557{
558#if USE(QUICK_LOOK)(defined USE_QUICK_LOOK && USE_QUICK_LOOK)
559 if (m_previewLoader && m_previewLoader->didReceiveData(buffer.makeContiguous()))
560 return;
561#endif
562
563 RefPtr resource = m_resource.get();
564 ASSERT(resource)((void)0);
565
566 if (resource->response().httpStatusCode() >= httpStatus400BadRequest && !resource->shouldIgnoreHTTPStatusCodeErrors())
567 return;
568 ASSERT(!resource->resourceToRevalidate())((void)0);
569 ASSERT(!resource->errorOccurred())((void)0);
570 ASSERT(m_state == Initialized)((void)0);
571 // Reference the object in this method since the additional processing can do
572 // anything including removing the last reference to this object; one example of this is 3266216.
573 Ref protectedThis { *this };
574
575 ResourceLoader::didReceiveBuffer(buffer, encodedDataLength, dataPayloadType);
576
577 if (!m_loadingMultipartContent) {
578 if (RefPtr resourceData = this->resourceData())
579 resource->updateBuffer(*resourceData);
580 else
581 resource->updateData(buffer.makeContiguous());
582 }
583}
584
585bool SubresourceLoader::responseHasHTTPStatusCodeError() const
586{
587 RefPtr resource = m_resource.get();
588 if (resource->response().httpStatusCode() < httpStatus400BadRequest || resource->shouldIgnoreHTTPStatusCodeErrors())
589 return false;
590 return true;
591}
592
593static void logResourceLoaded(LocalFrame* frame, CachedResource::Type type)
594{
595 if (!frame || !frame->page())
596 return;
597
598 String resourceType;
599 switch (type) {
600 case CachedResource::Type::MainResource:
601 resourceType = DiagnosticLoggingKeys::mainResourceKey();
602 break;
603 case CachedResource::Type::ImageResource:
604 resourceType = DiagnosticLoggingKeys::imageKey();
605 break;
606#if ENABLE(XSLT)(defined 1 && 1)
607 case CachedResource::Type::XSLStyleSheet:
608#endif
609 case CachedResource::Type::CSSStyleSheet:
610 resourceType = DiagnosticLoggingKeys::styleSheetKey();
611 break;
612 case CachedResource::Type::JSON:
613 case CachedResource::Type::Script:
614 resourceType = DiagnosticLoggingKeys::scriptKey();
615 break;
616 case CachedResource::Type::FontResource:
617 case CachedResource::Type::SVGFontResource:
618 resourceType = DiagnosticLoggingKeys::fontKey();
619 break;
620 case CachedResource::Type::Beacon:
621 case CachedResource::Type::Ping:
622 case CachedResource::Type::MediaResource:
623#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
624 case CachedResource::Type::EnvironmentMapResource:
625 case CachedResource::Type::ModelResource:
626#endif
627 case CachedResource::Type::Icon:
628 case CachedResource::Type::RawResource:
629 resourceType = DiagnosticLoggingKeys::rawKey();
630 break;
631 case CachedResource::Type::SVGDocumentResource:
632 resourceType = DiagnosticLoggingKeys::svgDocumentKey();
633 break;
634#if ENABLE(APPLICATION_MANIFEST)(defined 1 && 1)
635 case CachedResource::Type::ApplicationManifest:
636 resourceType = DiagnosticLoggingKeys::applicationManifestKey();
637 break;
638#endif
639 case CachedResource::Type::LinkPrefetch:
640#if ENABLE(VIDEO)(defined 1 && 1)
641 case CachedResource::Type::TextTrackResource:
642#endif
643 resourceType = DiagnosticLoggingKeys::otherKey();
644 break;
645 }
646
647 protect(frame->page())->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::resourceLoadedKey(), resourceType, ShouldSample::Yes);
648}
649
650Expected<void, String> SubresourceLoader::checkResponseCrossOriginAccessControl(const ResourceResponse& response)
651{
652 if (!m_resource->isCrossOrigin() || options().mode != FetchOptions::Mode::Cors)
653 return { };
654
655 if (response.source() == ResourceResponse::Source::ServiceWorker) {
656 if (response.tainting() == ResourceResponse::Tainting::Opaque) {
657 // FIXME: This should have an error message.
658 return makeUnexpected(String());
659 }
660 return { };
661 }
662
663 ASSERT(m_origin)((void)0);
664
665 return passesAccessControlCheck(response, options().credentials == FetchOptions::Credentials::Include ? StoredCredentialsPolicy::Use : StoredCredentialsPolicy::DoNotUse, *protect(m_origin), &CrossOriginAccessControlCheckDisabler::singleton());
666}
667
668Expected<void, String> SubresourceLoader::checkRedirectionCrossOriginAccessControl(const ResourceRequest& previousRequest, const ResourceResponse& redirectResponse, ResourceRequest& newRequest)
669{
670 bool crossOriginFlag = m_resource->isCrossOrigin();
671 bool isNextRequestCrossOrigin = m_origin && !protect(m_origin)->canRequest(newRequest.url(), OriginAccessPatternsForWebProcess::singleton());
672
673 if (isNextRequestCrossOrigin)
674 protect(cachedResource())->setCrossOrigin();
675 bool newCrossOriginFlag = m_resource->isCrossOrigin();
676
677 ASSERT(options().mode != FetchOptions::Mode::SameOrigin || !newCrossOriginFlag)((void)0);
678
679 // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 7 & 8.
680 if (options().mode == FetchOptions::Mode::Cors) {
681 if (newCrossOriginFlag) {
682 auto locationString = redirectResponse.httpHeaderField(HTTPHeaderName::Location);
683 String errorMessage = validateCrossOriginRedirectionURL(URL(redirectResponse.url(), locationString));
684 if (!errorMessage.isNull())
685 return makeUnexpected(WTF::move(errorMessage));
686 }
687
688 ASSERT(m_origin)((void)0);
689 if (crossOriginFlag) {
690 auto accessControlCheckResult = passesAccessControlCheck(redirectResponse, options().storedCredentialsPolicy, *protect(m_origin), &CrossOriginAccessControlCheckDisabler::singleton());
691 if (!accessControlCheckResult)
692 return accessControlCheckResult;
693 }
694 }
695
696 bool redirectingToNewOrigin = false;
697 if (newCrossOriginFlag) {
698 if (!crossOriginFlag && isNextRequestCrossOrigin)
699 redirectingToNewOrigin = true;
700 else
701 redirectingToNewOrigin = !protocolHostAndPortAreEqual(previousRequest.url(), newRequest.url());
702 }
703
704 // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 10.
705 if (crossOriginFlag && redirectingToNewOrigin)
706 m_origin = SecurityOrigin::createOpaque();
707
708 newRequest.redirectAsGETIfNeeded(previousRequest, redirectResponse);
709
710 // Implementing https://fetch.spec.whatwg.org/#concept-http-redirect-fetch step 14.
711 updateReferrerPolicy(redirectResponse.httpHeaderField(HTTPHeaderName::ReferrerPolicy));
712
713 if (options().mode == FetchOptions::Mode::Cors && redirectingToNewOrigin) {
714 cleanHTTPRequestHeadersForAccessControl(newRequest, options().httpHeadersToKeep);
715 updateRequestForAccessControl(newRequest, *protect(m_origin), options().storedCredentialsPolicy);
716 }
717
718 updateRequestReferrer(newRequest, referrerPolicy(), URL { previousRequest.httpReferrer() }, OriginAccessPatternsForWebProcess::singleton());
719
720 FrameLoader::addHTTPOriginIfNeeded(newRequest, m_origin ? protect(m_origin)->toString() : String());
721
722 return { };
723}
724
725void SubresourceLoader::updateReferrerPolicy(const String& referrerPolicyValue)
726{
727 if (auto referrerPolicy = parseReferrerPolicy(referrerPolicyValue, ReferrerPolicySource::HTTPHeader)) {
728 ASSERT(*referrerPolicy != ReferrerPolicy::EmptyString)((void)0);
729 setReferrerPolicy(*referrerPolicy);
730 }
731}
732
733void SubresourceLoader::didFinishLoading(const NetworkLoadMetrics& networkLoadMetrics)
734{
735 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDFINISHLOADING);
736
737#if USE(QUICK_LOOK)(defined USE_QUICK_LOOK && USE_QUICK_LOOK)
738 if (m_previewLoader && m_previewLoader->didFinishLoading())
739 return;
740#endif
741
742 if (m_state != Initialized)
743 return;
744
745 Ref protectedThis { *this };
746
747 ASSERT(!reachedTerminalState())((void)0);
748 RefPtr resource = m_resource.get();
749 if (!resource)
750 return;
751
752 ASSERT(!resource->resourceToRevalidate())((void)0);
753 // FIXME (129394): We should cancel the load when a decode error occurs instead of continuing the load to completion.
754 ASSERT(!resource->errorOccurred() || resource->status() == CachedResource::DecodeError || !resource->isLoading())((void)0);
755 LOG(ResourceLoading, "Received '%s'.", resource->url().string().latin1().data())((void)0);
756 logResourceLoaded(protect(frame()).get(), resource->type());
757
758 m_loadTiming.markEndTime();
759
760 if (networkLoadMetrics.isComplete())
761 reportResourceTiming(networkLoadMetrics);
762 else {
763 // This is the legacy path for platforms (and ResourceHandle paths) that do not provide
764 // complete load metrics in didFinishLoad. In those cases, fall back to the possibility
765 // that they populated partial load timing information on the ResourceResponse.
766 const auto* timing = resource->response().deprecatedNetworkLoadMetricsOrNull();
767 reportResourceTiming(timing ? *timing : NetworkLoadMetrics::emptyMetrics());
768 }
769
770 if (resource->type() != CachedResource::Type::MainResource)
771 tracePoint(SubresourceLoadDidEnd, identifier() ? identifier()->toUInt64() : 0);
772
773 m_state = Finishing;
774 if (m_loadingMultipartContent && !m_previousPartResponse.isNull())
775 resource->responseReceived(ResourceResponse { m_previousPartResponse });
776 resource->finishLoading(protect(resourceData()).get(), networkLoadMetrics);
777
778 if (wasCancelled()) {
779 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDFINISHLOADING_CANCELED);
780 return;
781 }
782
783 resource->finish();
784 ASSERT(!reachedTerminalState())((void)0);
785 didFinishLoadingOnePart(networkLoadMetrics);
786 notifyDone(LoadCompletionType::Finish);
787
788 if (reachedTerminalState()) {
789 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDFINISHLOADING_REACHED_TERMINAL_STATE);
790 return;
791 }
792 releaseResources();
793}
794
795void SubresourceLoader::didFail(const ResourceError& error)
796{
797 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_DIDFAIL, static_cast<int>(error.type()), error.errorCode());
798
799#if USE(QUICK_LOOK)(defined USE_QUICK_LOOK && USE_QUICK_LOOK)
800 if (m_previewLoader)
801 m_previewLoader->didFail();
802#endif
803
804 if (m_state != Initialized)
805 return;
806
807 ASSERT(!reachedTerminalState())((void)0);
808 RefPtr resource = m_resource.get();
809 LOG(ResourceLoading, "Failed to load '%s'.\n", resource->url().string().latin1().data())((void)0);
810
811 RefPtr frame = m_frame.get();
812 if (frame && frame->document() && error.isAccessControl() && error.domain() != InspectorNetworkAgent::errorDomain() && resource->type() != CachedResource::Type::Ping)
813 protect(frame->document())->addConsoleMessage(MessageSource::Security, MessageLevel::Error, error.localizedDescription());
814
815 Ref protectedThis { *this };
816 m_state = Finishing;
817
818 if (resource->type() != CachedResource::Type::MainResource)
819 tracePoint(SubresourceLoadDidEnd, identifier() ? identifier()->toUInt64() : 0);
820
821 if (resource->resourceToRevalidate())
822 MemoryCache::singleton().revalidationFailed(*resource);
823 resource->setResourceError(error);
824 if (!resource->isPreloaded())
825 MemoryCache::singleton().remove(*resource);
826 resource->error(CachedResource::LoadError);
827 cleanupForError(error);
828 notifyDone(LoadCompletionType::Cancel);
829 if (reachedTerminalState())
830 return;
831 releaseResources();
832}
833
834void SubresourceLoader::willCancel(const ResourceError& error)
835{
836 SUBRESOURCELOADER_RELEASE_LOG(SUBRESOURCELOADER_WILLCANCEL, static_cast<int>(error.type()), error.errorCode());
837
838#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
839 // Since we defer initialization to scheduling time on iOS but
840 // CachedResourceLoader stores resources in the memory cache immediately,
841 // m_resource might be cached despite its loader not being initialized.
842 if (m_state != Initialized && m_state != Uninitialized)
843#else
844 if (m_state != Initialized)
845#endif
846 return;
847
848 ASSERT(!reachedTerminalState())((void)0);
849
850 Ref protectedThis { *this };
851 RefPtr resource = m_resource.get();
852 LOG(ResourceLoading, "Cancelled load of '%s'.\n", resource->url().string().latin1().data())((void)0);
853
854#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
855 m_state = m_state == Uninitialized ? CancelledWhileInitializing : Finishing;
856#else
857 m_state = Finishing;
858#endif
859 Ref memoryCache = MemoryCache::singleton();
860 if (resource->resourceToRevalidate())
861 memoryCache->revalidationFailed(*resource);
862 resource->setResourceError(error);
863 memoryCache->remove(*resource);
864}
865
866void SubresourceLoader::didCancel(LoadWillContinueInAnotherProcess loadWillContinueInAnotherProcess)
867{
868 if (m_state == Uninitialized || reachedTerminalState())
869 return;
870
871 RefPtr resource = m_resource.get();
872 ASSERT(resource)((void)0);
873
874 if (resource->type() != CachedResource::Type::MainResource)
875 tracePoint(SubresourceLoadDidEnd, identifier() ? identifier()->toUInt64() : 0);
876
877 resource->cancelLoad(loadWillContinueInAnotherProcess);
878 notifyDone(LoadCompletionType::Cancel);
879}
880
881void SubresourceLoader::notifyDone(LoadCompletionType type)
882{
883 if (reachedTerminalState())
884 return;
885
886 m_requestCountTracker = std::nullopt;
887 bool shouldPerformPostLoadActions = true;
888#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
889 if (m_state == CancelledWhileInitializing)
890 shouldPerformPostLoadActions = false;
891#endif
892 if (RefPtr documentLoader = this->documentLoader())
893 protect(documentLoader->cachedResourceLoader())->loadDone(type, shouldPerformPostLoadActions);
894 else
895 SUBRESOURCELOADER_RELEASE_LOG_ERROR("notifyDone: document loader is null. Could not call loadDone()");
896
897 if (reachedTerminalState())
898 return;
899 if (RefPtr documentLoader = this->documentLoader())
900 documentLoader->removeSubresourceLoader(type, *this);
901 else
902 SUBRESOURCELOADER_RELEASE_LOG_ERROR("notifyDone: document loader is null. Could not call removeSubresourceLoader()");
903}
904
905void SubresourceLoader::releaseResources()
906{
907 ASSERT(!reachedTerminalState())((void)0);
908 m_requestCountTracker = std::nullopt;
909#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
910 if (m_state != Uninitialized && m_state != CancelledWhileInitializing)
911#else
912 if (m_state != Uninitialized)
913#endif
914 protect(cachedResource())->clearLoader();
915 m_resource = nullptr;
916 ResourceLoader::releaseResources();
917}
918
919void SubresourceLoader::reportResourceTiming(const NetworkLoadMetrics& networkLoadMetrics)
920{
921 RefPtr resource = m_resource.get();
922 ASSERT(resource)((void)0);
923 if (!resource || !ResourceTimingInformation::shouldAddResourceTiming(*resource))
924 return;
925
926 RefPtr documentLoader = this->documentLoader();
927 RefPtr document = documentLoader->cachedResourceLoader().document();
928 if (!document)
929 return;
930
931 Ref origin = m_origin ? *m_origin : document->securityOrigin();
932 auto resourceTiming = ResourceTiming::fromLoad(*resource, resource->resourceRequest().url(), resource->initiatorType(), m_loadTiming, networkLoadMetrics, origin);
933
934 // Worker resources loaded here are all CachedRawResources loaded through WorkerThreadableLoader.
935 // Pass the ResourceTiming information on so that WorkerThreadableLoader may add them to the
936 // Worker's Performance object.
937 if (options().initiatorContext == InitiatorContext::Worker) {
938 ASSERT(m_origin)((void)0);
939 downcast<CachedRawResource>(*resource).finishedTimingForWorkerLoad(WTF::move(resourceTiming));
940 return;
941 }
942
943 ASSERT(options().initiatorContext == InitiatorContext::Document)((void)0);
944 documentLoader->cachedResourceLoader().resourceTimingInformation().addResourceTiming(*cachedResource(), *document, WTF::move(resourceTiming));
Call argument is uncounted and unsafe
945}
946
947const HTTPHeaderMap* SubresourceLoader::originalHeaders() const
948{
949 return (m_resource && m_resource->originalRequest()) ? &m_resource->originalRequest()->httpHeaderFields() : nullptr;
950}
951
952} // namespace WebCore
953
954#undef PAGE_ID
955#undef FRAME_ID
956#undef SUBRESOURCELOADER_RELEASE_LOG
957#undef SUBRESOURCELOADER_RELEASE_LOG_ERROR