fe0441107c7410b7be5b33e42efc4b29958fe703
[WebKit-https.git] / Source / WebKit2 / UIProcess / WebContext.cpp
1 /*
2  * Copyright (C) 2010, 2011 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 "DownloadProxy.h"
30 #include "ImmutableArray.h"
31 #include "InjectedBundleMessageKinds.h"
32 #include "Logging.h"
33 #include "MutableDictionary.h"
34 #include "SandboxExtension.h"
35 #include "StatisticsData.h"
36 #include "TextChecker.h"
37 #include "WKContextPrivate.h"
38 #include "WebApplicationCacheManagerProxy.h"
39 #include "WebContextMessageKinds.h"
40 #include "WebContextUserMessageCoders.h"
41 #include "WebCookieManagerProxy.h"
42 #include "WebCoreArgumentCoders.h"
43 #include "WebDatabaseManagerProxy.h"
44 #include "WebGeolocationManagerProxy.h"
45 #include "WebIconDatabase.h"
46 #include "WebKeyValueStorageManagerProxy.h"
47 #include "WebMediaCacheManagerProxy.h"
48 #include "WebNotificationManagerProxy.h"
49 #include "WebPluginSiteDataManager.h"
50 #include "WebPageGroup.h"
51 #include "WebMemorySampler.h"
52 #include "WebProcessCreationParameters.h"
53 #include "WebProcessMessages.h"
54 #include "WebProcessProxy.h"
55 #include "WebResourceCacheManagerProxy.h"
56 #include <WebCore/Language.h>
57 #include <WebCore/LinkHash.h>
58 #include <WebCore/Logging.h>
59 #include <WebCore/ResourceRequest.h>
60 #include <WebCore/RunLoop.h>
61 #include <runtime/InitializeThreading.h>
62 #include <wtf/CurrentTime.h>
63 #include <wtf/MainThread.h>
64
65 #if ENABLE(BATTERY_STATUS)
66 #include "WebBatteryManagerProxy.h"
67 #endif
68
69 #if ENABLE(NETWORK_INFO)
70 #include "WebNetworkInfoManagerProxy.h"
71 #endif
72
73 #if USE(SOUP)
74 #include "WebSoupRequestManagerProxy.h"
75 #endif
76
77 #if ENABLE(VIBRATION)
78 #include "WebVibrationProxy.h"
79 #endif
80
81 #ifndef NDEBUG
82 #include <wtf/RefCountedLeakCounter.h>
83 #endif
84
85 using namespace WebCore;
86
87 namespace WebKit {
88
89 static const double sharedSecondaryProcessShutdownTimeout = 60;
90
91 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webContextCounter, ("WebContext"));
92
93 PassRefPtr<WebContext> WebContext::create(const String& injectedBundlePath)
94 {
95     JSC::initializeThreading();
96     WTF::initializeMainThread();
97     RunLoop::initializeMainRunLoop();
98     return adoptRef(new WebContext(ProcessModelSharedSecondaryProcess, injectedBundlePath));
99 }
100
101 static Vector<WebContext*>& contexts()
102 {
103     DEFINE_STATIC_LOCAL(Vector<WebContext*>, contexts, ());
104
105     return contexts;
106 }
107
108 const Vector<WebContext*>& WebContext::allContexts()
109 {
110     return contexts();
111 }
112
113 WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePath)
114     : m_processModel(processModel)
115     , m_haveInitialEmptyProcess(false)
116     , m_defaultPageGroup(WebPageGroup::create())
117     , m_injectedBundlePath(injectedBundlePath)
118     , m_visitedLinkProvider(this)
119     , m_alwaysUsesComplexTextCodePath(false)
120     , m_shouldUseFontSmoothing(true)
121     , m_cacheModel(CacheModelDocumentViewer)
122     , m_memorySamplerEnabled(false)
123     , m_memorySamplerInterval(1400.0)
124     , m_applicationCacheManagerProxy(WebApplicationCacheManagerProxy::create(this))
125 #if ENABLE(BATTERY_STATUS)
126     , m_batteryManagerProxy(WebBatteryManagerProxy::create(this))
127 #endif
128     , m_cookieManagerProxy(WebCookieManagerProxy::create(this))
129 #if ENABLE(SQL_DATABASE)
130     , m_databaseManagerProxy(WebDatabaseManagerProxy::create(this))
131 #endif
132     , m_geolocationManagerProxy(WebGeolocationManagerProxy::create(this))
133     , m_iconDatabase(WebIconDatabase::create(this))
134     , m_keyValueStorageManagerProxy(WebKeyValueStorageManagerProxy::create(this))
135     , m_mediaCacheManagerProxy(WebMediaCacheManagerProxy::create(this))
136 #if ENABLE(NETWORK_INFO)
137     , m_networkInfoManagerProxy(WebNetworkInfoManagerProxy::create(this))
138 #endif
139     , m_notificationManagerProxy(WebNotificationManagerProxy::create(this))
140     , m_pluginSiteDataManager(WebPluginSiteDataManager::create(this))
141     , m_resourceCacheManagerProxy(WebResourceCacheManagerProxy::create(this))
142 #if USE(SOUP)
143     , m_soupRequestManagerProxy(WebSoupRequestManagerProxy::create(this))
144 #endif
145 #if ENABLE(VIBRATION)
146     , m_vibrationProxy(WebVibrationProxy::create(this))
147 #endif
148 #if PLATFORM(WIN)
149     , m_shouldPaintNativeControls(true)
150     , m_initialHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicyAlways)
151 #endif
152     , m_processTerminationEnabled(true)
153 {
154 #if !LOG_DISABLED
155     WebKit::initializeLogChannelsIfNecessary();
156 #endif
157
158     contexts().append(this);
159
160     addLanguageChangeObserver(this, languageChanged);
161
162 #if !LOG_DISABLED
163     WebCore::initializeLoggingChannelsIfNecessary();
164 #endif // !LOG_DISABLED
165
166 #ifndef NDEBUG
167     webContextCounter.increment();
168 #endif
169 }
170
171 WebContext::~WebContext()
172 {
173     ASSERT(contexts().find(this) != notFound);
174     contexts().remove(contexts().find(this));
175
176     removeLanguageChangeObserver(this);
177
178     m_applicationCacheManagerProxy->invalidate();
179     m_applicationCacheManagerProxy->clearContext();
180
181 #if ENABLE(BATTERY_STATUS)
182     m_batteryManagerProxy->invalidate();
183     m_batteryManagerProxy->clearContext();
184 #endif
185
186     m_cookieManagerProxy->invalidate();
187     m_cookieManagerProxy->clearContext();
188
189 #if ENABLE(SQL_DATABASE)
190     m_databaseManagerProxy->invalidate();
191     m_databaseManagerProxy->clearContext();
192 #endif
193     
194     m_geolocationManagerProxy->invalidate();
195     m_geolocationManagerProxy->clearContext();
196
197     m_iconDatabase->invalidate();
198     m_iconDatabase->clearContext();
199     
200     m_keyValueStorageManagerProxy->invalidate();
201     m_keyValueStorageManagerProxy->clearContext();
202
203     m_mediaCacheManagerProxy->invalidate();
204     m_mediaCacheManagerProxy->clearContext();
205
206 #if ENABLE(NETWORK_INFO)
207     m_networkInfoManagerProxy->invalidate();
208     m_networkInfoManagerProxy->clearContext();
209 #endif
210     
211     m_notificationManagerProxy->invalidate();
212     m_notificationManagerProxy->clearContext();
213
214     m_pluginSiteDataManager->invalidate();
215     m_pluginSiteDataManager->clearContext();
216
217     m_resourceCacheManagerProxy->invalidate();
218     m_resourceCacheManagerProxy->clearContext();
219
220 #if USE(SOUP)
221     m_soupRequestManagerProxy->invalidate();
222     m_soupRequestManagerProxy->clearContext();
223 #endif
224
225 #if ENABLE(VIBRATION)
226     m_vibrationProxy->invalidate();
227     m_vibrationProxy->clearContext();
228 #endif
229
230     invalidateCallbackMap(m_dictionaryCallbacks);
231
232     platformInvalidateContext();
233     
234 #ifndef NDEBUG
235     webContextCounter.decrement();
236 #endif
237 }
238
239 void WebContext::initializeInjectedBundleClient(const WKContextInjectedBundleClient* client)
240 {
241     m_injectedBundleClient.initialize(client);
242 }
243
244 void WebContext::initializeConnectionClient(const WKContextConnectionClient* client)
245 {
246     m_connectionClient.initialize(client);
247 }
248
249 void WebContext::initializeHistoryClient(const WKContextHistoryClient* client)
250 {
251     m_historyClient.initialize(client);
252
253     sendToAllProcesses(Messages::WebProcess::SetShouldTrackVisitedLinks(m_historyClient.shouldTrackVisitedLinks()));
254 }
255
256 void WebContext::initializeDownloadClient(const WKContextDownloadClient* client)
257 {
258     m_downloadClient.initialize(client);
259 }
260
261 void WebContext::setProcessModel(ProcessModel processModel)
262 {
263     // Guard against API misuse.
264     if (!m_processes.isEmpty())
265         CRASH();
266     if (processModel != ProcessModelSharedSecondaryProcess && !m_messagesToInjectedBundlePostedToEmptyContext.isEmpty())
267         CRASH();
268
269 #if !ENABLE(PLUGIN_PROCESS)
270     // Plugin process is required for multiple web process mode.
271     if (processModel != ProcessModelSharedSecondaryProcess)
272         CRASH();
273 #endif
274
275     m_processModel = processModel;
276 }
277
278 WebProcessProxy* WebContext::deprecatedSharedProcess()
279 {
280     ASSERT(m_processModel == ProcessModelSharedSecondaryProcess);
281     if (m_processes.isEmpty())
282         return 0;
283     return m_processes[0].get();
284 }
285
286 void WebContext::languageChanged(void* context)
287 {
288     static_cast<WebContext*>(context)->languageChanged();
289 }
290
291 void WebContext::languageChanged()
292 {
293     sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(userPreferredLanguages()));
294 }
295
296 void WebContext::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
297 {
298     sendToAllProcesses(Messages::WebProcess::FullKeyboardAccessModeChanged(fullKeyboardAccessEnabled));
299 }
300
301 void WebContext::textCheckerStateChanged()
302 {
303     sendToAllProcesses(Messages::WebProcess::SetTextCheckerState(TextChecker::state()));
304 }
305
306 void WebContext::ensureSharedWebProcess()
307 {
308     if (m_processes.isEmpty())
309         createNewWebProcess();
310 }
311
312 PassRefPtr<WebProcessProxy> WebContext::createNewWebProcess()
313 {
314     RefPtr<WebProcessProxy> process = WebProcessProxy::create(this);
315
316     WebProcessCreationParameters parameters;
317
318     parameters.injectedBundlePath = injectedBundlePath();
319     if (!parameters.injectedBundlePath.isEmpty())
320         SandboxExtension::createHandle(parameters.injectedBundlePath, SandboxExtension::ReadOnly, parameters.injectedBundlePathExtensionHandle);
321
322     parameters.applicationCacheDirectory = applicationCacheDirectory();
323     if (!parameters.applicationCacheDirectory.isEmpty())
324         SandboxExtension::createHandleForReadWriteDirectory(parameters.applicationCacheDirectory, parameters.applicationCacheDirectoryExtensionHandle);
325
326     parameters.databaseDirectory = databaseDirectory();
327     if (!parameters.databaseDirectory.isEmpty())
328         SandboxExtension::createHandleForReadWriteDirectory(parameters.databaseDirectory, parameters.databaseDirectoryExtensionHandle);
329
330     parameters.localStorageDirectory = localStorageDirectory();
331     if (!parameters.localStorageDirectory.isEmpty())
332         SandboxExtension::createHandleForReadWriteDirectory(parameters.localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
333
334     parameters.shouldTrackVisitedLinks = m_historyClient.shouldTrackVisitedLinks();
335     parameters.cacheModel = m_cacheModel;
336     parameters.languages = userPreferredLanguages();
337
338     copyToVector(m_schemesToRegisterAsEmptyDocument, parameters.urlSchemesRegistererdAsEmptyDocument);
339     copyToVector(m_schemesToRegisterAsSecure, parameters.urlSchemesRegisteredAsSecure);
340     copyToVector(m_schemesToSetDomainRelaxationForbiddenFor, parameters.urlSchemesForWhichDomainRelaxationIsForbidden);
341     copyToVector(m_schemesToRegisterAsLocal, parameters.urlSchemesRegisteredAsLocal);
342     copyToVector(m_schemesToRegisterAsNoAccess, parameters.urlSchemesRegisteredAsNoAccess);
343     copyToVector(m_schemesToRegisterAsDisplayIsolated, parameters.urlSchemesRegisteredAsDisplayIsolated);
344     copyToVector(m_schemesToRegisterAsCORSEnabled, parameters.urlSchemesRegisteredAsCORSEnabled);
345
346     parameters.shouldAlwaysUseComplexTextCodePath = m_alwaysUsesComplexTextCodePath;
347     parameters.shouldUseFontSmoothing = m_shouldUseFontSmoothing;
348     
349     parameters.iconDatabaseEnabled = !iconDatabasePath().isEmpty();
350
351     parameters.terminationTimeout = (m_processModel == ProcessModelSharedSecondaryProcess) ? sharedSecondaryProcessShutdownTimeout : 0;
352
353     parameters.textCheckerState = TextChecker::state();
354
355     parameters.fullKeyboardAccessEnabled = WebProcessProxy::fullKeyboardAccessEnabled();
356
357     parameters.defaultRequestTimeoutInterval = WebURLRequest::defaultTimeoutInterval();
358
359 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
360     m_notificationManagerProxy->populateCopyOfNotificationPermissions(parameters.notificationPermissions);
361 #endif
362
363     // Add any platform specific parameters
364     platformInitializeWebProcess(parameters);
365
366     RefPtr<APIObject> injectedBundleInitializationUserData = m_injectedBundleClient.getInjectedBundleInitializationUserData(this);
367     if (!injectedBundleInitializationUserData)
368         injectedBundleInitializationUserData = m_injectedBundleInitializationUserData;
369     process->send(Messages::WebProcess::InitializeWebProcess(parameters, WebContextUserMessageEncoder(injectedBundleInitializationUserData.get())), 0);
370
371     m_processes.append(process);
372
373     if (m_processModel == ProcessModelSharedSecondaryProcess) {
374         for (size_t i = 0; i != m_messagesToInjectedBundlePostedToEmptyContext.size(); ++i) {
375             pair<String, RefPtr<APIObject> >& message = m_messagesToInjectedBundlePostedToEmptyContext[i];
376             process->deprecatedSend(InjectedBundleMessage::PostMessage, 0, CoreIPC::In(message.first, WebContextUserMessageEncoder(message.second.get())));
377         }
378         m_messagesToInjectedBundlePostedToEmptyContext.clear();
379     } else
380         ASSERT(m_messagesToInjectedBundlePostedToEmptyContext.isEmpty());
381
382
383     return process.release();
384 }
385
386 void WebContext::warmInitialProcess()  
387 {
388     if (m_haveInitialEmptyProcess) {
389         ASSERT(!m_processes.isEmpty());
390         return;
391     }
392
393     createNewWebProcess();
394     m_haveInitialEmptyProcess = true;
395 }
396
397 void WebContext::enableProcessTermination()
398 {
399     m_processTerminationEnabled = true;
400     Vector<RefPtr<WebProcessProxy> > processes = m_processes;
401     for (size_t i = 0; i < processes.size(); ++i) {
402         if (shouldTerminate(processes[i].get()))
403             processes[i]->terminate();
404     }
405 }
406
407 bool WebContext::shouldTerminate(WebProcessProxy* process)
408 {
409     ASSERT(m_processes.contains(process));
410
411     if (!m_processTerminationEnabled)
412         return false;
413
414     if (!m_downloads.isEmpty())
415         return false;
416
417     if (!m_applicationCacheManagerProxy->shouldTerminate(process))
418         return false;
419     if (!m_cookieManagerProxy->shouldTerminate(process))
420         return false;
421 #if ENABLE(SQL_DATABASE)
422     if (!m_databaseManagerProxy->shouldTerminate(process))
423         return false;
424 #endif
425     if (!m_keyValueStorageManagerProxy->shouldTerminate(process))
426         return false;
427     if (!m_mediaCacheManagerProxy->shouldTerminate(process))
428         return false;
429     if (!m_pluginSiteDataManager->shouldTerminate(process))
430         return false;
431     if (!m_resourceCacheManagerProxy->shouldTerminate(process))
432         return false;
433
434     return true;
435 }
436
437 void WebContext::processDidFinishLaunching(WebProcessProxy* process)
438 {
439     ASSERT(m_processes.contains(process));
440
441     m_visitedLinkProvider.processDidFinishLaunching(process);
442
443     // Sometimes the memorySampler gets initialized after process initialization has happened but before the process has finished launching
444     // so check if it needs to be started here
445     if (m_memorySamplerEnabled) {
446         SandboxExtension::Handle sampleLogSandboxHandle;        
447         double now = WTF::currentTime();
448         String sampleLogFilePath = String::format("WebProcess%llu", static_cast<unsigned long long>(now));
449         sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::WriteOnly, sampleLogSandboxHandle);
450         
451         process->send(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, m_memorySamplerInterval), 0);
452     }
453
454     m_connectionClient.didCreateConnection(this, process->webConnection());
455 }
456
457 void WebContext::disconnectProcess(WebProcessProxy* process)
458 {
459     ASSERT(m_processes.contains(process));
460
461     m_visitedLinkProvider.processDidClose(process);
462
463     if (m_haveInitialEmptyProcess && process == m_processes.last())
464         m_haveInitialEmptyProcess = false;
465
466     // 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.
467     // Clearing everything causes assertion failures, so it's less trouble to skip that for now.
468     if (m_processModel != ProcessModelSharedSecondaryProcess) {
469         RefPtr<WebProcessProxy> protect(process);
470         m_processes.remove(m_processes.find(process));
471         return;
472     }
473
474     // Invalidate all outstanding downloads.
475     for (HashMap<uint64_t, RefPtr<DownloadProxy> >::iterator::Values it = m_downloads.begin().values(), end = m_downloads.end().values(); it != end; ++it) {
476         (*it)->processDidClose();
477         (*it)->invalidate();
478     }
479
480     m_downloads.clear();
481
482     m_applicationCacheManagerProxy->invalidate();
483 #if ENABLE(BATTERY_STATUS)
484     m_batteryManagerProxy->invalidate();
485 #endif
486     m_cookieManagerProxy->invalidate();
487 #if ENABLE(SQL_DATABASE)
488     m_databaseManagerProxy->invalidate();
489 #endif
490     m_geolocationManagerProxy->invalidate();
491     m_keyValueStorageManagerProxy->invalidate();
492     m_mediaCacheManagerProxy->invalidate();
493 #if ENABLE(NETWORK_INFO)
494     m_networkInfoManagerProxy->invalidate();
495 #endif
496     m_notificationManagerProxy->invalidate();
497     m_resourceCacheManagerProxy->invalidate();
498 #if USE(SOUP)
499     m_soupRequestManagerProxy->invalidate();
500 #endif
501 #if ENABLE(VIBRATION)
502     m_vibrationProxy->invalidate();
503 #endif
504
505     // When out of process plug-ins are enabled, we don't want to invalidate the plug-in site data
506     // manager just because the web process crashes since it's not involved.
507 #if !ENABLE(PLUGIN_PROCESS)
508     m_pluginSiteDataManager->invalidate();
509 #endif
510
511     // The vector may have the last reference to process proxy, which in turn may have the last reference to the context.
512     // Since vector elements are destroyed in place, we would recurse into WebProcessProxy destructor
513     // if it were invoked from Vector::remove(). RefPtr delays destruction until it's safe.
514     RefPtr<WebProcessProxy> protect(process);
515     m_processes.remove(m_processes.find(process));
516 }
517
518 PassRefPtr<WebPageProxy> WebContext::createWebPage(PageClient* pageClient, WebPageGroup* pageGroup, WebPageProxy* relatedPage)
519 {
520     RefPtr<WebProcessProxy> process;
521     if (m_processModel == ProcessModelSharedSecondaryProcess) {
522         ensureSharedWebProcess();
523         process = m_processes[0];
524     } else {
525         if (m_haveInitialEmptyProcess) {
526             process = m_processes.last();
527             m_haveInitialEmptyProcess = false;
528         } else if (relatedPage) {
529             // Sharing processes, e.g. when creating the page via window.open().
530             process = relatedPage->process();
531         } else {
532             // FIXME (Multi-WebProcess): <rdar://problem/12239661> Consider limiting the number of web processes in per-tab process model.
533             process = createNewWebProcess();
534         }
535     }
536
537     if (!pageGroup)
538         pageGroup = m_defaultPageGroup.get();
539
540     return process->createWebPage(pageClient, this, pageGroup);
541 }
542
543 WebProcessProxy* WebContext::relaunchProcessIfNecessary()
544 {
545     if (m_processModel == ProcessModelSharedSecondaryProcess) {
546         ensureSharedWebProcess();
547         return m_processes[0].get();
548     }
549
550     ASSERT_NOT_REACHED();
551     return 0;
552 }
553
554 DownloadProxy* WebContext::download(WebPageProxy* initiatingPage, const ResourceRequest& request)
555 {
556     if (m_processModel == ProcessModelSharedSecondaryProcess) {
557         ensureSharedWebProcess();
558
559         DownloadProxy* download = createDownloadProxy();
560         uint64_t initiatingPageID = initiatingPage ? initiatingPage->pageID() : 0;
561
562 #if PLATFORM(QT)
563         ASSERT(initiatingPage); // Our design does not suppport downloads without a WebPage.
564         initiatingPage->handleDownloadRequest(download);
565 #endif
566
567         m_processes[0]->send(Messages::WebProcess::DownloadRequest(download->downloadID(), initiatingPageID, request), 0);
568         return download;
569
570     } else {
571         // FIXME (Multi-WebProcess): <rdar://problem/12239483> Make downloading work.
572         return 0;
573     }
574 }
575
576 void WebContext::postMessageToInjectedBundle(const String& messageName, APIObject* messageBody)
577 {
578     if (m_processes.isEmpty()) {
579         if (m_processModel == ProcessModelSharedSecondaryProcess)
580             m_messagesToInjectedBundlePostedToEmptyContext.append(std::make_pair(messageName, messageBody));
581         return;
582     }
583
584     // FIXME: Return early if the message body contains any references to WKPageRefs/WKFrameRefs etc. since they're local to a process.
585
586     for (size_t i = 0; i < m_processes.size(); ++i) {
587         // FIXME: We should consider returning false from this function if the messageBody cannot be encoded.
588         // FIXME: Can we encode the message body outside the loop for all the processes?
589         m_processes[i]->deprecatedSend(InjectedBundleMessage::PostMessage, 0, CoreIPC::In(messageName, WebContextUserMessageEncoder(messageBody)));
590     }
591 }
592
593 // InjectedBundle client
594
595 void WebContext::didReceiveMessageFromInjectedBundle(const String& messageName, APIObject* messageBody)
596 {
597     m_injectedBundleClient.didReceiveMessageFromInjectedBundle(this, messageName, messageBody);
598 }
599
600 void WebContext::didReceiveSynchronousMessageFromInjectedBundle(const String& messageName, APIObject* messageBody, RefPtr<APIObject>& returnData)
601 {
602     m_injectedBundleClient.didReceiveSynchronousMessageFromInjectedBundle(this, messageName, messageBody, returnData);
603 }
604
605 void WebContext::populateVisitedLinks()
606 {
607     m_historyClient.populateVisitedLinks(this);
608 }
609
610 WebContext::Statistics& WebContext::statistics()
611 {
612     static Statistics statistics = Statistics();
613
614     return statistics;
615 }
616
617 void WebContext::setAdditionalPluginsDirectory(const String& directory)
618 {
619     Vector<String> directories;
620     directories.append(directory);
621
622     m_pluginInfoStore.setAdditionalPluginsDirectories(directories);
623 }
624
625 void WebContext::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
626 {
627     m_alwaysUsesComplexTextCodePath = alwaysUseComplexText;
628     sendToAllProcesses(Messages::WebProcess::SetAlwaysUsesComplexTextCodePath(alwaysUseComplexText));
629 }
630
631 void WebContext::setShouldUseFontSmoothing(bool useFontSmoothing)
632 {
633     m_shouldUseFontSmoothing = useFontSmoothing;
634     sendToAllProcesses(Messages::WebProcess::SetShouldUseFontSmoothing(useFontSmoothing));
635 }
636
637 void WebContext::registerURLSchemeAsEmptyDocument(const String& urlScheme)
638 {
639     m_schemesToRegisterAsEmptyDocument.add(urlScheme);
640     sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsEmptyDocument(urlScheme));
641 }
642
643 void WebContext::registerURLSchemeAsSecure(const String& urlScheme)
644 {
645     m_schemesToRegisterAsSecure.add(urlScheme);
646     sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsSecure(urlScheme));
647 }
648
649 void WebContext::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme)
650 {
651     m_schemesToSetDomainRelaxationForbiddenFor.add(urlScheme);
652     sendToAllProcesses(Messages::WebProcess::SetDomainRelaxationForbiddenForURLScheme(urlScheme));
653 }
654
655 void WebContext::registerURLSchemeAsLocal(const String& urlScheme)
656 {
657     m_schemesToRegisterAsLocal.add(urlScheme);
658     sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsLocal(urlScheme));
659 }
660
661 void WebContext::registerURLSchemeAsNoAccess(const String& urlScheme)
662 {
663     m_schemesToRegisterAsNoAccess.add(urlScheme);
664     sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsNoAccess(urlScheme));
665 }
666
667 void WebContext::registerURLSchemeAsDisplayIsolated(const String& urlScheme)
668 {
669     m_schemesToRegisterAsDisplayIsolated.add(urlScheme);
670     sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsDisplayIsolated(urlScheme));
671 }
672
673 void WebContext::registerURLSchemeAsCORSEnabled(const String& urlScheme)
674 {
675     m_schemesToRegisterAsCORSEnabled.add(urlScheme);
676     sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsCORSEnabled(urlScheme));
677 }
678
679 void WebContext::setCacheModel(CacheModel cacheModel)
680 {
681     m_cacheModel = cacheModel;
682     sendToAllProcesses(Messages::WebProcess::SetCacheModel(static_cast<uint32_t>(m_cacheModel)));
683 }
684
685 void WebContext::setDefaultRequestTimeoutInterval(double timeoutInterval)
686 {
687     sendToAllProcesses(Messages::WebProcess::SetDefaultRequestTimeoutInterval(timeoutInterval));
688 }
689
690 void WebContext::addVisitedLink(const String& visitedURL)
691 {
692     if (visitedURL.isEmpty())
693         return;
694
695     LinkHash linkHash = visitedLinkHash(visitedURL.characters(), visitedURL.length());
696     addVisitedLinkHash(linkHash);
697 }
698
699 void WebContext::addVisitedLinkHash(LinkHash linkHash)
700 {
701     m_visitedLinkProvider.addVisitedLink(linkHash);
702 }
703
704 DownloadProxy* WebContext::createDownloadProxy()
705 {
706     RefPtr<DownloadProxy> downloadProxy = DownloadProxy::create(this);
707     m_downloads.set(downloadProxy->downloadID(), downloadProxy);
708     return downloadProxy.get();
709 }
710
711 void WebContext::downloadFinished(DownloadProxy* downloadProxy)
712 {
713     ASSERT(m_downloads.contains(downloadProxy->downloadID()));
714
715     downloadProxy->invalidate();
716     m_downloads.remove(downloadProxy->downloadID());
717 }
718
719 // FIXME: This is not the ideal place for this function.
720 HashSet<String, CaseFoldingHash> WebContext::pdfAndPostScriptMIMETypes()
721 {
722     HashSet<String, CaseFoldingHash> mimeTypes;
723
724     mimeTypes.add("application/pdf");
725     mimeTypes.add("application/postscript");
726     mimeTypes.add("text/pdf");
727     
728     return mimeTypes;
729 }
730
731 void WebContext::didReceiveMessage(WebProcessProxy* process, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
732 {
733     if (messageID.is<CoreIPC::MessageClassWebContext>()) {
734         didReceiveWebContextMessage(process->connection(), messageID, arguments);
735         return;
736     }
737
738     if (messageID.is<CoreIPC::MessageClassDownloadProxy>()) {
739         if (DownloadProxy* downloadProxy = m_downloads.get(arguments->destinationID()).get())
740             downloadProxy->didReceiveDownloadProxyMessage(process->connection(), messageID, arguments);
741         
742         return;
743     }
744
745     if (messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>()) {
746         m_applicationCacheManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
747         return;
748     }
749
750 #if ENABLE(BATTERY_STATUS)
751     if (messageID.is<CoreIPC::MessageClassWebBatteryManagerProxy>()) {
752         m_batteryManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
753         return;
754     }
755 #endif
756
757     if (messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>()) {
758         m_cookieManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
759         return;
760     }
761
762 #if ENABLE(SQL_DATABASE)
763     if (messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()) {
764         m_databaseManagerProxy->didReceiveWebDatabaseManagerProxyMessage(process->connection(), messageID, arguments);
765         return;
766     }
767 #endif
768
769     if (messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()) {
770         m_geolocationManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
771         return;
772     }
773     
774     if (messageID.is<CoreIPC::MessageClassWebIconDatabase>()) {
775         m_iconDatabase->didReceiveMessage(process->connection(), messageID, arguments);
776         return;
777     }
778
779     if (messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>()) {
780         m_keyValueStorageManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
781         return;
782     }
783
784     if (messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>()) {
785         m_mediaCacheManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
786         return;
787     }
788
789 #if ENABLE(NETWORK_INFO)
790     if (messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()) {
791         m_networkInfoManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
792         return;
793     }
794 #endif
795     
796     if (messageID.is<CoreIPC::MessageClassWebNotificationManagerProxy>()) {
797         m_notificationManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
798         return;
799     }
800
801     if (messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) {
802         m_resourceCacheManagerProxy->didReceiveWebResourceCacheManagerProxyMessage(process->connection(), messageID, arguments);
803         return;
804     }
805
806 #if USE(SOUP)
807     if (messageID.is<CoreIPC::MessageClassWebSoupRequestManagerProxy>()) {
808         m_soupRequestManagerProxy->didReceiveMessage(process->connection(), messageID, arguments);
809         return;
810     }
811 #endif
812
813 #if ENABLE(VIBRATION)
814     if (messageID.is<CoreIPC::MessageClassWebVibrationProxy>()) {
815         m_vibrationProxy->didReceiveMessage(process->connection(), messageID, arguments);
816         return;
817     }
818 #endif
819
820     switch (messageID.get<WebContextLegacyMessage::Kind>()) {
821         case WebContextLegacyMessage::PostMessage: {
822             String messageName;
823             RefPtr<APIObject> messageBody;
824             WebContextUserMessageDecoder messageDecoder(messageBody, process);
825             if (!arguments->decode(CoreIPC::Out(messageName, messageDecoder)))
826                 return;
827
828             didReceiveMessageFromInjectedBundle(messageName, messageBody.get());
829             return;
830         }
831         case WebContextLegacyMessage::PostSynchronousMessage:
832             ASSERT_NOT_REACHED();
833     }
834
835     ASSERT_NOT_REACHED();
836 }
837
838 void WebContext::didReceiveSyncMessage(WebProcessProxy* process, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply)
839 {
840     if (messageID.is<CoreIPC::MessageClassWebContext>()) {
841         didReceiveSyncWebContextMessage(process->connection(), messageID, arguments, reply);
842         return;
843     }
844
845     if (messageID.is<CoreIPC::MessageClassDownloadProxy>()) {
846         if (DownloadProxy* downloadProxy = m_downloads.get(arguments->destinationID()).get())
847             downloadProxy->didReceiveSyncDownloadProxyMessage(process->connection(), messageID, arguments, reply);
848         return;
849     }
850
851     if (messageID.is<CoreIPC::MessageClassWebIconDatabase>()) {
852         m_iconDatabase->didReceiveSyncMessage(process->connection(), messageID, arguments, reply);
853         return;
854     }
855
856 #if ENABLE(NETWORK_INFO)
857     if (messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()) {
858         m_networkInfoManagerProxy->didReceiveSyncMessage(process->connection(), messageID, arguments, reply);
859         return;
860     }
861 #endif
862     
863     switch (messageID.get<WebContextLegacyMessage::Kind>()) {
864         case WebContextLegacyMessage::PostSynchronousMessage: {
865             // FIXME: We should probably encode something in the case that the arguments do not decode correctly.
866
867             String messageName;
868             RefPtr<APIObject> messageBody;
869             WebContextUserMessageDecoder messageDecoder(messageBody, process);
870             if (!arguments->decode(CoreIPC::Out(messageName, messageDecoder)))
871                 return;
872
873             RefPtr<APIObject> returnData;
874             didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody.get(), returnData);
875             reply->encode(CoreIPC::In(WebContextUserMessageEncoder(returnData.get())));
876             return;
877         }
878         case WebContextLegacyMessage::PostMessage:
879             ASSERT_NOT_REACHED();
880     }
881 }
882
883 void WebContext::setEnhancedAccessibility(bool flag)
884 {
885     sendToAllProcesses(Messages::WebProcess::SetEnhancedAccessibility(flag));
886 }
887     
888 void WebContext::startMemorySampler(const double interval)
889 {    
890     // For new WebProcesses we will also want to start the Memory Sampler
891     m_memorySamplerEnabled = true;
892     m_memorySamplerInterval = interval;
893     
894     // For UIProcess
895 #if ENABLE(MEMORY_SAMPLER)
896     WebMemorySampler::shared()->start(interval);
897 #endif
898     
899     // For WebProcess
900     SandboxExtension::Handle sampleLogSandboxHandle;    
901     double now = WTF::currentTime();
902     String sampleLogFilePath = String::format("WebProcess%llu", static_cast<unsigned long long>(now));
903     sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::WriteOnly, sampleLogSandboxHandle);
904     
905     sendToAllProcesses(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, interval));
906 }
907
908 void WebContext::stopMemorySampler()
909 {    
910     // For WebProcess
911     m_memorySamplerEnabled = false;
912     
913     // For UIProcess
914 #if ENABLE(MEMORY_SAMPLER)
915     WebMemorySampler::shared()->stop();
916 #endif
917
918     sendToAllProcesses(Messages::WebProcess::StopMemorySampler());
919 }
920
921 String WebContext::databaseDirectory() const
922 {
923     if (!m_overrideDatabaseDirectory.isEmpty())
924         return m_overrideDatabaseDirectory;
925
926     return platformDefaultDatabaseDirectory();
927 }
928
929 void WebContext::setIconDatabasePath(const String& path)
930 {
931     m_overrideIconDatabasePath = path;
932     m_iconDatabase->setDatabasePath(path);
933 }
934
935 String WebContext::iconDatabasePath() const
936 {
937     if (!m_overrideIconDatabasePath.isEmpty())
938         return m_overrideIconDatabasePath;
939
940     return platformDefaultIconDatabasePath();
941 }
942
943 String WebContext::localStorageDirectory() const
944 {
945     if (!m_overrideLocalStorageDirectory.isEmpty())
946         return m_overrideLocalStorageDirectory;
947
948     return platformDefaultLocalStorageDirectory();
949 }
950
951 void WebContext::setHTTPPipeliningEnabled(bool enabled)
952 {
953 #if PLATFORM(MAC)
954     ResourceRequest::setHTTPPipeliningEnabled(enabled);
955 #else
956     UNUSED_PARAM(enabled);
957 #endif
958 }
959
960 bool WebContext::httpPipeliningEnabled() const
961 {
962 #if PLATFORM(MAC)
963     return ResourceRequest::httpPipeliningEnabled();
964 #else
965     return false;
966 #endif
967 }
968
969 void WebContext::getWebCoreStatistics(PassRefPtr<DictionaryCallback> callback)
970 {
971     if (m_processModel == ProcessModelSharedSecondaryProcess) {
972         if (m_processes.isEmpty()) {
973             callback->invalidate();
974             return;
975         }
976         
977         uint64_t callbackID = callback->callbackID();
978         m_dictionaryCallbacks.set(callbackID, callback.get());
979         m_processes[0]->send(Messages::WebProcess::GetWebCoreStatistics(callbackID), 0);
980
981     } else {
982         // FIXME (Multi-WebProcess): <rdar://problem/12239483> Make downloading work.
983         callback->invalidate();
984     }
985 }
986
987 static PassRefPtr<MutableDictionary> createDictionaryFromHashMap(const HashMap<String, uint64_t>& map)
988 {
989     RefPtr<MutableDictionary> result = MutableDictionary::create();
990     HashMap<String, uint64_t>::const_iterator end = map.end();
991     for (HashMap<String, uint64_t>::const_iterator it = map.begin(); it != end; ++it)
992         result->set(it->key, RefPtr<WebUInt64>(WebUInt64::create(it->value)).get());
993     
994     return result;
995 }
996
997 #if !PLATFORM(MAC)
998 void WebContext::dummy(bool&)
999 {
1000 }
1001 #endif
1002
1003 void WebContext::didGetWebCoreStatistics(const StatisticsData& statisticsData, uint64_t callbackID)
1004 {
1005     RefPtr<DictionaryCallback> callback = m_dictionaryCallbacks.take(callbackID);
1006     if (!callback) {
1007         // FIXME: Log error or assert.
1008         return;
1009     }
1010
1011     RefPtr<MutableDictionary> statistics = createDictionaryFromHashMap(statisticsData.statisticsNumbers);
1012     statistics->set("JavaScriptProtectedObjectTypeCounts", createDictionaryFromHashMap(statisticsData.javaScriptProtectedObjectTypeCounts).get());
1013     statistics->set("JavaScriptObjectTypeCounts", createDictionaryFromHashMap(statisticsData.javaScriptObjectTypeCounts).get());
1014     
1015     size_t cacheStatisticsCount = statisticsData.webCoreCacheStatistics.size();
1016     Vector<RefPtr<APIObject> > cacheStatisticsVector(cacheStatisticsCount);
1017     for (size_t i = 0; i < cacheStatisticsCount; ++i)
1018         cacheStatisticsVector[i] = createDictionaryFromHashMap(statisticsData.webCoreCacheStatistics[i]);
1019     statistics->set("WebCoreCacheStatistics", ImmutableArray::adopt(cacheStatisticsVector).get());
1020     
1021     callback->performCallbackWithReturnValue(statistics.get());
1022 }
1023     
1024 void WebContext::garbageCollectJavaScriptObjects()
1025 {
1026     sendToAllProcesses(Messages::WebProcess::GarbageCollectJavaScriptObjects());
1027 }
1028
1029 void WebContext::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
1030 {
1031     sendToAllProcesses(Messages::WebProcess::SetJavaScriptGarbageCollectorTimerEnabled(flag));
1032 }
1033
1034 } // namespace WebKit