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