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