4b3ffb8578f6a0034f5add133da8bf136881fcf8
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / cocoa / NetworkProcessCocoa.mm
1 /*
2  * Copyright (C) 2014, 2015 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 #if ENABLE(NETWORK_PROCESS)
30
31 #import "NetworkCache.h"
32 #import "NetworkProcessCreationParameters.h"
33 #import "NetworkResourceLoader.h"
34 #import "SandboxExtension.h"
35 #import <WebCore/CFNetworkSPI.h>
36 #import <mach/host_info.h>
37 #import <mach/mach.h>
38 #import <mach/mach_error.h>
39
40 namespace WebKit {
41
42 void NetworkProcess::platformLowMemoryHandler(bool)
43 {
44     CFURLConnectionInvalidateConnectionCache();
45     _CFURLCachePurgeMemoryCache(adoptCF(CFURLCacheCopySharedURLCache()).get());
46 }
47
48 void NetworkProcess::platformInitializeNetworkProcessCocoa(const NetworkProcessCreationParameters& parameters)
49 {
50 #if PLATFORM(IOS)
51     SandboxExtension::consumePermanently(parameters.cookieStorageDirectoryExtensionHandle);
52     SandboxExtension::consumePermanently(parameters.containerCachesDirectoryExtensionHandle);
53     SandboxExtension::consumePermanently(parameters.parentBundleDirectoryExtensionHandle);
54 #endif
55     m_diskCacheDirectory = parameters.diskCacheDirectory;
56
57 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
58     _CFNetworkSetATSContext(parameters.networkATSContext.get());
59 #endif
60
61     // FIXME: Most of what this function does for cache size gets immediately overridden by setCacheModel().
62     // - memory cache size passed from UI process is always ignored;
63     // - disk cache size passed from UI process is effectively a minimum size.
64     // 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.
65
66     ASSERT(!m_diskCacheIsDisabledForTesting || !parameters.nsURLCacheDiskCapacity);
67
68     if (!m_diskCacheDirectory.isNull()) {
69         SandboxExtension::consumePermanently(parameters.diskCacheDirectoryExtensionHandle);
70 #if ENABLE(NETWORK_CACHE)
71         if (parameters.shouldEnableNetworkCache && NetworkCache::singleton().initialize(m_diskCacheDirectory, parameters.shouldEnableNetworkCacheEfficacyLogging)) {
72             RetainPtr<NSURLCache> urlCache(adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]));
73             [NSURLCache setSharedURLCache:urlCache.get()];
74             return;
75         }
76 #endif
77 #if PLATFORM(IOS)
78         [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
79             _initWithMemoryCapacity:parameters.nsURLCacheMemoryCapacity
80             diskCapacity:parameters.nsURLCacheDiskCapacity
81             relativePath:parameters.uiProcessBundleIdentifier]).get()];
82 #else
83         [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
84             initWithMemoryCapacity:parameters.nsURLCacheMemoryCapacity
85             diskCapacity:parameters.nsURLCacheDiskCapacity
86             diskPath:parameters.diskCacheDirectory]).get()];
87 #endif
88     }
89
90     RetainPtr<CFURLCacheRef> cache = adoptCF(CFURLCacheCopySharedURLCache());
91     if (!cache)
92         return;
93
94     _CFURLCacheSetMinSizeForVMCachedResource(cache.get(), NetworkResourceLoader::fileBackedResourceMinimumSize());
95 }
96
97 static uint64_t memorySize()
98 {
99     static host_basic_info_data_t hostInfo;
100
101     static dispatch_once_t once;
102     dispatch_once(&once, ^() {
103         mach_port_t host = mach_host_self();
104         mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
105         kern_return_t r = host_info(host, HOST_BASIC_INFO, (host_info_t)&hostInfo, &count);
106         mach_port_deallocate(mach_task_self(), host);
107
108         if (r != KERN_SUCCESS)
109             LOG_ERROR("%s : host_info(%d) : %s.\n", __FUNCTION__, r, mach_error_string(r));
110     });
111
112     return hostInfo.max_mem;
113 }
114
115 static uint64_t volumeFreeSize(const String& path)
116 {
117     NSDictionary *fileSystemAttributesDictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:(NSString *)path error:NULL];
118     return [[fileSystemAttributesDictionary objectForKey:NSFileSystemFreeSize] unsignedLongLongValue];
119 }
120
121 void NetworkProcess::platformSetCacheModel(CacheModel cacheModel)
122 {
123     // As a fudge factor, use 1000 instead of 1024, in case the reported byte
124     // count doesn't align exactly to a megabyte boundary.
125     uint64_t memSize = memorySize() / 1024 / 1000;
126     uint64_t diskFreeSize = volumeFreeSize(m_diskCacheDirectory) / 1024 / 1000;
127
128     unsigned cacheTotalCapacity = 0;
129     unsigned cacheMinDeadCapacity = 0;
130     unsigned cacheMaxDeadCapacity = 0;
131     auto deadDecodedDataDeletionInterval = std::chrono::seconds { 0 };
132     unsigned pageCacheCapacity = 0;
133     unsigned long urlCacheMemoryCapacity = 0;
134     unsigned long urlCacheDiskCapacity = 0;
135
136     calculateCacheSizes(cacheModel, memSize, diskFreeSize,
137         cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval,
138         pageCacheCapacity, urlCacheMemoryCapacity, urlCacheDiskCapacity);
139
140     if (m_diskCacheSizeOverride >= 0)
141         urlCacheDiskCapacity = m_diskCacheSizeOverride;
142
143 #if ENABLE(NETWORK_CACHE)
144     auto& networkCache = NetworkCache::singleton();
145     if (networkCache.isEnabled()) {
146         networkCache.setCapacity(urlCacheDiskCapacity);
147         return;
148     }
149 #endif
150     NSURLCache *nsurlCache = [NSURLCache sharedURLCache];
151     [nsurlCache setMemoryCapacity:urlCacheMemoryCapacity];
152     if (!m_diskCacheIsDisabledForTesting)
153         [nsurlCache setDiskCapacity:std::max<unsigned long>(urlCacheDiskCapacity, [nsurlCache diskCapacity])]; // Don't shrink a big disk cache, since that would cause churn.
154 }
155
156 void NetworkProcess::clearDiskCache(std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler)
157 {
158 #if ENABLE(NETWORK_CACHE)
159     NetworkCache::singleton().clear();
160 #endif
161
162     if (!m_clearCacheDispatchGroup)
163         m_clearCacheDispatchGroup = dispatch_group_create();
164
165     dispatch_group_async(m_clearCacheDispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [modifiedSince, completionHandler] {
166         NSURLCache *cache = [NSURLCache sharedURLCache];
167
168 #if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
169         NSTimeInterval timeInterval = std::chrono::duration_cast<std::chrono::duration<double>>(modifiedSince.time_since_epoch()).count();
170         NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
171         [cache removeCachedResponsesSinceDate:date];
172 #else
173         [cache removeAllCachedResponses];
174 #endif
175         dispatch_async(dispatch_get_main_queue(), [completionHandler] {
176             completionHandler();
177         });
178     });
179 }
180
181 }
182
183 #endif