7f5928b647769e64f086e937eb28f5f428dacf6f
[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 "NetworkProximityManager.h"
34 #import "NetworkResourceLoader.h"
35 #import "NetworkSessionCocoa.h"
36 #import "SandboxExtension.h"
37 #import <WebCore/NetworkStorageSession.h>
38 #import <WebCore/PublicSuffix.h>
39 #import <WebCore/ResourceRequestCFNet.h>
40 #import <WebCore/RuntimeApplicationChecks.h>
41 #import <WebCore/SecurityOrigin.h>
42 #import <WebCore/SecurityOriginData.h>
43 #import <pal/spi/cf/CFNetworkSPI.h>
44 #import <wtf/BlockPtr.h>
45 #import <wtf/CallbackAggregator.h>
46 #import <wtf/ProcessPrivilege.h>
47 #import <wtf/RetainPtr.h>
48
49 namespace WebKit {
50
51 static void initializeNetworkSettings()
52 {
53     static const unsigned preferredConnectionCount = 6;
54
55     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPLoadWidth, preferredConnectionCount);
56
57     Boolean keyExistsAndHasValidFormat = false;
58     Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitEnableHTTPPipelining"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
59     if (keyExistsAndHasValidFormat)
60         WebCore::ResourceRequest::setHTTPPipeliningEnabled(prefValue);
61
62     if (WebCore::ResourceRequest::resourcePrioritiesEnabled()) {
63         const unsigned fastLaneConnectionCount = 1;
64
65         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPPriorityNumLevels, toPlatformRequestPriority(WebCore::ResourceLoadPriority::Highest));
66         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPMinimumFastLanePriority, toPlatformRequestPriority(WebCore::ResourceLoadPriority::Medium));
67         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPNumFastLanes, fastLaneConnectionCount);
68     }
69 }
70
71 void NetworkProcess::platformInitializeNetworkProcessCocoa(const NetworkProcessCreationParameters& parameters)
72 {
73     WebCore::setApplicationBundleIdentifier(parameters.uiProcessBundleIdentifier);
74     WebCore::setApplicationSDKVersion(parameters.uiProcessSDKVersion);
75
76 #if PLATFORM(IOS_FAMILY)
77     SandboxExtension::consumePermanently(parameters.cookieStorageDirectoryExtensionHandle);
78     SandboxExtension::consumePermanently(parameters.containerCachesDirectoryExtensionHandle);
79     SandboxExtension::consumePermanently(parameters.parentBundleDirectoryExtensionHandle);
80 #if ENABLE(INDEXED_DATABASE)
81     SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.indexedDatabaseTempBlobDirectoryExtensionHandle);
82 #endif
83 #endif
84     m_diskCacheDirectory = parameters.diskCacheDirectory;
85
86     _CFNetworkSetATSContext(parameters.networkATSContext.get());
87
88     m_uiProcessBundleIdentifier = parameters.uiProcessBundleIdentifier;
89
90 #if PLATFORM(IOS_FAMILY)
91     NetworkSessionCocoa::setCTDataConnectionServiceType(parameters.ctDataConnectionServiceType);
92 #endif
93
94     initializeNetworkSettings();
95
96 #if PLATFORM(MAC)
97     setSharedHTTPCookieStorage(parameters.uiProcessCookieStorageIdentifier);
98 #endif
99
100     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(parameters.storageAccessAPIEnabled);
101     m_suppressesConnectionTerminationOnSystemChange = parameters.suppressesConnectionTerminationOnSystemChange;
102
103     // FIXME: Most of what this function does for cache size gets immediately overridden by setCacheModel().
104     // - memory cache size passed from UI process is always ignored;
105     // - disk cache size passed from UI process is effectively a minimum size.
106     // 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.
107
108     ASSERT(!m_diskCacheIsDisabledForTesting);
109
110     if (m_diskCacheDirectory.isNull())
111         return;
112
113     SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
114     OptionSet<NetworkCache::Cache::Option> cacheOptions { NetworkCache::Cache::Option::RegisterNotify };
115     if (parameters.shouldEnableNetworkCacheEfficacyLogging)
116         cacheOptions.add(NetworkCache::Cache::Option::EfficacyLogging);
117     if (parameters.shouldUseTestingNetworkSession)
118         cacheOptions.add(NetworkCache::Cache::Option::TestingMode);
119 #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
120     if (parameters.shouldEnableNetworkCacheSpeculativeRevalidation)
121         cacheOptions.add(NetworkCache::Cache::Option::SpeculativeRevalidation);
122 #endif
123
124     m_cache = NetworkCache::Cache::open(*this, m_diskCacheDirectory, cacheOptions);
125     if (!m_cache)
126         RELEASE_LOG_ERROR(NetworkCache, "Failed to initialize the WebKit network disk cache");
127
128     // Disable NSURLCache.
129     auto urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
130     [NSURLCache setSharedURLCache:urlCache.get()];
131 }
132
133 RetainPtr<CFDataRef> NetworkProcess::sourceApplicationAuditData() const
134 {
135 #if USE(SOURCE_APPLICATION_AUDIT_DATA)
136     ASSERT(parentProcessConnection());
137     if (!parentProcessConnection())
138         return nullptr;
139     Optional<audit_token_t> auditToken = parentProcessConnection()->getAuditToken();
140     if (!auditToken)
141         return nullptr;
142     return adoptCF(CFDataCreate(nullptr, (const UInt8*)&*auditToken, sizeof(*auditToken)));
143 #else
144     return nullptr;
145 #endif
146 }
147
148 static void filterPreloadHSTSEntry(const void* key, const void* value, void* context)
149 {
150     HashSet<String>* hostnames = static_cast<HashSet<String>*>(context);
151     auto val = static_cast<CFDictionaryRef>(value);
152     if (CFDictionaryGetValue(val, _kCFNetworkHSTSPreloaded) != kCFBooleanTrue)
153         hostnames->add((CFStringRef)key);
154 }
155
156 void NetworkProcess::getHostNamesWithHSTSCache(WebCore::NetworkStorageSession& session, HashSet<String>& hostNames)
157 {
158     auto HSTSPolicies = adoptCF(_CFNetworkCopyHSTSPolicies(session.platformSession()));
159     CFDictionaryApplyFunction(HSTSPolicies.get(), filterPreloadHSTSEntry, &hostNames);
160 }
161
162 void NetworkProcess::deleteHSTSCacheForHostNames(WebCore::NetworkStorageSession& session, const Vector<String>& hostNames)
163 {
164     for (auto& hostName : hostNames) {
165         auto url = URL({ }, makeString("https://", hostName));
166         _CFNetworkResetHSTS(url.createCFURL().get(), session.platformSession());
167     }
168 }
169
170 void NetworkProcess::clearHSTSCache(WebCore::NetworkStorageSession& session, WallTime modifiedSince)
171 {
172     NSTimeInterval timeInterval = modifiedSince.secondsSinceEpoch().seconds();
173     NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
174
175     _CFNetworkResetHSTSHostsSinceDate(session.platformSession(), (__bridge CFDateRef)date);
176 }
177
178 void NetworkProcess::clearDiskCache(WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
179 {
180     if (!m_clearCacheDispatchGroup)
181         m_clearCacheDispatchGroup = dispatch_group_create();
182
183     auto* cache = this->cache();
184     if (!cache) {
185         completionHandler();
186         return;
187     }
188
189     auto group = m_clearCacheDispatchGroup;
190     dispatch_group_async(group, dispatch_get_main_queue(), makeBlockPtr([cache, modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
191         cache->clear(modifiedSince, WTFMove(completionHandler));
192     }).get());
193 }
194
195 #if PLATFORM(MAC)
196 void NetworkProcess::setSharedHTTPCookieStorage(const Vector<uint8_t>& identifier)
197 {
198     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
199     [NSHTTPCookieStorage _setSharedHTTPCookieStorage:adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorageFromIdentifyingData(identifier).get()]).get()];
200 }
201 #endif
202
203 void NetworkProcess::setStorageAccessAPIEnabled(bool enabled)
204 {
205     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(enabled);
206 }
207
208 void NetworkProcess::syncAllCookies()
209 {
210     platformSyncAllCookies([this] {
211         didSyncAllCookies();
212     });
213 }
214
215 #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER)
216 static void saveCookies(NSHTTPCookieStorage *cookieStorage, CompletionHandler<void()>&& completionHandler)
217 {
218     ASSERT(RunLoop::isMain());
219     [cookieStorage _saveCookies:makeBlockPtr([completionHandler = WTFMove(completionHandler)]() mutable {
220         // CFNetwork may call the completion block on a background queue, so we need to redispatch to the main thread.
221         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() mutable {
222             completionHandler();
223         });
224     }).get()];
225 }
226 #endif
227
228 void NetworkProcess::platformSyncAllCookies(CompletionHandler<void()>&& completionHander) {
229     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
230     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
231
232 #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER)
233     RefPtr<CallbackAggregator> callbackAggregator = CallbackAggregator::create(WTFMove(completionHander));
234     WebCore::NetworkStorageSession::forEach([&] (auto& networkStorageSession) {
235         saveCookies(networkStorageSession.nsCookieStorage(), [callbackAggregator] { });
236     });
237 #else
238     _CFHTTPCookieStorageFlushCookieStores();
239     completionHander();
240 #endif
241
242     ALLOW_DEPRECATED_DECLARATIONS_END
243 }
244
245 void NetworkProcess::platformPrepareToSuspend(CompletionHandler<void()>&& completionHandler)
246 {
247 #if ENABLE(PROXIMITY_NETWORKING)
248     proximityManager().suspend(SuspensionReason::ProcessSuspending, WTFMove(completionHandler));
249 #else
250     completionHandler();
251 #endif
252 }
253
254 void NetworkProcess::platformProcessDidResume()
255 {
256 #if ENABLE(PROXIMITY_NETWORKING)
257     proximityManager().resume(ResumptionReason::ProcessResuming);
258 #endif
259 }
260
261 void NetworkProcess::platformProcessDidTransitionToBackground()
262 {
263 #if ENABLE(PROXIMITY_NETWORKING)
264     proximityManager().suspend(SuspensionReason::ProcessBackgrounding, [] { });
265 #endif
266 }
267
268 void NetworkProcess::platformProcessDidTransitionToForeground()
269 {
270 #if ENABLE(PROXIMITY_NETWORKING)
271     proximityManager().resume(ResumptionReason::ProcessForegrounding);
272 #endif
273 }
274
275 } // namespace WebKit