db31788c05b9f9094e7d572e183369acda6f2cf4
[WebKit-https.git] / Source / WebKit / WebProcess / WebCoreSupport / WebPlatformStrategies.cpp
1 /*
2  * Copyright (C) 2010-2017 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 #include "config.h"
27 #include "WebPlatformStrategies.h"
28
29 #include "BlobRegistryProxy.h"
30 #include "BlockingResponseMap.h"
31 #include "DataReference.h"
32 #include "HangDetectionDisabler.h"
33 #include "NetworkConnectionToWebProcessMessages.h"
34 #include "NetworkProcessConnection.h"
35 #include "NetworkResourceLoadParameters.h"
36 #include "PluginInfoStore.h"
37 #include "SessionTracker.h"
38 #include "WebCookieManager.h"
39 #include "WebCoreArgumentCoders.h"
40 #include "WebErrors.h"
41 #include "WebFrame.h"
42 #include "WebFrameLoaderClient.h"
43 #include "WebLoaderStrategy.h"
44 #include "WebPage.h"
45 #include "WebPasteboardOverrides.h"
46 #include "WebPasteboardProxyMessages.h"
47 #include "WebProcess.h"
48 #include "WebProcessProxyMessages.h"
49 #include <WebCore/Color.h>
50 #include <WebCore/Document.h>
51 #include <WebCore/DocumentLoader.h>
52 #include <WebCore/LoaderStrategy.h>
53 #include <WebCore/MainFrame.h>
54 #include <WebCore/NetworkStorageSession.h>
55 #include <WebCore/NetworkingContext.h>
56 #include <WebCore/Page.h>
57 #include <WebCore/PageGroup.h>
58 #include <WebCore/PlatformCookieJar.h>
59 #include <WebCore/PlatformPasteboard.h>
60 #include <WebCore/ProgressTracker.h>
61 #include <WebCore/ResourceError.h>
62 #include <WebCore/StorageNamespace.h>
63 #include <WebCore/SubframeLoader.h>
64 #include <WebCore/URL.h>
65 #include <pal/SessionID.h>
66 #include <wtf/Atomics.h>
67
68 #if PLATFORM(MAC)
69 #include "StringUtilities.h"
70 #endif
71
72 #if PLATFORM(GTK)
73 #include "WebSelectionData.h"
74 #endif
75
76 using namespace WebCore;
77
78 namespace WebKit {
79
80 void WebPlatformStrategies::initialize()
81 {
82     static NeverDestroyed<WebPlatformStrategies> platformStrategies;
83     setPlatformStrategies(&platformStrategies.get());
84 }
85
86 WebPlatformStrategies::WebPlatformStrategies()
87 {
88 }
89
90 CookiesStrategy* WebPlatformStrategies::createCookiesStrategy()
91 {
92     return this;
93 }
94
95 LoaderStrategy* WebPlatformStrategies::createLoaderStrategy()
96 {
97     return &WebProcess::singleton().webLoaderStrategy();
98 }
99
100 PasteboardStrategy* WebPlatformStrategies::createPasteboardStrategy()
101 {
102     return this;
103 }
104
105 BlobRegistry* WebPlatformStrategies::createBlobRegistry()
106 {
107     return new BlobRegistryProxy;
108 }
109
110 // CookiesStrategy
111
112 std::pair<String, bool> WebPlatformStrategies::cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies)
113 {
114     String cookieString;
115     bool secureCookiesAccessed = false;
116     if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::CookiesForDOM(session.sessionID(), firstParty, url, frameID, pageID, includeSecureCookies), Messages::NetworkConnectionToWebProcess::CookiesForDOM::Reply(cookieString, secureCookiesAccessed), 0))
117         return { String(), false };
118
119     return { cookieString, secureCookiesAccessed };
120 }
121
122 void WebPlatformStrategies::setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, const String& cookieString)
123 {
124     WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCookiesFromDOM(session.sessionID(), firstParty, url, frameID, pageID, cookieString), 0);
125 }
126
127 bool WebPlatformStrategies::cookiesEnabled(const NetworkStorageSession& session)
128 {
129     bool result;
130     if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::CookiesEnabled(session.sessionID()), Messages::NetworkConnectionToWebProcess::CookiesEnabled::Reply(result), 0))
131         return false;
132     return result;
133 }
134
135 std::pair<String, bool> WebPlatformStrategies::cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies)
136 {
137     return cookieRequestHeaderFieldValue(session.sessionID(), firstParty, url, frameID, pageID, includeSecureCookies);
138 }
139
140 std::pair<String, bool> WebPlatformStrategies::cookieRequestHeaderFieldValue(PAL::SessionID sessionID, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies)
141 {
142     String cookieString;
143     bool secureCookiesAccessed = false;
144     if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::CookieRequestHeaderFieldValue(sessionID, firstParty, url, frameID, pageID, includeSecureCookies), Messages::NetworkConnectionToWebProcess::CookieRequestHeaderFieldValue::Reply(cookieString, secureCookiesAccessed), 0))
145         return { String(), false };
146     return { cookieString, secureCookiesAccessed };
147 }
148
149 bool WebPlatformStrategies::getRawCookies(const NetworkStorageSession& session, const URL& firstParty, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, Vector<Cookie>& rawCookies)
150 {
151     if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::NetworkConnectionToWebProcess::GetRawCookies(session.sessionID(), firstParty, url, frameID, pageID), Messages::NetworkConnectionToWebProcess::GetRawCookies::Reply(rawCookies), 0))
152         return false;
153     return true;
154 }
155
156 void WebPlatformStrategies::deleteCookie(const NetworkStorageSession& session, const URL& url, const String& cookieName)
157 {
158     WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::DeleteCookie(session.sessionID(), url, cookieName), 0);
159 }
160
161 #if PLATFORM(COCOA)
162 // PasteboardStrategy
163
164 void WebPlatformStrategies::getTypes(Vector<String>& types, const String& pasteboardName)
165 {
166     // First check the overrides.
167     // The purpose of the overrides is to avoid messaging back to the UI process.
168     // Therefore, if there are any overridden types, we return just those.
169     types = WebPasteboardOverrides::sharedPasteboardOverrides().overriddenTypes(pasteboardName);
170     if (!types.isEmpty())
171         return;
172
173     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardTypes(pasteboardName), Messages::WebPasteboardProxy::GetPasteboardTypes::Reply(types), 0);
174 }
175
176 RefPtr<WebCore::SharedBuffer> WebPlatformStrategies::bufferForType(const String& pasteboardType, const String& pasteboardName)
177 {
178     // First check the overrides.
179     Vector<char> overrideBuffer;
180     if (WebPasteboardOverrides::sharedPasteboardOverrides().getDataForOverride(pasteboardName, pasteboardType, overrideBuffer))
181         return SharedBuffer::create(WTFMove(overrideBuffer));
182
183     // Fallback to messaging the UI process for native pasteboard content.
184     SharedMemory::Handle handle;
185     uint64_t size = 0;
186     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardBufferForType(pasteboardName, pasteboardType), Messages::WebPasteboardProxy::GetPasteboardBufferForType::Reply(handle, size), 0);
187     if (handle.isNull())
188         return nullptr;
189     RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::map(handle, SharedMemory::Protection::ReadOnly);
190     return SharedBuffer::create(static_cast<unsigned char *>(sharedMemoryBuffer->data()), size);
191 }
192
193 void WebPlatformStrategies::getPathnamesForType(Vector<String>& pathnames, const String& pasteboardType, const String& pasteboardName)
194 {
195     SandboxExtension::HandleArray sandboxExtensionsHandleArray;
196     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardPathnamesForType(pasteboardName, pasteboardType),
197         Messages::WebPasteboardProxy::GetPasteboardPathnamesForType::Reply(pathnames, sandboxExtensionsHandleArray), 0);
198     ASSERT(pathnames.size() == sandboxExtensionsHandleArray.size());
199     for (size_t i = 0; i < sandboxExtensionsHandleArray.size(); i++) {
200         if (RefPtr<SandboxExtension> extension = SandboxExtension::create(WTFMove(sandboxExtensionsHandleArray[i])))
201             extension->consumePermanently();
202     }
203 }
204
205 String WebPlatformStrategies::stringForType(const String& pasteboardType, const String& pasteboardName)
206 {
207     String value;
208     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardStringForType(pasteboardName, pasteboardType), Messages::WebPasteboardProxy::GetPasteboardStringForType::Reply(value), 0);
209     return value;
210 }
211
212 long WebPlatformStrategies::changeCount(const WTF::String &pasteboardName)
213 {
214     uint64_t changeCount;
215     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardChangeCount(pasteboardName), Messages::WebPasteboardProxy::GetPasteboardChangeCount::Reply(changeCount), 0);
216     return changeCount;
217 }
218
219 String WebPlatformStrategies::uniqueName()
220 {
221     String pasteboardName;
222     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardUniqueName(), Messages::WebPasteboardProxy::GetPasteboardUniqueName::Reply(pasteboardName), 0);
223     return pasteboardName;
224 }
225
226 Color WebPlatformStrategies::color(const String& pasteboardName)
227 {
228     Color color;
229     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardColor(pasteboardName), Messages::WebPasteboardProxy::GetPasteboardColor::Reply(color), 0);
230     return color;
231 }
232
233 URL WebPlatformStrategies::url(const String& pasteboardName)
234 {
235     String urlString;
236     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardURL(pasteboardName), Messages::WebPasteboardProxy::GetPasteboardURL::Reply(urlString), 0);
237     return URL(ParsedURLString, urlString);
238 }
239
240 long WebPlatformStrategies::addTypes(const Vector<String>& pasteboardTypes, const String& pasteboardName)
241 {
242     uint64_t newChangeCount;
243     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::AddPasteboardTypes(pasteboardName, pasteboardTypes), Messages::WebPasteboardProxy::AddPasteboardTypes::Reply(newChangeCount), 0);
244     return newChangeCount;
245 }
246
247 long WebPlatformStrategies::setTypes(const Vector<String>& pasteboardTypes, const String& pasteboardName)
248 {
249     uint64_t newChangeCount;
250     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardTypes(pasteboardName, pasteboardTypes), Messages::WebPasteboardProxy::SetPasteboardTypes::Reply(newChangeCount), 0);
251     return newChangeCount;
252 }
253
254 long WebPlatformStrategies::setBufferForType(SharedBuffer* buffer, const String& pasteboardType, const String& pasteboardName)
255 {
256     SharedMemory::Handle handle;
257     if (buffer) {
258         RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::allocate(buffer->size());
259         // FIXME: Null check prevents crashing, but it is not great that we will have empty pasteboard content for this type,
260         // because we've already set the types.
261         if (sharedMemoryBuffer) {
262             memcpy(sharedMemoryBuffer->data(), buffer->data(), buffer->size());
263             sharedMemoryBuffer->createHandle(handle, SharedMemory::Protection::ReadOnly);
264         }
265     }
266     uint64_t newChangeCount;
267     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardBufferForType(pasteboardName, pasteboardType, handle, buffer ? buffer->size() : 0), Messages::WebPasteboardProxy::SetPasteboardBufferForType::Reply(newChangeCount), 0);
268     return newChangeCount;
269 }
270
271 long WebPlatformStrategies::setPathnamesForType(const Vector<String>& pathnames, const String& pasteboardType, const String& pasteboardName)
272 {
273     uint64_t newChangeCount;
274     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardPathnamesForType(pasteboardName, pasteboardType, pathnames), Messages::WebPasteboardProxy::SetPasteboardPathnamesForType::Reply(newChangeCount), 0);
275     return newChangeCount;
276 }
277
278 long WebPlatformStrategies::setStringForType(const String& string, const String& pasteboardType, const String& pasteboardName)
279 {
280     uint64_t newChangeCount;
281     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardStringForType(pasteboardName, pasteboardType, string), Messages::WebPasteboardProxy::SetPasteboardStringForType::Reply(newChangeCount), 0);
282     return newChangeCount;
283 }
284
285 int WebPlatformStrategies::getNumberOfFiles(const String& pasteboardName)
286 {
287     uint64_t numberOfFiles;
288     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetNumberOfFiles(pasteboardName), Messages::WebPasteboardProxy::GetNumberOfFiles::Reply(numberOfFiles), 0);
289     return numberOfFiles;
290 }
291
292 #if PLATFORM(IOS)
293 void WebPlatformStrategies::getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName)
294 {
295     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardTypesByFidelityForItemAtIndex(index, pasteboardName), Messages::WebPasteboardProxy::GetPasteboardTypesByFidelityForItemAtIndex::Reply(types), 0);
296 }
297
298 void WebPlatformStrategies::writeToPasteboard(const PasteboardURL& url, const String& pasteboardName)
299 {
300     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteURLToPasteboard(url, pasteboardName), 0);
301 }
302
303 void WebPlatformStrategies::writeToPasteboard(const WebCore::PasteboardWebContent& content, const String& pasteboardName)
304 {
305     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteWebContentToPasteboard(content, pasteboardName), 0);
306 }
307
308 void WebPlatformStrategies::writeToPasteboard(const WebCore::PasteboardImage& image, const String& pasteboardName)
309 {
310     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteImageToPasteboard(image, pasteboardName), 0);
311 }
312
313 void WebPlatformStrategies::writeToPasteboard(const String& pasteboardType, const String& text, const String& pasteboardName)
314 {
315     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteStringToPasteboard(pasteboardType, text, pasteboardName), 0);
316 }
317
318 int WebPlatformStrategies::getPasteboardItemsCount(const String& pasteboardName)
319 {
320     uint64_t itemsCount;
321     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardItemsCount(pasteboardName), Messages::WebPasteboardProxy::GetPasteboardItemsCount::Reply(itemsCount), 0);
322     return itemsCount;
323 }
324
325 void WebPlatformStrategies::getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName)
326 {
327     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetFilenamesForDataInteraction(pasteboardName), Messages::WebPasteboardProxy::GetFilenamesForDataInteraction::Reply(filenames), 0);
328 }
329
330 void WebPlatformStrategies::updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
331 {
332     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::UpdateSupportedTypeIdentifiers(identifiers, pasteboardName), 0);
333 }
334
335 RefPtr<WebCore::SharedBuffer> WebPlatformStrategies::readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName)
336 {
337     SharedMemory::Handle handle;
338     uint64_t size = 0;
339     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::ReadBufferFromPasteboard(index, pasteboardType, pasteboardName), Messages::WebPasteboardProxy::ReadBufferFromPasteboard::Reply(handle, size), 0);
340     if (handle.isNull())
341         return nullptr;
342     RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::map(handle, SharedMemory::Protection::ReadOnly);
343     return SharedBuffer::create(static_cast<unsigned char *>(sharedMemoryBuffer->data()), size);
344 }
345
346 WebCore::URL WebPlatformStrategies::readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title)
347 {
348     String urlString;
349     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::ReadURLFromPasteboard(index, pasteboardType, pasteboardName), Messages::WebPasteboardProxy::ReadURLFromPasteboard::Reply(urlString, title), 0);
350     return URL(ParsedURLString, urlString);
351 }
352
353 String WebPlatformStrategies::readStringFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName)
354 {
355     String value;
356     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::ReadStringFromPasteboard(index, pasteboardType, pasteboardName), Messages::WebPasteboardProxy::ReadStringFromPasteboard::Reply(value), 0);
357     return value;
358 }
359 #endif // PLATFORM(IOS)
360
361 #endif // PLATFORM(COCOA)
362
363 #if PLATFORM(GTK)
364 // PasteboardStrategy
365
366 void WebPlatformStrategies::writeToClipboard(const String& pasteboardName, const SelectionData& selection)
367 {
368     WebSelectionData selectionData(selection);
369     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteToClipboard(pasteboardName, selectionData), 0);
370 }
371
372 Ref<SelectionData> WebPlatformStrategies::readFromClipboard(const String& pasteboardName)
373 {
374     WebSelectionData selection;
375     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::ReadFromClipboard(pasteboardName), Messages::WebPasteboardProxy::ReadFromClipboard::Reply(selection), 0);
376     return WTFMove(selection.selectionData);
377 }
378
379 #endif // PLATFORM(GTK)
380
381 #if PLATFORM(WPE)
382 // PasteboardStrategy
383
384 void WebPlatformStrategies::getTypes(Vector<String>& types)
385 {
386     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardTypes(), Messages::WebPasteboardProxy::GetPasteboardTypes::Reply(types), 0);
387 }
388
389 String WebPlatformStrategies::readStringFromPasteboard(int index, const String& pasteboardType)
390 {
391     String value;
392     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::ReadStringFromPasteboard(index, pasteboardType), Messages::WebPasteboardProxy::ReadStringFromPasteboard::Reply(value), 0);
393     return value;
394 }
395
396 void WebPlatformStrategies::writeToPasteboard(const WebCore::PasteboardWebContent& content)
397 {
398     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteWebContentToPasteboard(content), 0);
399 }
400
401 void WebPlatformStrategies::writeToPasteboard(const String& pasteboardType, const String& text)
402 {
403     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::WriteStringToPasteboard(pasteboardType, text), 0);
404 }
405
406 #endif // PLATFORM(WPE)
407
408 Vector<String> WebPlatformStrategies::typesSafeForDOMToReadAndWrite(const String& pasteboardName, const String& origin)
409 {
410     Vector<String> types;
411     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::TypesSafeForDOMToReadAndWrite(pasteboardName, origin), Messages::WebPasteboardProxy::TypesSafeForDOMToReadAndWrite::Reply(types), 0);
412     return types;
413 }
414
415 long WebPlatformStrategies::writeCustomData(const WebCore::PasteboardCustomData& data, const String& pasteboardName)
416 {
417     uint64_t newChangeCount;
418     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::WriteCustomData(data, pasteboardName), Messages::WebPasteboardProxy::WriteCustomData::Reply(newChangeCount), 0);
419     return newChangeCount;
420 }
421
422 } // namespace WebKit