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