Bug Summary

File:Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm
Warning:line 82, column 12
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 -Os -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 UnifiedSource45-nonARC.mm -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/WebKit -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit -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/WebKit/WebKit/normal/arm64/UnifiedSource45-nonARC.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/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/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 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/PrivateFrameworks -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/3938699508861868627/WebKit2Prefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D HAVE_CORE_PREDICTION -D ENABLE_LOWER_FORMATREADERBUNDLE_CODESIGNING_REQUIREMENTS -D WEBKIT_BUNDLE_VERSION="625.1.11+" -D FRAMEWORK_NAME=WebKit -D OBJC_OLD_DISPATCH_PROTOTYPES=0 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -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/WebCore.framework/PrivateHeaders/ForwardingHeaders -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebKit -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebKit/IPC -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/pal/graphics/WebGPU -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/pal/graphics/WebGPU -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/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/Source/WebKit -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.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/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/PrivateFrameworks -D __STDC_WANT_LIB_EXT1__=1 -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 -Wno-implicit-atomic-properties -Wno-objc-interface-ivars -Wno-arc-repeated-use-of-weak -Wimplicit-retain-self -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wduplicate-method-match -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-selector -Wno-strict-selector-match -Wundeclared-selector -Wdeprecated-implementations -Wno-c++11-extensions -Wno-implicit-fallthrough -Wprotocol -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 -Wno-unused-parameter -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 -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -Wno-unknown-warning-option -Wno-missing-field-initializers -Wno-nullability-completeness -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 -fobjc-runtime=ios-26.2.0 -fobjc-weak -fobjc-exceptions -fexceptions -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/WebKit/WebKit/normal/arm64/UnifiedSource45-nonARC.plist -x objective-c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebKit/unified-sources/UnifiedSource45-nonARC.mm
1/*
2 * Copyright (C) 2014-2022 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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "WebPasteboardProxy.h"
28
29#import "Connection.h"
30#import "LegacyWebArchiveCallbackAggregator.h"
31#import "NetworkProcessMessages.h"
32#import "PageLoadState.h"
33#import "PasteboardAccessIntent.h"
34#import "RemotePageProxy.h"
35#import "SandboxExtension.h"
36#import "WebFrameProxy.h"
37#import "WebPageMessages.h"
38#import "WebPageProxy.h"
39#import "WebPageProxyIdentifier.h"
40#import "WebPreferences.h"
41#import "WebProcessMessages.h"
42#import "WebProcessProxy.h"
43#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
44#import <WebCore/Color.h>
45#import <WebCore/DataOwnerType.h>
46#import <WebCore/ImageUtilities.h>
47#import <WebCore/LegacyNSPasteboardTypes.h>
48#import <WebCore/MIMETypeRegistry.h>
49#import <WebCore/Pasteboard.h>
50#import <WebCore/PasteboardItemInfo.h>
51#import <WebCore/PlatformPasteboard.h>
52#import <WebCore/Quirks.h>
53#import <WebCore/SharedBuffer.h>
54#import <WebCore/UTIUtilities.h>
55#import <wtf/URL.h>
56
57#define MESSAGE_CHECK(assertion, connection) MESSAGE_CHECK_BASE(assertion, connection)do { if (!(assertion)) [[unlikely]] { os_fault_with_payload(31
, 0, nullptr, 0, makeString("/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm"
" " "57" ": Invalid message dispatched "_s, unsafeSpan(__PRETTY_FUNCTION__
)).utf8().data(), 0); IPC::markCurrentlyDispatchedMessageAsInvalid
(connection, "Message check failed: " "assertion"_s); if (IPC
::Connection::shouldCrashOnMessageCheckFailure()) { do { __asm__
volatile ("brk #0xc471"); __builtin_unreachable(); } while (
0); } { (void)0; } return; } } while (0)
58#define MESSAGE_CHECK_WITH_RETURN_VALUE(assertion, connection, returnValue) MESSAGE_CHECK_WITH_RETURN_VALUE_BASE(assertion, connection, returnValue)do { if (!(assertion)) [[unlikely]] { os_fault_with_payload(31
, 0, nullptr, 0, makeString("/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm"
" " "58" ": Invalid message dispatched "_s, unsafeSpan(__PRETTY_FUNCTION__
)).utf8().data(), 0); IPC::markCurrentlyDispatchedMessageAsInvalid
(connection, "Message check failed: " "assertion"_s); if (IPC
::Connection::shouldCrashOnMessageCheckFailure()) { do { __asm__
volatile ("brk #0xc471"); __builtin_unreachable(); } while (
0); } return (returnValue); } } while (0)
59#define MESSAGE_CHECK_COMPLETION(assertion, connection, completion) MESSAGE_CHECK_COMPLETION_BASE(assertion, connection, completion)do { if (!(assertion)) [[unlikely]] { os_fault_with_payload(31
, 0, nullptr, 0, makeString("/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm"
" " "59" ": Invalid message dispatched "_s, unsafeSpan(__PRETTY_FUNCTION__
)).utf8().data(), 0); IPC::markCurrentlyDispatchedMessageAsInvalid
(connection, "Message check failed: " "assertion"_s); if (IPC
::Connection::shouldCrashOnMessageCheckFailure()) { do { __asm__
volatile ("brk #0xc471"); __builtin_unreachable(); } while (
0); } { completion; } return; } } while (0)
60
61namespace WebKit {
62using namespace WebCore;
63
64static PasteboardDataLifetime determineDataLifetime(std::optional<WebPageProxyIdentifier> pageID)
65{
66 if (!pageID)
67 return PasteboardDataLifetime::Persistent;
68
69 if (RefPtr page = WebProcessProxy::webPage(*pageID))
70 return page->sessionID().isEphemeral() ? PasteboardDataLifetime::Ephemeral : PasteboardDataLifetime::Persistent;
71
72 return PasteboardDataLifetime::Persistent;
73}
74
75static bool shouldTranscodeHeicImagesForPage(std::optional<WebPageProxyIdentifier> pageID)
76{
77 if (!pageID)
78 return false;
79 RefPtr page = WebProcessProxy::webPage(*pageID);
80 if (!page)
81 return false;
82 return page->preferences().needsSiteSpecificQuirks() && Quirks::shouldTranscodeHeicImagesForURL(URL { page->currentURL() });
Call argument for 'this' parameter is uncounted and unsafe
83}
84
85void WebPasteboardProxy::grantAccessToCurrentTypes(WebProcessProxy& process, const String& pasteboardName)
86{
87 grantAccess(process, pasteboardName, PasteboardAccessType::Types);
88}
89
90std::optional<IPC::AsyncReplyID> WebPasteboardProxy::grantAccessToCurrentData(WebProcessProxy& process, const String& pasteboardName, CompletionHandler<void()>&& completionHandler)
91{
92 grantAccess(process, pasteboardName, PasteboardAccessType::TypesAndData);
93 auto pasteboard = PlatformPasteboard(pasteboardName);
94 auto allInfo = pasteboard.allPasteboardItemInfo(pasteboard.changeCount());
95 if (!allInfo) {
96 completionHandler();
97 return std::nullopt;
98 }
99 Vector<String> paths;
100 for (auto& info : *allInfo) {
101 paths.appendVector(info.pathsForFileUpload);
102 }
103#if PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
104 if (!paths.size())
105 pasteboard.getPathnamesForType(paths, legacyFilenamesPasteboardTypeSingleton());
106#endif
107
108 if (!paths.size()) {
109 completionHandler();
110 return std::nullopt;
111 }
112 auto processIdentifier = process.coreProcessIdentifier();
113 return protect(protect(process.websiteDataStore())->networkProcess())->sendWithAsyncReply(Messages::NetworkProcess::AllowFilesAccessFromWebProcess(processIdentifier, paths), WTF::move(completionHandler));
114}
115
116void WebPasteboardProxy::grantAccess(WebProcessProxy& process, const String& pasteboardName, PasteboardAccessType type)
117{
118 if (!m_webProcessProxySet.contains(process))
119 return;
120
121 if (pasteboardName.isEmpty()) {
122 ASSERT_NOT_REACHED()((void)0);
123 return;
124 }
125
126 auto changeCount = PlatformPasteboard(pasteboardName).changeCount();
127 auto changeCountsAndProcesses = m_pasteboardNameToAccessInformationMap.find(pasteboardName);
128 if (changeCountsAndProcesses != m_pasteboardNameToAccessInformationMap.end() && changeCountsAndProcesses->value.changeCount == changeCount) {
129 changeCountsAndProcesses->value.grantAccess(process, type);
130 return;
131 }
132
133 m_pasteboardNameToAccessInformationMap.set(pasteboardName, PasteboardAccessInformation { changeCount, {{ process, type }} });
134}
135
136void WebPasteboardProxy::revokeAccess(WebProcessProxy& process)
137{
138 for (auto& changeCountAndProcesses : m_pasteboardNameToAccessInformationMap.values())
139 changeCountAndProcesses.revokeAccess(process);
140}
141
142bool WebPasteboardProxy::canAccessPasteboardTypes(IPC::Connection& connection, const String& pasteboardName) const
143{
144 return !!accessType(connection, pasteboardName);
145}
146
147bool WebPasteboardProxy::canAccessPasteboardData(IPC::Connection& connection, const String& pasteboardName) const
148{
149 auto type = accessType(connection, pasteboardName);
150 return type && *type == PasteboardAccessType::TypesAndData;
151}
152
153std::optional<WebPasteboardProxy::PasteboardAccessType> WebPasteboardProxy::accessType(IPC::Connection& connection, const String& pasteboardName) const
154{
155 MESSAGE_CHECK_WITH_RETURN_VALUE(!pasteboardName.isEmpty(), connection, std::nullopt);
156
157 RefPtr process = webProcessProxyForConnection(connection);
158 MESSAGE_CHECK_WITH_RETURN_VALUE(process, connection, std::nullopt);
159
160 for (Ref page : process->pages()) {
161 Ref preferences = page->preferences();
162 if (preferences->shouldSuppressTextInputFromEditingDuringProvisionalNavigation() && page->pageLoadState().isProvisional())
163 continue;
164
165 if (!preferences->domPasteAllowed() || !preferences->javaScriptCanAccessClipboard())
166 continue;
167
168 // If a web page already allows JavaScript to programmatically read pasteboard data,
169 // then it is possible for any other web page residing in the same web process to send
170 // IPC messages that can read pasteboard data by pretending to be the page that has
171 // allowed unmitigated pasteboard access from script. As such, there is no security
172 // benefit in limiting the scope of pasteboard data access to only the web page that
173 // enables programmatic pasteboard access.
174 return PasteboardAccessType::TypesAndData;
175 }
176
177 auto changeCountAndProcesses = m_pasteboardNameToAccessInformationMap.find(pasteboardName);
178 if (changeCountAndProcesses == m_pasteboardNameToAccessInformationMap.end())
179 return std::nullopt;
180
181 auto& information = changeCountAndProcesses->value;
182 if (information.changeCount != PlatformPasteboard(pasteboardName).changeCount())
183 return std::nullopt;
184
185 return information.accessType(*process);
186}
187
188void WebPasteboardProxy::didModifyContentsOfPasteboard(IPC::Connection& connection, const String& pasteboardName, int64_t previousChangeCount, int64_t newChangeCount)
189{
190 RefPtr process = webProcessProxyForConnection(connection);
191 MESSAGE_CHECK(process, connection);
192
193 auto changeCountAndProcesses = m_pasteboardNameToAccessInformationMap.find(pasteboardName);
194 if (changeCountAndProcesses != m_pasteboardNameToAccessInformationMap.end() && previousChangeCount == changeCountAndProcesses->value.changeCount) {
195 if (auto accessType = changeCountAndProcesses->value.accessType(*process))
196 changeCountAndProcesses->value = PasteboardAccessInformation { newChangeCount, {{ *process, *accessType }} };
197 }
198}
199
200void WebPasteboardProxy::getPasteboardTypes(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
201{
202 if (!canAccessPasteboardTypes(connection, pasteboardName))
203 return completionHandler({ });
204
205 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
206 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
207
208 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
209 Vector<String> pasteboardTypes;
210 PlatformPasteboard(pasteboardName).getTypes(pasteboardTypes);
211 completionHandler(WTF::move(pasteboardTypes));
212 });
213}
214
215void WebPasteboardProxy::getPasteboardPathnamesForType(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, std::optional<WebPageProxyIdentifier> pageID,
216 CompletionHandler<void(Vector<String>&& pathnames, Vector<SandboxExtension::Handle>&& sandboxExtensions)>&& completionHandler)
217{
218 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }, { }));
219
220 // FIXME: This should consult canAccessPasteboardData() instead, and avoid responding with file paths if it returns false.
221 if (!canAccessPasteboardTypes(connection, pasteboardName))
222 return completionHandler({ }, { });
223
224 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
225 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }, { }));
226
227 PlatformPasteboard::performAsDataOwner(*dataOwner, [&, completionHandler = WTF::move(completionHandler)] mutable {
228 Vector<String> pathnames;
229 RefPtr process = webProcessProxyForConnection(connection);
230 if (!process) {
231 completionHandler({ }, { });
232 return;
233 }
234
235 PlatformPasteboard(pasteboardName).getPathnamesForType(pathnames, pasteboardType);
236
237#if PLATFORM(MAC)(defined WTF_PLATFORM_MAC && WTF_PLATFORM_MAC)
238 Vector<size_t> indicesToTranscode;
239 if (shouldTranscodeHeicImagesForPage(pageID)) {
240 for (size_t i = 0; i < pathnames.size(); ++i) {
241 auto mimeType = WebCore::MIMETypeRegistry::mimeTypeForPath(pathnames[i]);
242 if (mimeType == "image/heic"_s || mimeType == "image/heif"_s)
243 indicesToTranscode.append(i);
244 }
245 }
246
247 if (indicesToTranscode.isEmpty()) {
248 bool needsExtensions = pasteboardType == String(WebCore::legacyFilenamesPasteboardTypeSingleton());
249 auto sandboxExtensions = pathnames.map([needsExtensions](auto& filename) {
250 if (!needsExtensions || ![[NSFileManager defaultManager] fileExistsAtPath:filename.createNSString().get()])
251 return SandboxExtension::Handle { };
252 return valueOrDefault(SandboxExtension::createHandle(filename, SandboxExtension::Type::ReadOnly));
253 });
254 completionHandler(WTF::move(pathnames), WTF::move(sandboxExtensions));
255 return;
256 }
257
258 Vector<String> pathsToTranscode;
259 for (auto index : indicesToTranscode)
260 pathsToTranscode.append(pathnames[index]);
261
262 auto transcodingMIMEType = "image/jpeg"_s;
263 auto transcodingUTI = WebCore::UTIFromMIMEType(transcodingMIMEType);
264 auto transcodingExtension = WebCore::MIMETypeRegistry::preferredExtensionForMIMEType(transcodingMIMEType);
265
266 sharedImageTranscodingQueueSingleton().dispatch([process = WTF::move(process), pathnames = crossThreadCopy(WTF::move(pathnames)), pathsToTranscode = crossThreadCopy(WTF::move(pathsToTranscode)), indicesToTranscode = WTF::move(indicesToTranscode), transcodingUTI = crossThreadCopy(WTF::move(transcodingUTI)), transcodingExtension = crossThreadCopy(WTF::move(transcodingExtension)), pasteboardType = crossThreadCopy(pasteboardType), completionHandler = WTF::move(completionHandler)] mutable {
267 ASSERT(!RunLoop::isMain())((void)0);
268
269 auto transcodedPaths = transcodeImages(pathsToTranscode, transcodingUTI, transcodingExtension);
270
271 RunLoop::mainSingleton().dispatch([process = WTF::move(process), pathnames = crossThreadCopy(WTF::move(pathnames)), transcodedPaths = crossThreadCopy(WTF::move(transcodedPaths)), indicesToTranscode = WTF::move(indicesToTranscode), pasteboardType = WTF::move(pasteboardType), completionHandler = WTF::move(completionHandler)] mutable {
272 Vector<String> transcodedFilePaths;
273 for (size_t i = 0; i < indicesToTranscode.size(); ++i) {
274 if (!transcodedPaths[i].isEmpty()) {
275 pathnames[indicesToTranscode[i]] = transcodedPaths[i];
276 transcodedFilePaths.append(transcodedPaths[i]);
277 }
278 }
279
280 if (!transcodedFilePaths.isEmpty())
281 protect(protect(process->websiteDataStore())->networkProcess())->sendWithAsyncReply(Messages::NetworkProcess::AllowFilesAccessFromWebProcess(process->coreProcessIdentifier(), transcodedFilePaths), [] { });
282
283 bool needsExtensions = pasteboardType == String(WebCore::legacyFilenamesPasteboardTypeSingleton());
284 auto sandboxExtensions = pathnames.map([needsExtensions](auto& filename) {
285 if (!needsExtensions || ![[NSFileManager defaultManager] fileExistsAtPath:filename.createNSString().get()])
286 return SandboxExtension::Handle { };
287 return valueOrDefault(SandboxExtension::createHandle(filename, SandboxExtension::Type::ReadOnly));
288 });
289
290 completionHandler(WTF::move(pathnames), WTF::move(sandboxExtensions));
291 });
292 });
293 return;
294#else
295 completionHandler(WTF::move(pathnames), { });
296#endif
297 });
298}
299
300void WebPasteboardProxy::getPasteboardStringForType(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(String&&)>&& completionHandler)
301{
302 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }));
303
304 if (!canAccessPasteboardData(connection, pasteboardName))
305 return completionHandler({ });
306
307 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
308 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
309
310 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
311 completionHandler(PlatformPasteboard(pasteboardName).stringForType(pasteboardType));
312 });
313}
314
315void WebPasteboardProxy::getPasteboardStringsForType(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
316{
317 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }));
318
319 if (!canAccessPasteboardData(connection, pasteboardName))
320 return completionHandler({ });
321
322 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
323 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
324
325 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
326 completionHandler(PlatformPasteboard(pasteboardName).allStringsForType(pasteboardType));
327 });
328}
329
330void WebPasteboardProxy::getPasteboardBufferForType(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(WebCore::PasteboardBuffer&&)>&& completionHandler)
331{
332 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }));
333
334 if (!canAccessPasteboardData(connection, pasteboardName))
335 return completionHandler({ });
336
337 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
338 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
339
340 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
341 auto pasteboardBuffer = PlatformPasteboard(pasteboardName).bufferForType(pasteboardType);
342 completionHandler(WTF::move(pasteboardBuffer));
343 });
344}
345
346void WebPasteboardProxy::getPasteboardChangeCount(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
347{
348 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
349
350 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
351 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
352
353 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
354 completionHandler(PlatformPasteboard(pasteboardName).changeCount());
355 });
356}
357
358void WebPasteboardProxy::getPasteboardColor(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(WebCore::Color&&)>&& completionHandler)
359{
360 if (!canAccessPasteboardData(connection, pasteboardName))
361 return completionHandler({ });
362
363 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
364 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
365
366 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
367 completionHandler(PlatformPasteboard(pasteboardName).color());
368 });
369}
370
371void WebPasteboardProxy::getPasteboardURL(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(const String&)>&& completionHandler)
372{
373 if (!canAccessPasteboardData(connection, pasteboardName))
374 return completionHandler({ });
375
376 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
377 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
378
379 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
380 completionHandler(PlatformPasteboard(pasteboardName).url().string());
381 });
382}
383
384void WebPasteboardProxy::addPasteboardTypes(IPC::Connection& connection, const String& pasteboardName, const Vector<String>& pasteboardTypes, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
385{
386 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
387
388 for (auto& type : pasteboardTypes)
389 MESSAGE_CHECK_COMPLETION(!type.isEmpty(), connection, completionHandler(0));
390
391 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
392 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
393
394 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
395 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
396 auto newChangeCount = PlatformPasteboard(pasteboardName).addTypes(pasteboardTypes);
397 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
398 completionHandler(newChangeCount);
399 });
400}
401
402void WebPasteboardProxy::setPasteboardTypes(IPC::Connection& connection, const String& pasteboardName, const Vector<String>& pasteboardTypes, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
403{
404 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
405
406 for (auto& type : pasteboardTypes)
407 MESSAGE_CHECK_COMPLETION(!type.isEmpty(), connection, completionHandler(0));
408
409 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
410 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
411
412 auto dataLifeTime = determineDataLifetime(pageID);
413
414 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
415 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
416 auto newChangeCount = PlatformPasteboard(pasteboardName).setTypes(pasteboardTypes, dataLifeTime);
417 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
418 completionHandler(newChangeCount);
419 });
420}
421
422void WebPasteboardProxy::setPasteboardURL(IPC::Connection& connection, const PasteboardURL& pasteboardURL, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
423{
424 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
425
426 RefPtr process = webProcessProxyForConnection(connection);
427 MESSAGE_CHECK_COMPLETION(process, connection, completionHandler(0));
428
429 if (!pasteboardURL.url.isValid())
430 return completionHandler(0);
431
432 if (!process->checkURLReceivedFromWebProcess(pasteboardURL.url.string(), CheckBackForwardList::No))
433 return completionHandler(0);
434
435 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
436 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
437
438 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
439 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
440 auto newChangeCount = PlatformPasteboard(pasteboardName).setURL(pasteboardURL);
441 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
442 completionHandler(newChangeCount);
443 });
444}
445
446void WebPasteboardProxy::setPasteboardColor(IPC::Connection& connection, const String& pasteboardName, const WebCore::Color& color, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
447{
448 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
449
450 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
451 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
452
453 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
454 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
455 auto newChangeCount = PlatformPasteboard(pasteboardName).setColor(color);
456 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
457 completionHandler(newChangeCount);
458 });
459}
460
461void WebPasteboardProxy::setPasteboardStringForType(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, const String& string, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
462{
463 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
464 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler(0));
465
466 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
467 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
468
469 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
470 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
471 auto newChangeCount = PlatformPasteboard(pasteboardName).setStringForType(string, pasteboardType);
472 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
473 completionHandler(newChangeCount);
474 });
475}
476
477void WebPasteboardProxy::containsURLStringSuitableForLoading(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(bool)>&& completionHandler)
478{
479 if (!canAccessPasteboardTypes(connection, pasteboardName))
480 return completionHandler(false);
481
482 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
483 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(false));
484
485 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
486 completionHandler(PlatformPasteboard(pasteboardName).containsURLStringSuitableForLoading());
487 });
488}
489
490void WebPasteboardProxy::urlStringSuitableForLoading(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(String&& url, String&& title)>&& completionHandler)
491{
492 if (!canAccessPasteboardData(connection, pasteboardName))
493 return completionHandler({ }, { });
494
495 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
496 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }, { }));
497
498 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
499 String title;
500 auto urlString = PlatformPasteboard(pasteboardName).urlStringSuitableForLoading(title);
501 completionHandler(WTF::move(urlString), WTF::move(title));
502 });
503}
504
505void WebPasteboardProxy::setPasteboardBufferForType(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, RefPtr<SharedBuffer>&& buffer, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
506{
507 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
508 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler(0));
509
510 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
511 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
512
513 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
514 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
515 if (!buffer) {
516 auto newChangeCount = PlatformPasteboard(pasteboardName).setBufferForType(nullptr, pasteboardType);
517 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
518 return completionHandler(newChangeCount);
519 }
520 auto newChangeCount = PlatformPasteboard(pasteboardName).setBufferForType(buffer.get(), pasteboardType);
521 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
522 completionHandler(newChangeCount);
523 });
524}
525
526void WebPasteboardProxy::getNumberOfFiles(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(uint64_t)>&& completionHandler)
527{
528 if (!canAccessPasteboardTypes(connection, pasteboardName))
529 return completionHandler(0);
530
531 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
532 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
533
534 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
535 completionHandler(PlatformPasteboard(pasteboardName).numberOfFiles());
536 });
537}
538
539void WebPasteboardProxy::typesSafeForDOMToReadAndWrite(IPC::Connection& connection, const String& pasteboardName, const String& origin, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
540{
541 MESSAGE_CHECK_COMPLETION(!origin.isNull(), connection, completionHandler({ }));
542
543 if (!canAccessPasteboardTypes(connection, pasteboardName))
544 return completionHandler({ });
545
546 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
547 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
548
549 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
550 completionHandler(PlatformPasteboard(pasteboardName).typesSafeForDOMToReadAndWrite(origin));
551 });
552}
553
554void WebPasteboardProxy::writeCustomData(IPC::Connection& connection, const Vector<PasteboardCustomData>& data, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t)>&& completionHandler)
555{
556 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
557
558 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
559 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
560
561 auto dataLifeTime = determineDataLifetime(pageID);
562
563 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
564 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
565 auto newChangeCount = PlatformPasteboard(pasteboardName).write(data, dataLifeTime);
566 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, newChangeCount);
567 completionHandler(newChangeCount);
568 });
569}
570
571#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
572struct HEICTranscodingInfo {
573 size_t infoIndex { 0 };
574 size_t pathIndex { 0 };
575 String path;
576};
577
578static Vector<String> extractPathsToTranscode(const Vector<HEICTranscodingInfo>& transcodingInfo)
579{
580 Vector<String> paths;
581 for (auto& entry : transcodingInfo)
582 paths.append(entry.path);
583 return paths;
584}
585
586static std::pair<String, String> heicTranscodingParameters()
587{
588 auto transcodingMIMEType = "image/jpeg"_s;
589 return { WebCore::UTIFromMIMEType(transcodingMIMEType), WebCore::MIMETypeRegistry::preferredExtensionForMIMEType(transcodingMIMEType) };
590}
591
592static void notifyNetworkProcessOfTranscodedFiles(RefPtr<WebProcessProxy>& process, const Vector<String>& transcodedPaths)
593{
594 Vector<String> nonEmptyPaths;
595 for (auto& path : transcodedPaths) {
596 if (!path.isEmpty())
597 nonEmptyPaths.append(path);
598 }
599 if (!nonEmptyPaths.isEmpty())
600 protect(protect(process->websiteDataStore())->networkProcess())->sendWithAsyncReply(Messages::NetworkProcess::AllowFilesAccessFromWebProcess(process->coreProcessIdentifier(), nonEmptyPaths), [] { });
601}
602
603static Vector<HEICTranscodingInfo> findHEICPathsForTranscoding(Vector<PasteboardItemInfo>& allInfo)
604{
605 Vector<HEICTranscodingInfo> transcodingInfo;
606 for (size_t infoIndex = 0; infoIndex < allInfo.size(); ++infoIndex) {
607 auto& info = allInfo[infoIndex];
608 for (size_t pathIndex = 0; pathIndex < info.pathsForFileUpload.size(); ++pathIndex) {
609 auto& path = info.pathsForFileUpload[pathIndex];
610 if (path.isEmpty())
611 continue;
612 auto mimeType = WebCore::MIMETypeRegistry::mimeTypeForPath(path);
613 if (mimeType == "image/heic"_s || mimeType == "image/heif"_s)
614 transcodingInfo.append({ infoIndex, pathIndex, path });
615 }
616 }
617 return transcodingInfo;
618}
619
620static Vector<HEICTranscodingInfo> findHEICPathsForTranscoding(PasteboardItemInfo& info)
621{
622 Vector<PasteboardItemInfo> items { info };
623 return findHEICPathsForTranscoding(items);
624}
625#endif
626
627void WebPasteboardProxy::allPasteboardItemInfo(IPC::Connection& connection, const String& pasteboardName, int64_t changeCount, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(std::optional<Vector<PasteboardItemInfo>>&&)>&& completionHandler)
628{
629 if (!canAccessPasteboardTypes(connection, pasteboardName))
630 return completionHandler({ });
631
632 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
633 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
634
635 RefPtr process = webProcessProxyForConnection(connection);
636
637 PlatformPasteboard::performAsDataOwner(*dataOwner, [&, completionHandler = WTF::move(completionHandler)] mutable {
638 auto allInfo = PlatformPasteboard(pasteboardName).allPasteboardItemInfo(changeCount);
639
640#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
641 if (!allInfo || !process || !shouldTranscodeHeicImagesForPage(pageID)) {
642 completionHandler(WTF::move(allInfo));
643 return;
644 }
645
646 auto transcodingInfo = findHEICPathsForTranscoding(*allInfo);
647 if (transcodingInfo.isEmpty()) {
648 completionHandler(WTF::move(allInfo));
649 return;
650 }
651
652 auto pathsToTranscode = extractPathsToTranscode(transcodingInfo);
653 auto [transcodingUTI, transcodingExtension] = heicTranscodingParameters();
654
655 sharedImageTranscodingQueueSingleton().dispatch([process = WTF::move(process), allInfo = WTF::move(*allInfo), pathsToTranscode = crossThreadCopy(WTF::move(pathsToTranscode)), transcodingInfo = WTF::move(transcodingInfo), transcodingUTI = crossThreadCopy(WTF::move(transcodingUTI)), transcodingExtension = crossThreadCopy(WTF::move(transcodingExtension)), completionHandler = WTF::move(completionHandler)] mutable {
656 ASSERT(!RunLoop::isMain())((void)0);
657
658 auto transcodedPaths = transcodeImages(pathsToTranscode, transcodingUTI, transcodingExtension);
659
660 RunLoop::mainSingleton().dispatch([process = WTF::move(process), allInfo = WTF::move(allInfo), transcodedPaths = crossThreadCopy(WTF::move(transcodedPaths)), transcodingInfo = WTF::move(transcodingInfo), completionHandler = WTF::move(completionHandler)] mutable {
661 for (size_t i = 0; i < transcodingInfo.size(); ++i) {
662 if (!transcodedPaths[i].isEmpty())
663 allInfo[transcodingInfo[i].infoIndex].pathsForFileUpload[transcodingInfo[i].pathIndex] = transcodedPaths[i];
664 }
665
666 notifyNetworkProcessOfTranscodedFiles(process, transcodedPaths);
667
668 completionHandler(WTF::move(allInfo));
669 });
670 });
671#else
672 completionHandler(WTF::move(allInfo));
673#endif
674 });
675}
676
677void WebPasteboardProxy::informationForItemAtIndex(IPC::Connection& connection, uint64_t index, const String& pasteboardName, int64_t changeCount, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(std::optional<PasteboardItemInfo>&&)>&& completionHandler)
678{
679 if (!canAccessPasteboardTypes(connection, pasteboardName))
680 return completionHandler(std::nullopt);
681
682 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
683 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(std::nullopt));
684
685 RefPtr process = webProcessProxyForConnection(connection);
686
687 PlatformPasteboard::performAsDataOwner(*dataOwner, [&, completionHandler = WTF::move(completionHandler)] mutable {
688 auto info = PlatformPasteboard(pasteboardName).informationForItemAtIndex(index, changeCount);
689
690#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
691 if (!info || !process || !shouldTranscodeHeicImagesForPage(pageID)) {
692 completionHandler(WTF::move(info));
693 return;
694 }
695
696 auto transcodingInfo = findHEICPathsForTranscoding(*info);
697 if (transcodingInfo.isEmpty()) {
698 completionHandler(WTF::move(info));
699 return;
700 }
701
702 auto pathsToTranscode = extractPathsToTranscode(transcodingInfo);
703 auto [transcodingUTI, transcodingExtension] = heicTranscodingParameters();
704
705 sharedImageTranscodingQueueSingleton().dispatch([process = WTF::move(process), info = WTF::move(*info), pathsToTranscode = crossThreadCopy(WTF::move(pathsToTranscode)), transcodingInfo = WTF::move(transcodingInfo), transcodingUTI = crossThreadCopy(WTF::move(transcodingUTI)), transcodingExtension = crossThreadCopy(WTF::move(transcodingExtension)), completionHandler = WTF::move(completionHandler)] mutable {
706 ASSERT(!RunLoop::isMain())((void)0);
707
708 auto transcodedPaths = transcodeImages(pathsToTranscode, transcodingUTI, transcodingExtension);
709
710 RunLoop::mainSingleton().dispatch([process = WTF::move(process), info = WTF::move(info), transcodedPaths = crossThreadCopy(WTF::move(transcodedPaths)), transcodingInfo = WTF::move(transcodingInfo), completionHandler = WTF::move(completionHandler)] mutable {
711 for (size_t i = 0; i < transcodingInfo.size(); ++i) {
712 if (!transcodedPaths[i].isEmpty())
713 info.pathsForFileUpload[transcodingInfo[i].pathIndex] = transcodedPaths[i];
714 }
715
716 notifyNetworkProcessOfTranscodedFiles(process, transcodedPaths);
717
718 completionHandler(WTF::move(info));
719 });
720 });
721#else
722 completionHandler(WTF::move(info));
723#endif
724 });
725}
726
727void WebPasteboardProxy::getPasteboardItemsCount(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(uint64_t)>&& completionHandler)
728{
729 if (!canAccessPasteboardTypes(connection, pasteboardName))
730 return completionHandler(0);
731
732 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
733 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(0));
734
735 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
736 completionHandler(PlatformPasteboard(pasteboardName).count());
737 });
738}
739
740void WebPasteboardProxy::readStringFromPasteboard(IPC::Connection& connection, uint64_t index, const String& pasteboardType, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(String&&)>&& completionHandler)
741{
742 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }));
743
744 if (!canAccessPasteboardData(connection, pasteboardName))
745 return completionHandler({ });
746
747 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
748 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
749
750 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
751 completionHandler(PlatformPasteboard(pasteboardName).readString(index, pasteboardType));
752 });
753}
754
755void WebPasteboardProxy::readURLFromPasteboard(IPC::Connection& connection, uint64_t index, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(String&& url, String&& title)>&& completionHandler)
756{
757 if (!canAccessPasteboardData(connection, pasteboardName))
758 return completionHandler({ }, { });
759
760 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
761 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }, { }));
762
763 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
764 String title;
765 String url = PlatformPasteboard(pasteboardName).readURL(index, title).string();
766 completionHandler(WTF::move(url), WTF::move(title));
767 });
768}
769
770void WebPasteboardProxy::readBufferFromPasteboard(IPC::Connection& connection, std::optional<uint64_t> index, const String& pasteboardType, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(RefPtr<SharedBuffer>&&)>&& completionHandler)
771{
772 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler({ }));
773
774 if (!canAccessPasteboardData(connection, pasteboardName))
775 return completionHandler({ });
776
777 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
778 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler({ }));
779
780 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
781 completionHandler(PlatformPasteboard(pasteboardName).readBuffer(index, pasteboardType));
782 });
783}
784
785void WebPasteboardProxy::containsStringSafeForDOMToReadForType(IPC::Connection& connection, const String& type, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(bool)>&& completionHandler)
786{
787 if (!canAccessPasteboardTypes(connection, pasteboardName))
788 return completionHandler(false);
789
790 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Read);
791 MESSAGE_CHECK_COMPLETION(dataOwner, connection, completionHandler(false));
792
793 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
794 completionHandler(PlatformPasteboard(pasteboardName).containsStringSafeForDOMToReadForType(type));
795 });
796}
797
798#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
799
800void WebPasteboardProxy::writeURLToPasteboard(IPC::Connection& connection, const PasteboardURL& url, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID)
801{
802 MESSAGE_CHECK(!pasteboardName.isEmpty(), connection);
803
804 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
805 MESSAGE_CHECK(dataOwner, connection);
806
807 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
808 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
809 PlatformPasteboard(pasteboardName).write(url);
810 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, PlatformPasteboard(pasteboardName).changeCount());
811 if (auto process = webProcessProxyForConnection(connection))
812 process->send(Messages::WebProcess::DidWriteToPasteboardAsynchronously(pasteboardName), 0);
813 });
814}
815
816void WebPasteboardProxy::writeWebContentToPasteboardInternal(IPC::Connection& connection, const WebCore::PasteboardWebContent& content, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID)
817{
818 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
819 MESSAGE_CHECK(dataOwner, connection);
820
821 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
822 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
823 PlatformPasteboard(pasteboardName).write(content);
824 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, PlatformPasteboard(pasteboardName).changeCount());
825 if (auto process = webProcessProxyForConnection(connection))
826 process->send(Messages::WebProcess::DidWriteToPasteboardAsynchronously(pasteboardName), 0);
827 });
828}
829
830void WebPasteboardProxy::writeWebContentToPasteboard(IPC::Connection& connection, const WebCore::PasteboardWebContent& content, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID)
831{
832 MESSAGE_CHECK(!pasteboardName.isEmpty(), connection);
833
834 RefPtr webArchive = content.webArchive;
835 if (!webArchive) {
836 writeWebContentToPasteboardInternal(connection, content, pasteboardName, pageID);
837 return;
838 }
839
840 auto rootFrameIdentifier = webArchive->frameIdentifier();
841 if (!rootFrameIdentifier) {
842 writeWebContentToPasteboardInternal(connection, content, pasteboardName, pageID);
843 return;
844 }
845
846 Ref senderProcess = WebProcessProxy::fromConnection(connection);
847 auto localFrameArchives = content.localFrameArchives;
848 createOneWebArchiveFromFrames(senderProcess.get(), *rootFrameIdentifier, WTF::move(localFrameArchives), content.remoteFrameIdentifiers, [connection = Ref { connection }, content, pasteboardName, pageID](auto result) mutable {
849 auto updatedContent = content;
850 if (result) {
851 if (auto data = result->rawDataRepresentation())
852 updatedContent.dataInWebArchiveFormat = WebCore::SharedBuffer::create(data.get()).ptr();
853 }
854 WebPasteboardProxy::singleton().writeWebContentToPasteboardInternal(connection, updatedContent, pasteboardName, pageID);
855 });
856}
857
858void WebPasteboardProxy::writeImageToPasteboard(IPC::Connection& connection, const WebCore::PasteboardImage& pasteboardImage, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID)
859{
860 MESSAGE_CHECK(!pasteboardName.isEmpty(), connection);
861
862 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
863 MESSAGE_CHECK(dataOwner, connection);
864
865 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
866 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
867 PlatformPasteboard(pasteboardName).write(pasteboardImage);
868 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, PlatformPasteboard(pasteboardName).changeCount());
869 if (auto process = webProcessProxyForConnection(connection))
870 process->send(Messages::WebProcess::DidWriteToPasteboardAsynchronously(pasteboardName), 0);
871 });
872}
873
874void WebPasteboardProxy::writeStringToPasteboard(IPC::Connection& connection, const String& pasteboardType, const String& text, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID)
875{
876 MESSAGE_CHECK(!pasteboardName.isEmpty(), connection);
877 MESSAGE_CHECK(!pasteboardType.isEmpty() || text.isEmpty(), connection);
878
879 auto dataOwner = determineDataOwner(connection, pasteboardName, pageID, PasteboardAccessIntent::Write);
880 MESSAGE_CHECK(dataOwner, connection);
881
882 PlatformPasteboard::performAsDataOwner(*dataOwner, [&] {
883 auto previousChangeCount = PlatformPasteboard(pasteboardName).changeCount();
884 PlatformPasteboard(pasteboardName).write(pasteboardType, text);
885 didModifyContentsOfPasteboard(connection, pasteboardName, previousChangeCount, PlatformPasteboard(pasteboardName).changeCount());
886 if (auto process = webProcessProxyForConnection(connection))
887 process->send(Messages::WebProcess::DidWriteToPasteboardAsynchronously(pasteboardName), 0);
888 });
889}
890
891void WebPasteboardProxy::updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName, std::optional<WebPageProxyIdentifier>)
892{
893 PlatformPasteboard(pasteboardName).updateSupportedTypeIdentifiers(identifiers);
894}
895
896#endif // PLATFORM(IOS_FAMILY)
897
898std::optional<DataOwnerType> WebPasteboardProxy::determineDataOwner(IPC::Connection& connection, const String& pasteboardName, std::optional<WebPageProxyIdentifier> pageID, PasteboardAccessIntent intent) const
899{
900 MESSAGE_CHECK_WITH_RETURN_VALUE(!pasteboardName.isEmpty(), connection, std::nullopt);
901
902 RefPtr process = webProcessProxyForConnection(connection);
903 MESSAGE_CHECK_WITH_RETURN_VALUE(process, connection, std::nullopt);
904
905 if (!pageID)
906 return DataOwnerType::Undefined;
907
908 std::optional<DataOwnerType> result;
909 if (RefPtr page = WebProcessProxy::webPage(*pageID))
910 result = page->dataOwnerForPasteboard(intent);
911
912 // If this message check is hit, then the incoming web page ID doesn't correspond to any page
913 // currently known to the UI process.
914 MESSAGE_CHECK_WITH_RETURN_VALUE(result.has_value(), connection, std::nullopt);
915 return result;
916}
917
918void WebPasteboardProxy::PasteboardAccessInformation::grantAccess(WebProcessProxy& process, PasteboardAccessType type)
919{
920 auto matchIndex = processes.findIf([&](auto& processAndType) {
921 return processAndType.first == &process;
922 });
923
924 if (matchIndex == notFound) {
925 processes.append({ process, type });
926 return;
927 }
928
929 if (type == PasteboardAccessType::TypesAndData)
930 processes[matchIndex].second = type;
931
932 processes.removeAllMatching([](auto& processAndType) {
933 return !processAndType.first;
934 });
935}
936
937void WebPasteboardProxy::PasteboardAccessInformation::revokeAccess(WebProcessProxy& process)
938{
939 processes.removeFirstMatching([&](auto& processAndType) {
940 return processAndType.first == &process;
941 });
942}
943
944std::optional<WebPasteboardProxy::PasteboardAccessType> WebPasteboardProxy::PasteboardAccessInformation::accessType(WebProcessProxy& process) const
945{
946 auto matchIndex = processes.findIf([&](auto& processAndType) {
947 return processAndType.first == &process;
948 });
949
950 if (matchIndex == notFound)
951 return std::nullopt;
952
953 return processes[matchIndex].second;
954}
955
956void WebPasteboardProxy::writeWebArchiveToPasteBoard(IPC::Connection& connection, const String& pasteboardName, WebCore::FrameIdentifier rootFrameIdentifier, HashMap<FrameIdentifier, Ref<LegacyWebArchive>>&& localFrameArchives, const Vector<FrameIdentifier>& remoteFrameIdentifiers, CompletionHandler<void(int64_t)>&& completionHandler)
957{
958 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(0));
959
960 Ref senderProcess = WebProcessProxy::fromConnection(connection);
961 RefPtr webFrame = WebFrameProxy::webFrame(rootFrameIdentifier);
962 if (!webFrame)
963 return completionHandler(0);
964
965 RefPtr webPage = webFrame->page();
966 if (!webPage)
967 return completionHandler(0);
968
969 createOneWebArchiveFromFrames(senderProcess.get(), rootFrameIdentifier, WTF::move(localFrameArchives), remoteFrameIdentifiers, [connection = Ref { connection }, pasteboardName, pageIdentifier = webPage->identifier(), completionHandler = WTF::move(completionHandler)](auto result) mutable {
970 if (!result)
971 return completionHandler(0);
972
973 RetainPtr data = result->rawDataRepresentation();
974 if (!data)
975 return completionHandler(0);
976
977 RefPtr buffer = SharedBuffer::create(data.get());
978 WebPasteboardProxy::singleton().setPasteboardBufferForType(connection.get(), pasteboardName, String { WebCore::WebArchivePboardType }, RefPtr { buffer }, pageIdentifier, [connection, pasteboardName, pageIdentifier, buffer, completionHandler = WTF::move(completionHandler)](auto) mutable {
979 WebPasteboardProxy::singleton().setPasteboardBufferForType(connection.get(), pasteboardName, UTTypeWebArchive.identifier, WTF::move(buffer), pageIdentifier, WTF::move(completionHandler));
980 });
981 });
982}
983
984void WebPasteboardProxy::createOneWebArchiveFromFrames(WebProcessProxy& requestedProcess, FrameIdentifier rootFrameIdentifier, HashMap<FrameIdentifier, Ref<WebCore::LegacyWebArchive>>&& localFrameArchives, const Vector<FrameIdentifier>& remoteFrameIdentifiers, CompletionHandler<void(RefPtr<LegacyWebArchive>&&)>&& completionHandler)
985{
986 RefPtr webFrame = WebFrameProxy::webFrame(rootFrameIdentifier);
987 if (!webFrame)
988 return completionHandler(nullptr);
989
990 if (&webFrame->process() != &requestedProcess)
991 return completionHandler(nullptr);
992
993 RefPtr webPage = webFrame->page();
994 if (!webPage)
995 return completionHandler(nullptr);
996
997 auto callbackAggregator = LegacyWebArchiveCallbackAggregator::create(rootFrameIdentifier, WTF::move(localFrameArchives), WTF::move(completionHandler));
998 HashMap<Ref<WebProcessProxy>, Vector<WebCore::FrameIdentifier>> frameByProcess;
999 for (auto frameIdentifier : remoteFrameIdentifiers) {
1000 RefPtr currentFrame = WebFrameProxy::webFrame(frameIdentifier);
1001 if (!currentFrame)
1002 continue;
1003
1004 if (&currentFrame->process() == &requestedProcess) {
1005 // The frame is not remote to the sender process.
1006 // This is sync message so we must ensure no dead lock.
1007 continue;
1008 }
1009
1010 if (currentFrame->page() != webPage) {
1011 // The frame is not on the same page as the root frame.
1012 continue;
1013 }
1014
1015 frameByProcess.ensure(protect(currentFrame->process()), [&] {
1016 return Vector<WebCore::FrameIdentifier> { };
1017 }).iterator->value.append(frameIdentifier);
1018 }
1019
1020 for (auto& [process, frameIDs] : frameByProcess) {
1021 Ref { process }->sendWithAsyncReply(Messages::WebPage::GetWebArchivesForFrames(frameIDs), [frameIDs, callbackAggregator](auto&& result) {
1022 if (result.size() > frameIDs.size())
1023 return;
1024 callbackAggregator->addResult(WTF::move(result));
1025 }, webPage->webPageIDInProcess(process.get()));
1026 }
1027}
1028
1029#if ENABLE(IPC_TESTING_API)(defined ENABLE_IPC_TESTING_API && ENABLE_IPC_TESTING_API
)
1030void WebPasteboardProxy::testIPCSharedMemory(IPC::Connection& connection, const String& pasteboardName, const String& pasteboardType, SharedMemory::Handle&& handle, std::optional<WebPageProxyIdentifier> pageID, CompletionHandler<void(int64_t, String)>&& completionHandler)
1031{
1032 MESSAGE_CHECK_COMPLETION(!pasteboardName.isEmpty(), connection, completionHandler(-1, "error"_str));
1033 MESSAGE_CHECK_COMPLETION(!pasteboardType.isEmpty(), connection, completionHandler(-1, "error"_str));
1034
1035 auto sharedMemoryBuffer = SharedMemory::map(WTF::move(handle), SharedMemory::Protection::ReadOnly);
1036 if (!sharedMemoryBuffer) {
1037 completionHandler(-1, "error EOM"_s);
1038 return;
1039 }
1040
1041 completionHandler(sharedMemoryBuffer->size(), byteCast<Latin1Character>(sharedMemoryBuffer->span()));
1042}
1043#endif
1044
1045} // namespace WebKit
1046
1047#undef MESSAGE_CHECK_COMPLETION
1048#undef MESSAGE_CHECK_WITH_RETURN_VALUE
1049#undef MESSAGE_CHECK