1/*
2 * Copyright (C) 2010, 2011, 2012, 2013 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 "WebContext.h"
28
29#include "APIArray.h"
30#include "APIDownloadClient.h"
31#include "APIHistoryClient.h"
32#include "DownloadProxy.h"
33#include "DownloadProxyMessages.h"
34#include "Logging.h"
35#include "MutableDictionary.h"
36#include "SandboxExtension.h"
37#include "StatisticsData.h"
38#include "TextChecker.h"
39#include "WKContextPrivate.h"
40#include "WebApplicationCacheManagerProxy.h"
41#include "WebContextMessageKinds.h"
42#include "WebContextMessages.h"
43#include "WebContextSupplement.h"
44#include "WebContextUserMessageCoders.h"
45#include "WebCookieManagerProxy.h"
46#include "WebCoreArgumentCoders.h"
47#include "WebDatabaseManagerProxy.h"
48#include "WebGeolocationManagerProxy.h"
49#include "WebIconDatabase.h"
50#include "WebKeyValueStorageManager.h"
51#include "WebKit2Initialize.h"
52#include "WebMediaCacheManagerProxy.h"
53#include "WebNotificationManagerProxy.h"
54#include "WebPluginSiteDataManager.h"
55#include "WebPageGroup.h"
56#include "WebPreferences.h"
57#include "WebMemorySampler.h"
58#include "WebProcessCreationParameters.h"
59#include "WebProcessMessages.h"
60#include "WebProcessProxy.h"
61#include "WebResourceCacheManagerProxy.h"
62#include <WebCore/ApplicationCacheStorage.h>
63#include <WebCore/Language.h>
64#include <WebCore/LinkHash.h>
65#include <WebCore/Logging.h>
66#include <WebCore/ResourceRequest.h>
67#include <WebCore/SessionID.h>
68#include <runtime/JSCInlines.h>
69#include <wtf/CurrentTime.h>
70#include <wtf/MainThread.h>
71#include <wtf/NeverDestroyed.h>
72#include <wtf/RunLoop.h>
73
74#if ENABLE(BATTERY_STATUS)
75#include "WebBatteryManagerProxy.h"
76#endif
77
78#if ENABLE(DATABASE_PROCESS)
79#include "DatabaseProcessCreationParameters.h"
80#include "DatabaseProcessMessages.h"
81#include "WebOriginDataManagerProxy.h"
82#endif
83
84#if ENABLE(NETWORK_PROCESS)
85#include "NetworkProcessCreationParameters.h"
86#include "NetworkProcessMessages.h"
87#include "NetworkProcessProxy.h"
88#endif
89
90#if ENABLE(SERVICE_CONTROLS)
91#include "ServicesController.h"
92#endif
93
94#if ENABLE(CUSTOM_PROTOCOLS)
95#include "CustomProtocolManagerMessages.h"
96#endif
97
98#if ENABLE(REMOTE_INSPECTOR)
99#include <JavaScriptCore/RemoteInspector.h>
100#endif
101
102#if USE(SOUP)
103#if ENABLE(CUSTOM_PROTOCOLS)
104#include "WebSoupCustomProtocolRequestManager.h"
105#else
106#include "WebSoupRequestManagerProxy.h"
107#endif
108#endif
109
110#ifndef NDEBUG
111#include <wtf/RefCountedLeakCounter.h>
112#endif
113
114using namespace WebCore;
115
116namespace WebKit {
117
118static const double sharedSecondaryProcessShutdownTimeout = 60;
119
120DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webContextCounter, ("WebContext"));
121
122void WebContext::applyPlatformSpecificConfigurationDefaults(WebContextConfiguration& configuration)
123{
124    // FIXME: This function should not be needed; all ports should make sure that the configuration has the right
125    // values, and then we should get rid of the platform specific defaults inside WebContext.
126
127    if (!configuration.localStorageDirectory)
128        configuration.localStorageDirectory = platformDefaultLocalStorageDirectory();
129
130    if (!configuration.webSQLDatabaseDirectory)
131        configuration.webSQLDatabaseDirectory = platformDefaultWebSQLDatabaseDirectory();
132
133    // *********
134    // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
135    // *********
136    if (!configuration.indexedDBDatabaseDirectory)
137        configuration.indexedDBDatabaseDirectory = platformDefaultIndexedDBDatabaseDirectory();
138}
139
140PassRefPtr<WebContext> WebContext::create(WebContextConfiguration configuration)
141{
142    InitializeWebKit2();
143    return adoptRef(new WebContext(WTF::move(configuration)));
144}
145
146static Vector<WebContext*>& contexts()
147{
148    static NeverDestroyed<Vector<WebContext*>> contexts;
149    return contexts;
150}
151
152const Vector<WebContext*>& WebContext::allContexts()
153{
154    return contexts();
155}
156
157WebContext::WebContext(WebContextConfiguration configuration)
158    : m_processModel(ProcessModelSharedSecondaryProcess)
159    , m_webProcessCountLimit(UINT_MAX)
160    , m_haveInitialEmptyProcess(false)
161    , m_processWithPageCache(0)
162    , m_defaultPageGroup(WebPageGroup::createNonNull())
163    , m_injectedBundlePath(configuration.injectedBundlePath)
164    , m_downloadClient(std::make_unique<API::DownloadClient>())
165    , m_historyClient(std::make_unique<API::HistoryClient>())
166    , m_visitedLinkProvider(VisitedLinkProvider::create())
167    , m_visitedLinksPopulated(false)
168    , m_plugInAutoStartProvider(this)
169    , m_alwaysUsesComplexTextCodePath(false)
170    , m_shouldUseFontSmoothing(true)
171    , m_cacheModel(CacheModelDocumentViewer)
172    , m_memorySamplerEnabled(false)
173    , m_memorySamplerInterval(1400.0)
174    , m_storageManager(StorageManager::create(configuration.localStorageDirectory))
175#if USE(SOUP)
176    , m_initialHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain)
177#endif
178    , m_webSQLDatabaseDirectory(WTF::move(configuration.webSQLDatabaseDirectory))
179    , m_indexedDBDatabaseDirectory(WTF::move(configuration.indexedDBDatabaseDirectory))
180    , m_shouldUseTestingNetworkSession(false)
181    , m_processTerminationEnabled(true)
182#if ENABLE(NETWORK_PROCESS)
183    , m_usesNetworkProcess(false)
184#endif
185#if USE(SOUP)
186    , m_ignoreTLSErrors(true)
187#endif
188    , m_memoryCacheDisabled(false)
189{
190    platformInitialize();
191
192    addMessageReceiver(Messages::WebContext::messageReceiverName(), *this);
193    addMessageReceiver(WebContextLegacyMessages::messageReceiverName(), *this);
194
195    // NOTE: These sub-objects must be initialized after m_messageReceiverMap..
196    m_iconDatabase = WebIconDatabase::create(this);
197#if ENABLE(NETSCAPE_PLUGIN_API)
198    m_pluginSiteDataManager = WebPluginSiteDataManager::create(this);
199#endif // ENABLE(NETSCAPE_PLUGIN_API)
200
201    addSupplement<WebApplicationCacheManagerProxy>();
202    addSupplement<WebCookieManagerProxy>();
203    addSupplement<WebGeolocationManagerProxy>();
204    addSupplement<WebKeyValueStorageManager>();
205    addSupplement<WebMediaCacheManagerProxy>();
206    addSupplement<WebNotificationManagerProxy>();
207    addSupplement<WebResourceCacheManagerProxy>();
208#if ENABLE(SQL_DATABASE)
209    addSupplement<WebDatabaseManagerProxy>();
210#endif
211#if USE(SOUP)
212#if ENABLE(CUSTOM_PROTOCOLS)
213    addSupplement<WebSoupCustomProtocolRequestManager>();
214#else
215    addSupplement<WebSoupRequestManagerProxy>();
216#endif
217#endif
218#if ENABLE(BATTERY_STATUS)
219    addSupplement<WebBatteryManagerProxy>();
220#endif
221#if ENABLE(DATABASE_PROCESS)
222    addSupplement<WebOriginDataManagerProxy>();
223#endif
224
225    contexts().append(this);
226
227    addLanguageChangeObserver(this, languageChanged);
228
229#if !LOG_DISABLED
230    WebCore::initializeLoggingChannelsIfNecessary();
231    WebKit::initializeLogChannelsIfNecessary();
232#endif // !LOG_DISABLED
233
234#if ENABLE(NETSCAPE_PLUGIN_API)
235    m_pluginInfoStore.setClient(this);
236#endif
237
238#ifndef NDEBUG
239    webContextCounter.increment();
240#endif
241}
242
243#if !PLATFORM(COCOA)
244void WebContext::platformInitialize()
245{
246}
247#endif
248
249WebContext::~WebContext()
250{
251    ASSERT(contexts().find(this) != notFound);
252    contexts().remove(contexts().find(this));
253
254    removeLanguageChangeObserver(this);
255
256    m_messageReceiverMap.invalidate();
257
258    WebContextSupplementMap::const_iterator it = m_supplements.begin();
259    WebContextSupplementMap::const_iterator end = m_supplements.end();
260    for (; it != end; ++it) {
261        it->value->contextDestroyed();
262        it->value->clearContext();
263    }
264
265    m_iconDatabase->invalidate();
266    m_iconDatabase->clearContext();
267    WebIconDatabase* rawIconDatabase = m_iconDatabase.release().leakRef();
268    rawIconDatabase->derefWhenAppropriate();
269
270#if ENABLE(NETSCAPE_PLUGIN_API)
271    m_pluginSiteDataManager->invalidate();
272    m_pluginSiteDataManager->clearContext();
273#endif
274
275    invalidateCallbackMap(m_dictionaryCallbacks, CallbackBase::Error::OwnerWasInvalidated);
276
277    platformInvalidateContext();
278
279#if ENABLE(NETSCAPE_PLUGIN_API)
280    m_pluginInfoStore.setClient(0);
281#endif
282
283#ifndef NDEBUG
284    webContextCounter.decrement();
285#endif
286}
287
288void WebContext::initializeClient(const WKContextClientBase* client)
289{
290    m_client.initialize(client);
291}
292
293void WebContext::initializeInjectedBundleClient(const WKContextInjectedBundleClientBase* client)
294{
295    m_injectedBundleClient.initialize(client);
296}
297
298void WebContext::initializeConnectionClient(const WKContextConnectionClientBase* client)
299{
300    m_connectionClient.initialize(client);
301}
302
303void WebContext::setHistoryClient(std::unique_ptr<API::HistoryClient> historyClient)
304{
305    if (!historyClient)
306        m_historyClient = std::make_unique<API::HistoryClient>();
307    else
308        m_historyClient = WTF::move(historyClient);
309}
310
311void WebContext::setDownloadClient(std::unique_ptr<API::DownloadClient> downloadClient)
312{
313    if (!downloadClient)
314        m_downloadClient = std::make_unique<API::DownloadClient>();
315    else
316        m_downloadClient = WTF::move(downloadClient);
317}
318
319void WebContext::setProcessModel(ProcessModel processModel)
320{
321    // Guard against API misuse.
322    if (!m_processes.isEmpty())
323        CRASH();
324    if (processModel != ProcessModelSharedSecondaryProcess && !m_messagesToInjectedBundlePostedToEmptyContext.isEmpty())
325        CRASH();
326
327    m_processModel = processModel;
328}
329
330void WebContext::setMaximumNumberOfProcesses(unsigned maximumNumberOfProcesses)
331{
332    // Guard against API misuse.
333    if (!m_processes.isEmpty())
334        CRASH();
335
336    if (maximumNumberOfProcesses == 0)
337        m_webProcessCountLimit = UINT_MAX;
338    else
339        m_webProcessCountLimit = maximumNumberOfProcesses;
340}
341
342IPC::Connection* WebContext::networkingProcessConnection()
343{
344    switch (m_processModel) {
345    case ProcessModelSharedSecondaryProcess:
346#if ENABLE(NETWORK_PROCESS)
347        if (m_usesNetworkProcess)
348            return m_networkProcess->connection();
349#endif
350        return m_processes[0]->connection();
351    case ProcessModelMultipleSecondaryProcesses:
352#if ENABLE(NETWORK_PROCESS)
353        ASSERT(m_usesNetworkProcess);
354        return m_networkProcess->connection();
355#else
356        break;
357#endif
358    }
359    ASSERT_NOT_REACHED();
360    return 0;
361}
362
363void WebContext::languageChanged(void* context)
364{
365    static_cast<WebContext*>(context)->languageChanged();
366}
367
368void WebContext::languageChanged()
369{
370    sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(userPreferredLanguages()));
371#if USE(SOUP) && ENABLE(NETWORK_PROCESS)
372    if (m_usesNetworkProcess && m_networkProcess)
373        m_networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(userPreferredLanguages()), 0);
374#endif
375}
376
377void WebContext::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
378{
379    sendToAllProcesses(Messages::WebProcess::FullKeyboardAccessModeChanged(fullKeyboardAccessEnabled));
380}
381
382void WebContext::textCheckerStateChanged()
383{
384    sendToAllProcesses(Messages::WebProcess::SetTextCheckerState(TextChecker::state()));
385}
386
387void WebContext::setUsesNetworkProcess(bool usesNetworkProcess)
388{
389#if ENABLE(NETWORK_PROCESS)
390    m_usesNetworkProcess = usesNetworkProcess;
391#else
392    UNUSED_PARAM(usesNetworkProcess);
393#endif
394}
395
396bool WebContext::usesNetworkProcess() const
397{
398#if ENABLE(NETWORK_PROCESS)
399    return m_usesNetworkProcess;
400#else
401    return false;
402#endif
403}
404
405#if ENABLE(NETWORK_PROCESS)
406void WebContext::ensureNetworkProcess()
407{
408    if (m_networkProcess)
409        return;
410
411    m_networkProcess = NetworkProcessProxy::create(*this);
412
413    NetworkProcessCreationParameters parameters;
414
415    parameters.privateBrowsingEnabled = WebPreferences::anyPagesAreUsingPrivateBrowsing();
416
417    parameters.cacheModel = m_cacheModel;
418
419    parameters.diskCacheDirectory = stringByResolvingSymlinksInPath(diskCacheDirectory());
420    if (!parameters.diskCacheDirectory.isEmpty())
421        SandboxExtension::createHandleForReadWriteDirectory(parameters.diskCacheDirectory, parameters.diskCacheDirectoryExtensionHandle);
422
423    parameters.cookieStorageDirectory = cookieStorageDirectory();
424
425#if PLATFORM(IOS)
426    if (!parameters.cookieStorageDirectory.isEmpty())
427        SandboxExtension::createHandleForReadWriteDirectory(parameters.cookieStorageDirectory, parameters.cookieStorageDirectoryExtensionHandle);
428
429    String hstsDatabasePath = networkingHSTSDatabasePath();
430    if (!hstsDatabasePath.isEmpty())
431        SandboxExtension::createHandle(hstsDatabasePath, SandboxExtension::ReadWrite, parameters.hstsDatabasePathExtensionHandle);
432
433    String parentBundleDirectory = parentBundleDirectory();
434    if (!parentBundleDirectory.isEmpty())
435        SandboxExtension::createHandle(parentBundleDirectory, SandboxExtension::ReadOnly, parameters.parentBundleDirectoryExtensionHandle);
436#endif
437
438    parameters.shouldUseTestingNetworkSession = m_shouldUseTestingNetworkSession;
439
440    // Add any platform specific parameters
441    platformInitializeNetworkProcess(parameters);
442
443    // Initialize the network process.
444    m_networkProcess->send(Messages::NetworkProcess::InitializeNetworkProcess(parameters), 0);
445
446#if PLATFORM(COCOA)
447    m_networkProcess->send(Messages::NetworkProcess::SetQOS(networkProcessLatencyQOS(), networkProcessThroughputQOS()), 0);
448#endif
449}
450
451void WebContext::networkProcessCrashed(NetworkProcessProxy* networkProcessProxy)
452{
453    ASSERT(m_networkProcess);
454    ASSERT(networkProcessProxy == m_networkProcess.get());
455
456    WebContextSupplementMap::const_iterator it = m_supplements.begin();
457    WebContextSupplementMap::const_iterator end = m_supplements.end();
458    for (; it != end; ++it)
459        it->value->processDidClose(networkProcessProxy);
460
461    m_networkProcess = nullptr;
462
463    m_client.networkProcessDidCrash(this);
464}
465
466void WebContext::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply)
467{
468    ASSERT(reply);
469
470    ensureNetworkProcess();
471    ASSERT(m_networkProcess);
472
473    m_networkProcess->getNetworkProcessConnection(reply);
474}
475#endif
476
477#if ENABLE(DATABASE_PROCESS)
478void WebContext::ensureDatabaseProcess()
479{
480    if (m_databaseProcess)
481        return;
482
483    m_databaseProcess = DatabaseProcessProxy::create(this);
484
485    ASSERT(!m_indexedDBDatabaseDirectory.isEmpty());
486
487    // *********
488    // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
489    // *********
490    DatabaseProcessCreationParameters parameters;
491    parameters.indexedDatabaseDirectory = m_indexedDBDatabaseDirectory;
492
493    SandboxExtension::createHandleForReadWriteDirectory(parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
494
495    m_databaseProcess->send(Messages::DatabaseProcess::InitializeDatabaseProcess(parameters), 0);
496}
497
498void WebContext::getDatabaseProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetDatabaseProcessConnection::DelayedReply> reply)
499{
500    ASSERT(reply);
501
502    ensureDatabaseProcess();
503
504    m_databaseProcess->getDatabaseProcessConnection(reply);
505}
506
507void WebContext::databaseProcessCrashed(DatabaseProcessProxy* databaseProcessProxy)
508{
509    ASSERT(m_databaseProcess);
510    ASSERT(databaseProcessProxy == m_databaseProcess.get());
511
512    for (auto& supplement : m_supplements)
513        supplement.value->processDidClose(databaseProcessProxy);
514
515    m_databaseProcess = nullptr;
516}
517#endif
518
519void WebContext::willStartUsingPrivateBrowsing()
520{
521    const Vector<WebContext*>& contexts = allContexts();
522    for (size_t i = 0, count = contexts.size(); i < count; ++i)
523        contexts[i]->setAnyPageGroupMightHavePrivateBrowsingEnabled(true);
524}
525
526void WebContext::willStopUsingPrivateBrowsing()
527{
528    const Vector<WebContext*>& contexts = allContexts();
529    for (size_t i = 0, count = contexts.size(); i < count; ++i)
530        contexts[i]->setAnyPageGroupMightHavePrivateBrowsingEnabled(false);
531}
532
533void WebContext::windowServerConnectionStateChanged()
534{
535    size_t processCount = m_processes.size();
536    for (size_t i = 0; i < processCount; ++i)
537        m_processes[i]->windowServerConnectionStateChanged();
538}
539
540void WebContext::setAnyPageGroupMightHavePrivateBrowsingEnabled(bool privateBrowsingEnabled)
541{
542    m_iconDatabase->setPrivateBrowsingEnabled(privateBrowsingEnabled);
543
544#if ENABLE(NETWORK_PROCESS)
545    if (usesNetworkProcess() && networkProcess()) {
546        if (privateBrowsingEnabled)
547            networkProcess()->send(Messages::NetworkProcess::EnsurePrivateBrowsingSession(SessionID::legacyPrivateSessionID()), 0);
548        else
549            networkProcess()->send(Messages::NetworkProcess::DestroyPrivateBrowsingSession(SessionID::legacyPrivateSessionID()), 0);
550    }
551#endif // ENABLED(NETWORK_PROCESS)
552
553    if (privateBrowsingEnabled)
554        sendToAllProcesses(Messages::WebProcess::EnsurePrivateBrowsingSession(SessionID::legacyPrivateSessionID()));
555    else
556        sendToAllProcesses(Messages::WebProcess::DestroyPrivateBrowsingSession(SessionID::legacyPrivateSessionID()));
557}
558
559void (*s_invalidMessageCallback)(WKStringRef messageName);
560
561void WebContext::setInvalidMessageCallback(void (*invalidMessageCallback)(WKStringRef messageName))
562{
563    s_invalidMessageCallback = invalidMessageCallback;
564}
565
566void WebContext::didReceiveInvalidMessage(const IPC::StringReference& messageReceiverName, const IPC::StringReference& messageName)
567{
568    if (!s_invalidMessageCallback)
569        return;
570
571    StringBuilder messageNameStringBuilder;
572    messageNameStringBuilder.append(messageReceiverName.data(), messageReceiverName.size());
573    messageNameStringBuilder.append(".");
574    messageNameStringBuilder.append(messageName.data(), messageName.size());
575
576    s_invalidMessageCallback(toAPI(API::String::create(messageNameStringBuilder.toString()).get()));
577}
578
579void WebContext::processDidCachePage(WebProcessProxy* process)
580{
581    if (m_processWithPageCache && m_processWithPageCache != process)
582        m_processWithPageCache->releasePageCache();
583    m_processWithPageCache = process;
584}
585
586WebProcessProxy& WebContext::ensureSharedWebProcess()
587{
588    ASSERT(m_processModel == ProcessModelSharedSecondaryProcess);
589    if (m_processes.isEmpty())
590        createNewWebProcess();
591    return *m_processes[0];
592}
593
594WebProcessProxy& WebContext::createNewWebProcess()
595{
596#if ENABLE(NETWORK_PROCESS)
597    if (m_usesNetworkProcess)
598        ensureNetworkProcess();
599#endif
600
601    RefPtr<WebProcessProxy> process = WebProcessProxy::create(*this);
602
603    WebProcessCreationParameters parameters;
604
605    parameters.injectedBundlePath = injectedBundlePath();
606    if (!parameters.injectedBundlePath.isEmpty())
607        SandboxExtension::createHandle(parameters.injectedBundlePath, SandboxExtension::ReadOnly, parameters.injectedBundlePathExtensionHandle);
608
609    parameters.applicationCacheDirectory = applicationCacheDirectory();
610    if (!parameters.applicationCacheDirectory.isEmpty())
611        SandboxExtension::createHandleForReadWriteDirectory(parameters.applicationCacheDirectory, parameters.applicationCacheDirectoryExtensionHandle);
612
613    parameters.webSQLDatabaseDirectory = m_webSQLDatabaseDirectory;
614    if (!parameters.webSQLDatabaseDirectory.isEmpty())
615        SandboxExtension::createHandleForReadWriteDirectory(parameters.webSQLDatabaseDirectory, parameters.webSQLDatabaseDirectoryExtensionHandle);
616
617    parameters.diskCacheDirectory = diskCacheDirectory();
618    if (!parameters.diskCacheDirectory.isEmpty())
619        SandboxExtension::createHandleForReadWriteDirectory(parameters.diskCacheDirectory, parameters.diskCacheDirectoryExtensionHandle);
620
621    parameters.cookieStorageDirectory = cookieStorageDirectory();
622
623#if PLATFORM(IOS)
624    if (!parameters.cookieStorageDirectory.isEmpty())
625        SandboxExtension::createHandleForReadWriteDirectory(parameters.cookieStorageDirectory, parameters.cookieStorageDirectoryExtensionHandle);
626
627    String openGLCacheDirectory = openGLCacheDirectory();
628    if (!openGLCacheDirectory.isEmpty())
629        SandboxExtension::createHandleForReadWriteDirectory(openGLCacheDirectory, parameters.openGLCacheDirectoryExtensionHandle);
630
631    String containerTemporaryDirectory = containerTemporaryDirectory();
632    if (!containerTemporaryDirectory.isEmpty())
633        SandboxExtension::createHandleForReadWriteDirectory(containerTemporaryDirectory, parameters.containerTemporaryDirectoryExtensionHandle);
634
635    String hstsDatabasePath = webContentHSTSDatabasePath();
636    if (!hstsDatabasePath.isEmpty())
637        SandboxExtension::createHandle(hstsDatabasePath, SandboxExtension::ReadWrite, parameters.hstsDatabasePathExtensionHandle);
638#endif
639
640    parameters.shouldUseTestingNetworkSession = m_shouldUseTestingNetworkSession;
641
642    parameters.cacheModel = m_cacheModel;
643    parameters.languages = userPreferredLanguages();
644
645    copyToVector(m_schemesToRegisterAsEmptyDocument, parameters.urlSchemesRegistererdAsEmptyDocument);
646    copyToVector(m_schemesToRegisterAsSecure, parameters.urlSchemesRegisteredAsSecure);
647    copyToVector(m_schemesToSetDomainRelaxationForbiddenFor, parameters.urlSchemesForWhichDomainRelaxationIsForbidden);
648    copyToVector(m_schemesToRegisterAsLocal, parameters.urlSchemesRegisteredAsLocal);
649    copyToVector(m_schemesToRegisterAsNoAccess, parameters.urlSchemesRegisteredAsNoAccess);
650    copyToVector(m_schemesToRegisterAsDisplayIsolated, parameters.urlSchemesRegisteredAsDisplayIsolated);
651    copyToVector(m_schemesToRegisterAsCORSEnabled, parameters.urlSchemesRegisteredAsCORSEnabled);
652#if ENABLE(CACHE_PARTITIONING)
653    copyToVector(m_schemesToRegisterAsCachePartitioned, parameters.urlSchemesRegisteredAsCachePartitioned);
654#endif
655
656    parameters.shouldAlwaysUseComplexTextCodePath = m_alwaysUsesComplexTextCodePath;
657    parameters.shouldUseFontSmoothing = m_shouldUseFontSmoothing;
658
659    parameters.iconDatabaseEnabled = !iconDatabasePath().isEmpty();
660
661    parameters.terminationTimeout = (m_processModel == ProcessModelSharedSecondaryProcess) ? sharedSecondaryProcessShutdownTimeout : 0;
662
663    parameters.textCheckerState = TextChecker::state();
664
665    parameters.fullKeyboardAccessEnabled = WebProcessProxy::fullKeyboardAccessEnabled();
666
667    parameters.defaultRequestTimeoutInterval = API::URLRequest::defaultTimeoutInterval();
668
669#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
670    // FIXME: There should be a generic way for supplements to add to the intialization parameters.
671    supplement<WebNotificationManagerProxy>()->populateCopyOfNotificationPermissions(parameters.notificationPermissions);
672#endif
673
674#if ENABLE(NETWORK_PROCESS)
675    parameters.usesNetworkProcess = m_usesNetworkProcess;
676#endif
677
678    parameters.plugInAutoStartOriginHashes = m_plugInAutoStartProvider.autoStartOriginHashesCopy();
679    copyToVector(m_plugInAutoStartProvider.autoStartOrigins(), parameters.plugInAutoStartOrigins);
680
681    parameters.memoryCacheDisabled = m_memoryCacheDisabled;
682
683#if ENABLE(SERVICE_CONTROLS)
684    parameters.hasImageServices = ServicesController::shared().hasImageServices();
685    parameters.hasSelectionServices = ServicesController::shared().hasSelectionServices();
686    parameters.hasRichContentServices = ServicesController::shared().hasRichContentServices();
687    ServicesController::shared().refreshExistingServices();
688#endif
689
690    // Add any platform specific parameters
691    platformInitializeWebProcess(parameters);
692
693    RefPtr<API::Object> injectedBundleInitializationUserData = m_injectedBundleClient.getInjectedBundleInitializationUserData(this);
694    if (!injectedBundleInitializationUserData)
695        injectedBundleInitializationUserData = m_injectedBundleInitializationUserData;
696    process->send(Messages::WebProcess::InitializeWebProcess(parameters, WebContextUserMessageEncoder(injectedBundleInitializationUserData.get(), *process)), 0);
697
698#if PLATFORM(COCOA)
699    process->send(Messages::WebProcess::SetQOS(webProcessLatencyQOS(), webProcessThroughputQOS()), 0);
700#endif
701#if PLATFORM(IOS)
702    cacheStorage().setDefaultOriginQuota(25ULL * 1024 * 1024);
703#endif
704
705    if (WebPreferences::anyPagesAreUsingPrivateBrowsing())
706        process->send(Messages::WebProcess::EnsurePrivateBrowsingSession(SessionID::legacyPrivateSessionID()), 0);
707
708    m_processes.append(process);
709
710    if (m_processModel == ProcessModelSharedSecondaryProcess) {
711        for (size_t i = 0; i != m_messagesToInjectedBundlePostedToEmptyContext.size(); ++i) {
712            std::pair<String, RefPtr<API::Object>>& message = m_messagesToInjectedBundlePostedToEmptyContext[i];
713
714            IPC::ArgumentEncoder messageData;
715
716            messageData.encode(message.first);
717            messageData.encode(WebContextUserMessageEncoder(message.second.get(), *process));
718            process->send(Messages::WebProcess::PostInjectedBundleMessage(IPC::DataReference(messageData.buffer(), messageData.bufferSize())), 0);
719        }
720        m_messagesToInjectedBundlePostedToEmptyContext.clear();
721    } else
722        ASSERT(m_messagesToInjectedBundlePostedToEmptyContext.isEmpty());
723
724#if ENABLE(REMOTE_INSPECTOR)
725    // Initialize remote inspector connection now that we have a sub-process that is hosting one of our web views.
726    Inspector::RemoteInspector::shared();
727#endif
728
729    return *process;
730}
731
732void WebContext::warmInitialProcess()
733{
734    if (m_haveInitialEmptyProcess) {
735        ASSERT(!m_processes.isEmpty());
736        return;
737    }
738
739    if (m_processes.size() >= m_webProcessCountLimit)
740        return;
741
742    createNewWebProcess();
743    m_haveInitialEmptyProcess = true;
744}
745
746void WebContext::enableProcessTermination()
747{
748    m_processTerminationEnabled = true;
749    Vector<RefPtr<WebProcessProxy>> processes = m_processes;
750    for (size_t i = 0; i < processes.size(); ++i) {
751        if (shouldTerminate(processes[i].get()))
752            processes[i]->terminate();
753    }
754}
755
756bool WebContext::shouldTerminate(WebProcessProxy* process)
757{
758    ASSERT(m_processes.contains(process));
759
760    if (!m_processTerminationEnabled)
761        return false;
762
763    for (const auto& supplement : m_supplements.values()) {
764        if (!supplement->shouldTerminate(process))
765            return false;
766    }
767
768    return true;
769}
770
771void WebContext::processWillOpenConnection(WebProcessProxy* process)
772{
773    m_storageManager->processWillOpenConnection(process);
774}
775
776void WebContext::processWillCloseConnection(WebProcessProxy* process)
777{
778    m_storageManager->processWillCloseConnection(process);
779}
780
781void WebContext::applicationWillTerminate()
782{
783    m_storageManager->applicationWillTerminate();
784}
785
786void WebContext::processDidFinishLaunching(WebProcessProxy* process)
787{
788    ASSERT(m_processes.contains(process));
789
790    if (!m_visitedLinksPopulated) {
791        populateVisitedLinks();
792        m_visitedLinksPopulated = true;
793    }
794
795    // Sometimes the memorySampler gets initialized after process initialization has happened but before the process has finished launching
796    // so check if it needs to be started here
797    if (m_memorySamplerEnabled) {
798        SandboxExtension::Handle sampleLogSandboxHandle;
799        double now = WTF::currentTime();
800        String sampleLogFilePath = String::format("WebProcess%llupid%d", static_cast<unsigned long long>(now), process->processIdentifier());
801        sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::ReadWrite, sampleLogSandboxHandle);
802
803        process->send(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, m_memorySamplerInterval), 0);
804    }
805
806    m_connectionClient.didCreateConnection(this, process->webConnection());
807}
808
809void WebContext::disconnectProcess(WebProcessProxy* process)
810{
811    ASSERT(m_processes.contains(process));
812
813    if (m_haveInitialEmptyProcess && process == m_processes.last())
814        m_haveInitialEmptyProcess = false;
815
816    // FIXME (Multi-WebProcess): <rdar://problem/12239765> Some of the invalidation calls below are still necessary in multi-process mode, but they should only affect data structures pertaining to the process being disconnected.
817    // Clearing everything causes assertion failures, so it's less trouble to skip that for now.
818    if (m_processModel != ProcessModelSharedSecondaryProcess) {
819        RefPtr<WebProcessProxy> protect(process);
820        if (m_processWithPageCache == process)
821            m_processWithPageCache = 0;
822
823        static_cast<WebContextSupplement*>(supplement<WebGeolocationManagerProxy>())->processDidClose(process);
824
825        m_processes.remove(m_processes.find(process));
826        return;
827    }
828
829    WebContextSupplementMap::const_iterator it = m_supplements.begin();
830    WebContextSupplementMap::const_iterator end = m_supplements.end();
831    for (; it != end; ++it)
832        it->value->processDidClose(process);
833
834    // The vector may have the last reference to process proxy, which in turn may have the last reference to the context.
835    // Since vector elements are destroyed in place, we would recurse into WebProcessProxy destructor
836    // if it were invoked from Vector::remove(). RefPtr delays destruction until it's safe.
837    RefPtr<WebProcessProxy> protect(process);
838    if (m_processWithPageCache == process)
839        m_processWithPageCache = 0;
840    m_processes.remove(m_processes.find(process));
841}
842
843WebProcessProxy& WebContext::createNewWebProcessRespectingProcessCountLimit()
844{
845    if (m_processes.size() < m_webProcessCountLimit)
846        return createNewWebProcess();
847
848    // Choose the process with fewest pages.
849    auto& process = *std::min_element(m_processes.begin(), m_processes.end(), [](const RefPtr<WebProcessProxy>& a, const RefPtr<WebProcessProxy>& b) {
850        return a->pageCount() < b->pageCount();
851    });
852
853    return *process;
854}
855
856PassRefPtr<WebPageProxy> WebContext::createWebPage(PageClient& pageClient, WebPageConfiguration configuration)
857{
858    if (!configuration.pageGroup)
859        configuration.pageGroup = &m_defaultPageGroup.get();
860    if (!configuration.preferences)
861        configuration.preferences = &configuration.pageGroup->preferences();
862    if (!configuration.visitedLinkProvider)
863        configuration.visitedLinkProvider = m_visitedLinkProvider.get();
864    if (!configuration.session)
865        configuration.session = configuration.preferences->privateBrowsingEnabled() ? &API::Session::legacyPrivateSession() : &API::Session::defaultSession();
866
867    RefPtr<WebProcessProxy> process;
868    if (m_processModel == ProcessModelSharedSecondaryProcess) {
869        process = &ensureSharedWebProcess();
870    } else {
871        if (m_haveInitialEmptyProcess) {
872            process = m_processes.last();
873            m_haveInitialEmptyProcess = false;
874        } else if (configuration.relatedPage) {
875            // Sharing processes, e.g. when creating the page via window.open().
876            process = &configuration.relatedPage->process();
877        } else
878            process = &createNewWebProcessRespectingProcessCountLimit();
879    }
880
881    return process->createWebPage(pageClient, WTF::move(configuration));
882}
883
884DownloadProxy* WebContext::download(WebPageProxy* initiatingPage, const ResourceRequest& request)
885{
886    DownloadProxy* downloadProxy = createDownloadProxy();
887    uint64_t initiatingPageID = initiatingPage ? initiatingPage->pageID() : 0;
888
889#if ENABLE(NETWORK_PROCESS)
890    if (usesNetworkProcess() && networkProcess()) {
891        // FIXME (NetworkProcess): Replicate whatever FrameLoader::setOriginalURLForDownloadRequest does with the request here.
892        networkProcess()->send(Messages::NetworkProcess::DownloadRequest(downloadProxy->downloadID(), request), 0);
893        return downloadProxy;
894    }
895#endif
896
897    m_processes[0]->send(Messages::WebProcess::DownloadRequest(downloadProxy->downloadID(), initiatingPageID, request), 0);
898    return downloadProxy;
899}
900
901void WebContext::postMessageToInjectedBundle(const String& messageName, API::Object* messageBody)
902{
903    if (m_processes.isEmpty()) {
904        if (m_processModel == ProcessModelSharedSecondaryProcess)
905            m_messagesToInjectedBundlePostedToEmptyContext.append(std::make_pair(messageName, messageBody));
906        return;
907    }
908
909    for (auto& process : m_processes) {
910        // FIXME: Return early if the message body contains any references to WKPageRefs/WKFrameRefs etc. since they're local to a process.
911        IPC::ArgumentEncoder messageData;
912        messageData.encode(messageName);
913        messageData.encode(WebContextUserMessageEncoder(messageBody, *process.get()));
914
915        process->send(Messages::WebProcess::PostInjectedBundleMessage(IPC::DataReference(messageData.buffer(), messageData.bufferSize())), 0);
916    }
917}
918
919// InjectedBundle client
920
921void WebContext::didReceiveMessageFromInjectedBundle(const String& messageName, API::Object* messageBody)
922{
923    m_injectedBundleClient.didReceiveMessageFromInjectedBundle(this, messageName, messageBody);
924}
925
926void WebContext::didReceiveSynchronousMessageFromInjectedBundle(const String& messageName, API::Object* messageBody, RefPtr<API::Object>& returnData)
927{
928    m_injectedBundleClient.didReceiveSynchronousMessageFromInjectedBundle(this, messageName, messageBody, returnData);
929}
930
931void WebContext::populateVisitedLinks()
932{
933    m_historyClient->populateVisitedLinks(this);
934}
935
936WebContext::Statistics& WebContext::statistics()
937{
938    static Statistics statistics = Statistics();
939
940    return statistics;
941}
942
943#if ENABLE(NETSCAPE_PLUGIN_API)
944void WebContext::setAdditionalPluginsDirectory(const String& directory)
945{
946    Vector<String> directories;
947    directories.append(directory);
948
949    m_pluginInfoStore.setAdditionalPluginsDirectories(directories);
950}
951#endif // ENABLE(NETSCAPE_PLUGIN_API)
952
953void WebContext::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
954{
955    m_alwaysUsesComplexTextCodePath = alwaysUseComplexText;
956    sendToAllProcesses(Messages::WebProcess::SetAlwaysUsesComplexTextCodePath(alwaysUseComplexText));
957}
958
959void WebContext::setShouldUseFontSmoothing(bool useFontSmoothing)
960{
961    m_shouldUseFontSmoothing = useFontSmoothing;
962    sendToAllProcesses(Messages::WebProcess::SetShouldUseFontSmoothing(useFontSmoothing));
963}
964
965void WebContext::registerURLSchemeAsEmptyDocument(const String& urlScheme)
966{
967    m_schemesToRegisterAsEmptyDocument.add(urlScheme);
968    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsEmptyDocument(urlScheme));
969}
970
971void WebContext::registerURLSchemeAsSecure(const String& urlScheme)
972{
973    m_schemesToRegisterAsSecure.add(urlScheme);
974    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsSecure(urlScheme));
975}
976
977void WebContext::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme)
978{
979    m_schemesToSetDomainRelaxationForbiddenFor.add(urlScheme);
980    sendToAllProcesses(Messages::WebProcess::SetDomainRelaxationForbiddenForURLScheme(urlScheme));
981}
982
983void WebContext::registerURLSchemeAsLocal(const String& urlScheme)
984{
985    m_schemesToRegisterAsLocal.add(urlScheme);
986    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsLocal(urlScheme));
987}
988
989void WebContext::registerURLSchemeAsNoAccess(const String& urlScheme)
990{
991    m_schemesToRegisterAsNoAccess.add(urlScheme);
992    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsNoAccess(urlScheme));
993}
994
995void WebContext::registerURLSchemeAsDisplayIsolated(const String& urlScheme)
996{
997    m_schemesToRegisterAsDisplayIsolated.add(urlScheme);
998    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsDisplayIsolated(urlScheme));
999}
1000
1001void WebContext::registerURLSchemeAsCORSEnabled(const String& urlScheme)
1002{
1003    m_schemesToRegisterAsCORSEnabled.add(urlScheme);
1004    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsCORSEnabled(urlScheme));
1005}
1006
1007#if ENABLE(CUSTOM_PROTOCOLS)
1008HashSet<String>& WebContext::globalURLSchemesWithCustomProtocolHandlers()
1009{
1010    static NeverDestroyed<HashSet<String>> set;
1011    return set;
1012}
1013
1014void WebContext::registerGlobalURLSchemeAsHavingCustomProtocolHandlers(const String& urlScheme)
1015{
1016    if (!urlScheme)
1017        return;
1018
1019    String schemeLower = urlScheme.lower();
1020    globalURLSchemesWithCustomProtocolHandlers().add(schemeLower);
1021    for (auto* context : allContexts())
1022        context->registerSchemeForCustomProtocol(schemeLower);
1023}
1024
1025void WebContext::unregisterGlobalURLSchemeAsHavingCustomProtocolHandlers(const String& urlScheme)
1026{
1027    if (!urlScheme)
1028        return;
1029
1030    String schemeLower = urlScheme.lower();
1031    globalURLSchemesWithCustomProtocolHandlers().remove(schemeLower);
1032    for (auto* context : allContexts())
1033        context->unregisterSchemeForCustomProtocol(schemeLower);
1034}
1035#endif
1036
1037#if ENABLE(CACHE_PARTITIONING)
1038void WebContext::registerURLSchemeAsCachePartitioned(const String& urlScheme)
1039{
1040    m_schemesToRegisterAsCachePartitioned.add(urlScheme);
1041    sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsCachePartitioned(urlScheme));
1042}
1043#endif
1044
1045void WebContext::setCacheModel(CacheModel cacheModel)
1046{
1047    m_cacheModel = cacheModel;
1048    sendToAllProcesses(Messages::WebProcess::SetCacheModel(static_cast<uint32_t>(m_cacheModel)));
1049
1050    // FIXME: Inform the Network Process if in use.
1051}
1052
1053void WebContext::setDefaultRequestTimeoutInterval(double timeoutInterval)
1054{
1055    sendToAllProcesses(Messages::WebProcess::SetDefaultRequestTimeoutInterval(timeoutInterval));
1056}
1057
1058DownloadProxy* WebContext::createDownloadProxy()
1059{
1060#if ENABLE(NETWORK_PROCESS)
1061    if (usesNetworkProcess()) {
1062        ensureNetworkProcess();
1063        ASSERT(m_networkProcess);
1064        return m_networkProcess->createDownloadProxy();
1065    }
1066#endif
1067
1068    return ensureSharedWebProcess().createDownloadProxy();
1069}
1070
1071void WebContext::addMessageReceiver(IPC::StringReference messageReceiverName, IPC::MessageReceiver& messageReceiver)
1072{
1073    m_messageReceiverMap.addMessageReceiver(messageReceiverName, messageReceiver);
1074}
1075
1076void WebContext::addMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID, IPC::MessageReceiver& messageReceiver)
1077{
1078    m_messageReceiverMap.addMessageReceiver(messageReceiverName, destinationID, messageReceiver);
1079}
1080
1081void WebContext::removeMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID)
1082{
1083    m_messageReceiverMap.removeMessageReceiver(messageReceiverName, destinationID);
1084}
1085
1086bool WebContext::dispatchMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
1087{
1088    return m_messageReceiverMap.dispatchMessage(connection, decoder);
1089}
1090
1091bool WebContext::dispatchSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
1092{
1093    return m_messageReceiverMap.dispatchSyncMessage(connection, decoder, replyEncoder);
1094}
1095
1096void WebContext::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
1097{
1098    if (decoder.messageReceiverName() == Messages::WebContext::messageReceiverName()) {
1099        didReceiveWebContextMessage(connection, decoder);
1100        return;
1101    }
1102
1103    if (decoder.messageReceiverName() == WebContextLegacyMessages::messageReceiverName()
1104        && decoder.messageName() == WebContextLegacyMessages::postMessageMessageName()) {
1105        String messageName;
1106        RefPtr<API::Object> messageBody;
1107        WebContextUserMessageDecoder messageBodyDecoder(messageBody, *WebProcessProxy::fromConnection(connection));
1108        if (!decoder.decode(messageName))
1109            return;
1110        if (!decoder.decode(messageBodyDecoder))
1111            return;
1112
1113        didReceiveMessageFromInjectedBundle(messageName, messageBody.get());
1114        return;
1115    }
1116
1117    ASSERT_NOT_REACHED();
1118}
1119
1120void WebContext::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
1121{
1122    if (decoder.messageReceiverName() == Messages::WebContext::messageReceiverName()) {
1123        didReceiveSyncWebContextMessage(connection, decoder, replyEncoder);
1124        return;
1125    }
1126
1127    if (decoder.messageReceiverName() == WebContextLegacyMessages::messageReceiverName()
1128        && decoder.messageName() == WebContextLegacyMessages::postSynchronousMessageMessageName()) {
1129        // FIXME: We should probably encode something in the case that the arguments do not decode correctly.
1130
1131        WebProcessProxy* process = WebProcessProxy::fromConnection(connection);
1132
1133        String messageName;
1134        RefPtr<API::Object> messageBody;
1135        WebContextUserMessageDecoder messageBodyDecoder(messageBody, *process);
1136        if (!decoder.decode(messageName))
1137            return;
1138        if (!decoder.decode(messageBodyDecoder))
1139            return;
1140
1141        RefPtr<API::Object> returnData;
1142        didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody.get(), returnData);
1143        replyEncoder->encode(WebContextUserMessageEncoder(returnData.get(), *process));
1144        return;
1145    }
1146
1147    ASSERT_NOT_REACHED();
1148}
1149
1150void WebContext::setEnhancedAccessibility(bool flag)
1151{
1152    sendToAllProcesses(Messages::WebProcess::SetEnhancedAccessibility(flag));
1153}
1154
1155void WebContext::startMemorySampler(const double interval)
1156{
1157    // For new WebProcesses we will also want to start the Memory Sampler
1158    m_memorySamplerEnabled = true;
1159    m_memorySamplerInterval = interval;
1160
1161    // For UIProcess
1162#if ENABLE(MEMORY_SAMPLER)
1163    WebMemorySampler::shared()->start(interval);
1164#endif
1165
1166    // For WebProcess
1167    SandboxExtension::Handle sampleLogSandboxHandle;
1168    double now = WTF::currentTime();
1169    String sampleLogFilePath = String::format("WebProcess%llu", static_cast<unsigned long long>(now));
1170    sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::ReadWrite, sampleLogSandboxHandle);
1171
1172    sendToAllProcesses(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, interval));
1173}
1174
1175void WebContext::stopMemorySampler()
1176{
1177    // For WebProcess
1178    m_memorySamplerEnabled = false;
1179
1180    // For UIProcess
1181#if ENABLE(MEMORY_SAMPLER)
1182    WebMemorySampler::shared()->stop();
1183#endif
1184
1185    sendToAllProcesses(Messages::WebProcess::StopMemorySampler());
1186}
1187
1188String WebContext::applicationCacheDirectory() const
1189{
1190    if (!m_overrideApplicationCacheDirectory.isEmpty())
1191        return m_overrideApplicationCacheDirectory;
1192
1193    return platformDefaultApplicationCacheDirectory();
1194}
1195
1196void WebContext::setIconDatabasePath(const String& path)
1197{
1198    m_overrideIconDatabasePath = path;
1199    m_iconDatabase->setDatabasePath(path);
1200}
1201
1202String WebContext::iconDatabasePath() const
1203{
1204    if (!m_overrideIconDatabasePath.isEmpty())
1205        return m_overrideIconDatabasePath;
1206
1207    return platformDefaultIconDatabasePath();
1208}
1209
1210String WebContext::diskCacheDirectory() const
1211{
1212    if (!m_overrideDiskCacheDirectory.isEmpty())
1213        return m_overrideDiskCacheDirectory;
1214
1215    return platformDefaultDiskCacheDirectory();
1216}
1217
1218String WebContext::cookieStorageDirectory() const
1219{
1220    if (!m_overrideCookieStorageDirectory.isEmpty())
1221        return m_overrideCookieStorageDirectory;
1222
1223    return platformDefaultCookieStorageDirectory();
1224}
1225
1226void WebContext::useTestingNetworkSession()
1227{
1228    ASSERT(m_processes.isEmpty());
1229#if ENABLE(NETWORK_PROCESS)
1230    ASSERT(!m_networkProcess);
1231
1232    if (m_networkProcess)
1233        return;
1234#endif
1235
1236    if (!m_processes.isEmpty())
1237        return;
1238
1239    m_shouldUseTestingNetworkSession = true;
1240}
1241
1242void WebContext::allowSpecificHTTPSCertificateForHost(const WebCertificateInfo* certificate, const String& host)
1243{
1244#if ENABLE(NETWORK_PROCESS)
1245    if (m_usesNetworkProcess && m_networkProcess) {
1246        m_networkProcess->send(Messages::NetworkProcess::AllowSpecificHTTPSCertificateForHost(certificate->certificateInfo(), host), 0);
1247        return;
1248    }
1249#endif
1250
1251#if USE(SOUP)
1252    m_processes[0]->send(Messages::WebProcess::AllowSpecificHTTPSCertificateForHost(certificate->certificateInfo(), host), 0);
1253    return;
1254#else
1255    UNUSED_PARAM(certificate);
1256    UNUSED_PARAM(host);
1257#endif
1258
1259#if !PLATFORM(IOS)
1260    ASSERT_NOT_REACHED();
1261#endif
1262}
1263
1264void WebContext::setHTTPPipeliningEnabled(bool enabled)
1265{
1266#if PLATFORM(COCOA)
1267    ResourceRequest::setHTTPPipeliningEnabled(enabled);
1268#else
1269    UNUSED_PARAM(enabled);
1270#endif
1271}
1272
1273bool WebContext::httpPipeliningEnabled() const
1274{
1275#if PLATFORM(COCOA)
1276    return ResourceRequest::httpPipeliningEnabled();
1277#else
1278    return false;
1279#endif
1280}
1281
1282void WebContext::getStatistics(uint32_t statisticsMask, std::function<void (ImmutableDictionary*, CallbackBase::Error)> callbackFunction)
1283{
1284    if (!statisticsMask) {
1285        callbackFunction(nullptr, CallbackBase::Error::Unknown);
1286        return;
1287    }
1288
1289    RefPtr<StatisticsRequest> request = StatisticsRequest::create(DictionaryCallback::create(WTF::move(callbackFunction)));
1290
1291    if (statisticsMask & StatisticsRequestTypeWebContent)
1292        requestWebContentStatistics(request.get());
1293
1294    if (statisticsMask & StatisticsRequestTypeNetworking)
1295        requestNetworkingStatistics(request.get());
1296}
1297
1298void WebContext::requestWebContentStatistics(StatisticsRequest* request)
1299{
1300    if (m_processModel == ProcessModelSharedSecondaryProcess) {
1301        if (m_processes.isEmpty())
1302            return;
1303
1304        uint64_t requestID = request->addOutstandingRequest();
1305        m_statisticsRequests.set(requestID, request);
1306        m_processes[0]->send(Messages::WebProcess::GetWebCoreStatistics(requestID), 0);
1307
1308    } else {
1309        // FIXME (Multi-WebProcess) <rdar://problem/13200059>: Make getting statistics from multiple WebProcesses work.
1310    }
1311}
1312
1313void WebContext::requestNetworkingStatistics(StatisticsRequest* request)
1314{
1315    bool networkProcessUnavailable;
1316#if ENABLE(NETWORK_PROCESS)
1317    networkProcessUnavailable = !m_usesNetworkProcess || !m_networkProcess;
1318#else
1319    networkProcessUnavailable = true;
1320#endif
1321
1322    if (networkProcessUnavailable) {
1323        LOG_ERROR("Attempt to get NetworkProcess statistics but the NetworkProcess is unavailable");
1324        return;
1325    }
1326
1327#if ENABLE(NETWORK_PROCESS)
1328    uint64_t requestID = request->addOutstandingRequest();
1329    m_statisticsRequests.set(requestID, request);
1330    m_networkProcess->send(Messages::NetworkProcess::GetNetworkProcessStatistics(requestID), 0);
1331#else
1332    UNUSED_PARAM(request);
1333#endif
1334}
1335
1336#if !PLATFORM(COCOA)
1337void WebContext::dummy(bool&)
1338{
1339}
1340#endif
1341
1342void WebContext::didGetStatistics(const StatisticsData& statisticsData, uint64_t requestID)
1343{
1344    RefPtr<StatisticsRequest> request = m_statisticsRequests.take(requestID);
1345    if (!request) {
1346        LOG_ERROR("Cannot report networking statistics.");
1347        return;
1348    }
1349
1350    request->completedRequest(requestID, statisticsData);
1351}
1352
1353void WebContext::garbageCollectJavaScriptObjects()
1354{
1355    sendToAllProcesses(Messages::WebProcess::GarbageCollectJavaScriptObjects());
1356}
1357
1358void WebContext::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
1359{
1360    sendToAllProcesses(Messages::WebProcess::SetJavaScriptGarbageCollectorTimerEnabled(flag));
1361}
1362
1363void WebContext::addPlugInAutoStartOriginHash(const String& pageOrigin, unsigned plugInOriginHash, SessionID sessionID)
1364{
1365    m_plugInAutoStartProvider.addAutoStartOriginHash(pageOrigin, plugInOriginHash, sessionID);
1366}
1367
1368void WebContext::plugInDidReceiveUserInteraction(unsigned plugInOriginHash, SessionID sessionID)
1369{
1370    m_plugInAutoStartProvider.didReceiveUserInteraction(plugInOriginHash, sessionID);
1371}
1372
1373PassRefPtr<ImmutableDictionary> WebContext::plugInAutoStartOriginHashes() const
1374{
1375    return m_plugInAutoStartProvider.autoStartOriginsTableCopy();
1376}
1377
1378void WebContext::setPlugInAutoStartOriginHashes(ImmutableDictionary& dictionary)
1379{
1380    m_plugInAutoStartProvider.setAutoStartOriginsTable(dictionary);
1381}
1382
1383void WebContext::setPlugInAutoStartOrigins(API::Array& array)
1384{
1385    m_plugInAutoStartProvider.setAutoStartOriginsArray(array);
1386}
1387
1388void WebContext::setPlugInAutoStartOriginsFilteringOutEntriesAddedAfterTime(ImmutableDictionary& dictionary, double time)
1389{
1390    m_plugInAutoStartProvider.setAutoStartOriginsFilteringOutEntriesAddedAfterTime(dictionary, time);
1391}
1392
1393#if ENABLE(CUSTOM_PROTOCOLS)
1394void WebContext::registerSchemeForCustomProtocol(const String& scheme)
1395{
1396    sendToNetworkingProcess(Messages::CustomProtocolManager::RegisterScheme(scheme));
1397}
1398
1399void WebContext::unregisterSchemeForCustomProtocol(const String& scheme)
1400{
1401    sendToNetworkingProcess(Messages::CustomProtocolManager::UnregisterScheme(scheme));
1402}
1403#endif
1404
1405#if ENABLE(NETSCAPE_PLUGIN_API)
1406void WebContext::pluginInfoStoreDidLoadPlugins(PluginInfoStore* store)
1407{
1408#ifdef NDEBUG
1409    UNUSED_PARAM(store);
1410#endif
1411    ASSERT(store == &m_pluginInfoStore);
1412
1413    Vector<PluginModuleInfo> pluginModules = m_pluginInfoStore.plugins();
1414
1415    Vector<RefPtr<API::Object>> plugins;
1416    plugins.reserveInitialCapacity(pluginModules.size());
1417
1418    for (const auto& pluginModule : pluginModules) {
1419        ImmutableDictionary::MapType map;
1420        map.set(ASCIILiteral("path"), API::String::create(pluginModule.path));
1421        map.set(ASCIILiteral("name"), API::String::create(pluginModule.info.name));
1422        map.set(ASCIILiteral("file"), API::String::create(pluginModule.info.file));
1423        map.set(ASCIILiteral("desc"), API::String::create(pluginModule.info.desc));
1424
1425        Vector<RefPtr<API::Object>> mimeTypes;
1426        mimeTypes.reserveInitialCapacity(pluginModule.info.mimes.size());
1427        for (const auto& mimeClassInfo : pluginModule.info.mimes)
1428            mimeTypes.uncheckedAppend(API::String::create(mimeClassInfo.type));
1429        map.set(ASCIILiteral("mimes"), API::Array::create(WTF::move(mimeTypes)));
1430
1431#if PLATFORM(COCOA)
1432        map.set(ASCIILiteral("bundleId"), API::String::create(pluginModule.bundleIdentifier));
1433        map.set(ASCIILiteral("version"), API::String::create(pluginModule.versionString));
1434#endif
1435
1436        plugins.uncheckedAppend(ImmutableDictionary::create(WTF::move(map)));
1437    }
1438
1439    m_client.plugInInformationBecameAvailable(this, API::Array::create(WTF::move(plugins)).get());
1440}
1441#endif
1442
1443void WebContext::setMemoryCacheDisabled(bool disabled)
1444{
1445    m_memoryCacheDisabled = disabled;
1446    sendToAllProcesses(Messages::WebProcess::SetMemoryCacheDisabled(disabled));
1447}
1448
1449} // namespace WebKit
1450