Storage Access API: UI process should update network process about granted access
[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 "RemoteNetworkingContext.h"
34 #import "SandboxExtension.h"
35 #import "SessionTracker.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
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::setUsesNetworkCache(parameters.shouldEnableNetworkCache);
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     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(parameters.storageAccessAPIEnabled);
100
101     // FIXME: Most of what this function does for cache size gets immediately overridden by setCacheModel().
102     // - memory cache size passed from UI process is always ignored;
103     // - disk cache size passed from UI process is effectively a minimum size.
104     // 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.
105
106     ASSERT(!m_diskCacheIsDisabledForTesting || !parameters.nsURLCacheDiskCapacity);
107
108     if (!parameters.cacheStorageDirectory.isNull()) {
109         m_cacheStorageDirectory = parameters.cacheStorageDirectory;
110         m_cacheStoragePerOriginQuota = parameters.cacheStoragePerOriginQuota;
111         SandboxExtension::consumePermanently(parameters.cacheStorageDirectoryExtensionHandle);
112     }
113
114     if (!m_diskCacheDirectory.isNull()) {
115         SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
116         if (parameters.shouldEnableNetworkCache) {
117             OptionSet<NetworkCache::Cache::Option> cacheOptions { NetworkCache::Cache::Option::RegisterNotify };
118             if (parameters.shouldEnableNetworkCacheEfficacyLogging)
119                 cacheOptions |= NetworkCache::Cache::Option::EfficacyLogging;
120             if (parameters.shouldUseTestingNetworkSession)
121                 cacheOptions |= NetworkCache::Cache::Option::TestingMode;
122 #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
123             if (parameters.shouldEnableNetworkCacheSpeculativeRevalidation)
124                 cacheOptions |= NetworkCache::Cache::Option::SpeculativeRevalidation;
125 #endif
126             m_cache = NetworkCache::Cache::open(m_diskCacheDirectory, cacheOptions);
127
128             if (m_cache) {
129                 // Disable NSURLCache.
130                 auto urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
131                 [NSURLCache setSharedURLCache:urlCache.get()];
132                 return;
133             }
134         }
135         String nsURLCacheDirectory = m_diskCacheDirectory;
136 #if PLATFORM(IOS)
137         // NSURLCache path is relative to network process cache directory.
138         // This puts cache files under <container>/Library/Caches/com.apple.WebKit.Networking/
139         nsURLCacheDirectory = ".";
140 #endif
141         [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
142             initWithMemoryCapacity:parameters.nsURLCacheMemoryCapacity
143             diskCapacity:parameters.nsURLCacheDiskCapacity
144             diskPath:nsURLCacheDirectory]).get()];
145     }
146 }
147
148 void NetworkProcess::platformSetURLCacheSize(unsigned urlCacheMemoryCapacity, uint64_t urlCacheDiskCapacity)
149 {
150     NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
151     [nsurlCache setMemoryCapacity:urlCacheMemoryCapacity];
152     if (!m_diskCacheIsDisabledForTesting)
153         [nsurlCache setDiskCapacity:std::max<uint64_t>(urlCacheDiskCapacity, [nsurlCache diskCapacity])]; // Don't shrink a big disk cache, since that would cause churn.
154 }
155
156 RetainPtr<CFDataRef> NetworkProcess::sourceApplicationAuditData() const
157 {
158 #if PLATFORM(IOS)
159     audit_token_t auditToken;
160     ASSERT(parentProcessConnection());
161     if (!parentProcessConnection() || !parentProcessConnection()->getAuditToken(auditToken))
162         return nullptr;
163     return adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
164 #else
165     return nullptr;
166 #endif
167 }
168
169 void NetworkProcess::clearHSTSCache(WebCore::NetworkStorageSession& session, std::chrono::system_clock::time_point modifiedSince)
170 {
171     NSTimeInterval timeInterval = std::chrono::duration_cast<std::chrono::duration<double>>(modifiedSince.time_since_epoch()).count();
172     NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
173
174     _CFNetworkResetHSTSHostsSinceDate(session.platformSession(), (__bridge CFDateRef)date);
175 }
176
177 static void clearNSURLCache(dispatch_group_t group, std::chrono::system_clock::time_point modifiedSince, Function<void ()>&& completionHandler)
178 {
179     dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), BlockPtr<void()>::fromCallable([modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
180         NSURLCache *cache = [NSURLCache sharedURLCache];
181
182         NSTimeInterval timeInterval = std::chrono::duration_cast<std::chrono::duration<double>>(modifiedSince.time_since_epoch()).count();
183         NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
184         [cache removeCachedResponsesSinceDate:date];
185
186         dispatch_async(dispatch_get_main_queue(), BlockPtr<void()>::fromCallable([completionHandler = WTFMove(completionHandler)] {
187             completionHandler();
188         }).get());
189     }).get());
190 }
191
192 void NetworkProcess::clearDiskCache(std::chrono::system_clock::time_point modifiedSince, Function<void ()>&& completionHandler)
193 {
194     if (!m_clearCacheDispatchGroup)
195         m_clearCacheDispatchGroup = dispatch_group_create();
196
197     if (auto* cache = NetworkProcess::singleton().cache()) {
198         auto group = m_clearCacheDispatchGroup;
199         dispatch_group_async(group, dispatch_get_main_queue(), BlockPtr<void()>::fromCallable([cache, group, modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
200             cache->clear(modifiedSince, [group, modifiedSince, completionHandler = WTFMove(completionHandler)] () mutable {
201                 // FIXME: Probably not necessary.
202                 clearNSURLCache(group, modifiedSince, WTFMove(completionHandler));
203             });
204         }).get());
205         return;
206     }
207     clearNSURLCache(m_clearCacheDispatchGroup, modifiedSince, WTFMove(completionHandler));
208 }
209
210 void NetworkProcess::setCookieStoragePartitioningEnabled(bool enabled)
211 {
212     WebCore::NetworkStorageSession::setCookieStoragePartitioningEnabled(enabled);
213 }
214
215 void NetworkProcess::setStorageAccessAPIEnabled(bool enabled)
216 {
217     WebCore::NetworkStorageSession::setStorageAccessAPIEnabled(enabled);
218 }
219
220 void NetworkProcess::syncAllCookies()
221 {
222 #pragma clang diagnostic push
223 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
224     _CFHTTPCookieStorageFlushCookieStores();
225 #pragma clang diagnostic pop
226 }
227
228 }