bb163b37f62163961270e620c19af46c2e756ce3
[WebKit-https.git] / Source / WebKit / UIProcess / API / Cocoa / WKProcessPool.mm
1 /*
2  * Copyright (C) 2014-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 #import "config.h"
27 #import "WKProcessPoolInternal.h"
28
29 #import "AutomationClient.h"
30 #import "CacheModel.h"
31 #import "DownloadClient.h"
32 #import "Logging.h"
33 #import "PluginProcessManager.h"
34 #import "SandboxUtilities.h"
35 #import "UIGamepadProvider.h"
36 #import "WKObject.h"
37 #import "WKWebViewInternal.h"
38 #import "WebCertificateInfo.h"
39 #import "WebCookieManagerProxy.h"
40 #import "WebProcessCache.h"
41 #import "WebProcessMessages.h"
42 #import "WebProcessPool.h"
43 #import "_WKAutomationDelegate.h"
44 #import "_WKAutomationSessionInternal.h"
45 #import "_WKDownloadDelegate.h"
46 #import "_WKDownloadInternal.h"
47 #import "_WKProcessPoolConfigurationInternal.h"
48 #import <WebCore/CertificateInfo.h>
49 #import <WebCore/PluginData.h>
50 #import <pal/spi/cf/CFNetworkSPI.h>
51 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
52 #import <wtf/BlockPtr.h>
53 #import <wtf/RetainPtr.h>
54 #import <wtf/WeakObjCPtr.h>
55
56 #if PLATFORM(IOS_FAMILY)
57 #import <WebCore/WebCoreThreadSystemInterface.h>
58 #import "WKGeolocationProviderIOS.h"
59 #endif
60
61 static WKProcessPool *sharedProcessPool;
62
63 @implementation WKProcessPool {
64     WeakObjCPtr<id <_WKAutomationDelegate>> _automationDelegate;
65     WeakObjCPtr<id <_WKDownloadDelegate>> _downloadDelegate;
66
67     RetainPtr<_WKAutomationSession> _automationSession;
68 #if PLATFORM(IOS_FAMILY)
69     RetainPtr<WKGeolocationProviderIOS> _geolocationProvider;
70     RetainPtr<id <_WKGeolocationCoreLocationProvider>> _coreLocationProvider;
71 #endif // PLATFORM(IOS_FAMILY)
72 }
73
74 - (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration
75 {
76     if (!(self = [super init]))
77         return nil;
78
79     API::Object::constructInWrapper<WebKit::WebProcessPool>(self, *configuration->_processPoolConfiguration);
80
81     return self;
82 }
83
84 - (instancetype)init
85 {
86     return [self _initWithConfiguration:adoptNS([[_WKProcessPoolConfiguration alloc] init]).get()];
87 }
88
89 - (void)dealloc
90 {
91     _processPool->~WebProcessPool();
92
93     [super dealloc];
94 }
95
96 + (BOOL)supportsSecureCoding
97 {
98     return YES;
99 }
100
101 - (void)encodeWithCoder:(NSCoder *)coder
102 {
103     if (self == sharedProcessPool) {
104         [coder encodeBool:YES forKey:@"isSharedProcessPool"];
105         return;
106     }
107 }
108
109 - (instancetype)initWithCoder:(NSCoder *)coder
110 {
111     if (!(self = [self init]))
112         return nil;
113
114     if ([coder decodeBoolForKey:@"isSharedProcessPool"]) {
115         [self release];
116
117         return [[WKProcessPool _sharedProcessPool] retain];
118     }
119
120     return self;
121 }
122
123 - (NSString *)description
124 {
125     return [NSString stringWithFormat:@"<%@: %p; configuration = %@>", NSStringFromClass(self.class), self, wrapper(_processPool->configuration())];
126 }
127
128 - (_WKProcessPoolConfiguration *)_configuration
129 {
130     return wrapper(_processPool->configuration().copy());
131 }
132
133 - (API::Object&)_apiObject
134 {
135     return *_processPool;
136 }
137
138 #if PLATFORM(IOS_FAMILY)
139 - (WKGeolocationProviderIOS *)_geolocationProvider
140 {
141     if (!_geolocationProvider)
142         _geolocationProvider = adoptNS([[WKGeolocationProviderIOS alloc] initWithProcessPool:*_processPool]);
143     return _geolocationProvider.get();
144 }
145 #endif // PLATFORM(IOS_FAMILY)
146
147 @end
148
149 @implementation WKProcessPool (WKPrivate)
150
151 + (WKProcessPool *)_sharedProcessPool
152 {
153     static dispatch_once_t onceToken;
154     dispatch_once(&onceToken, ^{
155         sharedProcessPool = [[WKProcessPool alloc] init];
156     });
157
158     return sharedProcessPool;
159 }
160
161 + (NSArray<WKProcessPool *> *)_allProcessPoolsForTesting
162 {
163     auto& allPools = WebKit::WebProcessPool::allProcessPools();
164     auto nsAllPools = adoptNS([[NSMutableArray alloc] initWithCapacity:allPools.size()]);
165     for (auto* pool : allPools)
166         [nsAllPools addObject:wrapper(*pool)];
167     return nsAllPools.autorelease();
168 }
169
170 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL
171 {
172     return [WKProcessPool _websiteDataURLForContainerWithURL:containerURL bundleIdentifierIfNotInContainer:nil];
173 }
174
175 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL bundleIdentifierIfNotInContainer:(NSString *)bundleIdentifier
176 {
177     NSURL *url = [containerURL URLByAppendingPathComponent:@"Library" isDirectory:YES];
178     url = [url URLByAppendingPathComponent:@"WebKit" isDirectory:YES];
179
180     if (!WebKit::processHasContainer() && bundleIdentifier)
181         url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
182
183     return [url URLByAppendingPathComponent:@"WebsiteData" isDirectory:YES];
184 }
185
186 - (void)_setAllowsSpecificHTTPSCertificate:(NSArray *)certificateChain forHost:(NSString *)host
187 {
188     _processPool->allowSpecificHTTPSCertificateForHost(WebKit::WebCertificateInfo::create(WebCore::CertificateInfo((__bridge CFArrayRef)certificateChain)).ptr(), host);
189 }
190
191 - (void)_registerURLSchemeServiceWorkersCanHandle:(NSString *)scheme
192 {
193     _processPool->registerURLSchemeServiceWorkersCanHandle(scheme);
194 }
195
196 - (void)_registerURLSchemeAsCanDisplayOnlyIfCanRequest:(NSString *)scheme
197 {
198     _processPool->registerURLSchemeAsCanDisplayOnlyIfCanRequest(scheme);
199 }
200
201 - (void)_setCanHandleHTTPSServerTrustEvaluation:(BOOL)value
202 {
203     _processPool->setCanHandleHTTPSServerTrustEvaluation(value);
204 }
205
206 static WebKit::HTTPCookieAcceptPolicy toHTTPCookieAcceptPolicy(NSHTTPCookieAcceptPolicy policy)
207 {
208     switch (static_cast<NSUInteger>(policy)) {
209     case NSHTTPCookieAcceptPolicyAlways:
210         return WebKit::HTTPCookieAcceptPolicyAlways;
211     case NSHTTPCookieAcceptPolicyNever:
212         return WebKit::HTTPCookieAcceptPolicyNever;
213     case NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:
214         return WebKit::HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
215     case NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain:
216         return WebKit::HTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
217     }
218
219     ASSERT_NOT_REACHED();
220     return WebKit::HTTPCookieAcceptPolicyAlways;
221 }
222
223 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy
224 {
225     _processPool->supplement<WebKit::WebCookieManagerProxy>()->setHTTPCookieAcceptPolicy(PAL::SessionID::defaultSessionID(), toHTTPCookieAcceptPolicy(policy), [](WebKit::CallbackBase::Error){});
226 }
227
228 - (id)_objectForBundleParameter:(NSString *)parameter
229 {
230     return [_processPool->bundleParameters() objectForKey:parameter];
231 }
232
233 - (void)_setObject:(id <NSCopying, NSSecureCoding>)object forBundleParameter:(NSString *)parameter
234 {
235     auto copy = adoptNS([(NSObject *)object copy]);
236     auto keyedArchiver = secureArchiver();
237
238     @try {
239         [keyedArchiver encodeObject:copy.get() forKey:@"parameter"];
240         [keyedArchiver finishEncoding];
241     } @catch (NSException *exception) {
242         LOG_ERROR("Failed to encode bundle parameter: %@", exception);
243     }
244
245     if (copy)
246         [_processPool->ensureBundleParameters() setObject:copy.get() forKey:parameter];
247     else
248         [_processPool->ensureBundleParameters() removeObjectForKey:parameter];
249
250     auto data = keyedArchiver.get().encodedData;
251     _processPool->sendToAllProcesses(Messages::WebProcess::SetInjectedBundleParameter(parameter, IPC::DataReference(static_cast<const uint8_t*>([data bytes]), [data length])));
252 }
253
254 - (void)_setObjectsForBundleParametersWithDictionary:(NSDictionary *)dictionary
255 {
256     auto copy = adoptNS([[NSDictionary alloc] initWithDictionary:dictionary copyItems:YES]);
257     auto keyedArchiver = secureArchiver();
258
259     @try {
260         [keyedArchiver encodeObject:copy.get() forKey:@"parameters"];
261         [keyedArchiver finishEncoding];
262     } @catch (NSException *exception) {
263         LOG_ERROR("Failed to encode bundle parameters: %@", exception);
264     }
265
266     [_processPool->ensureBundleParameters() setValuesForKeysWithDictionary:copy.get()];
267
268     auto data = keyedArchiver.get().encodedData;
269     _processPool->sendToAllProcesses(Messages::WebProcess::SetInjectedBundleParameters(IPC::DataReference(static_cast<const uint8_t*>([data bytes]), [data length])));
270 }
271
272 #if !TARGET_OS_IPHONE
273
274 #if ENABLE(NETSCAPE_PLUGIN_API)
275
276 static bool isPluginLoadClientPolicyAcceptable(unsigned policy)
277 {
278     return policy <= WebCore::PluginLoadClientPolicyMaximum;
279 }
280 static HashMap<String, HashMap<String, HashMap<String, uint8_t>>> toPluginLoadClientPoliciesHashMap(NSDictionary* dictionary)
281 {
282     __block HashMap<String, HashMap<String, HashMap<String, uint8_t>>> pluginLoadClientPolicies;
283     [dictionary enumerateKeysAndObjectsUsingBlock:^(id nsHost, id nsPoliciesForHost, BOOL *stop) {
284         if (![nsHost isKindOfClass:[NSString class]]) {
285             RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
286             return;
287         }
288         if (![nsPoliciesForHost isKindOfClass:[NSDictionary class]]) {
289             RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
290             return;
291         }
292
293         String host = (NSString *)nsHost;
294         __block HashMap<String, HashMap<String, uint8_t>> policiesForHost;
295         [nsPoliciesForHost enumerateKeysAndObjectsUsingBlock:^(id nsIdentifier, id nsVersionsToPolicies, BOOL *stop) {
296             if (![nsIdentifier isKindOfClass:[NSString class]]) {
297                 RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
298                 return;
299             }
300             if (![nsVersionsToPolicies isKindOfClass:[NSDictionary class]]) {
301                 RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
302                 return;
303             }
304
305             String bundleIdentifier = (NSString *)nsIdentifier;
306             __block HashMap<String, uint8_t> versionsToPolicies;
307             [nsVersionsToPolicies enumerateKeysAndObjectsUsingBlock:^(id nsVersion, id nsPolicy, BOOL *stop) {
308                 if (![nsVersion isKindOfClass:[NSString class]]) {
309                     RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
310                     return;
311                 }
312                 if (![nsPolicy isKindOfClass:[NSNumber class]]) {
313                     RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
314                     return;
315                 }
316                 unsigned policy = ((NSNumber *)nsPolicy).unsignedIntValue;
317                 if (!isPluginLoadClientPolicyAcceptable(policy)) {
318                     RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
319                     return;
320                 }
321                 String version = (NSString *)nsVersion;
322                 versionsToPolicies.add(version, static_cast<uint8_t>(policy));
323             }];
324             if (!versionsToPolicies.isEmpty())
325                 policiesForHost.add(bundleIdentifier, WTFMove(versionsToPolicies));
326         }];
327         if (!policiesForHost.isEmpty())
328             pluginLoadClientPolicies.add(host, WTFMove(policiesForHost));
329     }];
330     return pluginLoadClientPolicies;
331 }
332
333 static NSDictionary *policiesHashMapToDictionary(const HashMap<String, HashMap<String, HashMap<String, uint8_t>>>& map)
334 {
335     auto policies = adoptNS([[NSMutableDictionary alloc] initWithCapacity:map.size()]);
336     for (auto& hostPair : map) {
337         NSString *host = hostPair.key;
338         policies.get()[host] = adoptNS([[NSMutableDictionary alloc] initWithCapacity:hostPair.value.size()]).get();
339         for (auto& bundleIdentifierPair : hostPair.value) {
340             NSString *bundlerIdentifier = bundleIdentifierPair.key;
341             policies.get()[host][bundlerIdentifier] = adoptNS([[NSMutableDictionary alloc] initWithCapacity:bundleIdentifierPair.value.size()]).get();
342             for (auto& versionPair : bundleIdentifierPair.value) {
343                 NSString *version = versionPair.key;
344                 policies.get()[host][bundlerIdentifier][version] = adoptNS([[NSNumber alloc] initWithUnsignedInt:versionPair.value]).get();
345             }
346         }
347     }
348     return policies.autorelease();
349 }
350
351 #endif
352
353 - (void)_resetPluginLoadClientPolicies:(NSDictionary *)policies
354 {
355 #if ENABLE(NETSCAPE_PLUGIN_API)
356     _processPool->resetPluginLoadClientPolicies(toPluginLoadClientPoliciesHashMap(policies));
357 #endif
358 }
359
360 -(NSDictionary *)_pluginLoadClientPolicies
361 {
362     auto& map = _processPool->pluginLoadClientPolicies();
363     return policiesHashMapToDictionary(map);
364 }
365 #endif
366
367
368 - (id <_WKDownloadDelegate>)_downloadDelegate
369 {
370     return _downloadDelegate.getAutoreleased();
371 }
372
373 - (void)_setDownloadDelegate:(id <_WKDownloadDelegate>)downloadDelegate
374 {
375     _downloadDelegate = downloadDelegate;
376     _processPool->setDownloadClient(std::make_unique<WebKit::DownloadClient>(downloadDelegate));
377 }
378
379 - (id <_WKAutomationDelegate>)_automationDelegate
380 {
381     return _automationDelegate.getAutoreleased();
382 }
383
384 - (void)_setAutomationDelegate:(id <_WKAutomationDelegate>)automationDelegate
385 {
386     _automationDelegate = automationDelegate;
387     _processPool->setAutomationClient(std::make_unique<WebKit::AutomationClient>(self, automationDelegate));
388 }
389
390 - (void)_warmInitialProcess
391 {
392     _processPool->prewarmProcess(nullptr, WebKit::WebProcessPool::MayCreateDefaultDataStore::Yes);
393 }
394
395 - (void)_automationCapabilitiesDidChange
396 {
397     _processPool->updateAutomationCapabilities();
398 }
399
400 - (void)_setAutomationSession:(_WKAutomationSession *)automationSession
401 {
402     _automationSession = automationSession;
403     _processPool->setAutomationSession(automationSession ? automationSession->_session.get() : nullptr);
404 }
405
406 - (void)_addSupportedPlugin:(NSString *) domain named:(NSString *) name withMimeTypes: (NSSet<NSString *> *) nsMimeTypes withExtensions: (NSSet<NSString *> *) nsExtensions
407 {
408     HashSet<String> mimeTypes;
409     for (NSString *mimeType in nsMimeTypes)
410         mimeTypes.add(mimeType);
411     HashSet<String> extensions;
412     for (NSString *extension in nsExtensions)
413         extensions.add(extension);
414
415     _processPool->addSupportedPlugin(domain, name, WTFMove(mimeTypes), WTFMove(extensions));
416 }
417
418 - (void)_clearSupportedPlugins
419 {
420     _processPool->clearSupportedPlugins();
421 }
422
423 - (void)_terminateNetworkProcess
424 {
425     _processPool->terminateNetworkProcess();
426 }
427
428 - (void)_terminateServiceWorkerProcesses
429 {
430     _processPool->terminateServiceWorkerProcesses();
431 }
432
433 - (void)_disableServiceWorkerProcessTerminationDelay
434 {
435     _processPool->disableServiceWorkerProcessTerminationDelay();
436 }
437
438 - (pid_t)_networkProcessIdentifier
439 {
440     return _processPool->networkProcessIdentifier();
441 }
442
443 - (void)_syncNetworkProcessCookies
444 {
445     _processPool->syncNetworkProcessCookies();
446 }
447
448 - (size_t)_webProcessCount
449 {
450     return _processPool->processes().size();
451 }
452
453 - (void)_makeNextWebProcessLaunchFailForTesting
454 {
455     _processPool->setShouldMakeNextWebProcessLaunchFailForTesting(true);
456 }
457
458 - (void)_makeNextNetworkProcessLaunchFailForTesting
459 {
460     _processPool->setShouldMakeNextNetworkProcessLaunchFailForTesting(true);
461 }
462
463 - (BOOL)_hasPrewarmedWebProcess
464 {
465     for (auto& process : _processPool->processes()) {
466         if (process->isPrewarmed())
467             return YES;
468     }
469     return NO;
470 }
471
472 - (size_t)_webProcessCountIgnoringPrewarmed
473 {
474     return [self _webProcessCount] - ([self _hasPrewarmedWebProcess] ? 1 : 0);
475 }
476
477 - (size_t)_webProcessCountIgnoringPrewarmedAndCached
478 {
479     size_t count = 0;
480     for (auto& process : _processPool->processes()) {
481         if (!process->isInProcessCache() && !process->isPrewarmed())
482             ++count;
483     }
484     return count;
485 }
486
487 - (size_t)_webPageContentProcessCount
488 {
489     auto allWebProcesses = _processPool->processes();
490 #if ENABLE(SERVICE_WORKER)
491     auto& serviceWorkerProcesses = _processPool->serviceWorkerProxies();
492     if (serviceWorkerProcesses.isEmpty())
493         return allWebProcesses.size();
494
495     return allWebProcesses.size() - serviceWorkerProcesses.size();
496 #else
497     return allWebProcesses.size();
498 #endif
499 }
500
501 - (void)_preconnectToServer:(NSURL *)serverURL
502 {
503     _processPool->preconnectToServer(serverURL);
504 }
505
506 - (size_t)_pluginProcessCount
507 {
508 #if !PLATFORM(IOS_FAMILY)
509     return WebKit::PluginProcessManager::singleton().pluginProcesses().size();
510 #else
511     return 0;
512 #endif
513 }
514
515 - (NSUInteger)_maximumSuspendedPageCount
516 {
517     return _processPool->maxSuspendedPageCount();
518 }
519
520 - (NSUInteger)_processCacheCapacity
521 {
522     return _processPool->webProcessCache().capacity();
523 }
524
525 - (NSUInteger)_processCacheSize
526 {
527     return _processPool->webProcessCache().size();
528 }
529
530 - (size_t)_serviceWorkerProcessCount
531 {
532 #if ENABLE(SERVICE_WORKER)
533     return _processPool->serviceWorkerProxies().size();
534 #else
535     return 0;
536 #endif
537 }
538
539 + (void)_forceGameControllerFramework
540 {
541 #if ENABLE(GAMEPAD)
542     WebKit::UIGamepadProvider::setUsesGameControllerFramework();
543 #endif
544 }
545
546 - (BOOL)_isCookieStoragePartitioningEnabled
547 {
548     return _processPool->cookieStoragePartitioningEnabled();
549 }
550
551 - (void)_setCookieStoragePartitioningEnabled:(BOOL)enabled
552 {
553     _processPool->setCookieStoragePartitioningEnabled(enabled);
554 }
555
556 - (BOOL)_isStorageAccessAPIEnabled
557 {
558     return _processPool->storageAccessAPIEnabled();
559 }
560
561 - (void)_setStorageAccessAPIEnabled:(BOOL)enabled
562 {
563     _processPool->setStorageAccessAPIEnabled(enabled);
564 }
565
566 - (void)_setAllowsAnySSLCertificateForServiceWorker:(BOOL) allows
567 {
568 #if ENABLE(SERVICE_WORKER)
569     _processPool->setAllowsAnySSLCertificateForServiceWorker(allows);
570 #endif
571 }
572
573 #if PLATFORM(IOS_FAMILY)
574 - (id <_WKGeolocationCoreLocationProvider>)_coreLocationProvider
575 {
576     return _coreLocationProvider.get();
577 }
578
579 - (void)_setCoreLocationProvider:(id<_WKGeolocationCoreLocationProvider>)coreLocationProvider
580 {
581     if (_geolocationProvider)
582         [NSException raise:NSGenericException format:@"Changing the location provider is not supported after a web view in the process pool has begun servicing geolocation requests."];
583
584     _coreLocationProvider = coreLocationProvider;
585 }
586 #endif // PLATFORM(IOS_FAMILY)
587
588 - (_WKDownload *)_downloadURLRequest:(NSURLRequest *)request originatingWebView:(WKWebView *)webView
589 {
590     return (_WKDownload *)_processPool->download([webView _page], request)->wrapper();
591 }
592
593 - (_WKDownload *)_resumeDownloadFromData:(NSData *)resumeData path:(NSString *)path originatingWebView:(WKWebView *)webView
594 {
595     return wrapper(_processPool->resumeDownload([webView _page], API::Data::createWithoutCopying(resumeData).ptr(), path));
596 }
597
598 - (void)_getActivePagesOriginsInWebProcessForTesting:(pid_t)pid completionHandler:(void(^)(NSArray<NSString *> *))completionHandler
599 {
600     _processPool->activePagesOriginsInWebProcessForTesting(pid, [completionHandler = makeBlockPtr(completionHandler)] (Vector<String>&& activePagesOrigins) {
601         NSMutableArray<NSString *> *array = [[[NSMutableArray alloc] initWithCapacity:activePagesOrigins.size()] autorelease];
602         for (auto& origin : activePagesOrigins)
603             [array addObject:origin];
604         completionHandler(array);
605     });
606 }
607
608 - (BOOL)_networkProcessHasEntitlementForTesting:(NSString *)entitlement
609 {
610     return _processPool->networkProcessHasEntitlementForTesting(entitlement);
611 }
612
613 @end