Move NetworkCache ownership from NetworkProcess to NetworkSession
[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 HAVE(HSTS_STORAGE_PATH)
76     if (!parameters.hstsStorageDirectory.isNull()) {
77         SandboxExtension::consumePermanently(parameters.hstsStorageDirectoryExtensionHandle);
78         _CFNetworkSetHSTSStoragePath(parameters.hstsStorageDirectory.createCFString().get());
79     }
80 #endif
81
82 #if PLATFORM(IOS_FAMILY)
83     SandboxExtension::consumePermanently(parameters.cookieStorageDirectoryExtensionHandle);
84     SandboxExtension::consumePermanently(parameters.containerCachesDirectoryExtensionHandle);
85     SandboxExtension::consumePermanently(parameters.parentBundleDirectoryExtensionHandle);
86 #if ENABLE(INDEXED_DATABASE)
87     SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.indexedDatabaseTempBlobDirectoryExtensionHandle);
88 #endif
89 #endif
90     m_diskCacheDirectory = parameters.diskCacheDirectory;
91
92     _CFNetworkSetATSContext(parameters.networkATSContext.get());
93
94     m_uiProcessBundleIdentifier = parameters.uiProcessBundleIdentifier;
95
96 #if PLATFORM(IOS_FAMILY)
97     NetworkSessionCocoa::setCTDataConnectionServiceType(parameters.ctDataConnectionServiceType);
98 #endif
99
100     initializeNetworkSettings();
101
102 #if PLATFORM(MAC)
103     setSharedHTTPCookieStorage(parameters.uiProcessCookieStorageIdentifier);
104 #endif
105
106     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(parameters.storageAccessAPIEnabled);
107     m_suppressesConnectionTerminationOnSystemChange = parameters.suppressesConnectionTerminationOnSystemChange;
108
109     // FIXME: Most of what this function does for cache size gets immediately overridden by setCacheModel().
110     // - memory cache size passed from UI process is always ignored;
111     // - disk cache size passed from UI process is effectively a minimum size.
112     // 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.
113
114     ASSERT(!m_diskCacheIsDisabledForTesting);
115
116     if (m_diskCacheDirectory.isNull())
117         return;
118
119     SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
120     m_cacheOptions = { NetworkCache::CacheOption::RegisterNotify };
121     if (parameters.shouldUseTestingNetworkSession)
122         m_cacheOptions.add(NetworkCache::CacheOption::TestingMode);
123 #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
124     if (parameters.shouldEnableNetworkCacheSpeculativeRevalidation)
125         m_cacheOptions.add(NetworkCache::CacheOption::SpeculativeRevalidation);
126 #endif
127
128     // Disable NSURLCache.
129     auto urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
130     [NSURLCache setSharedURLCache:urlCache.get()];
131 }
132
133 std::unique_ptr<WebCore::NetworkStorageSession> NetworkProcess::platformCreateDefaultStorageSession() const
134 {
135     return std::make_unique<WebCore::NetworkStorageSession>(PAL::SessionID::defaultSessionID());
136 }
137
138 RetainPtr<CFDataRef> NetworkProcess::sourceApplicationAuditData() const
139 {
140 #if USE(SOURCE_APPLICATION_AUDIT_DATA)
141     ASSERT(parentProcessConnection());
142     if (!parentProcessConnection())
143         return nullptr;
144     Optional<audit_token_t> auditToken = parentProcessConnection()->getAuditToken();
145     if (!auditToken)
146         return nullptr;
147     return adoptCF(CFDataCreate(nullptr, (const UInt8*)&*auditToken, sizeof(*auditToken)));
148 #else
149     return nullptr;
150 #endif
151 }
152
153 static void filterPreloadHSTSEntry(const void* key, const void* value, void* context)
154 {
155     RELEASE_ASSERT(context);
156
157     ASSERT(key);
158     ASSERT(value);
159     if (!key || !value)
160         return;
161
162     ASSERT(key != kCFNull);
163     if (key == kCFNull)
164         return;
165     
166     auto* hostnames = static_cast<HashSet<String>*>(context);
167     auto val = static_cast<CFDictionaryRef>(value);
168     if (CFDictionaryGetValue(val, _kCFNetworkHSTSPreloaded) != kCFBooleanTrue)
169         hostnames->add((CFStringRef)key);
170 }
171
172 void NetworkProcess::getHostNamesWithHSTSCache(WebCore::NetworkStorageSession& session, HashSet<String>& hostNames)
173 {
174     if (auto HSTSPolicies = adoptCF(_CFNetworkCopyHSTSPolicies(session.platformSession())))
175         CFDictionaryApplyFunction(HSTSPolicies.get(), filterPreloadHSTSEntry, &hostNames);
176 }
177
178 void NetworkProcess::deleteHSTSCacheForHostNames(WebCore::NetworkStorageSession& session, const Vector<String>& hostNames)
179 {
180     for (auto& hostName : hostNames) {
181         auto url = URL({ }, makeString("https://", hostName));
182         _CFNetworkResetHSTS(url.createCFURL().get(), session.platformSession());
183     }
184 }
185
186 void NetworkProcess::clearHSTSCache(WebCore::NetworkStorageSession& session, WallTime modifiedSince)
187 {
188     NSTimeInterval timeInterval = modifiedSince.secondsSinceEpoch().seconds();
189     NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
190
191     _CFNetworkResetHSTSHostsSinceDate(session.platformSession(), (__bridge CFDateRef)date);
192 }
193
194 void NetworkProcess::clearDiskCache(WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
195 {
196     if (!m_clearCacheDispatchGroup)
197         m_clearCacheDispatchGroup = dispatch_group_create();
198
199     auto group = m_clearCacheDispatchGroup;
200     dispatch_group_async(group, dispatch_get_main_queue(), makeBlockPtr([this, protectedThis = makeRef(*this), modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
201         auto aggregator = CallbackAggregator::create(WTFMove(completionHandler));
202         for (auto& session : networkSessions().values()) {
203             if (auto* cache = session->cache())
204                 cache->clear(modifiedSince, [aggregator = aggregator.copyRef()] () { });
205         }
206     }).get());
207 }
208
209 #if PLATFORM(MAC)
210 void NetworkProcess::setSharedHTTPCookieStorage(const Vector<uint8_t>& identifier)
211 {
212     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
213     [NSHTTPCookieStorage _setSharedHTTPCookieStorage:adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorageFromIdentifyingData(identifier).get()]).get()];
214 }
215 #endif
216
217 void NetworkProcess::setStorageAccessAPIEnabled(bool enabled)
218 {
219     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(enabled);
220 }
221
222 void NetworkProcess::syncAllCookies()
223 {
224     platformSyncAllCookies([this] {
225         didSyncAllCookies();
226     });
227 }
228
229 #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER)
230 static void saveCookies(NSHTTPCookieStorage *cookieStorage, CompletionHandler<void()>&& completionHandler)
231 {
232     ASSERT(RunLoop::isMain());
233     [cookieStorage _saveCookies:makeBlockPtr([completionHandler = WTFMove(completionHandler)]() mutable {
234         // CFNetwork may call the completion block on a background queue, so we need to redispatch to the main thread.
235         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() mutable {
236             completionHandler();
237         });
238     }).get()];
239 }
240 #endif
241
242 void NetworkProcess::platformSyncAllCookies(CompletionHandler<void()>&& completionHander) {
243     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
244     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
245
246 #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER)
247     RefPtr<CallbackAggregator> callbackAggregator = CallbackAggregator::create(WTFMove(completionHander));
248     forEachNetworkStorageSession([&] (auto& networkStorageSession) {
249         saveCookies(networkStorageSession.nsCookieStorage(), [callbackAggregator] { });
250     });
251 #else
252     _CFHTTPCookieStorageFlushCookieStores();
253     completionHander();
254 #endif
255
256     ALLOW_DEPRECATED_DECLARATIONS_END
257 }
258
259 void NetworkProcess::platformPrepareToSuspend(CompletionHandler<void()>&& completionHandler)
260 {
261     completionHandler();
262 }
263
264 void NetworkProcess::platformProcessDidResume()
265 {
266 }
267
268 void NetworkProcess::platformProcessDidTransitionToBackground()
269 {
270 }
271
272 void NetworkProcess::platformProcessDidTransitionToForeground()
273 {
274 }
275
276 NetworkHTTPSUpgradeChecker& NetworkProcess::networkHTTPSUpgradeChecker()
277 {
278     if (!m_networkHTTPSUpgradeChecker)
279         m_networkHTTPSUpgradeChecker = std::make_unique<NetworkHTTPSUpgradeChecker>();
280     return *m_networkHTTPSUpgradeChecker;
281 }
282
283 } // namespace WebKit