Clean up more networking code
[WebKit-https.git] / Source / WebKit / NetworkProcess / cocoa / NetworkProcessCocoa.mm
1 /*
2  * Copyright (C) 2014-2017 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 "NetworkCache.h"
30 #import "NetworkProcessCreationParameters.h"
31 #import "NetworkResourceLoader.h"
32 #import "NetworkSessionCocoa.h"
33 #import "SandboxExtension.h"
34 #import "SessionTracker.h"
35 #import <WebCore/NetworkStorageSession.h>
36 #import <WebCore/PublicSuffix.h>
37 #import <WebCore/ResourceRequestCFNet.h>
38 #import <WebCore/RuntimeApplicationChecks.h>
39 #import <WebCore/SecurityOrigin.h>
40 #import <WebCore/SecurityOriginData.h>
41 #import <pal/spi/cf/CFNetworkSPI.h>
42 #import <wtf/BlockPtr.h>
43
44 namespace WebKit {
45
46 static void initializeNetworkSettings()
47 {
48     static const unsigned preferredConnectionCount = 6;
49
50     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPLoadWidth, preferredConnectionCount);
51
52     Boolean keyExistsAndHasValidFormat = false;
53     Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitEnableHTTPPipelining"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
54     if (keyExistsAndHasValidFormat)
55         WebCore::ResourceRequest::setHTTPPipeliningEnabled(prefValue);
56
57     if (WebCore::ResourceRequest::resourcePrioritiesEnabled()) {
58         const unsigned fastLaneConnectionCount = 1;
59
60         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPPriorityNumLevels, toPlatformRequestPriority(WebCore::ResourceLoadPriority::Highest));
61         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPMinimumFastLanePriority, toPlatformRequestPriority(WebCore::ResourceLoadPriority::Medium));
62         _CFNetworkHTTPConnectionCacheSetLimit(kHTTPNumFastLanes, fastLaneConnectionCount);
63     }
64 }
65
66 void NetworkProcess::platformInitializeNetworkProcessCocoa(const NetworkProcessCreationParameters& parameters)
67 {
68     WebCore::setApplicationBundleIdentifier(parameters.uiProcessBundleIdentifier);
69
70 #if PLATFORM(IOS)
71     SandboxExtension::consumePermanently(parameters.cookieStorageDirectoryExtensionHandle);
72     SandboxExtension::consumePermanently(parameters.containerCachesDirectoryExtensionHandle);
73     SandboxExtension::consumePermanently(parameters.parentBundleDirectoryExtensionHandle);
74 #endif
75     m_diskCacheDirectory = parameters.diskCacheDirectory;
76
77     _CFNetworkSetATSContext(parameters.networkATSContext.get());
78
79     SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
80
81     NetworkSessionCocoa::setSourceApplicationAuditTokenData(sourceApplicationAuditData());
82     NetworkSessionCocoa::setSourceApplicationBundleIdentifier(parameters.sourceApplicationBundleIdentifier);
83     NetworkSessionCocoa::setSourceApplicationSecondaryIdentifier(parameters.sourceApplicationSecondaryIdentifier);
84     NetworkSessionCocoa::setUsesNetworkCache(parameters.shouldEnableNetworkCache);
85 #if PLATFORM(IOS)
86     NetworkSessionCocoa::setCTDataConnectionServiceType(parameters.ctDataConnectionServiceType);
87 #endif
88
89     initializeNetworkSettings();
90
91 #if PLATFORM(MAC)
92     setSharedHTTPCookieStorage(parameters.uiProcessCookieStorageIdentifier);
93 #endif
94
95     WebCore::NetworkStorageSession::setCookieStoragePartitioningEnabled(parameters.cookieStoragePartitioningEnabled);
96     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(parameters.storageAccessAPIEnabled);
97
98     // FIXME: Most of what this function does for cache size gets immediately overridden by setCacheModel().
99     // - memory cache size passed from UI process is always ignored;
100     // - disk cache size passed from UI process is effectively a minimum size.
101     // 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.
102
103     ASSERT(!m_diskCacheIsDisabledForTesting || !parameters.nsURLCacheDiskCapacity);
104
105     if (!parameters.cacheStorageDirectory.isNull()) {
106         m_cacheStorageDirectory = parameters.cacheStorageDirectory;
107         m_cacheStoragePerOriginQuota = parameters.cacheStoragePerOriginQuota;
108         SandboxExtension::consumePermanently(parameters.cacheStorageDirectoryExtensionHandle);
109     }
110
111     if (!m_diskCacheDirectory.isNull()) {
112         SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
113         if (parameters.shouldEnableNetworkCache) {
114             OptionSet<NetworkCache::Cache::Option> cacheOptions { NetworkCache::Cache::Option::RegisterNotify };
115             if (parameters.shouldEnableNetworkCacheEfficacyLogging)
116                 cacheOptions |= NetworkCache::Cache::Option::EfficacyLogging;
117             if (parameters.shouldUseTestingNetworkSession)
118                 cacheOptions |= NetworkCache::Cache::Option::TestingMode;
119 #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
120             if (parameters.shouldEnableNetworkCacheSpeculativeRevalidation)
121                 cacheOptions |= NetworkCache::Cache::Option::SpeculativeRevalidation;
122 #endif
123             m_cache = NetworkCache::Cache::open(m_diskCacheDirectory, cacheOptions);
124
125             if (m_cache) {
126                 // Disable NSURLCache.
127                 auto urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
128                 [NSURLCache setSharedURLCache:urlCache.get()];
129                 return;
130             }
131         }
132         String nsURLCacheDirectory = m_diskCacheDirectory;
133 #if PLATFORM(IOS)
134         // NSURLCache path is relative to network process cache directory.
135         // This puts cache files under <container>/Library/Caches/com.apple.WebKit.Networking/
136         nsURLCacheDirectory = ".";
137 #endif
138         [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
139             initWithMemoryCapacity:parameters.nsURLCacheMemoryCapacity
140             diskCapacity:parameters.nsURLCacheDiskCapacity
141             diskPath:nsURLCacheDirectory]).get()];
142     }
143 }
144
145 void NetworkProcess::platformSetURLCacheSize(unsigned urlCacheMemoryCapacity, uint64_t urlCacheDiskCapacity)
146 {
147     NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
148     [nsurlCache setMemoryCapacity:urlCacheMemoryCapacity];
149     if (!m_diskCacheIsDisabledForTesting)
150         [nsurlCache setDiskCapacity:std::max<uint64_t>(urlCacheDiskCapacity, [nsurlCache diskCapacity])]; // Don't shrink a big disk cache, since that would cause churn.
151 }
152
153 RetainPtr<CFDataRef> NetworkProcess::sourceApplicationAuditData() const
154 {
155 #if PLATFORM(IOS)
156     audit_token_t auditToken;
157     ASSERT(parentProcessConnection());
158     if (!parentProcessConnection() || !parentProcessConnection()->getAuditToken(auditToken))
159         return nullptr;
160     return adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
161 #else
162     return nullptr;
163 #endif
164 }
165
166 void NetworkProcess::clearHSTSCache(WebCore::NetworkStorageSession& session, WallTime modifiedSince)
167 {
168     NSTimeInterval timeInterval = modifiedSince.secondsSinceEpoch().seconds();
169     NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
170
171     _CFNetworkResetHSTSHostsSinceDate(session.platformSession(), (__bridge CFDateRef)date);
172 }
173
174 static void clearNSURLCache(dispatch_group_t group, WallTime modifiedSince, Function<void ()>&& completionHandler)
175 {
176     dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), BlockPtr<void()>::fromCallable([modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
177         NSURLCache *cache = [NSURLCache sharedURLCache];
178
179         NSTimeInterval timeInterval = modifiedSince.secondsSinceEpoch().seconds();
180         NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
181         [cache removeCachedResponsesSinceDate:date];
182
183         dispatch_async(dispatch_get_main_queue(), BlockPtr<void()>::fromCallable([completionHandler = WTFMove(completionHandler)] {
184             completionHandler();
185         }).get());
186     }).get());
187 }
188
189 void NetworkProcess::clearDiskCache(WallTime modifiedSince, Function<void ()>&& completionHandler)
190 {
191     if (!m_clearCacheDispatchGroup)
192         m_clearCacheDispatchGroup = dispatch_group_create();
193
194     if (auto* cache = NetworkProcess::singleton().cache()) {
195         auto group = m_clearCacheDispatchGroup;
196         dispatch_group_async(group, dispatch_get_main_queue(), BlockPtr<void()>::fromCallable([cache, group, modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
197             cache->clear(modifiedSince, [group, modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
198                 // FIXME: Probably not necessary.
199                 clearNSURLCache(group, modifiedSince, WTFMove(completionHandler));
200             });
201         }).get());
202         return;
203     }
204     clearNSURLCache(m_clearCacheDispatchGroup, modifiedSince, WTFMove(completionHandler));
205 }
206
207 void NetworkProcess::setCookieStoragePartitioningEnabled(bool enabled)
208 {
209     WebCore::NetworkStorageSession::setCookieStoragePartitioningEnabled(enabled);
210 }
211
212 void NetworkProcess::setStorageAccessAPIEnabled(bool enabled)
213 {
214     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(enabled);
215 }
216
217 void NetworkProcess::syncAllCookies()
218 {
219 #pragma clang diagnostic push
220 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
221     _CFHTTPCookieStorageFlushCookieStores();
222 #pragma clang diagnostic pop
223 }
224
225 }