[iOS] Deny mach lookup access to content filter service in the WebContent sandbox
[WebKit.git] / Source / WebKit / UIProcess / Cocoa / WebProcessPoolCocoa.mm
1 /*
2  * Copyright (C) 2010-2019 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 "Logging.h"
32 #import "NetworkProcessCreationParameters.h"
33 #import "NetworkProcessMessages.h"
34 #import "NetworkProcessProxy.h"
35 #import "PluginProcessManager.h"
36 #import "SandboxUtilities.h"
37 #import "TextChecker.h"
38 #import "VersionChecks.h"
39 #import "WKBrowsingContextControllerInternal.h"
40 #import "WebBackForwardCache.h"
41 #import "WebMemoryPressureHandler.h"
42 #import "WebPageGroup.h"
43 #import "WebPreferencesKeys.h"
44 #import "WebProcessCache.h"
45 #import "WebProcessCreationParameters.h"
46 #import "WebProcessMessages.h"
47 #import "WindowServerConnection.h"
48 #import <WebCore/Color.h>
49 #import <WebCore/NetworkStorageSession.h>
50 #import <WebCore/NotImplemented.h>
51 #import <WebCore/PlatformPasteboard.h>
52 #import <WebCore/RuntimeApplicationChecks.h>
53 #import <WebCore/SharedBuffer.h>
54 #import <objc/runtime.h>
55 #import <pal/spi/cf/CFNetworkSPI.h>
56 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
57 #import <sys/param.h>
58 #import <wtf/FileSystem.h>
59 #import <wtf/ProcessPrivilege.h>
60 #import <wtf/SoftLinking.h>
61 #import <wtf/cocoa/Entitlements.h>
62 #import <wtf/spi/darwin/dyldSPI.h>
63
64 #if PLATFORM(MAC)
65 #import <QuartzCore/CARemoteLayerServer.h>
66 #else
67 #import "AccessibilitySupportSPI.h"
68 #import "UIKitSPI.h"
69 #endif
70
71 #if PLATFORM(IOS)
72 #import <pal/spi/cocoa/WebFilterEvaluatorSPI.h>
73 #import <sys/utsname.h>
74
75 SOFT_LINK_PRIVATE_FRAMEWORK(WebContentAnalysis);
76 SOFT_LINK_CLASS(WebContentAnalysis, WebFilterEvaluator);
77 #endif
78
79 #if PLATFORM(COCOA)
80 #import <pal/spi/cocoa/NEFilterSourceSPI.h>
81
82 SOFT_LINK_FRAMEWORK_OPTIONAL(NetworkExtension);
83 SOFT_LINK_CLASS_OPTIONAL(NetworkExtension, NEFilterSource);
84 #endif
85
86 NSString *WebServiceWorkerRegistrationDirectoryDefaultsKey = @"WebServiceWorkerRegistrationDirectory";
87 NSString *WebKitLocalCacheDefaultsKey = @"WebKitLocalCache";
88 NSString *WebKitJSCJITEnabledDefaultsKey = @"WebKitJSCJITEnabledDefaultsKey";
89 NSString *WebKitJSCFTLJITEnabledDefaultsKey = @"WebKitJSCFTLJITEnabledDefaultsKey";
90
91 #if !PLATFORM(IOS_FAMILY)
92 static NSString *WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification = @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification";
93 #endif
94
95 static NSString * const WebKitSuppressMemoryPressureHandlerDefaultsKey = @"WebKitSuppressMemoryPressureHandler";
96
97 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
98 static NSString * const WebKitLogCookieInformationDefaultsKey = @"WebKitLogCookieInformation";
99 #endif
100
101 #if PLATFORM(IOS)
102 SOFT_LINK_PRIVATE_FRAMEWORK(BackBoardServices)
103 SOFT_LINK(BackBoardServices, BKSDisplayBrightnessGetCurrent, float, (), ());
104 #endif
105
106 namespace WebKit {
107 using namespace WebCore;
108
109 static void registerUserDefaultsIfNeeded()
110 {
111     static bool didRegister;
112     if (didRegister)
113         return;
114
115     didRegister = true;
116     NSMutableDictionary *registrationDictionary = [NSMutableDictionary dictionary];
117     
118     [registrationDictionary setObject:@YES forKey:WebKitJSCJITEnabledDefaultsKey];
119     [registrationDictionary setObject:@YES forKey:WebKitJSCFTLJITEnabledDefaultsKey];
120
121     [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDictionary];
122 }
123
124 void WebProcessPool::updateProcessSuppressionState()
125 {
126     if (m_networkProcess)
127         m_networkProcess->setProcessSuppressionEnabled(processSuppressionEnabled());
128
129 #if ENABLE(NETSCAPE_PLUGIN_API)
130     if (!m_processSuppressionDisabledForPageCounter.value())
131         m_pluginProcessManagerProcessSuppressionDisabledToken = nullptr;
132     else if (!m_pluginProcessManagerProcessSuppressionDisabledToken)
133         m_pluginProcessManagerProcessSuppressionDisabledToken = PluginProcessManager::singleton().processSuppressionDisabledToken();
134 #endif
135 }
136
137 NSMutableDictionary *WebProcessPool::ensureBundleParameters()
138 {
139     if (!m_bundleParameters)
140         m_bundleParameters = adoptNS([[NSMutableDictionary alloc] init]);
141
142     return m_bundleParameters.get();
143 }
144
145 void WebProcessPool::platformInitialize()
146 {
147     registerUserDefaultsIfNeeded();
148     registerNotificationObservers();
149     initializeClassesForParameterCoding();
150
151     // FIXME: This should be able to share code with WebCore's MemoryPressureHandler (and be platform independent).
152     // Right now it cannot because WebKit1 and WebKit2 need to be able to coexist in the UI process,
153     // and you can only have one WebCore::MemoryPressureHandler.
154
155     if (![[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitSuppressMemoryPressureHandler"])
156         installMemoryPressureHandler();
157
158     setLegacyCustomProtocolManagerClient(makeUnique<LegacyCustomProtocolManagerClient>());
159 }
160
161 #if PLATFORM(IOS_FAMILY)
162 String WebProcessPool::cookieStorageDirectory()
163 {
164     String path = pathForProcessContainer();
165     if (path.isEmpty())
166         path = NSHomeDirectory();
167
168     path = path + "/Library/Cookies";
169     path = stringByResolvingSymlinksInPath(path);
170     return path;
171 }
172 #endif
173
174 void WebProcessPool::platformResolvePathsForSandboxExtensions()
175 {
176     m_resolvedPaths.uiProcessBundleResourcePath = resolvePathForSandboxExtension([[NSBundle mainBundle] resourcePath]);
177
178 #if PLATFORM(IOS_FAMILY)
179     m_resolvedPaths.cookieStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebProcessPool::cookieStorageDirectory());
180     m_resolvedPaths.containerCachesDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebProcessPool::webContentCachesDirectory());
181     m_resolvedPaths.containerTemporaryDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebProcessPool::containerTemporaryDirectory());
182 #endif
183 }
184
185 #if PLATFORM(IOS)
186 static bool deviceHasAGXCompilerService()
187 {
188     static bool deviceHasAGXCompilerService = false;
189     static std::once_flag flag;
190     std::call_once(
191         flag,
192         [] () {
193             struct utsname systemInfo;
194             if (uname(&systemInfo))
195                 return;
196             const char* machine = systemInfo.machine;
197             if (!strcmp(machine, "iPad5,1") || !strcmp(machine, "iPad5,2") || !strcmp(machine, "iPad5,3") || !strcmp(machine, "iPad5,4"))
198                 deviceHasAGXCompilerService = true;
199         });
200     return deviceHasAGXCompilerService;
201 }
202 #endif
203
204 void WebProcessPool::platformInitializeWebProcess(const WebProcessProxy& process, WebProcessCreationParameters& parameters)
205 {
206     parameters.mediaMIMETypes = process.mediaMIMETypes();
207
208 #if PLATFORM(MAC)
209     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
210     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
211     parameters.accessibilityEnhancedUserInterfaceEnabled = [[NSApp accessibilityAttributeValue:@"AXEnhancedUserInterface"] boolValue];
212     ALLOW_DEPRECATED_DECLARATIONS_END
213 #else
214     parameters.accessibilityEnhancedUserInterfaceEnabled = false;
215 #endif
216
217     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
218
219     parameters.shouldEnableJIT = [defaults boolForKey:WebKitJSCJITEnabledDefaultsKey];
220     parameters.shouldEnableFTLJIT = [defaults boolForKey:WebKitJSCFTLJITEnabledDefaultsKey];
221     parameters.shouldEnableMemoryPressureReliefLogging = [defaults boolForKey:@"LogMemoryJetsamDetails"];
222     parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey];
223
224 #if HAVE(HOSTED_CORE_ANIMATION)
225 #if !PLATFORM(IOS_FAMILY)
226     parameters.acceleratedCompositingPort = MachSendRight::create([CARemoteLayerServer sharedServer].serverPort);
227 #endif
228 #endif
229
230     // FIXME: This should really be configurable; we shouldn't just blindly allow read access to the UI process bundle.
231     parameters.uiProcessBundleResourcePath = m_resolvedPaths.uiProcessBundleResourcePath;
232     SandboxExtension::createHandleWithoutResolvingPath(parameters.uiProcessBundleResourcePath, SandboxExtension::Type::ReadOnly, parameters.uiProcessBundleResourcePathExtensionHandle);
233
234     parameters.uiProcessBundleIdentifier = String([[NSBundle mainBundle] bundleIdentifier]);
235     parameters.uiProcessSDKVersion = dyld_get_program_sdk_version();
236
237 #if PLATFORM(IOS_FAMILY)
238     if (!m_resolvedPaths.cookieStorageDirectory.isEmpty())
239         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.cookieStorageDirectory, SandboxExtension::Type::ReadWrite, parameters.cookieStorageDirectoryExtensionHandle);
240
241     if (!m_resolvedPaths.containerCachesDirectory.isEmpty())
242         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerCachesDirectory, SandboxExtension::Type::ReadWrite, parameters.containerCachesDirectoryExtensionHandle);
243
244     if (!m_resolvedPaths.containerTemporaryDirectory.isEmpty())
245         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerTemporaryDirectory, SandboxExtension::Type::ReadWrite, parameters.containerTemporaryDirectoryExtensionHandle);
246 #endif
247
248     parameters.fontWhitelist = m_fontWhitelist;
249
250     if (m_bundleParameters) {
251         auto keyedArchiver = secureArchiver();
252
253         @try {
254             [keyedArchiver encodeObject:m_bundleParameters.get() forKey:@"parameters"];
255             [keyedArchiver finishEncoding];
256         } @catch (NSException *exception) {
257             LOG_ERROR("Failed to encode bundle parameters: %@", exception);
258         }
259
260         auto data = keyedArchiver.get().encodedData;
261
262         parameters.bundleParameterData = API::Data::createWithoutCopying(WTFMove(data));
263     }
264     parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext());
265
266 #if ENABLE(MEDIA_STREAM)
267     // Allow microphone access if either preference is set because WebRTC requires microphone access.
268     bool mediaDevicesEnabled = m_defaultPageGroup->preferences().mediaDevicesEnabled();
269     bool webRTCEnabled = m_defaultPageGroup->preferences().peerConnectionEnabled();
270     if ([defaults objectForKey:@"ExperimentalPeerConnectionEnabled"])
271         webRTCEnabled = [defaults boolForKey:@"ExperimentalPeerConnectionEnabled"];
272
273     bool isSafari = false;
274 #if PLATFORM(IOS_FAMILY)
275     if (WebCore::IOSApplication::isMobileSafari())
276         isSafari = true;
277 #elif PLATFORM(MAC)
278     if (WebCore::MacApplication::isSafari())
279         isSafari = true;
280 #endif
281
282 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
283     parameters.webCoreLoggingChannels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
284     parameters.webKitLoggingChannels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
285 #endif
286
287     // FIXME: Remove this and related parameter when <rdar://problem/29448368> is fixed.
288     if (isSafari && !parameters.shouldCaptureAudioInUIProcess && mediaDevicesEnabled)
289         SandboxExtension::createHandleForGenericExtension("com.apple.webkit.microphone", parameters.audioCaptureExtensionHandle);
290 #endif
291
292 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
293     parameters.shouldLogUserInteraction = [defaults boolForKey:WebKitLogCookieInformationDefaultsKey];
294 #endif
295     
296 #if PLATFORM(MAC)
297     auto screenProperties = WebCore::collectScreenProperties();
298     parameters.screenProperties = WTFMove(screenProperties);
299     parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay);
300 #endif
301     
302 #if PLATFORM(IOS)
303     if (deviceHasAGXCompilerService()) {
304         SandboxExtension::Handle compilerServiceExtensionHandle;
305         SandboxExtension::createHandleForMachLookup("com.apple.AGXCompilerService", WTF::nullopt, compilerServiceExtensionHandle);
306         parameters.compilerServiceExtensionHandle = WTFMove(compilerServiceExtensionHandle);
307     }
308 #endif
309     
310 #if PLATFORM(COCOA)
311     if ([getNEFilterSourceClass() filterRequired]) {
312         SandboxExtension::Handle handle;
313         SandboxExtension::createHandleForMachLookup("com.apple.nehelper", WTF::nullopt, handle);
314         parameters.neHelperExtensionHandle = WTFMove(handle);
315         SandboxExtension::createHandleForMachLookup("com.apple.nesessionmanager.content-filter", WTF::nullopt, handle);
316         parameters.neSessionManagerExtensionHandle = WTFMove(handle);
317     }
318 #endif
319     
320 #if PLATFORM(IOS)
321     if ([getWebFilterEvaluatorClass() isManagedSession]) {
322         SandboxExtension::Handle handle;
323         SandboxExtension::createHandleForMachLookup("com.apple.uikit.viewservice.com.apple.WebContentFilter.remoteUI", WTF::nullopt, handle);
324         parameters.contentFilterExtensionHandle = WTFMove(handle);
325     }
326 #endif
327 }
328
329 void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationParameters& parameters)
330 {
331     parameters.uiProcessBundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
332     parameters.uiProcessSDKVersion = dyld_get_program_sdk_version();
333
334     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
335
336     {
337         bool isSafari = false;
338 #if PLATFORM(IOS_FAMILY)
339         isSafari = WebCore::IOSApplication::isMobileSafari();
340 #elif PLATFORM(MAC)
341         isSafari = WebCore::MacApplication::isSafari();
342 #endif
343         if (isSafari) {
344             parameters.defaultDataStoreParameters.networkSessionParameters.httpProxy = URL(URL(), [defaults stringForKey:(NSString *)WebKit2HTTPProxyDefaultsKey]);
345             parameters.defaultDataStoreParameters.networkSessionParameters.httpsProxy = URL(URL(), [defaults stringForKey:(NSString *)WebKit2HTTPSProxyDefaultsKey]);
346         }
347     }
348
349     parameters.enableLegacyTLS = false;
350     if (id value = [defaults objectForKey:@"WebKitEnableLegacyTLS"])
351         parameters.enableLegacyTLS = [value boolValue];
352     parameters.defaultDataStoreParameters.networkSessionParameters.enableLegacyTLS = parameters.enableLegacyTLS;
353
354     parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext());
355
356 #if PLATFORM(IOS_FAMILY)
357     parameters.ctDataConnectionServiceType = m_configuration->ctDataConnectionServiceType();
358 #endif
359
360     parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey];
361
362 #if PLATFORM(MAC)
363     ASSERT(parameters.uiProcessCookieStorageIdentifier.isEmpty());
364     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
365     parameters.uiProcessCookieStorageIdentifier = identifyingDataFromCookieStorage([[NSHTTPCookieStorage sharedHTTPCookieStorage] _cookieStorage]);
366 #endif
367
368     parameters.storageAccessAPIEnabled = storageAccessAPIEnabled();
369     parameters.suppressesConnectionTerminationOnSystemChange = m_configuration->suppressesConnectionTerminationOnSystemChange();
370
371     parameters.shouldEnableITPDatabase = [defaults boolForKey:[NSString stringWithFormat:@"InternalDebug%@", WebPreferencesKey::isITPDatabaseEnabledKey().createCFString().get()]];
372
373     parameters.enableAdClickAttributionDebugMode = [defaults boolForKey:[NSString stringWithFormat:@"Experimental%@", WebPreferencesKey::adClickAttributionDebugModeEnabledKey().createCFString().get()]];
374 }
375
376 void WebProcessPool::platformInvalidateContext()
377 {
378     unregisterNotificationObservers();
379 }
380
381 #if PLATFORM(IOS_FAMILY)
382 String WebProcessPool::parentBundleDirectory()
383 {
384     return [[[NSBundle mainBundle] bundlePath] stringByStandardizingPath];
385 }
386
387 String WebProcessPool::networkingCachesDirectory()
388 {
389     String path = pathForProcessContainer();
390     if (path.isEmpty())
391         path = NSHomeDirectory();
392
393     path = path + "/Library/Caches/com.apple.WebKit.Networking/";
394     path = stringByResolvingSymlinksInPath(path);
395
396     NSError *error = nil;
397     NSString* nsPath = path;
398     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
399         NSLog(@"could not create networking caches directory \"%@\", error %@", nsPath, error);
400         return String();
401     }
402
403     return path;
404 }
405
406 String WebProcessPool::webContentCachesDirectory()
407 {
408     String path = pathForProcessContainer();
409     if (path.isEmpty())
410         path = NSHomeDirectory();
411
412     path = path + "/Library/Caches/com.apple.WebKit.WebContent/";
413     path = stringByResolvingSymlinksInPath(path);
414
415     NSError *error = nil;
416     NSString* nsPath = path;
417     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
418         NSLog(@"could not create web content caches directory \"%@\", error %@", nsPath, error);
419         return String();
420     }
421
422     return path;
423 }
424
425 String WebProcessPool::containerTemporaryDirectory()
426 {
427     String path = NSTemporaryDirectory();
428     return stringByResolvingSymlinksInPath(path);
429 }
430 #endif
431
432 #if PLATFORM(IOS_FAMILY)
433 void WebProcessPool::setJavaScriptConfigurationFileEnabledFromDefaults()
434 {
435     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
436
437     setJavaScriptConfigurationFileEnabled([defaults boolForKey:@"WebKitJavaScriptCoreUseConfigFile"]);
438 }
439 #endif
440
441 bool WebProcessPool::omitPDFSupport()
442 {
443     // Since this is a "secret default" we don't bother registering it.
444     return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
445 }
446
447 bool WebProcessPool::processSuppressionEnabled() const
448 {
449     return !m_userObservablePageCounter.value() && !m_processSuppressionDisabledForPageCounter.value();
450 }
451
452 bool WebProcessPool::networkProcessHasEntitlementForTesting(const String& entitlement)
453 {
454     return WTF::hasEntitlement(ensureNetworkProcess().connection()->xpcConnection(), entitlement.utf8().data());
455 }
456
457 #if PLATFORM(IOS)
458 float WebProcessPool::displayBrightness()
459 {
460     return BKSDisplayBrightnessGetCurrent();
461 }
462     
463 void WebProcessPool::backlightLevelDidChangeCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
464 {
465     WebProcessPool* pool = reinterpret_cast<WebProcessPool*>(observer);
466     pool->sendToAllProcesses(Messages::WebProcess::BacklightLevelDidChange(BKSDisplayBrightnessGetCurrent()));
467 }
468 #endif
469
470 void WebProcessPool::registerNotificationObservers()
471 {
472 #if !PLATFORM(IOS_FAMILY)
473     // Listen for enhanced accessibility changes and propagate them to the WebProcess.
474     m_enhancedAccessibilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
475         setEnhancedAccessibility([[[note userInfo] objectForKey:@"AXEnhancedUserInterface"] boolValue]);
476     }];
477
478     m_automaticTextReplacementNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticTextReplacementNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
479         TextChecker::didChangeAutomaticTextReplacementEnabled();
480         textCheckerStateChanged();
481     }];
482     
483     m_automaticSpellingCorrectionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticSpellingCorrectionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
484         TextChecker::didChangeAutomaticSpellingCorrectionEnabled();
485         textCheckerStateChanged();
486     }];
487
488     m_automaticQuoteSubstitutionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticQuoteSubstitutionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
489         TextChecker::didChangeAutomaticQuoteSubstitutionEnabled();
490         textCheckerStateChanged();
491     }];
492
493     m_automaticDashSubstitutionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticDashSubstitutionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
494         TextChecker::didChangeAutomaticDashSubstitutionEnabled();
495         textCheckerStateChanged();
496     }];
497
498     m_accessibilityDisplayOptionsNotificationObserver = [[NSWorkspace.sharedWorkspace notificationCenter] addObserverForName:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
499         screenPropertiesStateChanged();
500     }];
501
502 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
503     m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
504         auto scrollbarStyle = [NSScroller preferredScrollerStyle];
505         sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(scrollbarStyle));
506     }];
507 #endif
508
509     m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
510         setApplicationIsActive(true);
511     }];
512
513     m_deactivationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidResignActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
514         setApplicationIsActive(false);
515     }];
516 #elif PLATFORM(IOS)
517     CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, backlightLevelDidChangeCallback, static_cast<CFStringRef>(UIBacklightLevelChangedNotification), nullptr, CFNotificationSuspensionBehaviorCoalesce);
518     m_accessibilityEnabledObserver = [[NSNotificationCenter defaultCenter] addObserverForName:(__bridge id)kAXSApplicationAccessibilityEnabledNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *) {
519         for (size_t i = 0; i < m_processes.size(); ++i)
520             m_processes[i]->unblockAccessibilityServerIfNeeded();
521     }];
522 #endif // !PLATFORM(IOS_FAMILY)
523 }
524
525 void WebProcessPool::unregisterNotificationObservers()
526 {
527 #if !PLATFORM(IOS_FAMILY)
528     [[NSNotificationCenter defaultCenter] removeObserver:m_enhancedAccessibilityObserver.get()];
529     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticTextReplacementNotificationObserver.get()];
530     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticSpellingCorrectionNotificationObserver.get()];
531     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticQuoteSubstitutionNotificationObserver.get()];
532     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticDashSubstitutionNotificationObserver.get()];
533     [[NSWorkspace.sharedWorkspace notificationCenter] removeObserver:m_accessibilityDisplayOptionsNotificationObserver.get()];
534 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
535     [[NSNotificationCenter defaultCenter] removeObserver:m_scrollerStyleNotificationObserver.get()];
536 #endif
537     [[NSNotificationCenter defaultCenter] removeObserver:m_activationObserver.get()];
538     [[NSNotificationCenter defaultCenter] removeObserver:m_deactivationObserver.get()];
539 #elif PLATFORM(IOS)
540     CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, static_cast<CFStringRef>(UIBacklightLevelChangedNotification) , nullptr);
541     [[NSNotificationCenter defaultCenter] removeObserver:m_accessibilityEnabledObserver.get()];
542 #endif // !PLATFORM(IOS_FAMILY)
543 }
544
545 static CFURLStorageSessionRef privateBrowsingSession()
546 {
547     static CFURLStorageSessionRef session;
548     static dispatch_once_t once;
549     dispatch_once(&once, ^{
550         NSString *identifier = [NSString stringWithFormat:@"%@.PrivateBrowsing", [[NSBundle mainBundle] bundleIdentifier]];
551         session = createPrivateStorageSession((__bridge CFStringRef)identifier);
552     });
553
554     return session;
555 }
556
557 bool WebProcessPool::isURLKnownHSTSHost(const String& urlString) const
558 {
559     RetainPtr<CFURLRef> url = URL(URL(), urlString).createCFURL();
560
561     return _CFNetworkIsKnownHSTSHostWithSession(url.get(), nullptr);
562 }
563
564 void WebProcessPool::resetHSTSHosts()
565 {
566     _CFNetworkResetHSTSHostsWithSession(nullptr);
567     _CFNetworkResetHSTSHostsWithSession(privateBrowsingSession());
568 }
569
570 void WebProcessPool::resetHSTSHostsAddedAfterDate(double startDateIntervalSince1970)
571 {
572     NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:startDateIntervalSince1970];
573     _CFNetworkResetHSTSHostsSinceDate(nullptr, (__bridge CFDateRef)startDate);
574     _CFNetworkResetHSTSHostsSinceDate(privateBrowsingSession(), (__bridge CFDateRef)startDate);
575 }
576
577 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
578 void WebProcessPool::startDisplayLink(IPC::Connection& connection, unsigned observerID, uint32_t displayID)
579 {
580     for (auto& displayLink : m_displayLinks) {
581         if (displayLink->displayID() == displayID) {
582             displayLink->addObserver(connection, observerID);
583             return;
584         }
585     }
586     auto displayLink = makeUnique<DisplayLink>(displayID);
587     displayLink->addObserver(connection, observerID);
588     m_displayLinks.append(WTFMove(displayLink));
589 }
590
591 void WebProcessPool::stopDisplayLink(IPC::Connection& connection, unsigned observerID, uint32_t displayID)
592 {
593     for (auto& displayLink : m_displayLinks) {
594         if (displayLink->displayID() == displayID) {
595             displayLink->removeObserver(connection, observerID);
596             return;
597         }
598     }
599 }
600
601 void WebProcessPool::stopDisplayLinks(IPC::Connection& connection)
602 {
603     for (auto& displayLink : m_displayLinks)
604         displayLink->removeObservers(connection);
605 }
606 #endif
607
608 // FIXME: Deprecated. Left here until a final decision is made.
609 void WebProcessPool::setCookieStoragePartitioningEnabled(bool enabled)
610 {
611     m_cookieStoragePartitioningEnabled = enabled;
612 }
613
614 void WebProcessPool::clearPermanentCredentialsForProtectionSpace(WebCore::ProtectionSpace&& protectionSpace)
615 {
616     auto sharedStorage = [NSURLCredentialStorage sharedCredentialStorage];
617     auto credentials = [sharedStorage credentialsForProtectionSpace:protectionSpace.nsSpace()];
618     for (NSString* user in credentials) {
619         auto credential = credentials[user];
620         if (credential.persistence == NSURLCredentialPersistencePermanent)
621             [sharedStorage removeCredential:credentials[user] forProtectionSpace:protectionSpace.nsSpace()];
622     }
623 }
624
625 int networkProcessLatencyQOS()
626 {
627     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitNetworkProcessLatencyQOS"];
628     return qos;
629 }
630
631 int networkProcessThroughputQOS()
632 {
633     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitNetworkProcessThroughputQOS"];
634     return qos;
635 }
636
637 int webProcessLatencyQOS()
638 {
639     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitWebProcessLatencyQOS"];
640     return qos;
641 }
642
643 int webProcessThroughputQOS()
644 {
645     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitWebProcessThroughputQOS"];
646     return qos;
647 }
648
649 #if PLATFORM(IOS_FAMILY)
650 void WebProcessPool::applicationIsAboutToSuspend()
651 {
652     RELEASE_LOG(ProcessSuspension, "WebProcessPool::applicationIsAboutToSuspend() Terminating non-critical processes");
653
654     m_backForwardCache->pruneToSize(1);
655     m_webProcessCache->clear();
656 }
657
658 void WebProcessPool::notifyProcessPoolsApplicationIsAboutToSuspend()
659 {
660     for (auto* processPool : allProcessPools())
661         processPool->applicationIsAboutToSuspend();
662 }
663 #endif
664
665 void WebProcessPool::initializeClassesForParameterCoding()
666 {
667     const auto& customClasses = m_configuration->customClassesForParameterCoder();
668     if (customClasses.isEmpty())
669         return;
670
671     auto standardClasses = [NSSet setWithObjects:[NSArray class], [NSData class], [NSDate class], [NSDictionary class], [NSNull class],
672         [NSNumber class], [NSSet class], [NSString class], [NSTimeZone class], [NSURL class], [NSUUID class], nil];
673     
674     auto mutableSet = adoptNS([standardClasses mutableCopy]);
675
676     for (const auto& customClass : customClasses) {
677         const auto* className = customClass.utf8().data();
678         Class objectClass = objc_lookUpClass(className);
679         if (!objectClass) {
680             WTFLogAlways("InjectedBundle::extendClassesForParameterCoder - Class %s is not a valid Objective C class.\n", className);
681             break;
682         }
683
684         [mutableSet.get() addObject:objectClass];
685     }
686
687     m_classesForParameterCoder = mutableSet;
688 }
689
690 NSSet *WebProcessPool::allowedClassesForParameterCoding() const
691 {
692     return m_classesForParameterCoder.get();
693 }
694
695 } // namespace WebKit