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