[WK2] Prune more resources from the MemoryCache before process suspension
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / NetworkProcess.cpp
1 /*
2  * Copyright (C) 2012-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 #include "config.h"
27 #include "NetworkProcess.h"
28
29 #if ENABLE(NETWORK_PROCESS)
30
31 #include "ArgumentCoders.h"
32 #include "Attachment.h"
33 #include "AuthenticationManager.h"
34 #include "ChildProcessMessages.h"
35 #include "CustomProtocolManager.h"
36 #include "Logging.h"
37 #include "NetworkConnectionToWebProcess.h"
38 #include "NetworkProcessCreationParameters.h"
39 #include "NetworkProcessPlatformStrategies.h"
40 #include "NetworkProcessProxyMessages.h"
41 #include "NetworkResourceLoader.h"
42 #include "RemoteNetworkingContext.h"
43 #include "SecurityOriginData.h"
44 #include "SessionTracker.h"
45 #include "StatisticsData.h"
46 #include "WebCookieManager.h"
47 #include "WebProcessPoolMessages.h"
48 #include "WebResourceCacheManager.h"
49 #include "WebsiteData.h"
50 #include <WebCore/Logging.h>
51 #include <WebCore/PlatformCookieJar.h>
52 #include <WebCore/ResourceRequest.h>
53 #include <WebCore/SecurityOriginHash.h>
54 #include <WebCore/SessionID.h>
55 #include <wtf/RunLoop.h>
56 #include <wtf/text/CString.h>
57
58 #if ENABLE(SEC_ITEM_SHIM)
59 #include "SecItemShim.h"
60 #endif
61
62 #if ENABLE(NETWORK_CACHE)
63 #include "NetworkCache.h"
64 #include "NetworkCacheCoders.h"
65 #endif
66
67 using namespace WebCore;
68
69 namespace WebKit {
70
71 NetworkProcess& NetworkProcess::singleton()
72 {
73     static NeverDestroyed<NetworkProcess> networkProcess;
74     return networkProcess;
75 }
76
77 NetworkProcess::NetworkProcess()
78     : m_hasSetCacheModel(false)
79     , m_cacheModel(CacheModelDocumentViewer)
80     , m_diskCacheIsDisabledForTesting(false)
81     , m_canHandleHTTPSServerTrustEvaluation(true)
82 #if PLATFORM(COCOA)
83     , m_clearCacheDispatchGroup(0)
84 #endif
85 #if PLATFORM(IOS)
86     , m_webSQLiteDatabaseTracker(*this)
87 #endif
88 {
89     NetworkProcessPlatformStrategies::initialize();
90
91     addSupplement<AuthenticationManager>();
92     addSupplement<WebCookieManager>();
93     addSupplement<CustomProtocolManager>();
94 }
95
96 NetworkProcess::~NetworkProcess()
97 {
98 }
99
100 AuthenticationManager& NetworkProcess::authenticationManager()
101 {
102     return *supplement<AuthenticationManager>();
103 }
104
105 DownloadManager& NetworkProcess::downloadManager()
106 {
107     static NeverDestroyed<DownloadManager> downloadManager(this);
108     return downloadManager;
109 }
110
111 void NetworkProcess::removeNetworkConnectionToWebProcess(NetworkConnectionToWebProcess* connection)
112 {
113     size_t vectorIndex = m_webProcessConnections.find(connection);
114     ASSERT(vectorIndex != notFound);
115
116     m_webProcessConnections.remove(vectorIndex);
117 }
118
119 bool NetworkProcess::shouldTerminate()
120 {
121     // Network process keeps session cookies and credentials, so it should never terminate (as long as UI process connection is alive).
122     return false;
123 }
124
125 void NetworkProcess::didReceiveMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
126 {
127     if (messageReceiverMap().dispatchMessage(connection, decoder))
128         return;
129
130     if (decoder.messageReceiverName() == Messages::ChildProcess::messageReceiverName()) {
131         ChildProcess::didReceiveMessage(connection, decoder);
132         return;
133     }
134
135     didReceiveNetworkProcessMessage(connection, decoder);
136 }
137
138 void NetworkProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
139 {
140     if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder))
141         return;
142
143     didReceiveSyncNetworkProcessMessage(connection, decoder, replyEncoder);
144 }
145
146 void NetworkProcess::didClose(IPC::Connection&)
147 {
148     // The UIProcess just exited.
149     RunLoop::current().stop();
150 }
151
152 void NetworkProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
153 {
154     RunLoop::current().stop();
155 }
156
157 void NetworkProcess::didCreateDownload()
158 {
159     disableTermination();
160 }
161
162 void NetworkProcess::didDestroyDownload()
163 {
164     enableTermination();
165 }
166
167 IPC::Connection* NetworkProcess::downloadProxyConnection()
168 {
169     return parentProcessConnection();
170 }
171
172 AuthenticationManager& NetworkProcess::downloadsAuthenticationManager()
173 {
174     return authenticationManager();
175 }
176
177 void NetworkProcess::lowMemoryHandler(Critical critical)
178 {
179     platformLowMemoryHandler(critical);
180     WTF::releaseFastMallocFreeMemory();
181 }
182
183 void NetworkProcess::initializeNetworkProcess(const NetworkProcessCreationParameters& parameters)
184 {
185     platformInitializeNetworkProcess(parameters);
186
187     WTF::setCurrentThreadIsUserInitiated();
188
189     auto& memoryPressureHandler = MemoryPressureHandler::singleton();
190     memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous) {
191         lowMemoryHandler(critical);
192     });
193     memoryPressureHandler.install();
194
195     m_diskCacheIsDisabledForTesting = parameters.shouldUseTestingNetworkSession;
196
197     m_diskCacheSizeOverride = parameters.diskCacheSizeOverride;
198     setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
199
200     setCanHandleHTTPSServerTrustEvaluation(parameters.canHandleHTTPSServerTrustEvaluation);
201
202 #if PLATFORM(MAC) || USE(CFNETWORK)
203     SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
204 #endif
205
206     // FIXME: instead of handling this here, a message should be sent later (scales to multiple sessions)
207     if (parameters.privateBrowsingEnabled)
208         RemoteNetworkingContext::ensurePrivateBrowsingSession(SessionID::legacyPrivateSessionID());
209
210     if (parameters.shouldUseTestingNetworkSession)
211         NetworkStorageSession::switchToNewTestingSession();
212
213     NetworkProcessSupplementMap::const_iterator it = m_supplements.begin();
214     NetworkProcessSupplementMap::const_iterator end = m_supplements.end();
215     for (; it != end; ++it)
216         it->value->initialize(parameters);
217 }
218
219 void NetworkProcess::initializeConnection(IPC::Connection* connection)
220 {
221     ChildProcess::initializeConnection(connection);
222
223 #if ENABLE(SEC_ITEM_SHIM)
224     SecItemShim::singleton().initializeConnection(connection);
225 #endif
226
227     NetworkProcessSupplementMap::const_iterator it = m_supplements.begin();
228     NetworkProcessSupplementMap::const_iterator end = m_supplements.end();
229     for (; it != end; ++it)
230         it->value->initializeConnection(connection);
231 }
232
233 void NetworkProcess::createNetworkConnectionToWebProcess()
234 {
235 #if OS(DARWIN)
236     // Create the listening port.
237     mach_port_t listeningPort;
238     mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort);
239
240     // Create a listening connection.
241     RefPtr<NetworkConnectionToWebProcess> connection = NetworkConnectionToWebProcess::create(IPC::Connection::Identifier(listeningPort));
242     m_webProcessConnections.append(connection.release());
243
244     IPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND);
245     parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientPort), 0);
246 #elif USE(UNIX_DOMAIN_SOCKETS)
247     IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
248
249     RefPtr<NetworkConnectionToWebProcess> connection = NetworkConnectionToWebProcess::create(socketPair.server);
250     m_webProcessConnections.append(connection.release());
251
252     IPC::Attachment clientSocket(socketPair.client);
253     parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientSocket), 0);
254 #else
255     notImplemented();
256 #endif
257 }
258
259 void NetworkProcess::ensurePrivateBrowsingSession(SessionID sessionID)
260 {
261     RemoteNetworkingContext::ensurePrivateBrowsingSession(sessionID);
262 }
263
264 void NetworkProcess::destroyPrivateBrowsingSession(SessionID sessionID)
265 {
266     SessionTracker::destroySession(sessionID);
267 }
268
269 #if USE(CFURLCACHE)
270 static Vector<Ref<SecurityOrigin>> cfURLCacheOrigins()
271 {
272     Vector<Ref<SecurityOrigin>> result;
273
274     WebResourceCacheManager::cfURLCacheHostNamesWithCallback([&result](RetainPtr<CFArrayRef> cfURLHosts) {
275         for (CFIndex i = 0, size = CFArrayGetCount(cfURLHosts.get()); i < size; ++i) {
276             CFStringRef host = static_cast<CFStringRef>(CFArrayGetValueAtIndex(cfURLHosts.get(), i));
277
278             result.append(SecurityOrigin::create("http", host, 0));
279         }
280     });
281
282     return result;
283 }
284 #endif
285
286 static void fetchDiskCacheEntries(SessionID sessionID, std::function<void (Vector<WebsiteData::Entry>)> completionHandler)
287 {
288 #if ENABLE(NETWORK_CACHE)
289     if (NetworkCache::singleton().isEnabled()) {
290         auto* origins = new HashSet<RefPtr<SecurityOrigin>>();
291
292         NetworkCache::singleton().traverse([completionHandler, origins](const NetworkCache::Entry *entry) {
293             if (!entry) {
294                 Vector<WebsiteData::Entry> entries;
295
296                 for (auto& origin : *origins)
297                     entries.append(WebsiteData::Entry { origin, WebsiteDataTypeDiskCache });
298
299                 delete origins;
300
301                 RunLoop::main().dispatch([completionHandler, entries] {
302                     completionHandler(entries);
303                 });
304
305                 return;
306             }
307
308             origins->add(SecurityOrigin::create(entry->response().url()));
309         });
310
311         return;
312     }
313 #endif
314
315     Vector<WebsiteData::Entry> entries;
316
317 #if USE(CFURLCACHE)
318     for (auto& origin : cfURLCacheOrigins())
319         entries.append(WebsiteData::Entry { WTF::move(origin), WebsiteDataTypeDiskCache });
320 #endif
321
322     RunLoop::main().dispatch([completionHandler, entries] {
323         completionHandler(entries);
324     });
325 }
326
327 void NetworkProcess::fetchWebsiteData(SessionID sessionID, uint64_t websiteDataTypes, uint64_t callbackID)
328 {
329     struct CallbackAggregator final : public RefCounted<CallbackAggregator> {
330         explicit CallbackAggregator(std::function<void (WebsiteData)> completionHandler)
331             : m_completionHandler(WTF::move(completionHandler))
332         {
333         }
334
335         ~CallbackAggregator()
336         {
337             ASSERT(RunLoop::isMain());
338
339             auto completionHandler = WTF::move(m_completionHandler);
340             auto websiteData = WTF::move(m_websiteData);
341
342             RunLoop::main().dispatch([completionHandler, websiteData] {
343                 completionHandler(websiteData);
344             });
345         }
346
347         std::function<void (WebsiteData)> m_completionHandler;
348         WebsiteData m_websiteData;
349     };
350
351     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator([this, callbackID](WebsiteData websiteData) {
352         parentProcessConnection()->send(Messages::NetworkProcessProxy::DidFetchWebsiteData(callbackID, websiteData), 0);
353     }));
354
355     if (websiteDataTypes & WebsiteDataTypeCookies) {
356         if (auto* networkStorageSession = SessionTracker::session(sessionID))
357             getHostnamesWithCookies(*networkStorageSession, callbackAggregator->m_websiteData.hostNamesWithCookies);
358     }
359
360     if (websiteDataTypes & WebsiteDataTypeDiskCache) {
361         fetchDiskCacheEntries(sessionID, [callbackAggregator](Vector<WebsiteData::Entry> entries) {
362             callbackAggregator->m_websiteData.entries.appendVector(entries);
363         });
364     }
365 }
366
367 void NetworkProcess::deleteWebsiteData(SessionID sessionID, uint64_t websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID)
368 {
369     if (websiteDataTypes & WebsiteDataTypeCookies) {
370         if (auto* networkStorageSession = SessionTracker::session(sessionID))
371             deleteAllCookiesModifiedSince(*networkStorageSession, modifiedSince);
372     }
373
374     auto completionHandler = [this, callbackID] {
375         parentProcessConnection()->send(Messages::NetworkProcessProxy::DidDeleteWebsiteData(callbackID), 0);
376     };
377
378     if ((websiteDataTypes & WebsiteDataTypeDiskCache) && !sessionID.isEphemeral()) {
379         clearDiskCache(modifiedSince, WTF::move(completionHandler));
380         return;
381     }
382
383     completionHandler();
384 }
385
386 static void clearDiskCacheEntries(const Vector<SecurityOriginData>& origins, std::function<void ()> completionHandler)
387 {
388 #if ENABLE(NETWORK_CACHE)
389     if (NetworkCache::singleton().isEnabled()) {
390         auto* originsToDelete = new HashSet<RefPtr<SecurityOrigin>>();
391
392         for (auto& origin : origins)
393             originsToDelete->add(origin.securityOrigin());
394
395         auto* cacheKeysToDelete = new Vector<NetworkCache::Key>;
396
397         NetworkCache::singleton().traverse([completionHandler, originsToDelete, cacheKeysToDelete](const NetworkCache::Entry *entry) {
398
399             if (entry) {
400                 if (originsToDelete->contains(SecurityOrigin::create(entry->response().url())))
401                     cacheKeysToDelete->append(entry->key());
402                 return;
403             }
404
405             delete originsToDelete;
406
407             for (auto& key : *cacheKeysToDelete)
408                 NetworkCache::singleton().remove(key);
409
410             delete cacheKeysToDelete;
411
412             RunLoop::main().dispatch(completionHandler);
413             return;
414         });
415
416         return;
417     }
418 #endif
419
420 #if USE(CFURLCACHE)
421     auto hostNames = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
422     for (auto& origin : origins)
423         CFArrayAppendValue(hostNames.get(), origin.host.createCFString().get());
424
425     CFShow(hostNames.get());
426     WebResourceCacheManager::clearCFURLCacheForHostNames(hostNames.get());
427 #endif
428
429     RunLoop::main().dispatch(WTF::move(completionHandler));
430 }
431
432 void NetworkProcess::deleteWebsiteDataForOrigins(SessionID sessionID, uint64_t websiteDataTypes, const Vector<SecurityOriginData>& origins, const Vector<String>& cookieHostNames, uint64_t callbackID)
433 {
434     if (websiteDataTypes & WebsiteDataTypeCookies) {
435         if (auto* networkStorageSession = SessionTracker::session(sessionID)) {
436             for (const auto& cookieHostName : cookieHostNames)
437                 deleteCookiesForHostname(*networkStorageSession, cookieHostName);
438         }
439     }
440
441     auto completionHandler = [this, callbackID] {
442         parentProcessConnection()->send(Messages::NetworkProcessProxy::DidDeleteWebsiteDataForOrigins(callbackID), 0);
443     };
444
445     if ((websiteDataTypes & WebsiteDataTypeDiskCache) && !sessionID.isEphemeral()) {
446         clearDiskCacheEntries(origins, WTF::move(completionHandler));
447         return;
448     }
449
450     completionHandler();
451 }
452
453 void NetworkProcess::downloadRequest(uint64_t downloadID, const ResourceRequest& request)
454 {
455     downloadManager().startDownload(downloadID, request);
456 }
457
458 void NetworkProcess::resumeDownload(uint64_t downloadID, const IPC::DataReference& resumeData, const String& path, const WebKit::SandboxExtension::Handle& sandboxExtensionHandle)
459 {
460     downloadManager().resumeDownload(downloadID, resumeData, path, sandboxExtensionHandle);
461 }
462
463 void NetworkProcess::cancelDownload(uint64_t downloadID)
464 {
465     downloadManager().cancelDownload(downloadID);
466 }
467
468 void NetworkProcess::setCacheModel(uint32_t cm)
469 {
470     CacheModel cacheModel = static_cast<CacheModel>(cm);
471
472     if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
473         m_hasSetCacheModel = true;
474         m_cacheModel = cacheModel;
475         platformSetCacheModel(cacheModel);
476     }
477 }
478
479 void NetworkProcess::setCanHandleHTTPSServerTrustEvaluation(bool value)
480 {
481     m_canHandleHTTPSServerTrustEvaluation = value;
482 }
483
484 void NetworkProcess::getNetworkProcessStatistics(uint64_t callbackID)
485 {
486     StatisticsData data;
487
488     auto& networkProcess = NetworkProcess::singleton();
489     data.statisticsNumbers.set("DownloadsActiveCount", networkProcess.downloadManager().activeDownloadCount());
490     data.statisticsNumbers.set("OutstandingAuthenticationChallengesCount", networkProcess.authenticationManager().outstandingAuthenticationChallengeCount());
491
492     parentProcessConnection()->send(Messages::WebProcessPool::DidGetStatistics(data, callbackID), 0);
493 }
494
495 void NetworkProcess::logDiagnosticMessage(uint64_t webPageID, const String& message, const String& description, WebCore::ShouldSample shouldSample)
496 {
497     parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessage(webPageID, message, description, shouldSample == ShouldSample::Yes), 0);
498 }
499
500 void NetworkProcess::logDiagnosticMessageWithResult(uint64_t webPageID, const String& message, const String& description, WebCore::DiagnosticLoggingResultType result, WebCore::ShouldSample shouldSample)
501 {
502     parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessageWithResult(webPageID, message, description, result, shouldSample == ShouldSample::Yes), 0);
503 }
504
505 void NetworkProcess::logDiagnosticMessageWithValue(uint64_t webPageID, const String& message, const String& description, const String& value, WebCore::ShouldSample shouldSample)
506 {
507     parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessageWithValue(webPageID, message, description, value, shouldSample == ShouldSample::Yes), 0);
508 }
509
510 void NetworkProcess::terminate()
511 {
512     platformTerminate();
513     ChildProcess::terminate();
514 }
515
516 void NetworkProcess::processWillSuspendImminently(bool& handled)
517 {
518     lowMemoryHandler(Critical::Yes);
519     handled = true;
520 }
521
522 void NetworkProcess::prepareToSuspend()
523 {
524     lowMemoryHandler(Critical::Yes);
525     parentProcessConnection()->send(Messages::NetworkProcessProxy::ProcessReadyToSuspend(), 0);
526 }
527
528 void NetworkProcess::cancelPrepareToSuspend()
529 {
530     parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCancelProcessSuspension(), 0);
531 }
532
533 void NetworkProcess::processDidResume()
534 {
535 }
536
537 #if !PLATFORM(COCOA)
538 void NetworkProcess::initializeProcess(const ChildProcessInitializationParameters&)
539 {
540 }
541
542 void NetworkProcess::initializeProcessName(const ChildProcessInitializationParameters&)
543 {
544 }
545
546 void NetworkProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
547 {
548 }
549
550 void NetworkProcess::platformLowMemoryHandler(Critical)
551 {
552 }
553 #endif
554
555 } // namespace WebKit
556
557 #endif // ENABLE(NETWORK_PROCESS)