81567e2a0eaa12324337b67b488b2629258db9e9
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / WebProcessPoolCocoa.mm
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 #import "config.h"
27 #import "WebProcessPool.h"
28
29 #import "CookieStorageUtilsCF.h"
30 #import "LegacyCustomProtocolManagerClient.h"
31 #import "NetworkProcessCreationParameters.h"
32 #import "NetworkProcessMessages.h"
33 #import "NetworkProcessProxy.h"
34 #import "PluginProcessManager.h"
35 #import "SandboxUtilities.h"
36 #import "TextChecker.h"
37 #import "VersionChecks.h"
38 #import "WKBrowsingContextControllerInternal.h"
39 #import "WebPageGroup.h"
40 #import "WebPreferencesKeys.h"
41 #import "WebProcessCreationParameters.h"
42 #import "WebProcessMessages.h"
43 #import "WindowServerConnection.h"
44 #import <WebCore/Color.h>
45 #import <WebCore/FileSystem.h>
46 #import <WebCore/NetworkStorageSession.h>
47 #import <WebCore/NotImplemented.h>
48 #import <WebCore/PlatformPasteboard.h>
49 #import <WebCore/RuntimeApplicationChecks.h>
50 #import <WebCore/SharedBuffer.h>
51 #import <pal/spi/cf/CFNetworkSPI.h>
52 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
53 #import <sys/param.h>
54
55 #if PLATFORM(IOS)
56 #import "ArgumentCodersCF.h"
57 #import "WebMemoryPressureHandlerIOS.h"
58 #else
59 #import <QuartzCore/CARemoteLayerServer.h>
60 #endif
61
62 using namespace WebCore;
63
64 NSString *WebDatabaseDirectoryDefaultsKey = @"WebDatabaseDirectory";
65 NSString *WebServiceWorkerRegistrationDirectoryDefaultsKey = @"WebServiceWorkerRegistrationDirectory";
66 NSString *WebKitLocalCacheDefaultsKey = @"WebKitLocalCache";
67 NSString *WebStorageDirectoryDefaultsKey = @"WebKitLocalStorageDatabasePathPreferenceKey";
68 NSString *WebKitJSCJITEnabledDefaultsKey = @"WebKitJSCJITEnabledDefaultsKey";
69 NSString *WebKitJSCFTLJITEnabledDefaultsKey = @"WebKitJSCFTLJITEnabledDefaultsKey";
70 NSString *WebKitMediaKeysStorageDirectoryDefaultsKey = @"WebKitMediaKeysStorageDirectory";
71 NSString *WebKitMediaCacheDirectoryDefaultsKey = @"WebKitMediaCacheDirectory";
72
73 #if !PLATFORM(IOS)
74 static NSString *WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification = @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification";
75 #endif
76
77 // FIXME: <rdar://problem/9138817> - After this "backwards compatibility" radar is removed, this code should be removed to only return an empty String.
78 NSString *WebIconDatabaseDirectoryDefaultsKey = @"WebIconDatabaseDirectoryDefaultsKey";
79
80 static NSString * const WebKit2HTTPProxyDefaultsKey = @"WebKit2HTTPProxy";
81 static NSString * const WebKit2HTTPSProxyDefaultsKey = @"WebKit2HTTPSProxy";
82
83 static NSString * const WebKitNetworkCacheEnabledDefaultsKey = @"WebKitNetworkCacheEnabled";
84 static NSString * const WebKitNetworkCacheEfficacyLoggingEnabledDefaultsKey = @"WebKitNetworkCacheEfficacyLoggingEnabled";
85
86 static NSString * const WebKitSuppressMemoryPressureHandlerDefaultsKey = @"WebKitSuppressMemoryPressureHandler";
87 static NSString * const WebKitNetworkLoadThrottleLatencyMillisecondsDefaultsKey = @"WebKitNetworkLoadThrottleLatencyMilliseconds";
88
89 #if ENABLE(NETWORK_CAPTURE)
90 static NSString * const WebKitRecordReplayModeDefaultsKey = @"WebKitRecordReplayMode";
91 static NSString * const WebKitRecordReplayCacheLocationDefaultsKey = @"WebKitRecordReplayCacheLocation";
92 #endif
93
94 namespace WebKit {
95
96 NSString *SchemeForCustomProtocolRegisteredNotificationName = @"WebKitSchemeForCustomProtocolRegisteredNotification";
97 NSString *SchemeForCustomProtocolUnregisteredNotificationName = @"WebKitSchemeForCustomProtocolUnregisteredNotification";
98
99 static void registerUserDefaultsIfNeeded()
100 {
101     static bool didRegister;
102     if (didRegister)
103         return;
104
105     didRegister = true;
106     NSMutableDictionary *registrationDictionary = [NSMutableDictionary dictionary];
107     
108     [registrationDictionary setObject:@YES forKey:WebKitJSCJITEnabledDefaultsKey];
109     [registrationDictionary setObject:@YES forKey:WebKitJSCFTLJITEnabledDefaultsKey];
110
111     [registrationDictionary setObject:@YES forKey:WebKitNetworkCacheEnabledDefaultsKey];
112     [registrationDictionary setObject:@NO forKey:WebKitNetworkCacheEfficacyLoggingEnabledDefaultsKey];
113
114     [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDictionary];
115 }
116
117 void WebProcessPool::updateProcessSuppressionState()
118 {
119     if (m_networkProcess)
120         m_networkProcess->setProcessSuppressionEnabled(processSuppressionEnabled());
121
122 #if ENABLE(NETSCAPE_PLUGIN_API)
123     if (!m_processSuppressionDisabledForPageCounter.value())
124         m_pluginProcessManagerProcessSuppressionDisabledToken = nullptr;
125     else if (!m_pluginProcessManagerProcessSuppressionDisabledToken)
126         m_pluginProcessManagerProcessSuppressionDisabledToken = PluginProcessManager::singleton().processSuppressionDisabledToken();
127 #endif
128 }
129
130 NSMutableDictionary *WebProcessPool::ensureBundleParameters()
131 {
132     if (!m_bundleParameters)
133         m_bundleParameters = adoptNS([[NSMutableDictionary alloc] init]);
134
135     return m_bundleParameters.get();
136 }
137
138 void WebProcessPool::platformInitialize()
139 {
140     registerUserDefaultsIfNeeded();
141     registerNotificationObservers();
142
143 #if PLATFORM(IOS)
144     IPC::setAllowsDecodingSecKeyRef(true);
145     installMemoryPressureHandler();
146 #endif
147
148     setLegacyCustomProtocolManagerClient(std::make_unique<LegacyCustomProtocolManagerClient>());
149 }
150
151 #if PLATFORM(IOS)
152 String WebProcessPool::cookieStorageDirectory() const
153 {
154     String path = pathForProcessContainer();
155     if (path.isEmpty())
156         path = NSHomeDirectory();
157
158     path = path + "/Library/Cookies";
159     path = stringByResolvingSymlinksInPath(path);
160     return path;
161 }
162 #endif
163
164 void WebProcessPool::platformResolvePathsForSandboxExtensions()
165 {
166     m_resolvedPaths.uiProcessBundleResourcePath = resolvePathForSandboxExtension([[NSBundle mainBundle] resourcePath]);
167
168 #if PLATFORM(IOS)
169     m_resolvedPaths.cookieStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(cookieStorageDirectory());
170     m_resolvedPaths.containerCachesDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(webContentCachesDirectory());
171     m_resolvedPaths.containerTemporaryDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(containerTemporaryDirectory());
172 #endif
173 }
174
175 void WebProcessPool::platformInitializeWebProcess(WebProcessCreationParameters& parameters)
176 {
177 #if PLATFORM(MAC)
178 #pragma clang diagnostic push
179 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
180     parameters.accessibilityEnhancedUserInterfaceEnabled = [[NSApp accessibilityAttributeValue:@"AXEnhancedUserInterface"] boolValue];
181 #pragma clang diagnostic pop
182 #else
183     parameters.accessibilityEnhancedUserInterfaceEnabled = false;
184 #endif
185
186     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
187
188     parameters.shouldEnableJIT = [defaults boolForKey:WebKitJSCJITEnabledDefaultsKey];
189     parameters.shouldEnableFTLJIT = [defaults boolForKey:WebKitJSCFTLJITEnabledDefaultsKey];
190     parameters.shouldEnableMemoryPressureReliefLogging = [defaults boolForKey:@"LogMemoryJetsamDetails"];
191     parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey];
192
193 #if HAVE(HOSTED_CORE_ANIMATION)
194 #if !PLATFORM(IOS)
195     parameters.acceleratedCompositingPort = MachSendRight::create([CARemoteLayerServer sharedServer].serverPort);
196 #endif
197 #endif
198
199     // FIXME: This should really be configurable; we shouldn't just blindly allow read access to the UI process bundle.
200     parameters.uiProcessBundleResourcePath = m_resolvedPaths.uiProcessBundleResourcePath;
201     SandboxExtension::createHandleWithoutResolvingPath(parameters.uiProcessBundleResourcePath, SandboxExtension::Type::ReadOnly, parameters.uiProcessBundleResourcePathExtensionHandle);
202
203     parameters.uiProcessBundleIdentifier = String([[NSBundle mainBundle] bundleIdentifier]);
204
205 #if PLATFORM(IOS)
206     if (!m_resolvedPaths.cookieStorageDirectory.isEmpty())
207         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.cookieStorageDirectory, SandboxExtension::Type::ReadWrite, parameters.cookieStorageDirectoryExtensionHandle);
208
209     if (!m_resolvedPaths.containerCachesDirectory.isEmpty())
210         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerCachesDirectory, SandboxExtension::Type::ReadWrite, parameters.containerCachesDirectoryExtensionHandle);
211
212     if (!m_resolvedPaths.containerTemporaryDirectory.isEmpty())
213         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerTemporaryDirectory, SandboxExtension::Type::ReadWrite, parameters.containerTemporaryDirectoryExtensionHandle);
214 #endif
215
216     parameters.fontWhitelist = m_fontWhitelist;
217
218     if (m_bundleParameters) {
219 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
220         auto data = adoptNS([[NSMutableData alloc] init]);
221         auto keyedArchiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
222
223         [keyedArchiver setRequiresSecureCoding:YES];
224 #else
225         auto keyedArchiver = secureArchiver();
226 #endif
227
228         @try {
229             [keyedArchiver encodeObject:m_bundleParameters.get() forKey:@"parameters"];
230             [keyedArchiver finishEncoding];
231         } @catch (NSException *exception) {
232             LOG_ERROR("Failed to encode bundle parameters: %@", exception);
233         }
234
235 #if (!PLATFORM(MAC) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
236         auto data = retainPtr(keyedArchiver.get().encodedData);
237 #endif
238
239         parameters.bundleParameterData = API::Data::createWithoutCopying((const unsigned char*)[data bytes], [data length], [] (unsigned char*, const void* data) {
240             [(NSData *)data release];
241         }, data.leakRef());
242     }
243     parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext());
244
245 #if PLATFORM(MAC)
246     ASSERT(parameters.uiProcessCookieStorageIdentifier.isEmpty());
247     parameters.uiProcessCookieStorageIdentifier = identifyingDataFromCookieStorage([[NSHTTPCookieStorage sharedHTTPCookieStorage] _cookieStorage]);
248 #endif
249 #if ENABLE(MEDIA_STREAM)
250     // Allow microphone access if either preference is set because WebRTC requires microphone access.
251     bool mediaDevicesEnabled = m_defaultPageGroup->preferences().mediaDevicesEnabled();
252     bool webRTCEnabled = m_defaultPageGroup->preferences().peerConnectionEnabled();
253     if ([defaults objectForKey:@"ExperimentalPeerConnectionEnabled"])
254         webRTCEnabled = [defaults boolForKey:@"ExperimentalPeerConnectionEnabled"];
255
256     bool isSafari = false;
257 #if PLATFORM(IOS)
258     if (WebCore::IOSApplication::isMobileSafari())
259         isSafari = true;
260 #elif PLATFORM(MAC)
261     if (WebCore::MacApplication::isSafari())
262         isSafari = true;
263 #endif
264
265 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
266     parameters.webCoreLoggingChannels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
267     parameters.webKitLoggingChannels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
268 #endif
269
270     // FIXME: Remove this and related parameter when <rdar://problem/29448368> is fixed.
271     if (isSafari && !parameters.shouldCaptureAudioInUIProcess && mediaDevicesEnabled)
272         SandboxExtension::createHandleForGenericExtension("com.apple.webkit.microphone", parameters.audioCaptureExtensionHandle);
273 #endif
274 }
275
276 void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationParameters& parameters)
277 {
278     NSURLCache *urlCache = [NSURLCache sharedURLCache];
279     parameters.nsURLCacheMemoryCapacity = [urlCache memoryCapacity];
280     parameters.nsURLCacheDiskCapacity = [urlCache diskCapacity];
281
282     parameters.parentProcessName = [[NSProcessInfo processInfo] processName];
283     parameters.uiProcessBundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
284
285     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
286
287     parameters.httpProxy = [defaults stringForKey:WebKit2HTTPProxyDefaultsKey];
288     parameters.httpsProxy = [defaults stringForKey:WebKit2HTTPSProxyDefaultsKey];
289     parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext());
290
291     parameters.shouldEnableNetworkCache = isNetworkCacheEnabled();
292     parameters.shouldEnableNetworkCacheEfficacyLogging = [defaults boolForKey:WebKitNetworkCacheEfficacyLoggingEnabledDefaultsKey];
293
294     parameters.sourceApplicationBundleIdentifier = m_configuration->sourceApplicationBundleIdentifier();
295     parameters.sourceApplicationSecondaryIdentifier = m_configuration->sourceApplicationSecondaryIdentifier();
296 #if PLATFORM(IOS)
297     parameters.ctDataConnectionServiceType = m_configuration->ctDataConnectionServiceType();
298 #endif
299
300     parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey];
301     parameters.loadThrottleLatency = Seconds { [defaults integerForKey:WebKitNetworkLoadThrottleLatencyMillisecondsDefaultsKey] / 1000. };
302
303 #if PLATFORM(MAC)
304     ASSERT(parameters.uiProcessCookieStorageIdentifier.isEmpty());
305     parameters.uiProcessCookieStorageIdentifier = identifyingDataFromCookieStorage([[NSHTTPCookieStorage sharedHTTPCookieStorage] _cookieStorage]);
306 #endif
307
308     parameters.cookieStoragePartitioningEnabled = cookieStoragePartitioningEnabled();
309     parameters.storageAccessAPIEnabled = storageAccessAPIEnabled();
310
311 #if ENABLE(NETWORK_CAPTURE)
312     parameters.recordReplayMode = [defaults stringForKey:WebKitRecordReplayModeDefaultsKey];
313     parameters.recordReplayCacheLocation = [defaults stringForKey:WebKitRecordReplayCacheLocationDefaultsKey];
314     if (parameters.recordReplayCacheLocation.isEmpty())
315         parameters.recordReplayCacheLocation = parameters.diskCacheDirectory;
316 #endif
317 }
318
319 void WebProcessPool::platformInvalidateContext()
320 {
321     unregisterNotificationObservers();
322 }
323
324 #if PLATFORM(IOS)
325 String WebProcessPool::parentBundleDirectory() const
326 {
327     return [[[NSBundle mainBundle] bundlePath] stringByStandardizingPath];
328 }
329
330 String WebProcessPool::networkingCachesDirectory() const
331 {
332     String path = pathForProcessContainer();
333     if (path.isEmpty())
334         path = NSHomeDirectory();
335
336     path = path + "/Library/Caches/com.apple.WebKit.Networking/";
337     path = stringByResolvingSymlinksInPath(path);
338
339     NSError *error = nil;
340     NSString* nsPath = path;
341     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
342         NSLog(@"could not create networking caches directory \"%@\", error %@", nsPath, error);
343         return String();
344     }
345
346     return path;
347 }
348
349 String WebProcessPool::webContentCachesDirectory() const
350 {
351     String path = pathForProcessContainer();
352     if (path.isEmpty())
353         path = NSHomeDirectory();
354
355     path = path + "/Library/Caches/com.apple.WebKit.WebContent/";
356     path = stringByResolvingSymlinksInPath(path);
357
358     NSError *error = nil;
359     NSString* nsPath = path;
360     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
361         NSLog(@"could not create web content caches directory \"%@\", error %@", nsPath, error);
362         return String();
363     }
364
365     return path;
366 }
367
368 String WebProcessPool::containerTemporaryDirectory() const
369 {
370     String path = NSTemporaryDirectory();
371     return stringByResolvingSymlinksInPath(path);
372 }
373 #endif
374
375 String WebProcessPool::legacyPlatformDefaultWebSQLDatabaseDirectory()
376 {
377     registerUserDefaultsIfNeeded();
378
379     NSString *databasesDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebDatabaseDirectoryDefaultsKey];
380     if (!databasesDirectory || ![databasesDirectory isKindOfClass:[NSString class]])
381         databasesDirectory = @"~/Library/WebKit/Databases";
382     return stringByResolvingSymlinksInPath([databasesDirectory stringByStandardizingPath]);
383 }
384
385 String WebProcessPool::legacyPlatformDefaultIndexedDBDatabaseDirectory()
386 {
387     // Indexed databases exist in a subdirectory of the "database directory path."
388     // Currently, the top level of that directory contains entities related to WebSQL databases.
389     // We should fix this, and move WebSQL into a subdirectory (https://bugs.webkit.org/show_bug.cgi?id=124807)
390     // In the meantime, an entity name prefixed with three underscores will not conflict with any WebSQL entities.
391     return FileSystem::pathByAppendingComponent(legacyPlatformDefaultWebSQLDatabaseDirectory(), "___IndexedDB");
392 }
393
394 String WebProcessPool::legacyPlatformDefaultServiceWorkerRegistrationDirectory()
395 {
396     registerUserDefaultsIfNeeded();
397
398     NSString *directory = [[NSUserDefaults standardUserDefaults] objectForKey:WebServiceWorkerRegistrationDirectoryDefaultsKey];
399     if (!directory || ![directory isKindOfClass:[NSString class]])
400         directory = @"~/Library/WebKit/ServiceWorkers";
401     return stringByResolvingSymlinksInPath([directory stringByStandardizingPath]);
402 }
403
404 String WebProcessPool::legacyPlatformDefaultLocalStorageDirectory()
405 {
406     registerUserDefaultsIfNeeded();
407
408     NSString *localStorageDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebStorageDirectoryDefaultsKey];
409     if (!localStorageDirectory || ![localStorageDirectory isKindOfClass:[NSString class]])
410         localStorageDirectory = @"~/Library/WebKit/LocalStorage";
411     return stringByResolvingSymlinksInPath([localStorageDirectory stringByStandardizingPath]);
412 }
413
414 String WebProcessPool::legacyPlatformDefaultMediaCacheDirectory()
415 {
416     registerUserDefaultsIfNeeded();
417     
418     NSString *mediaKeysCacheDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitMediaCacheDirectoryDefaultsKey];
419     if (!mediaKeysCacheDirectory || ![mediaKeysCacheDirectory isKindOfClass:[NSString class]]) {
420         mediaKeysCacheDirectory = NSTemporaryDirectory();
421         
422         if (!WebKit::processHasContainer()) {
423             NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
424             if (!bundleIdentifier)
425                 bundleIdentifier = [NSProcessInfo processInfo].processName;
426             mediaKeysCacheDirectory = [mediaKeysCacheDirectory stringByAppendingPathComponent:bundleIdentifier];
427         }
428         mediaKeysCacheDirectory = [mediaKeysCacheDirectory stringByAppendingPathComponent:@"WebKit/MediaCache"];
429     }
430     return stringByResolvingSymlinksInPath([mediaKeysCacheDirectory stringByStandardizingPath]);
431 }
432
433 String WebProcessPool::legacyPlatformDefaultMediaKeysStorageDirectory()
434 {
435     registerUserDefaultsIfNeeded();
436
437     NSString *mediaKeysStorageDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebKitMediaKeysStorageDirectoryDefaultsKey];
438     if (!mediaKeysStorageDirectory || ![mediaKeysStorageDirectory isKindOfClass:[NSString class]])
439         mediaKeysStorageDirectory = @"~/Library/WebKit/MediaKeys";
440     return stringByResolvingSymlinksInPath([mediaKeysStorageDirectory stringByStandardizingPath]);
441 }
442
443 String WebProcessPool::legacyPlatformDefaultApplicationCacheDirectory()
444 {
445     NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
446     if (!appName)
447         appName = [[NSProcessInfo processInfo] processName];
448 #if PLATFORM(IOS)
449     // This quirk used to make these apps share application cache storage, but doesn't accomplish that any more.
450     // Preserving it avoids the need to migrate data when upgrading.
451     if (IOSApplication::isMobileSafari() || IOSApplication::isWebApp())
452         appName = @"com.apple.WebAppCache";
453 #endif
454
455     ASSERT(appName);
456
457 #if PLATFORM(IOS)
458     NSString *cacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
459 #else
460     char cacheDirectory[MAXPATHLEN];
461     size_t cacheDirectoryLen = confstr(_CS_DARWIN_USER_CACHE_DIR, cacheDirectory, MAXPATHLEN);
462     if (!cacheDirectoryLen)
463         return String();
464
465     NSString *cacheDir = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:cacheDirectory length:cacheDirectoryLen - 1];
466 #endif
467     NSString* cachePath = [cacheDir stringByAppendingPathComponent:appName];
468     return stringByResolvingSymlinksInPath([cachePath stringByStandardizingPath]);
469 }
470
471 String WebProcessPool::legacyPlatformDefaultNetworkCacheDirectory()
472 {
473     RetainPtr<NSString> cachePath = adoptNS((NSString *)_CFURLCacheCopyCacheDirectory([[NSURLCache sharedURLCache] _CFURLCache]));
474     if (!cachePath)
475         cachePath = @"~/Library/Caches/com.apple.WebKit.WebProcess";
476
477     if (isNetworkCacheEnabled())
478         cachePath = [cachePath stringByAppendingPathComponent:@"WebKitCache"];
479
480     return stringByResolvingSymlinksInPath([cachePath stringByStandardizingPath]);
481 }
482
483 String WebProcessPool::legacyPlatformDefaultJavaScriptConfigurationDirectory()
484 {
485 #if PLATFORM(IOS)
486     String path = pathForProcessContainer();
487     if (path.isEmpty())
488         path = NSHomeDirectory();
489     
490     path = path + "/Library/WebKit/JavaScriptCoreDebug";
491     path = stringByResolvingSymlinksInPath(path);
492
493     return path;
494 #else
495     RetainPtr<NSString> javaScriptConfigPath = @"~/Library/WebKit/JavaScriptCoreDebug";
496     
497     return stringByResolvingSymlinksInPath([javaScriptConfigPath stringByStandardizingPath]);
498 #endif
499 }
500
501 #if PLATFORM(IOS)
502 void WebProcessPool::setJavaScriptConfigurationFileEnabledFromDefaults()
503 {
504     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
505
506     setJavaScriptConfigurationFileEnabled([defaults boolForKey:@"WebKitJavaScriptCoreUseConfigFile"]);
507 }
508 #endif
509
510 bool WebProcessPool::isNetworkCacheEnabled()
511 {
512     registerUserDefaultsIfNeeded();
513
514     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
515
516     bool networkCacheEnabledByDefaults = [defaults boolForKey:WebKitNetworkCacheEnabledDefaultsKey];
517
518     return networkCacheEnabledByDefaults && linkedOnOrAfter(SDKVersion::FirstWithNetworkCache);
519 }
520
521 bool WebProcessPool::omitPDFSupport()
522 {
523     // Since this is a "secret default" we don't bother registering it.
524     return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
525 }
526
527 bool WebProcessPool::processSuppressionEnabled() const
528 {
529     return !m_userObservablePageCounter.value() && !m_processSuppressionDisabledForPageCounter.value();
530 }
531
532 void WebProcessPool::registerNotificationObservers()
533 {
534 #if !PLATFORM(IOS)
535     // Listen for enhanced accessibility changes and propagate them to the WebProcess.
536     m_enhancedAccessibilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
537         setEnhancedAccessibility([[[note userInfo] objectForKey:@"AXEnhancedUserInterface"] boolValue]);
538     }];
539
540     m_automaticTextReplacementNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticTextReplacementNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
541         TextChecker::didChangeAutomaticTextReplacementEnabled();
542         textCheckerStateChanged();
543     }];
544     
545     m_automaticSpellingCorrectionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticSpellingCorrectionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
546         TextChecker::didChangeAutomaticSpellingCorrectionEnabled();
547         textCheckerStateChanged();
548     }];
549
550     m_automaticQuoteSubstitutionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticQuoteSubstitutionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
551         TextChecker::didChangeAutomaticQuoteSubstitutionEnabled();
552         textCheckerStateChanged();
553     }];
554
555     m_automaticDashSubstitutionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticDashSubstitutionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
556         TextChecker::didChangeAutomaticDashSubstitutionEnabled();
557         textCheckerStateChanged();
558     }];
559 #endif // !PLATFORM(IOS)
560 }
561
562 void WebProcessPool::unregisterNotificationObservers()
563 {
564 #if !PLATFORM(IOS)
565     [[NSNotificationCenter defaultCenter] removeObserver:m_enhancedAccessibilityObserver.get()];    
566     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticTextReplacementNotificationObserver.get()];
567     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticSpellingCorrectionNotificationObserver.get()];
568     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticQuoteSubstitutionNotificationObserver.get()];
569     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticDashSubstitutionNotificationObserver.get()];
570 #endif // !PLATFORM(IOS)
571 }
572
573 static CFURLStorageSessionRef privateBrowsingSession()
574 {
575     static CFURLStorageSessionRef session;
576     static dispatch_once_t once;
577     dispatch_once(&once, ^{
578         NSString *identifier = [NSString stringWithFormat:@"%@.PrivateBrowsing", [[NSBundle mainBundle] bundleIdentifier]];
579
580         session = createPrivateStorageSession((CFStringRef)identifier);
581     });
582
583     return session;
584 }
585
586 bool WebProcessPool::isURLKnownHSTSHost(const String& urlString, bool privateBrowsingEnabled) const
587 {
588     RetainPtr<CFURLRef> url = URL(URL(), urlString).createCFURL();
589
590     return _CFNetworkIsKnownHSTSHostWithSession(url.get(), privateBrowsingEnabled ? privateBrowsingSession() : nullptr);
591 }
592
593 void WebProcessPool::resetHSTSHosts()
594 {
595     _CFNetworkResetHSTSHostsWithSession(nullptr);
596     _CFNetworkResetHSTSHostsWithSession(privateBrowsingSession());
597 }
598
599 void WebProcessPool::resetHSTSHostsAddedAfterDate(double startDateIntervalSince1970)
600 {
601     NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:startDateIntervalSince1970];
602     _CFNetworkResetHSTSHostsSinceDate(nullptr, (__bridge CFDateRef)startDate);
603     _CFNetworkResetHSTSHostsSinceDate(privateBrowsingSession(), (__bridge CFDateRef)startDate);
604 }
605
606 void WebProcessPool::setCookieStoragePartitioningEnabled(bool enabled)
607 {
608     m_cookieStoragePartitioningEnabled = enabled;
609     sendToNetworkingProcess(Messages::NetworkProcess::SetCookieStoragePartitioningEnabled(enabled));
610 }
611
612 void WebProcessPool::setStorageAccessAPIEnabled(bool enabled)
613 {
614     m_storageAccessAPIEnabled = enabled;
615     sendToNetworkingProcess(Messages::NetworkProcess::SetStorageAccessAPIEnabled(enabled));
616 }
617
618 int networkProcessLatencyQOS()
619 {
620     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitNetworkProcessLatencyQOS"];
621     return qos;
622 }
623
624 int networkProcessThroughputQOS()
625 {
626     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitNetworkProcessThroughputQOS"];
627     return qos;
628 }
629
630 int webProcessLatencyQOS()
631 {
632     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitWebProcessLatencyQOS"];
633     return qos;
634 }
635
636 int webProcessThroughputQOS()
637 {
638     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitWebProcessThroughputQOS"];
639     return qos;
640 }
641
642 } // namespace WebKit