diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/WebContext.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/WebContext.cpp | 739 |
1 files changed, 483 insertions, 256 deletions
diff --git a/Source/WebKit2/UIProcess/WebContext.cpp b/Source/WebKit2/UIProcess/WebContext.cpp index 3f818d1c1..e1ef1021d 100644 --- a/Source/WebKit2/UIProcess/WebContext.cpp +++ b/Source/WebKit2/UIProcess/WebContext.cpp @@ -38,28 +38,31 @@ #include "WebApplicationCacheManagerProxy.h" #include "WebContextMessageKinds.h" #include "WebContextMessages.h" +#include "WebContextSupplement.h" #include "WebContextUserMessageCoders.h" #include "WebCookieManagerProxy.h" #include "WebCoreArgumentCoders.h" #include "WebDatabaseManagerProxy.h" #include "WebGeolocationManagerProxy.h" #include "WebIconDatabase.h" -#include "WebKeyValueStorageManagerProxy.h" +#include "WebKeyValueStorageManager.h" #include "WebMediaCacheManagerProxy.h" #include "WebNotificationManagerProxy.h" #include "WebPluginSiteDataManager.h" #include "WebPageGroup.h" +#include "WebPreferences.h" #include "WebMemorySampler.h" #include "WebProcessCreationParameters.h" #include "WebProcessMessages.h" #include "WebProcessProxy.h" #include "WebResourceCacheManagerProxy.h" +#include <WebCore/InitializeLogging.h> #include <WebCore/Language.h> #include <WebCore/LinkHash.h> -#include <WebCore/Logging.h> #include <WebCore/ResourceRequest.h> #include <WebCore/RunLoop.h> #include <runtime/InitializeThreading.h> +#include <runtime/Operations.h> #include <wtf/CurrentTime.h> #include <wtf/MainThread.h> @@ -72,7 +75,13 @@ #endif #if ENABLE(NETWORK_PROCESS) -#include "NetworkProcessManager.h" +#include "NetworkProcessCreationParameters.h" +#include "NetworkProcessMessages.h" +#include "NetworkProcessProxy.h" +#endif + +#if ENABLE(CUSTOM_PROTOCOLS) +#include "CustomProtocolManagerMessages.h" #endif #if USE(SOUP) @@ -96,9 +105,6 @@ PassRefPtr<WebContext> WebContext::create(const String& injectedBundlePath) JSC::initializeThreading(); WTF::initializeMainThread(); RunLoop::initializeMainRunLoop(); -#if PLATFORM(MAC) - WebContext::initializeProcessSuppressionSupport(); -#endif return adoptRef(new WebContext(ProcessModelSharedSecondaryProcess, injectedBundlePath)); } @@ -116,54 +122,62 @@ const Vector<WebContext*>& WebContext::allContexts() WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePath) : m_processModel(processModel) + , m_webProcessCountLimit(UINT_MAX) , m_haveInitialEmptyProcess(false) + , m_processWithPageCache(0) , m_defaultPageGroup(WebPageGroup::create()) , m_injectedBundlePath(injectedBundlePath) , m_visitedLinkProvider(this) + , m_plugInAutoStartProvider(this) , m_alwaysUsesComplexTextCodePath(false) , m_shouldUseFontSmoothing(true) , m_cacheModel(CacheModelDocumentViewer) , m_memorySamplerEnabled(false) , m_memorySamplerInterval(1400.0) -#if PLATFORM(WIN) - , m_shouldPaintNativeControls(true) - , m_initialHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicyAlways) + , m_storageManager(StorageManager::create()) +#if USE(SOUP) + , m_initialHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicyOnlyFromMainDocumentDomain) #endif , m_processTerminationEnabled(true) #if ENABLE(NETWORK_PROCESS) , m_usesNetworkProcess(false) #endif +#if PLATFORM(MAC) + , m_processSuppressionEnabled(true) +#endif +#if USE(SOUP) + , m_ignoreTLSErrors(true) +#endif { + platformInitialize(); + addMessageReceiver(Messages::WebContext::messageReceiverName(), this); - addMessageReceiver(CoreIPC::MessageKindTraits<WebContextLegacyMessage::Kind>::messageReceiverName(), this); + addMessageReceiver(WebContextLegacyMessages::messageReceiverName(), this); // NOTE: These sub-objects must be initialized after m_messageReceiverMap.. - m_applicationCacheManagerProxy = WebApplicationCacheManagerProxy::create(this); -#if ENABLE(BATTERY_STATUS) - m_batteryManagerProxy = WebBatteryManagerProxy::create(this); -#endif - m_cookieManagerProxy = WebCookieManagerProxy::create(this); -#if ENABLE(SQL_DATABASE) - m_databaseManagerProxy = WebDatabaseManagerProxy::create(this); -#endif - m_geolocationManagerProxy = WebGeolocationManagerProxy::create(this); m_iconDatabase = WebIconDatabase::create(this); - m_keyValueStorageManagerProxy = WebKeyValueStorageManagerProxy::create(this); - m_mediaCacheManagerProxy = WebMediaCacheManagerProxy::create(this); -#if ENABLE(NETWORK_INFO) - m_networkInfoManagerProxy = WebNetworkInfoManagerProxy::create(this); -#endif - m_notificationManagerProxy = WebNotificationManagerProxy::create(this); #if ENABLE(NETSCAPE_PLUGIN_API) m_pluginSiteDataManager = WebPluginSiteDataManager::create(this); #endif // ENABLE(NETSCAPE_PLUGIN_API) - m_resourceCacheManagerProxy = WebResourceCacheManagerProxy::create(this); + + addSupplement<WebApplicationCacheManagerProxy>(); + addSupplement<WebCookieManagerProxy>(); + addSupplement<WebGeolocationManagerProxy>(); + addSupplement<WebKeyValueStorageManager>(); + addSupplement<WebMediaCacheManagerProxy>(); + addSupplement<WebNotificationManagerProxy>(); + addSupplement<WebResourceCacheManagerProxy>(); +#if ENABLE(SQL_DATABASE) + addSupplement<WebDatabaseManagerProxy>(); +#endif #if USE(SOUP) - m_soupRequestManagerProxy = WebSoupRequestManagerProxy::create(this); + addSupplement<WebSoupRequestManagerProxy>(); #endif - -#if !LOG_DISABLED - WebKit::initializeLogChannelsIfNecessary(); +#if ENABLE(BATTERY_STATUS) + addSupplement<WebBatteryManagerProxy>(); +#endif +#if ENABLE(NETWORK_INFO) + addSupplement<WebNetworkInfoManagerProxy>(); #endif contexts().append(this); @@ -172,13 +186,26 @@ WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePa #if !LOG_DISABLED WebCore::initializeLoggingChannelsIfNecessary(); + WebKit::initializeLogChannelsIfNecessary(); #endif // !LOG_DISABLED +#if ENABLE(NETSCAPE_PLUGIN_API) + m_pluginInfoStore.setClient(this); +#endif + #ifndef NDEBUG webContextCounter.increment(); #endif + + m_storageManager->setLocalStorageDirectory(localStorageDirectory()); } +#if !PLATFORM(MAC) +void WebContext::platformInitialize() +{ +} +#endif + WebContext::~WebContext() { ASSERT(contexts().find(this) != notFound); @@ -188,64 +215,39 @@ WebContext::~WebContext() m_messageReceiverMap.invalidate(); - m_applicationCacheManagerProxy->invalidate(); - m_applicationCacheManagerProxy->clearContext(); - -#if ENABLE(BATTERY_STATUS) - m_batteryManagerProxy->invalidate(); - m_batteryManagerProxy->clearContext(); -#endif - - m_cookieManagerProxy->invalidate(); - m_cookieManagerProxy->clearContext(); - -#if ENABLE(SQL_DATABASE) - m_databaseManagerProxy->invalidate(); - m_databaseManagerProxy->clearContext(); -#endif - - m_geolocationManagerProxy->invalidate(); - m_geolocationManagerProxy->clearContext(); + WebContextSupplementMap::const_iterator it = m_supplements.begin(); + WebContextSupplementMap::const_iterator end = m_supplements.end(); + for (; it != end; ++it) { + it->value->contextDestroyed(); + it->value->clearContext(); + } m_iconDatabase->invalidate(); m_iconDatabase->clearContext(); - m_keyValueStorageManagerProxy->invalidate(); - m_keyValueStorageManagerProxy->clearContext(); - - m_mediaCacheManagerProxy->invalidate(); - m_mediaCacheManagerProxy->clearContext(); - -#if ENABLE(NETWORK_INFO) - m_networkInfoManagerProxy->invalidate(); - m_networkInfoManagerProxy->clearContext(); -#endif - - m_notificationManagerProxy->invalidate(); - m_notificationManagerProxy->clearContext(); - #if ENABLE(NETSCAPE_PLUGIN_API) m_pluginSiteDataManager->invalidate(); m_pluginSiteDataManager->clearContext(); #endif - m_resourceCacheManagerProxy->invalidate(); - m_resourceCacheManagerProxy->clearContext(); - -#if USE(SOUP) - m_soupRequestManagerProxy->invalidate(); - m_soupRequestManagerProxy->clearContext(); -#endif - invalidateCallbackMap(m_dictionaryCallbacks); platformInvalidateContext(); - + +#if ENABLE(NETSCAPE_PLUGIN_API) + m_pluginInfoStore.setClient(0); +#endif + #ifndef NDEBUG webContextCounter.decrement(); #endif } +void WebContext::initializeClient(const WKContextClient* client) +{ + m_client.initialize(client); +} + void WebContext::initializeInjectedBundleClient(const WKContextInjectedBundleClient* client) { m_injectedBundleClient.initialize(client); @@ -285,12 +287,37 @@ void WebContext::setProcessModel(ProcessModel processModel) m_processModel = processModel; } -WebProcessProxy* WebContext::deprecatedSharedProcess() +void WebContext::setMaximumNumberOfProcesses(unsigned maximumNumberOfProcesses) { - ASSERT(m_processModel == ProcessModelSharedSecondaryProcess); - if (m_processes.isEmpty()) - return 0; - return m_processes[0].get(); + // Guard against API misuse. + if (!m_processes.isEmpty()) + CRASH(); + + if (maximumNumberOfProcesses == 0) + m_webProcessCountLimit = UINT_MAX; + else + m_webProcessCountLimit = maximumNumberOfProcesses; +} + +CoreIPC::Connection* WebContext::networkingProcessConnection() +{ + switch (m_processModel) { + case ProcessModelSharedSecondaryProcess: +#if ENABLE(NETWORK_PROCESS) + if (m_usesNetworkProcess) + return m_networkProcess->connection(); +#endif + return m_processes[0]->connection(); + case ProcessModelMultipleSecondaryProcesses: +#if ENABLE(NETWORK_PROCESS) + ASSERT(m_usesNetworkProcess); + return m_networkProcess->connection(); +#else + break; +#endif + } + ASSERT_NOT_REACHED(); + return 0; } void WebContext::languageChanged(void* context) @@ -322,6 +349,119 @@ void WebContext::setUsesNetworkProcess(bool usesNetworkProcess) #endif } +bool WebContext::usesNetworkProcess() const +{ +#if ENABLE(NETWORK_PROCESS) + return m_usesNetworkProcess; +#else + return false; +#endif +} + +#if ENABLE(NETWORK_PROCESS) +void WebContext::ensureNetworkProcess() +{ + if (m_networkProcess) + return; + + m_networkProcess = NetworkProcessProxy::create(this); + + NetworkProcessCreationParameters parameters; + + parameters.diskCacheDirectory = diskCacheDirectory(); + if (!parameters.diskCacheDirectory.isEmpty()) + SandboxExtension::createHandleForReadWriteDirectory(parameters.diskCacheDirectory, parameters.diskCacheDirectoryExtensionHandle); + + parameters.privateBrowsingEnabled = WebPreferences::anyPageGroupsAreUsingPrivateBrowsing(); + + parameters.cacheModel = m_cacheModel; + + // Add any platform specific parameters + platformInitializeNetworkProcess(parameters); + + // Initialize the network process. + m_networkProcess->send(Messages::NetworkProcess::InitializeNetworkProcess(parameters), 0); +} + +void WebContext::networkProcessCrashed(NetworkProcessProxy* networkProcessProxy) +{ + ASSERT(m_networkProcess); + ASSERT(networkProcessProxy == m_networkProcess.get()); + + WebContextSupplementMap::const_iterator it = m_supplements.begin(); + WebContextSupplementMap::const_iterator end = m_supplements.end(); + for (; it != end; ++it) + it->value->processDidClose(networkProcessProxy); + + m_networkProcess = nullptr; + + m_client.networkProcessDidCrash(this); +} + +void WebContext::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply) +{ + ASSERT(reply); + + ensureNetworkProcess(); + ASSERT(m_networkProcess); + + m_networkProcess->getNetworkProcessConnection(reply); +} +#endif + + +void WebContext::willStartUsingPrivateBrowsing() +{ + const Vector<WebContext*>& contexts = allContexts(); + for (size_t i = 0, count = contexts.size(); i < count; ++i) { +#if ENABLE(NETWORK_PROCESS) + if (contexts[i]->usesNetworkProcess() && contexts[i]->networkProcess()) + contexts[i]->networkProcess()->send(Messages::NetworkProcess::EnsurePrivateBrowsingSession(), 0); +#endif + contexts[i]->sendToAllProcesses(Messages::WebProcess::EnsurePrivateBrowsingSession()); + } +} + +void WebContext::willStopUsingPrivateBrowsing() +{ + const Vector<WebContext*>& contexts = allContexts(); + for (size_t i = 0, count = contexts.size(); i < count; ++i) { +#if ENABLE(NETWORK_PROCESS) + if (contexts[i]->usesNetworkProcess() && contexts[i]->networkProcess()) + contexts[i]->networkProcess()->send(Messages::NetworkProcess::DestroyPrivateBrowsingSession(), 0); +#endif + + contexts[i]->sendToAllProcesses(Messages::WebProcess::DestroyPrivateBrowsingSession()); + } +} + +void (*s_invalidMessageCallback)(WKStringRef messageName); + +void WebContext::setInvalidMessageCallback(void (*invalidMessageCallback)(WKStringRef messageName)) +{ + s_invalidMessageCallback = invalidMessageCallback; +} + +void WebContext::didReceiveInvalidMessage(const CoreIPC::StringReference& messageReceiverName, const CoreIPC::StringReference& messageName) +{ + if (!s_invalidMessageCallback) + return; + + StringBuilder messageNameStringBuilder; + messageNameStringBuilder.append(messageReceiverName.data(), messageReceiverName.size()); + messageNameStringBuilder.append("."); + messageNameStringBuilder.append(messageName.data(), messageName.size()); + + s_invalidMessageCallback(toAPI(WebString::create(messageNameStringBuilder.toString()).get())); +} + +void WebContext::processDidCachePage(WebProcessProxy* process) +{ + if (m_processWithPageCache && m_processWithPageCache != process) + m_processWithPageCache->releasePageCache(); + m_processWithPageCache = process; +} + WebProcessProxy* WebContext::ensureSharedWebProcess() { ASSERT(m_processModel == ProcessModelSharedSecondaryProcess); @@ -330,11 +470,11 @@ WebProcessProxy* WebContext::ensureSharedWebProcess() return m_processes[0].get(); } -PassRefPtr<WebProcessProxy> WebContext::createNewWebProcess() +WebProcessProxy* WebContext::createNewWebProcess() { #if ENABLE(NETWORK_PROCESS) if (m_usesNetworkProcess) - NetworkProcessManager::shared().ensureNetworkProcess(); + ensureNetworkProcess(); #endif RefPtr<WebProcessProxy> process = WebProcessProxy::create(this); @@ -363,7 +503,7 @@ PassRefPtr<WebProcessProxy> WebContext::createNewWebProcess() parameters.cookieStorageDirectory = cookieStorageDirectory(); if (!parameters.cookieStorageDirectory.isEmpty()) - SandboxExtension::createHandle(parameters.cookieStorageDirectory, SandboxExtension::ReadWrite, parameters.cookieStorageDirectoryExtensionHandle); + SandboxExtension::createHandleForReadWriteDirectory(parameters.cookieStorageDirectory, parameters.cookieStorageDirectoryExtensionHandle); parameters.shouldTrackVisitedLinks = m_historyClient.shouldTrackVisitedLinks(); parameters.cacheModel = m_cacheModel; @@ -391,13 +531,17 @@ PassRefPtr<WebProcessProxy> WebContext::createNewWebProcess() parameters.defaultRequestTimeoutInterval = WebURLRequest::defaultTimeoutInterval(); #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - m_notificationManagerProxy->populateCopyOfNotificationPermissions(parameters.notificationPermissions); + // FIXME: There should be a generic way for supplements to add to the intialization parameters. + supplement<WebNotificationManagerProxy>()->populateCopyOfNotificationPermissions(parameters.notificationPermissions); #endif #if ENABLE(NETWORK_PROCESS) parameters.usesNetworkProcess = m_usesNetworkProcess; #endif + parameters.plugInAutoStartOriginHashes = m_plugInAutoStartProvider.autoStartOriginHashesCopy(); + copyToVector(m_plugInAutoStartProvider.autoStartOrigins(), parameters.plugInAutoStartOrigins); + // Add any platform specific parameters platformInitializeWebProcess(parameters); @@ -406,11 +550,14 @@ PassRefPtr<WebProcessProxy> WebContext::createNewWebProcess() injectedBundleInitializationUserData = m_injectedBundleInitializationUserData; process->send(Messages::WebProcess::InitializeWebProcess(parameters, WebContextUserMessageEncoder(injectedBundleInitializationUserData.get())), 0); + if (WebPreferences::anyPageGroupsAreUsingPrivateBrowsing()) + process->send(Messages::WebProcess::EnsurePrivateBrowsingSession(), 0); + m_processes.append(process); if (m_processModel == ProcessModelSharedSecondaryProcess) { for (size_t i = 0; i != m_messagesToInjectedBundlePostedToEmptyContext.size(); ++i) { - pair<String, RefPtr<APIObject> >& message = m_messagesToInjectedBundlePostedToEmptyContext[i]; + pair<String, RefPtr<APIObject>>& message = m_messagesToInjectedBundlePostedToEmptyContext[i]; OwnPtr<CoreIPC::ArgumentEncoder> messageData = CoreIPC::ArgumentEncoder::create(); @@ -422,8 +569,7 @@ PassRefPtr<WebProcessProxy> WebContext::createNewWebProcess() } else ASSERT(m_messagesToInjectedBundlePostedToEmptyContext.isEmpty()); - - return process.release(); + return process.get(); } void WebContext::warmInitialProcess() @@ -433,6 +579,9 @@ void WebContext::warmInitialProcess() return; } + if (m_processes.size() >= m_webProcessCountLimit) + return; + createNewWebProcess(); m_haveInitialEmptyProcess = true; } @@ -440,7 +589,7 @@ void WebContext::warmInitialProcess() void WebContext::enableProcessTermination() { m_processTerminationEnabled = true; - Vector<RefPtr<WebProcessProxy> > processes = m_processes; + Vector<RefPtr<WebProcessProxy>> processes = m_processes; for (size_t i = 0; i < processes.size(); ++i) { if (shouldTerminate(processes[i].get())) processes[i]->terminate(); @@ -454,31 +603,31 @@ bool WebContext::shouldTerminate(WebProcessProxy* process) if (!m_processTerminationEnabled) return false; - if (!m_downloads.isEmpty()) - return false; + WebContextSupplementMap::const_iterator it = m_supplements.begin(); + WebContextSupplementMap::const_iterator end = m_supplements.end(); + for (; it != end; ++it) { + if (!it->value->shouldTerminate(process)) + return false; + } - if (!m_applicationCacheManagerProxy->shouldTerminate(process)) - return false; - if (!m_cookieManagerProxy->shouldTerminate(process)) - return false; -#if ENABLE(SQL_DATABASE) - if (!m_databaseManagerProxy->shouldTerminate(process)) - return false; -#endif - if (!m_keyValueStorageManagerProxy->shouldTerminate(process)) - return false; - if (!m_mediaCacheManagerProxy->shouldTerminate(process)) - return false; #if ENABLE(NETSCAPE_PLUGIN_API) if (!m_pluginSiteDataManager->shouldTerminate(process)) return false; #endif - if (!m_resourceCacheManagerProxy->shouldTerminate(process)) - return false; return true; } +void WebContext::processWillOpenConnection(WebProcessProxy* process) +{ + m_storageManager->processWillOpenConnection(process); +} + +void WebContext::processWillCloseConnection(WebProcessProxy* process) +{ + m_storageManager->processWillCloseConnection(process); +} + void WebContext::processDidFinishLaunching(WebProcessProxy* process) { ASSERT(m_processes.contains(process)); @@ -491,7 +640,7 @@ void WebContext::processDidFinishLaunching(WebProcessProxy* process) SandboxExtension::Handle sampleLogSandboxHandle; double now = WTF::currentTime(); String sampleLogFilePath = String::format("WebProcess%llupid%d", static_cast<unsigned long long>(now), process->processIdentifier()); - sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::WriteOnly, sampleLogSandboxHandle); + sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::ReadWrite, sampleLogSandboxHandle); process->send(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, m_memorySamplerInterval), 0); } @@ -508,41 +657,20 @@ void WebContext::disconnectProcess(WebProcessProxy* process) if (m_haveInitialEmptyProcess && process == m_processes.last()) m_haveInitialEmptyProcess = false; - // FIXME (Multi-WebProcess): <rdar://problem/12239765> All the invalidation calls below are still necessary in multi-process mode, but they should only affect data structures pertaining to the process being disconnected. + // 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. // Clearing everything causes assertion failures, so it's less trouble to skip that for now. if (m_processModel != ProcessModelSharedSecondaryProcess) { RefPtr<WebProcessProxy> protect(process); + if (m_processWithPageCache == process) + m_processWithPageCache = 0; m_processes.remove(m_processes.find(process)); return; } - // Invalidate all outstanding downloads. - for (HashMap<uint64_t, RefPtr<DownloadProxy> >::iterator::Values it = m_downloads.begin().values(), end = m_downloads.end().values(); it != end; ++it) { - (*it)->processDidClose(); - (*it)->invalidate(); - } - - m_downloads.clear(); - - m_applicationCacheManagerProxy->invalidate(); -#if ENABLE(BATTERY_STATUS) - m_batteryManagerProxy->invalidate(); -#endif - m_cookieManagerProxy->invalidate(); -#if ENABLE(SQL_DATABASE) - m_databaseManagerProxy->invalidate(); -#endif - m_geolocationManagerProxy->invalidate(); - m_keyValueStorageManagerProxy->invalidate(); - m_mediaCacheManagerProxy->invalidate(); -#if ENABLE(NETWORK_INFO) - m_networkInfoManagerProxy->invalidate(); -#endif - m_notificationManagerProxy->invalidate(); - m_resourceCacheManagerProxy->invalidate(); -#if USE(SOUP) - m_soupRequestManagerProxy->invalidate(); -#endif + WebContextSupplementMap::const_iterator it = m_supplements.begin(); + WebContextSupplementMap::const_iterator end = m_supplements.end(); + for (; it != end; ++it) + it->value->processDidClose(process); // When out of process plug-ins are enabled, we don't want to invalidate the plug-in site data // manager just because the web process crashes since it's not involved. @@ -554,9 +682,28 @@ void WebContext::disconnectProcess(WebProcessProxy* process) // Since vector elements are destroyed in place, we would recurse into WebProcessProxy destructor // if it were invoked from Vector::remove(). RefPtr delays destruction until it's safe. RefPtr<WebProcessProxy> protect(process); + if (m_processWithPageCache == process) + m_processWithPageCache = 0; m_processes.remove(m_processes.find(process)); } +WebProcessProxy* WebContext::createNewWebProcessRespectingProcessCountLimit() +{ + if (m_processes.size() < m_webProcessCountLimit) + return createNewWebProcess(); + + // Choose a process with fewest pages, to achieve flat distribution. + WebProcessProxy* result = 0; + unsigned fewestPagesSeen = UINT_MAX; + for (unsigned i = 0; i < m_processes.size(); ++i) { + if (fewestPagesSeen > m_processes[i]->pages().size()) { + result = m_processes[i].get(); + fewestPagesSeen = m_processes[i]->pages().size(); + } + } + return result; +} + PassRefPtr<WebPageProxy> WebContext::createWebPage(PageClient* pageClient, WebPageGroup* pageGroup, WebPageProxy* relatedPage) { RefPtr<WebProcessProxy> process; @@ -569,10 +716,8 @@ PassRefPtr<WebPageProxy> WebContext::createWebPage(PageClient* pageClient, WebPa } else if (relatedPage) { // Sharing processes, e.g. when creating the page via window.open(). process = relatedPage->process(); - } else { - // FIXME (Multi-WebProcess): <rdar://problem/12239661> Consider limiting the number of web processes in per-tab process model. - process = createNewWebProcess(); - } + } else + process = createNewWebProcessRespectingProcessCountLimit(); } if (!pageGroup) @@ -583,24 +728,24 @@ PassRefPtr<WebPageProxy> WebContext::createWebPage(PageClient* pageClient, WebPa DownloadProxy* WebContext::download(WebPageProxy* initiatingPage, const ResourceRequest& request) { - if (m_processModel == ProcessModelSharedSecondaryProcess) { - ensureSharedWebProcess(); + DownloadProxy* downloadProxy = createDownloadProxy(); + uint64_t initiatingPageID = initiatingPage ? initiatingPage->pageID() : 0; - DownloadProxy* download = createDownloadProxy(); - uint64_t initiatingPageID = initiatingPage ? initiatingPage->pageID() : 0; +#if ENABLE(NETWORK_PROCESS) + if (usesNetworkProcess() && networkProcess()) { + // FIXME (NetworkProcess): Replicate whatever FrameLoader::setOriginalURLForDownloadRequest does with the request here. + networkProcess()->connection()->send(Messages::NetworkProcess::DownloadRequest(downloadProxy->downloadID(), request), 0); + return downloadProxy; + } +#endif #if PLATFORM(QT) - ASSERT(initiatingPage); // Our design does not suppport downloads without a WebPage. - initiatingPage->handleDownloadRequest(download); + ASSERT(initiatingPage); // Our design does not suppport downloads without a WebPage. + initiatingPage->handleDownloadRequest(downloadProxy); #endif - m_processes[0]->send(Messages::WebProcess::DownloadRequest(download->downloadID(), initiatingPageID, request), 0); - return download; - - } else { - // FIXME (Multi-WebProcess): <rdar://problem/12239483> Make downloading work. - return 0; - } + m_processes[0]->send(Messages::WebProcess::DownloadRequest(downloadProxy->downloadID(), initiatingPageID, request), 0); + return downloadProxy; } void WebContext::postMessageToInjectedBundle(const String& messageName, APIObject* messageBody) @@ -714,6 +859,8 @@ void WebContext::setCacheModel(CacheModel cacheModel) { m_cacheModel = cacheModel; sendToAllProcesses(Messages::WebProcess::SetCacheModel(static_cast<uint32_t>(m_cacheModel))); + + // FIXME: Inform the Network Process if in use. } void WebContext::setDefaultRequestTimeoutInterval(double timeoutInterval) @@ -737,31 +884,12 @@ void WebContext::addVisitedLinkHash(LinkHash linkHash) DownloadProxy* WebContext::createDownloadProxy() { - RefPtr<DownloadProxy> downloadProxy = DownloadProxy::create(this); - m_downloads.set(downloadProxy->downloadID(), downloadProxy); - addMessageReceiver(Messages::DownloadProxy::messageReceiverName(), downloadProxy->downloadID(), this); - return downloadProxy.get(); -} - -void WebContext::downloadFinished(DownloadProxy* downloadProxy) -{ - ASSERT(m_downloads.contains(downloadProxy->downloadID())); - - downloadProxy->invalidate(); - removeMessageReceiver(Messages::DownloadProxy::messageReceiverName(), downloadProxy->downloadID()); - m_downloads.remove(downloadProxy->downloadID()); -} - -// FIXME: This is not the ideal place for this function. -HashSet<String, CaseFoldingHash> WebContext::pdfAndPostScriptMIMETypes() -{ - HashSet<String, CaseFoldingHash> mimeTypes; +#if ENABLE(NETWORK_PROCESS) + if (usesNetworkProcess()) + return m_networkProcess->createDownloadProxy(); +#endif - mimeTypes.add("application/pdf"); - mimeTypes.add("application/postscript"); - mimeTypes.add("text/pdf"); - - return mimeTypes; + return ensureSharedWebProcess()->createDownloadProxy(); } void WebContext::addMessageReceiver(CoreIPC::StringReference messageReceiverName, CoreIPC::MessageReceiver* messageReceiver) @@ -779,83 +907,66 @@ void WebContext::removeMessageReceiver(CoreIPC::StringReference messageReceiverN m_messageReceiverMap.removeMessageReceiver(messageReceiverName, destinationID); } -bool WebContext::dispatchMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::MessageDecoder& decoder) +bool WebContext::dispatchMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder) { - return m_messageReceiverMap.dispatchMessage(connection, messageID, decoder); + return m_messageReceiverMap.dispatchMessage(connection, decoder); } -bool WebContext::dispatchSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder) +bool WebContext::dispatchSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder) { - return m_messageReceiverMap.dispatchSyncMessage(connection, messageID, decoder, replyEncoder); + return m_messageReceiverMap.dispatchSyncMessage(connection, decoder, replyEncoder); } -void WebContext::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::MessageDecoder& decoder) +void WebContext::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder) { - if (messageID.is<CoreIPC::MessageClassWebContext>()) { - didReceiveWebContextMessage(connection, messageID, decoder); + if (decoder.messageReceiverName() == Messages::WebContext::messageReceiverName()) { + didReceiveWebContextMessage(connection, decoder); return; } - if (messageID.is<CoreIPC::MessageClassDownloadProxy>()) { - if (DownloadProxy* downloadProxy = m_downloads.get(decoder.destinationID()).get()) - downloadProxy->didReceiveDownloadProxyMessage(connection, messageID, decoder); - - return; - } - - switch (messageID.get<WebContextLegacyMessage::Kind>()) { - case WebContextLegacyMessage::PostMessage: { - String messageName; - RefPtr<APIObject> messageBody; - WebContextUserMessageDecoder messageBodyDecoder(messageBody, WebProcessProxy::fromConnection(connection)); - if (!decoder.decode(messageName)) - return; - if (!decoder.decode(messageBodyDecoder)) - return; - - didReceiveMessageFromInjectedBundle(messageName, messageBody.get()); + if (decoder.messageReceiverName() == WebContextLegacyMessages::messageReceiverName() + && decoder.messageName() == WebContextLegacyMessages::postMessageMessageName()) { + String messageName; + RefPtr<APIObject> messageBody; + WebContextUserMessageDecoder messageBodyDecoder(messageBody, WebProcessProxy::fromConnection(connection)); + if (!decoder.decode(messageName)) return; - } - case WebContextLegacyMessage::PostSynchronousMessage: - ASSERT_NOT_REACHED(); + if (!decoder.decode(messageBodyDecoder)) + return; + + didReceiveMessageFromInjectedBundle(messageName, messageBody.get()); + return; } ASSERT_NOT_REACHED(); } -void WebContext::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder) +void WebContext::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageDecoder& decoder, OwnPtr<CoreIPC::MessageEncoder>& replyEncoder) { - if (messageID.is<CoreIPC::MessageClassWebContext>()) { - didReceiveSyncWebContextMessage(connection, messageID, decoder, replyEncoder); + if (decoder.messageReceiverName() == Messages::WebContext::messageReceiverName()) { + didReceiveSyncWebContextMessage(connection, decoder, replyEncoder); return; } - if (messageID.is<CoreIPC::MessageClassDownloadProxy>()) { - if (DownloadProxy* downloadProxy = m_downloads.get(decoder.destinationID()).get()) - downloadProxy->didReceiveSyncDownloadProxyMessage(connection, messageID, decoder, replyEncoder); - return; - } + if (decoder.messageReceiverName() == WebContextLegacyMessages::messageReceiverName() + && decoder.messageName() == WebContextLegacyMessages::postSynchronousMessageMessageName()) { + // FIXME: We should probably encode something in the case that the arguments do not decode correctly. - switch (messageID.get<WebContextLegacyMessage::Kind>()) { - case WebContextLegacyMessage::PostSynchronousMessage: { - // FIXME: We should probably encode something in the case that the arguments do not decode correctly. - - String messageName; - RefPtr<APIObject> messageBody; - WebContextUserMessageDecoder messageBodyDecoder(messageBody, WebProcessProxy::fromConnection(connection)); - if (!decoder.decode(messageName)) - return; - if (!decoder.decode(messageBodyDecoder)) - return; - - RefPtr<APIObject> returnData; - didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody.get(), returnData); - replyEncoder->encode(WebContextUserMessageEncoder(returnData.get())); + String messageName; + RefPtr<APIObject> messageBody; + WebContextUserMessageDecoder messageBodyDecoder(messageBody, WebProcessProxy::fromConnection(connection)); + if (!decoder.decode(messageName)) return; - } - case WebContextLegacyMessage::PostMessage: - ASSERT_NOT_REACHED(); + if (!decoder.decode(messageBodyDecoder)) + return; + + RefPtr<APIObject> returnData; + didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody.get(), returnData); + replyEncoder->encode(WebContextUserMessageEncoder(returnData.get())); + return; } + + ASSERT_NOT_REACHED(); } void WebContext::setEnhancedAccessibility(bool flag) @@ -878,7 +989,7 @@ void WebContext::startMemorySampler(const double interval) SandboxExtension::Handle sampleLogSandboxHandle; double now = WTF::currentTime(); String sampleLogFilePath = String::format("WebProcess%llu", static_cast<unsigned long long>(now)); - sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::WriteOnly, sampleLogSandboxHandle); + sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::ReadWrite, sampleLogSandboxHandle); sendToAllProcesses(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, interval)); } @@ -896,6 +1007,14 @@ void WebContext::stopMemorySampler() sendToAllProcesses(Messages::WebProcess::StopMemorySampler()); } +String WebContext::applicationCacheDirectory() const +{ + if (!m_overrideApplicationCacheDirectory.isEmpty()) + return m_overrideApplicationCacheDirectory; + + return platformDefaultApplicationCacheDirectory(); +} + String WebContext::databaseDirectory() const { if (!m_overrideDatabaseDirectory.isEmpty()) @@ -918,6 +1037,12 @@ String WebContext::iconDatabasePath() const return platformDefaultIconDatabasePath(); } +void WebContext::setLocalStorageDirectory(const String& directory) +{ + m_overrideLocalStorageDirectory = directory; + m_storageManager->setLocalStorageDirectory(localStorageDirectory()); +} + String WebContext::localStorageDirectory() const { if (!m_overrideLocalStorageDirectory.isEmpty()) @@ -942,6 +1067,21 @@ String WebContext::cookieStorageDirectory() const return platformDefaultCookieStorageDirectory(); } +void WebContext::allowSpecificHTTPSCertificateForHost(const WebCertificateInfo* certificate, const String& host) +{ +#if ENABLE(NETWORK_PROCESS) + if (m_usesNetworkProcess && m_networkProcess) { + m_networkProcess->send(Messages::NetworkProcess::AllowSpecificHTTPSCertificateForHost(certificate->platformCertificateInfo(), host), 0); + return; + } +#else + UNUSED_PARAM(certificate); + UNUSED_PARAM(host); +#endif + // FIXME: It's unclear whether we want this SPI to be exposed and used for clients that don't use the NetworkProcess. + ASSERT_NOT_REACHED(); +} + void WebContext::setHTTPPipeliningEnabled(bool enabled) { #if PLATFORM(MAC) @@ -960,32 +1100,58 @@ bool WebContext::httpPipeliningEnabled() const #endif } -void WebContext::getWebCoreStatistics(PassRefPtr<DictionaryCallback> callback) +void WebContext::getStatistics(uint32_t statisticsMask, PassRefPtr<DictionaryCallback> callback) +{ + if (!statisticsMask) { + callback->invalidate(); + return; + } + + RefPtr<StatisticsRequest> request = StatisticsRequest::create(callback); + + if (statisticsMask & StatisticsRequestTypeWebContent) + requestWebContentStatistics(request.get()); + + if (statisticsMask & StatisticsRequestTypeNetworking) + requestNetworkingStatistics(request.get()); +} + +void WebContext::requestWebContentStatistics(StatisticsRequest* request) { if (m_processModel == ProcessModelSharedSecondaryProcess) { - if (m_processes.isEmpty()) { - callback->invalidate(); + if (m_processes.isEmpty()) return; - } - uint64_t callbackID = callback->callbackID(); - m_dictionaryCallbacks.set(callbackID, callback.get()); - m_processes[0]->send(Messages::WebProcess::GetWebCoreStatistics(callbackID), 0); + uint64_t requestID = request->addOutstandingRequest(); + m_statisticsRequests.set(requestID, request); + m_processes[0]->send(Messages::WebProcess::GetWebCoreStatistics(requestID), 0); } else { - // FIXME (Multi-WebProcess): <rdar://problem/12239483> Make downloading work. - callback->invalidate(); + // FIXME (Multi-WebProcess) <rdar://problem/13200059>: Make getting statistics from multiple WebProcesses work. } } -static PassRefPtr<MutableDictionary> createDictionaryFromHashMap(const HashMap<String, uint64_t>& map) +void WebContext::requestNetworkingStatistics(StatisticsRequest* request) { - RefPtr<MutableDictionary> result = MutableDictionary::create(); - HashMap<String, uint64_t>::const_iterator end = map.end(); - for (HashMap<String, uint64_t>::const_iterator it = map.begin(); it != end; ++it) - result->set(it->key, RefPtr<WebUInt64>(WebUInt64::create(it->value)).get()); - - return result; + bool networkProcessUnavailable; +#if ENABLE(NETWORK_PROCESS) + networkProcessUnavailable = !m_usesNetworkProcess || !m_networkProcess; +#else + networkProcessUnavailable = true; +#endif + + if (networkProcessUnavailable) { + LOG_ERROR("Attempt to get NetworkProcess statistics but the NetworkProcess is unavailable"); + return; + } + +#if ENABLE(NETWORK_PROCESS) + uint64_t requestID = request->addOutstandingRequest(); + m_statisticsRequests.set(requestID, request); + m_networkProcess->send(Messages::NetworkProcess::GetNetworkProcessStatistics(requestID), 0); +#else + UNUSED_PARAM(request); +#endif } #if !PLATFORM(MAC) @@ -994,25 +1160,15 @@ void WebContext::dummy(bool&) } #endif -void WebContext::didGetWebCoreStatistics(const StatisticsData& statisticsData, uint64_t callbackID) +void WebContext::didGetStatistics(const StatisticsData& statisticsData, uint64_t requestID) { - RefPtr<DictionaryCallback> callback = m_dictionaryCallbacks.take(callbackID); - if (!callback) { - // FIXME: Log error or assert. + RefPtr<StatisticsRequest> request = m_statisticsRequests.take(requestID); + if (!request) { + LOG_ERROR("Cannot report networking statistics."); return; } - RefPtr<MutableDictionary> statistics = createDictionaryFromHashMap(statisticsData.statisticsNumbers); - statistics->set("JavaScriptProtectedObjectTypeCounts", createDictionaryFromHashMap(statisticsData.javaScriptProtectedObjectTypeCounts).get()); - statistics->set("JavaScriptObjectTypeCounts", createDictionaryFromHashMap(statisticsData.javaScriptObjectTypeCounts).get()); - - size_t cacheStatisticsCount = statisticsData.webCoreCacheStatistics.size(); - Vector<RefPtr<APIObject> > cacheStatisticsVector(cacheStatisticsCount); - for (size_t i = 0; i < cacheStatisticsCount; ++i) - cacheStatisticsVector[i] = createDictionaryFromHashMap(statisticsData.webCoreCacheStatistics[i]); - statistics->set("WebCoreCacheStatistics", ImmutableArray::adopt(cacheStatisticsVector).get()); - - callback->performCallbackWithReturnValue(statistics.get()); + request->completedRequest(requestID, statisticsData); } void WebContext::garbageCollectJavaScriptObjects() @@ -1025,4 +1181,75 @@ void WebContext::setJavaScriptGarbageCollectorTimerEnabled(bool flag) sendToAllProcesses(Messages::WebProcess::SetJavaScriptGarbageCollectorTimerEnabled(flag)); } +void WebContext::addPlugInAutoStartOriginHash(const String& pageOrigin, unsigned plugInOriginHash) +{ + m_plugInAutoStartProvider.addAutoStartOriginHash(pageOrigin, plugInOriginHash); +} + +void WebContext::plugInDidReceiveUserInteraction(unsigned plugInOriginHash) +{ + m_plugInAutoStartProvider.didReceiveUserInteraction(plugInOriginHash); +} + +PassRefPtr<ImmutableDictionary> WebContext::plugInAutoStartOriginHashes() const +{ + return m_plugInAutoStartProvider.autoStartOriginsTableCopy(); +} + +void WebContext::setPlugInAutoStartOriginHashes(ImmutableDictionary& dictionary) +{ + m_plugInAutoStartProvider.setAutoStartOriginsTable(dictionary); +} + +void WebContext::setPlugInAutoStartOrigins(ImmutableArray& array) +{ + m_plugInAutoStartProvider.setAutoStartOriginsArray(array); +} + +#if ENABLE(CUSTOM_PROTOCOLS) +void WebContext::registerSchemeForCustomProtocol(const String& scheme) +{ + sendToNetworkingProcess(Messages::CustomProtocolManager::RegisterScheme(scheme)); +} + +void WebContext::unregisterSchemeForCustomProtocol(const String& scheme) +{ + sendToNetworkingProcess(Messages::CustomProtocolManager::UnregisterScheme(scheme)); +} +#endif + +#if ENABLE(NETSCAPE_PLUGIN_API) +void WebContext::pluginInfoStoreDidLoadPlugins(PluginInfoStore* store) +{ +#ifdef NDEBUG + UNUSED_PARAM(store); +#endif + ASSERT(store == &m_pluginInfoStore); + + Vector<RefPtr<APIObject>> pluginArray; + + Vector<PluginModuleInfo> plugins = m_pluginInfoStore.plugins(); + for (size_t i = 0; i < plugins.size(); ++i) { + PluginModuleInfo& plugin = plugins[i]; + ImmutableDictionary::MapType map; + map.set(ASCIILiteral("path"), WebString::create(plugin.path)); + map.set(ASCIILiteral("name"), WebString::create(plugin.info.name)); + map.set(ASCIILiteral("file"), WebString::create(plugin.info.file)); + map.set(ASCIILiteral("desc"), WebString::create(plugin.info.desc)); + Vector<RefPtr<APIObject>> mimeArray; + for (size_t j = 0; j < plugin.info.mimes.size(); ++j) + mimeArray.append(WebString::create(plugin.info.mimes[j].type)); + map.set(ASCIILiteral("mimes"), ImmutableArray::adopt(mimeArray)); +#if PLATFORM(MAC) + map.set(ASCIILiteral("bundleId"), WebString::create(plugin.bundleIdentifier)); + map.set(ASCIILiteral("version"), WebString::create(plugin.versionString)); +#endif + + pluginArray.append(ImmutableDictionary::adopt(map)); + } + + m_client.plugInInformationBecameAvailable(this, ImmutableArray::adopt(pluginArray).get()); +} +#endif + } // namespace WebKit |