-[WKWebsiteDataStore removeDataOfTypes:forDataRecords:completionHandler:] doesn't...
[WebKit-https.git] / Source / WebKit / NetworkProcess / cocoa / NetworkProcessCocoa.mm
1 /*
2  * Copyright (C) 2014-2018 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 "NetworkProcess.h"
28
29 #import "CookieStorageUtilsCF.h"
30 #import "Logging.h"
31 #import "NetworkCache.h"
32 #import "NetworkProcessCreationParameters.h"
33 #import "NetworkResourceLoader.h"
34 #import "NetworkSessionCocoa.h"
35 #import "SandboxExtension.h"
36 #import <WebCore/NetworkStorageSession.h>
37 #import <WebCore/PublicSuffix.h>
38 #import <WebCore/ResourceRequestCFNet.h>
39 #import <WebCore/RuntimeApplicationChecks.h>
40 #import <WebCore/SecurityOrigin.h>
41 #import <WebCore/SecurityOriginData.h>
42 #import <pal/spi/cf/CFNetworkSPI.h>
43 #import <wtf/BlockPtr.h>
44 #import <wtf/CallbackAggregator.h>
45 #import <wtf/ProcessPrivilege.h>
46 #import <wtf/RetainPtr.h>
47
48 namespace WebKit {
49
50 static void initializeNetworkSettings()
51 {
52     static const unsigned preferredConnectionCount = 6;
53
54     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPLoadWidth, preferredConnectionCount);
55
56     Boolean keyExistsAndHasValidFormat = false;
57     Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitEnableHTTPPipelining"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
58     if (keyExistsAndHasValidFormat)
59         WebCore::ResourceRequest::setHTTPPipeliningEnabled(prefValue);
60
61     if (WebCore::ResourceRequest::resourcePrioritiesEnabled()) {
62         const unsigned fastLaneConnectionCount = 1;
63
64         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPPriorityNumLevels, toPlatformRequestPriority(WebCore::ResourceLoadPriority::Highest));
65         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPMinimumFastLanePriority, toPlatformRequestPriority(WebCore::ResourceLoadPriority::Medium));
66         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPNumFastLanes, fastLaneConnectionCount);
67     }
68 }
69
70 void NetworkProcess::platformInitializeNetworkProcessCocoa(const NetworkProcessCreationParameters& parameters)
71 {
72     WebCore::setApplicationBundleIdentifier(parameters.uiProcessBundleIdentifier);
73     WebCore::setApplicationSDKVersion(parameters.uiProcessSDKVersion);
74
75 #if PLATFORM(IOS_FAMILY)
76     SandboxExtension::consumePermanently(parameters.cookieStorageDirectoryExtensionHandle);
77     SandboxExtension::consumePermanently(parameters.containerCachesDirectoryExtensionHandle);
78     SandboxExtension::consumePermanently(parameters.parentBundleDirectoryExtensionHandle);
79 #if ENABLE(INDEXED_DATABASE)
80     SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.indexedDatabaseTempBlobDirectoryExtensionHandle);
81 #endif
82 #endif
83     m_diskCacheDirectory = parameters.diskCacheDirectory;
84
85     _CFNetworkSetATSContext(parameters.networkATSContext.get());
86
87     m_uiProcessBundleIdentifier = parameters.uiProcessBundleIdentifier;
88
89 #if PLATFORM(IOS_FAMILY)
90     NetworkSessionCocoa::setCTDataConnectionServiceType(parameters.ctDataConnectionServiceType);
91 #endif
92
93     initializeNetworkSettings();
94
95 #if PLATFORM(MAC)
96     setSharedHTTPCookieStorage(parameters.uiProcessCookieStorageIdentifier);
97 #endif
98
99     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(parameters.storageAccessAPIEnabled);
100     m_suppressesConnectionTerminationOnSystemChange = parameters.suppressesConnectionTerminationOnSystemChange;
101
102     // FIXME: Most of what this function does for cache size gets immediately overridden by setCacheModel().
103     // - memory cache size passed from UI process is always ignored;
104     // - disk cache size passed from UI process is effectively a minimum size.
105     // One non-obvious constraint is that we need to use -setSharedURLCache: even in testing mode, to prevent creating a default one on disk later, when some other code touches the cache.
106
107     ASSERT(!m_diskCacheIsDisabledForTesting);
108
109     if (m_diskCacheDirectory.isNull())
110         return;
111
112     SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
113     OptionSet<NetworkCache::Cache::Option> cacheOptions { NetworkCache::Cache::Option::RegisterNotify };
114     if (parameters.shouldUseTestingNetworkSession)
115         cacheOptions.add(NetworkCache::Cache::Option::TestingMode);
116 #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
117     if (parameters.shouldEnableNetworkCacheSpeculativeRevalidation)
118         cacheOptions.add(NetworkCache::Cache::Option::SpeculativeRevalidation);
119 #endif
120
121     m_cache = NetworkCache::Cache::open(*this, m_diskCacheDirectory, cacheOptions);
122     if (!m_cache)
123         RELEASE_LOG_ERROR(NetworkCache, "Failed to initialize the WebKit network disk cache");
124
125     // Disable NSURLCache.
126     auto urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
127     [NSURLCache setSharedURLCache:urlCache.get()];
128 }
129
130 std::unique_ptr<WebCore::NetworkStorageSession> NetworkProcess::platformCreateDefaultStorageSession() const
131 {
132     return std::make_unique<WebCore::NetworkStorageSession>(PAL::SessionID::defaultSessionID());
133 }
134
135 RetainPtr<CFDataRef> NetworkProcess::sourceApplicationAuditData() const
136 {
137 #if USE(SOURCE_APPLICATION_AUDIT_DATA)
138     ASSERT(parentProcessConnection());
139     if (!parentProcessConnection())
140         return nullptr;
141     Optional<audit_token_t> auditToken = parentProcessConnection()->getAuditToken();
142     if (!auditToken)
143         return nullptr;
144     return adoptCF(CFDataCreate(nullptr, (const UInt8*)&*auditToken, sizeof(*auditToken)));
145 #else
146     return nullptr;
147 #endif
148 }
149
150 static void filterPreloadHSTSEntry(const void* key, const void* value, void* context)
151 {
152     RELEASE_ASSERT(context);
153
154     ASSERT(key);
155     ASSERT(value);
156     if (!key || !value)
157         return;
158
159     ASSERT(key != kCFNull);
160     if (key == kCFNull)
161         return;
162     
163     auto* hostnames = static_cast<HashSet<String>*>(context);
164     auto val = static_cast<CFDictionaryRef>(value);
165     if (CFDictionaryGetValue(val, _kCFNetworkHSTSPreloaded) != kCFBooleanTrue)
166         hostnames->add((CFStringRef)key);
167 }
168
169 void NetworkProcess::getHostNamesWithHSTSCache(WebCore::NetworkStorageSession& session, HashSet<String>& hostNames)
170 {
171     if (auto HSTSPolicies = adoptCF(_CFNetworkCopyHSTSPolicies(session.platformSession())))
172         CFDictionaryApplyFunction(HSTSPolicies.get(), filterPreloadHSTSEntry, &hostNames);
173 }
174
175 void NetworkProcess::deleteHSTSCacheForHostNames(WebCore::NetworkStorageSession& session, const Vector<String>& hostNames)
176 {
177     for (auto& hostName : hostNames) {
178         auto url = URL({ }, makeString("https://", hostName));
179         _CFNetworkResetHSTS(url.createCFURL().get(), session.platformSession());
180     }
181 }
182
183 void NetworkProcess::clearHSTSCache(WebCore::NetworkStorageSession& session, WallTime modifiedSince)
184 {
185     NSTimeInterval timeInterval = modifiedSince.secondsSinceEpoch().seconds();
186     NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
187
188     _CFNetworkResetHSTSHostsSinceDate(session.platformSession(), (__bridge CFDateRef)date);
189 }
190
191 void NetworkProcess::clearDiskCache(WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
192 {
193     if (!m_clearCacheDispatchGroup)
194         m_clearCacheDispatchGroup = dispatch_group_create();
195
196     auto* cache = this->cache();
197     if (!cache) {
198         completionHandler();
199         return;
200     }
201
202     auto group = m_clearCacheDispatchGroup;
203     dispatch_group_async(group, dispatch_get_main_queue(), makeBlockPtr([cache, modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
204         cache->clear(modifiedSince, WTFMove(completionHandler));
205     }).get());
206 }
207
208 void NetworkProcess::removeCredential(WebCore::Credential&& credential, WebCore::ProtectionSpace&& protectionSpace, CompletionHandler<void()>&& completionHandler)
209 {
210     NSURLProtectionSpace *nsSpace = protectionSpace.nsSpace();
211     NSURLCredential *nsCredential = [[[NSURLCredentialStorage sharedCredentialStorage] credentialsForProtectionSpace:nsSpace] objectForKey:credential.user()];
212     RELEASE_ASSERT(nsCredential);
213     RELEASE_ASSERT([nsCredential.user isEqualToString:credential.user()]);
214     RELEASE_ASSERT([nsCredential.password isEqualToString:credential.password()]);
215     [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:nsCredential forProtectionSpace:nsSpace];
216     RELEASE_ASSERT(![[[NSURLCredentialStorage sharedCredentialStorage] credentialsForProtectionSpace:nsSpace] objectForKey:credential.user()]);
217     completionHandler();
218 }
219
220 void NetworkProcess::originsWithPersistentCredentials(CompletionHandler<void(Vector<WebCore::SecurityOriginData>)>&& completionHandler)
221 {
222     completionHandler(WebCore::CredentialStorage::originsWithPersistentCredentials());
223 }
224
225 void NetworkProcess::removeCredentialsWithOrigins(const Vector<WebCore::SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
226 {
227     for (auto& origin : origins) {
228         auto allCredentials = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
229         for (NSURLProtectionSpace* space in allCredentials) {
230             if (origin.protocol == String(space.protocol)
231                 && origin.host == String(space.host)
232                 && origin.port
233                 && *origin.port == space.port) {
234                 auto credentials = allCredentials[space];
235                 for (NSString* user in credentials) {
236                     auto credential = credentials[user];
237                     [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:credential forProtectionSpace:space];
238                 }
239             }
240         }
241     }
242     completionHandler();
243 }
244
245 #if PLATFORM(MAC)
246 void NetworkProcess::setSharedHTTPCookieStorage(const Vector<uint8_t>& identifier)
247 {
248     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
249     [NSHTTPCookieStorage _setSharedHTTPCookieStorage:adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorageFromIdentifyingData(identifier).get()]).get()];
250 }
251 #endif
252
253 void NetworkProcess::setStorageAccessAPIEnabled(bool enabled)
254 {
255     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(enabled);
256 }
257
258 void NetworkProcess::syncAllCookies()
259 {
260     platformSyncAllCookies([this] {
261         didSyncAllCookies();
262     });
263 }
264
265 #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER)
266 static void saveCookies(NSHTTPCookieStorage *cookieStorage, CompletionHandler<void()>&& completionHandler)
267 {
268     ASSERT(RunLoop::isMain());
269     [cookieStorage _saveCookies:makeBlockPtr([completionHandler = WTFMove(completionHandler)]() mutable {
270         // CFNetwork may call the completion block on a background queue, so we need to redispatch to the main thread.
271         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() mutable {
272             completionHandler();
273         });
274     }).get()];
275 }
276 #endif
277
278 void NetworkProcess::platformSyncAllCookies(CompletionHandler<void()>&& completionHander) {
279     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
280     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
281
282 #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER)
283     RefPtr<CallbackAggregator> callbackAggregator = CallbackAggregator::create(WTFMove(completionHander));
284     forEachNetworkStorageSession([&] (auto& networkStorageSession) {
285         saveCookies(networkStorageSession.nsCookieStorage(), [callbackAggregator] { });
286     });
287 #else
288     _CFHTTPCookieStorageFlushCookieStores();
289     completionHander();
290 #endif
291
292     ALLOW_DEPRECATED_DECLARATIONS_END
293 }
294
295 void NetworkProcess::platformPrepareToSuspend(CompletionHandler<void()>&& completionHandler)
296 {
297     completionHandler();
298 }
299
300 void NetworkProcess::platformProcessDidResume()
301 {
302 }
303
304 void NetworkProcess::platformProcessDidTransitionToBackground()
305 {
306 }
307
308 void NetworkProcess::platformProcessDidTransitionToForeground()
309 {
310 }
311
312 } // namespace WebKit