7c947b043ef1c21ef8c90e3ccc7f0a7ef83a9db0
[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 #if WK_API_ENABLED
30
31 #import "AutomationClient.h"
32 #import "CacheModel.h"
33 #import "DownloadClient.h"
34 #import "Logging.h"
35 #import "PluginProcessManager.h"
36 #import "SandboxUtilities.h"
37 #import "UIGamepadProvider.h"
38 #import "WKObject.h"
39 #import "WeakObjCPtr.h"
40 #import "WebCertificateInfo.h"
41 #import "WebCookieManagerProxy.h"
42 #import "WebProcessMessages.h"
43 #import "WebProcessPool.h"
44 #import "_WKAutomationDelegate.h"
45 #import "_WKAutomationSessionInternal.h"
46 #import "_WKDownloadDelegate.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/RetainPtr.h>
53
54 #if PLATFORM(IOS)
55 #import <WebCore/WebCoreThreadSystemInterface.h>
56 #import "WKGeolocationProviderIOS.h"
57 #endif
58
59 static WKProcessPool *sharedProcessPool;
60
61 @implementation WKProcessPool {
62     WebKit::WeakObjCPtr<id <_WKAutomationDelegate>> _automationDelegate;
63     WebKit::WeakObjCPtr<id <_WKDownloadDelegate>> _downloadDelegate;
64
65     RetainPtr<_WKAutomationSession> _automationSession;
66 #if PLATFORM(IOS)
67     RetainPtr<WKGeolocationProviderIOS> _geolocationProvider;
68     RetainPtr<id <_WKGeolocationCoreLocationProvider>> _coreLocationProvider;
69 #endif // PLATFORM(IOS)
70 }
71
72 - (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration
73 {
74     if (!(self = [super init]))
75         return nil;
76
77 #if PLATFORM(IOS)
78     // FIXME: Remove once <rdar://problem/15256572> is fixed.
79     InitWebCoreThreadSystemInterface();
80 #endif
81
82     API::Object::constructInWrapper<WebKit::WebProcessPool>(self, *configuration->_processPoolConfiguration);
83
84     return self;
85 }
86
87 - (instancetype)init
88 {
89     return [self _initWithConfiguration:adoptNS([[_WKProcessPoolConfiguration alloc] init]).get()];
90 }
91
92 - (void)dealloc
93 {
94     _processPool->~WebProcessPool();
95
96     [super dealloc];
97 }
98
99 - (void)encodeWithCoder:(NSCoder *)coder
100 {
101     if (self == sharedProcessPool) {
102         [coder encodeBool:YES forKey:@"isSharedProcessPool"];
103         return;
104     }
105 }
106
107 - (instancetype)initWithCoder:(NSCoder *)coder
108 {
109     if (!(self = [self init]))
110         return nil;
111
112     if ([coder decodeBoolForKey:@"isSharedProcessPool"]) {
113         [self release];
114
115         return [[WKProcessPool _sharedProcessPool] retain];
116     }
117
118     return self;
119 }
120
121 - (NSString *)description
122 {
123     return [NSString stringWithFormat:@"<%@: %p; configuration = %@>", NSStringFromClass(self.class), self, wrapper(_processPool->configuration())];
124 }
125
126 - (_WKProcessPoolConfiguration *)_configuration
127 {
128     return wrapper(_processPool->configuration().copy().leakRef());
129 }
130
131 - (API::Object&)_apiObject
132 {
133     return *_processPool;
134 }
135
136 #if PLATFORM(IOS)
137 - (WKGeolocationProviderIOS *)_geolocationProvider
138 {
139     if (!_geolocationProvider)
140         _geolocationProvider = adoptNS([[WKGeolocationProviderIOS alloc] initWithProcessPool:*_processPool]);
141     return _geolocationProvider.get();
142 }
143 #endif // PLATFORM(IOS)
144
145 @end
146
147 @implementation WKProcessPool (WKPrivate)
148
149 + (WKProcessPool *)_sharedProcessPool
150 {
151     static dispatch_once_t onceToken;
152     dispatch_once(&onceToken, ^{
153         sharedProcessPool = [[WKProcessPool alloc] init];
154     });
155
156     return sharedProcessPool;
157 }
158
159 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL
160 {
161     return [WKProcessPool _websiteDataURLForContainerWithURL:containerURL bundleIdentifierIfNotInContainer:nil];
162 }
163
164 + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL bundleIdentifierIfNotInContainer:(NSString *)bundleIdentifier
165 {
166     NSURL *url = [containerURL URLByAppendingPathComponent:@"Library" isDirectory:YES];
167     url = [url URLByAppendingPathComponent:@"WebKit" isDirectory:YES];
168
169     if (!WebKit::processHasContainer() && bundleIdentifier)
170         url = [url URLByAppendingPathComponent:bundleIdentifier isDirectory:YES];
171
172     return [url URLByAppendingPathComponent:@"WebsiteData" isDirectory:YES];
173 }
174
175 - (void)_setAllowsSpecificHTTPSCertificate:(NSArray *)certificateChain forHost:(NSString *)host
176 {
177     _processPool->allowSpecificHTTPSCertificateForHost(WebKit::WebCertificateInfo::create(WebCore::CertificateInfo((CFArrayRef)certificateChain)).ptr(), host);
178 }
179
180 - (void)_setCanHandleHTTPSServerTrustEvaluation:(BOOL)value
181 {
182     _processPool->setCanHandleHTTPSServerTrustEvaluation(value);
183 }
184
185 static WebKit::HTTPCookieAcceptPolicy toHTTPCookieAcceptPolicy(NSHTTPCookieAcceptPolicy policy)
186 {
187     switch (static_cast<NSUInteger>(policy)) {
188     case NSHTTPCookieAcceptPolicyAlways:
189         return WebKit::HTTPCookieAcceptPolicyAlways;
190     case NSHTTPCookieAcceptPolicyNever:
191         return WebKit::HTTPCookieAcceptPolicyNever;
192     case NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:
193         return WebKit::HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
194     case NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain:
195         return WebKit::HTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
196     }
197
198     ASSERT_NOT_REACHED();
199     return WebKit::HTTPCookieAcceptPolicyAlways;
200 }
201
202 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy
203 {
204     _processPool->supplement<WebKit::WebCookieManagerProxy>()->setHTTPCookieAcceptPolicy(PAL::SessionID::defaultSessionID(), toHTTPCookieAcceptPolicy(policy), [](WebKit::CallbackBase::Error){});
205 }
206
207 - (id)_objectForBundleParameter:(NSString *)parameter
208 {
209     return [_processPool->bundleParameters() objectForKey:parameter];
210 }
211
212 - (void)_setObject:(id <NSCopying, NSSecureCoding>)object forBundleParameter:(NSString *)parameter
213 {
214     auto copy = adoptNS([(NSObject *)object copy]);
215
216 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
217     auto data = adoptNS([[NSMutableData alloc] init]);
218     auto keyedArchiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
219     [keyedArchiver setRequiresSecureCoding:YES];
220 #else
221     auto keyedArchiver = secureArchiver();
222 #endif
223
224     @try {
225         [keyedArchiver encodeObject:copy.get() forKey:@"parameter"];
226         [keyedArchiver finishEncoding];
227     } @catch (NSException *exception) {
228         LOG_ERROR("Failed to encode bundle parameter: %@", exception);
229     }
230
231     if (copy)
232         [_processPool->ensureBundleParameters() setObject:copy.get() forKey:parameter];
233     else
234         [_processPool->ensureBundleParameters() removeObjectForKey:parameter];
235
236 #if (!PLATFORM(MAC) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
237     auto data = keyedArchiver.get().encodedData;
238 #endif
239
240     _processPool->sendToAllProcesses(Messages::WebProcess::SetInjectedBundleParameter(parameter, IPC::DataReference(static_cast<const uint8_t*>([data bytes]), [data length])));
241 }
242
243 - (void)_setObjectsForBundleParametersWithDictionary:(NSDictionary *)dictionary
244 {
245     auto copy = adoptNS([[NSDictionary alloc] initWithDictionary:dictionary copyItems:YES]);
246
247 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
248     auto data = adoptNS([[NSMutableData alloc] init]);
249     auto keyedArchiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
250     [keyedArchiver setRequiresSecureCoding:YES];
251 #else
252     auto keyedArchiver = secureArchiver();
253 #endif
254
255     @try {
256         [keyedArchiver encodeObject:copy.get() forKey:@"parameters"];
257         [keyedArchiver finishEncoding];
258     } @catch (NSException *exception) {
259         LOG_ERROR("Failed to encode bundle parameters: %@", exception);
260     }
261
262     [_processPool->ensureBundleParameters() setValuesForKeysWithDictionary:copy.get()];
263
264 #if (!PLATFORM(MAC) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
265     auto data = keyedArchiver.get().encodedData;
266 #endif
267
268     _processPool->sendToAllProcesses(Messages::WebProcess::SetInjectedBundleParameters(IPC::DataReference(static_cast<const uint8_t*>([data bytes]), [data length])));
269 }
270
271 #if !TARGET_OS_IPHONE
272
273 #if ENABLE(NETSCAPE_PLUGIN_API)
274
275 static bool isPluginLoadClientPolicyAcceptable(unsigned policy)
276 {
277     return policy <= WebCore::PluginLoadClientPolicyMaximum;
278 }
279 static HashMap<String, HashMap<String, HashMap<String, uint8_t>>> toPluginLoadClientPoliciesHashMap(NSDictionary* dictionary)
280 {
281     __block HashMap<String, HashMap<String, HashMap<String, uint8_t>>> pluginLoadClientPolicies;
282     [dictionary enumerateKeysAndObjectsUsingBlock:^(id nsHost, id nsPoliciesForHost, BOOL *stop) {
283         if (![nsHost isKindOfClass:[NSString class]]) {
284             RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
285             return;
286         }
287         if (![nsPoliciesForHost isKindOfClass:[NSDictionary class]]) {
288             RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
289             return;
290         }
291
292         String host = (NSString *)nsHost;
293         __block HashMap<String, HashMap<String, uint8_t>> policiesForHost;
294         [nsPoliciesForHost enumerateKeysAndObjectsUsingBlock:^(id nsIdentifier, id nsVersionsToPolicies, BOOL *stop) {
295             if (![nsIdentifier isKindOfClass:[NSString class]]) {
296                 RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
297                 return;
298             }
299             if (![nsVersionsToPolicies isKindOfClass:[NSDictionary class]]) {
300                 RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
301                 return;
302             }
303
304             String bundleIdentifier = (NSString *)nsIdentifier;
305             __block HashMap<String, uint8_t> versionsToPolicies;
306             [nsVersionsToPolicies enumerateKeysAndObjectsUsingBlock:^(id nsVersion, id nsPolicy, BOOL *stop) {
307                 if (![nsVersion isKindOfClass:[NSString class]]) {
308                     RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
309                     return;
310                 }
311                 if (![nsPolicy isKindOfClass:[NSNumber class]]) {
312                     RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
313                     return;
314                 }
315                 unsigned policy = ((NSNumber *)nsPolicy).unsignedIntValue;
316                 if (!isPluginLoadClientPolicyAcceptable(policy)) {
317                     RELEASE_LOG_ERROR(Plugins, "_resetPluginLoadClientPolicies was called with dictionary in wrong format");
318                     return;
319                 }
320                 String version = (NSString *)nsVersion;
321                 versionsToPolicies.add(version, static_cast<uint8_t>(policy));
322             }];
323             if (!versionsToPolicies.isEmpty())
324                 policiesForHost.add(bundleIdentifier, WTFMove(versionsToPolicies));
325         }];
326         if (!policiesForHost.isEmpty())
327             pluginLoadClientPolicies.add(host, WTFMove(policiesForHost));
328     }];
329     return pluginLoadClientPolicies;
330 }
331
332 static NSDictionary *policiesHashMapToDictionary(const HashMap<String, HashMap<String, HashMap<String, uint8_t>>>& map)
333 {
334     auto policies = adoptNS([[NSMutableDictionary alloc] initWithCapacity:map.size()]);
335     for (auto& hostPair : map) {
336         NSString *host = hostPair.key;
337         policies.get()[host] = adoptNS([[NSMutableDictionary alloc] initWithCapacity:hostPair.value.size()]).get();
338         for (auto& bundleIdentifierPair : hostPair.value) {
339             NSString *bundlerIdentifier = bundleIdentifierPair.key;
340             policies.get()[host][bundlerIdentifier] = adoptNS([[NSMutableDictionary alloc] initWithCapacity:bundleIdentifierPair.value.size()]).get();
341             for (auto& versionPair : bundleIdentifierPair.value) {
342                 NSString *version = versionPair.key;
343                 policies.get()[host][bundlerIdentifier][version] = adoptNS([[NSNumber alloc] initWithUnsignedInt:versionPair.value]).get();
344             }
345         }
346     }
347     return policies.autorelease();
348 }
349
350 #endif
351
352 - (void)_resetPluginLoadClientPolicies:(NSDictionary *)policies
353 {
354 #if ENABLE(NETSCAPE_PLUGIN_API)
355     _processPool->resetPluginLoadClientPolicies(toPluginLoadClientPoliciesHashMap(policies));
356 #endif
357 }
358
359 -(NSDictionary *)_pluginLoadClientPolicies
360 {
361     auto& map = _processPool->pluginLoadClientPolicies();
362     return policiesHashMapToDictionary(map);
363 }
364 #endif
365
366
367 - (id <_WKDownloadDelegate>)_downloadDelegate
368 {
369     return _downloadDelegate.getAutoreleased();
370 }
371
372 - (void)_setDownloadDelegate:(id <_WKDownloadDelegate>)downloadDelegate
373 {
374     _downloadDelegate = downloadDelegate;
375     _processPool->setDownloadClient(std::make_unique<WebKit::DownloadClient>(downloadDelegate));
376 }
377
378 - (id <_WKAutomationDelegate>)_automationDelegate
379 {
380     return _automationDelegate.getAutoreleased();
381 }
382
383 - (void)_setAutomationDelegate:(id <_WKAutomationDelegate>)automationDelegate
384 {
385     _automationDelegate = automationDelegate;
386     _processPool->setAutomationClient(std::make_unique<WebKit::AutomationClient>(self, automationDelegate));
387 }
388
389 - (void)_warmInitialProcess
390 {
391     _processPool->warmInitialProcess();
392 }
393
394 - (void)_automationCapabilitiesDidChange
395 {
396     _processPool->updateAutomationCapabilities();
397 }
398
399 - (void)_setAutomationSession:(_WKAutomationSession *)automationSession
400 {
401     _automationSession = automationSession;
402     _processPool->setAutomationSession(automationSession ? automationSession->_session.get() : nullptr);
403 }
404
405 - (void)_terminateStorageProcess
406 {
407     _processPool->terminateStorageProcess();
408 }
409
410 - (void)_terminateNetworkProcess
411 {
412     _processPool->terminateNetworkProcess();
413 }
414
415 - (void)_terminateServiceWorkerProcess
416 {
417     _processPool->terminateServiceWorkerProcess();
418 }
419
420 - (pid_t)_networkProcessIdentifier
421 {
422     return _processPool->networkProcessIdentifier();
423 }
424
425 - (pid_t)_storageProcessIdentifier
426 {
427     return _processPool->storageProcessIdentifier();
428 }
429
430 - (void)_syncNetworkProcessCookies
431 {
432     _processPool->syncNetworkProcessCookies();
433 }
434
435 - (size_t)_webProcessCount
436 {
437     return _processPool->processes().size();
438 }
439
440 - (void)_preconnectToServer:(NSURL *)serverURL
441 {
442     _processPool->preconnectToServer(serverURL);
443 }
444
445 - (size_t)_pluginProcessCount
446 {
447 #if !PLATFORM(IOS)
448     return WebKit::PluginProcessManager::singleton().pluginProcesses().size();
449 #else
450     return 0;
451 #endif
452 }
453
454 + (void)_forceGameControllerFramework
455 {
456 #if ENABLE(GAMEPAD)
457     WebKit::UIGamepadProvider::setUsesGameControllerFramework();
458 #endif
459 }
460
461 - (BOOL)_isCookieStoragePartitioningEnabled
462 {
463     return _processPool->cookieStoragePartitioningEnabled();
464 }
465
466 - (void)_setCookieStoragePartitioningEnabled:(BOOL)enabled
467 {
468     _processPool->setCookieStoragePartitioningEnabled(enabled);
469 }
470
471 - (BOOL)_isStorageAccessAPIEnabled
472 {
473     return _processPool->storageAccessAPIEnabled();
474 }
475
476 - (void)_setStorageAccessAPIEnabled:(BOOL)enabled
477 {
478     _processPool->setStorageAccessAPIEnabled(enabled);
479 }
480
481 - (void)_setAllowsAnySSLCertificateForServiceWorker:(BOOL) allows
482 {
483 #if ENABLE(SERVICE_WORKER)
484     _processPool->setAllowsAnySSLCertificateForServiceWorker(allows);
485 #endif
486 }
487
488 #if PLATFORM(IOS)
489 - (id <_WKGeolocationCoreLocationProvider>)_coreLocationProvider
490 {
491     return _coreLocationProvider.get();
492 }
493
494 - (void)_setCoreLocationProvider:(id<_WKGeolocationCoreLocationProvider>)coreLocationProvider
495 {
496     if (_geolocationProvider)
497         [NSException raise:NSGenericException format:@"Changing the location provider is not supported after a web view in the process pool has begun servicing geolocation requests."];
498
499     _coreLocationProvider = coreLocationProvider;
500 }
501 #endif // PLATFORM(IOS)
502
503 @end
504
505 #endif // WK_API_ENABLED