3e70fee419bf593d7004f46a0c7c0f680a88f6eb
[WebKit-https.git] / Source / WebKit2 / UIProcess / WebProcessProxy.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 "WebProcessProxy.h"
28
29 #include "DataReference.h"
30 #include "PluginInfoStore.h"
31 #include "PluginProcessManager.h"
32 #include "TextChecker.h"
33 #include "TextCheckerState.h"
34 #include "WebBackForwardListItem.h"
35 #include "WebContext.h"
36 #include "WebNavigationDataStore.h"
37 #include "WebNotificationManagerProxy.h"
38 #include "WebPageProxy.h"
39 #include "WebPluginSiteDataManager.h"
40 #include "WebProcessMessages.h"
41 #include "WebProcessProxyMessages.h"
42 #include <WebCore/KURL.h>
43 #include <stdio.h>
44 #include <wtf/MainThread.h>
45 #include <wtf/text/CString.h>
46 #include <wtf/text/WTFString.h>
47
48 #if PLATFORM(MAC)
49 #include "BuiltInPDFView.h"
50 #endif
51
52 using namespace WebCore;
53 using namespace std;
54
55 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
56 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
57
58 namespace WebKit {
59
60 template<typename HashMap>
61 static inline bool isGoodKey(const typename HashMap::KeyType& key)
62 {
63     return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key);
64 }
65
66 static uint64_t generatePageID()
67 {
68     static uint64_t uniquePageID = 1;
69     return uniquePageID++;
70 }
71
72 static WorkQueue& pluginWorkQueue()
73 {
74     DEFINE_STATIC_LOCAL(WorkQueue, queue, ("com.apple.CoreIPC.PluginQueue"));
75     return queue;
76 }
77
78 PassRefPtr<WebProcessProxy> WebProcessProxy::create(PassRefPtr<WebContext> context)
79 {
80     return adoptRef(new WebProcessProxy(context));
81 }
82
83 WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context)
84     : m_responsivenessTimer(this)
85     , m_context(context)
86     , m_mayHaveUniversalFileReadSandboxExtension(false)
87 {
88     connect();
89 }
90
91 WebProcessProxy::~WebProcessProxy()
92 {
93     if (m_connection)
94         m_connection->invalidate();
95     
96     for (size_t i = 0; i < m_pendingMessages.size(); ++i)
97         m_pendingMessages[i].first.releaseArguments();
98
99     if (m_processLauncher) {
100         m_processLauncher->invalidate();
101         m_processLauncher = 0;
102     }
103 }
104
105 void WebProcessProxy::connect()
106 {
107     ASSERT(!m_processLauncher);
108
109     ProcessLauncher::LaunchOptions launchOptions;
110     launchOptions.processType = ProcessLauncher::WebProcess;
111
112 #if PLATFORM(MAC)
113     // We want the web process to match the architecture of the UI process.
114     launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture;
115     launchOptions.executableHeap = false;
116 #if HAVE(XPC)
117     launchOptions.useXPC = getenv("WEBKIT_USE_XPC_SERVICE_FOR_WEB_PROCESS");
118 #endif
119 #endif
120 #ifndef NDEBUG
121     const char* webProcessCmdPrefix = getenv("WEB_PROCESS_CMD_PREFIX");
122     if (webProcessCmdPrefix && *webProcessCmdPrefix)
123         launchOptions.processCmdPrefix = String::fromUTF8(webProcessCmdPrefix);
124 #endif
125
126     m_processLauncher = ProcessLauncher::create(this, launchOptions);
127 }
128
129 void WebProcessProxy::disconnect()
130 {
131     if (m_connection) {
132         m_connection->connection()->removeQueueClient(this);
133         m_connection->invalidate();
134         m_connection = nullptr;
135     }
136
137     m_responsivenessTimer.stop();
138
139     Vector<RefPtr<WebFrameProxy> > frames;
140     copyValuesToVector(m_frameMap, frames);
141
142     for (size_t i = 0, size = frames.size(); i < size; ++i)
143         frames[i]->disconnect();
144     m_frameMap.clear();
145
146     m_context->disconnectProcess(this);
147 }
148
149 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags)
150 {
151     // If we're waiting for the web process to launch, we need to stash away the messages so we can send them once we have
152     // a CoreIPC connection.
153     if (isLaunching()) {
154         m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags));
155         return true;
156     }
157
158     // If the web process has exited, m_connection will be null here.
159     if (!m_connection)
160         return false;
161
162     return connection()->sendMessage(messageID, arguments, messageSendFlags);
163 }
164
165 bool WebProcessProxy::isLaunching() const
166 {
167     if (m_processLauncher)
168         return m_processLauncher->isLaunching();
169
170     return false;
171 }
172
173 void WebProcessProxy::terminate()
174 {
175     if (m_processLauncher)
176         m_processLauncher->terminateProcess();
177 }
178
179 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
180 {
181     return m_pageMap.get(pageID);
182 }
183
184 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup)
185 {
186     uint64_t pageID = generatePageID();
187     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID);
188     m_pageMap.set(pageID, webPage.get());
189     return webPage.release();
190 }
191
192 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
193 {
194     m_pageMap.set(pageID, webPage);
195 }
196
197 void WebProcessProxy::removeWebPage(uint64_t pageID)
198 {
199     m_pageMap.remove(pageID);
200 }
201
202 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
203 {
204     return m_backForwardListItemMap.get(itemID).get();
205 }
206
207 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
208 {
209     // This item was just created by the UIProcess and is being added to the map for the first time
210     // so we should not already have an item for this ID.
211     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
212
213     m_backForwardListItemMap.set(item->itemID(), item);
214 }
215
216 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
217 {
218     KURL url(KURL(), urlString);
219     if (!url.isLocalFile())
220         return;
221
222     // There's a chance that urlString does not point to a directory.
223     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
224     KURL baseURL(KURL(), url.baseAsString());
225     
226     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
227     // to have read access to this directory already.
228     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
229 }
230
231 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
232 {
233     return checkURLReceivedFromWebProcess(KURL(KURL(), urlString));
234 }
235
236 bool WebProcessProxy::checkURLReceivedFromWebProcess(const KURL& url)
237 {
238     // FIXME: Consider checking that the URL is valid. Currently, WebProcess sends invalid URLs in many cases, but it probably doesn't have good reasons to do that.
239
240     // Any other non-file URL is OK.
241     if (!url.isLocalFile())
242         return true;
243
244     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
245     if (m_mayHaveUniversalFileReadSandboxExtension)
246         return true;
247
248     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
249     // There are no ".." components, because all URLs received from WebProcess are parsed with KURL, which removes those.
250     String path = url.fileSystemPath();
251     for (HashSet<String>::const_iterator iter = m_localPathsWithAssumedReadAccess.begin(); iter != m_localPathsWithAssumedReadAccess.end(); ++iter) {
252         if (path.startsWith(*iter))
253             return true;
254     }
255
256     // Items in back/forward list have been already checked.
257     // One case where we don't have sandbox extensions for file URLs in b/f list is if the list has been reinstated after a crash or a browser restart.
258     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
259         if (KURL(KURL(), iter->second->url()).fileSystemPath() == path)
260             return true;
261         if (KURL(KURL(), iter->second->originalURL()).fileSystemPath() == path)
262             return true;
263     }
264
265     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
266     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
267     return false;
268 }
269
270 #if !PLATFORM(MAC)
271 bool WebProcessProxy::fullKeyboardAccessEnabled()
272 {
273     return false;
274 }
275 #endif
276
277 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
278 {
279     MESSAGE_CHECK_URL(originalURL);
280     MESSAGE_CHECK_URL(url);
281
282     WebBackForwardListItemMap::AddResult result = m_backForwardListItemMap.add(itemID, 0);
283     if (result.isNewEntry) {
284         result.iterator->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
285         return;
286     }
287
288     // Update existing item.
289     result.iterator->second->setOriginalURL(originalURL);
290     result.iterator->second->setURL(url);
291     result.iterator->second->setTitle(title);
292     result.iterator->second->setBackForwardData(backForwardData.data(), backForwardData.size());
293 }
294
295 void WebProcessProxy::sendDidGetPlugins(uint64_t requestID, PassOwnPtr<Vector<PluginInfo> > pluginInfos)
296 {
297     ASSERT(isMainThread());
298
299     OwnPtr<Vector<PluginInfo> > plugins(pluginInfos);
300
301 #if PLATFORM(MAC)
302     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
303     // NOTE: This has to be done on the main thread as it calls localizedString().
304     if (!m_context->omitPDFSupport())
305         plugins->append(BuiltInPDFView::pluginInfo());
306 #endif
307
308     send(Messages::WebProcess::DidGetPlugins(requestID, *plugins), 0);
309 }
310
311 void WebProcessProxy::handleGetPlugins(uint64_t requestID, bool refresh)
312 {
313     if (refresh)
314         m_context->pluginInfoStore().refresh();
315
316     OwnPtr<Vector<PluginInfo> > pluginInfos = adoptPtr(new Vector<PluginInfo>);
317
318     Vector<PluginModuleInfo> plugins = m_context->pluginInfoStore().plugins();
319     for (size_t i = 0; i < plugins.size(); ++i)
320         pluginInfos->append(plugins[i].info);
321
322     // NOTE: We have to pass the PluginInfo vector to the secondary thread via a pointer as otherwise
323     //       we'd end up with a deref() race on all the WTF::Strings it contains.
324     RunLoop::main()->dispatch(bind(&WebProcessProxy::sendDidGetPlugins, this, requestID, pluginInfos.release()));
325 }
326
327 void WebProcessProxy::getPlugins(CoreIPC::Connection*, uint64_t requestID, bool refresh)
328 {
329     pluginWorkQueue().dispatch(bind(&WebProcessProxy::handleGetPlugins, this, requestID, refresh));
330 }
331
332 void WebProcessProxy::getPluginPath(const String& mimeType, const String& urlString, String& pluginPath, bool& blocked)
333 {
334     MESSAGE_CHECK_URL(urlString);
335
336     String newMimeType = mimeType.lower();
337
338     blocked = false;
339     PluginModuleInfo plugin = m_context->pluginInfoStore().findPlugin(newMimeType, KURL(KURL(), urlString));
340     if (!plugin.path)
341         return;
342
343     if (m_context->pluginInfoStore().shouldBlockPlugin(plugin)) {
344         blocked = true;
345         return;
346     }
347
348     pluginPath = plugin.path;
349 }
350
351 #if ENABLE(PLUGIN_PROCESS)
352
353 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
354 {
355     PluginProcessManager::shared().getPluginProcessConnection(m_context->pluginInfoStore(), pluginPath, reply);
356 }
357
358 void WebProcessProxy::pluginSyncMessageSendTimedOut(const String& pluginPath)
359 {
360     PluginProcessManager::shared().pluginSyncMessageSendTimedOut(pluginPath);
361 }
362
363 #else
364
365 void WebProcessProxy::didGetSitesWithPluginData(const Vector<String>& sites, uint64_t callbackID)
366 {
367     m_context->pluginSiteDataManager()->didGetSitesWithData(sites, callbackID);
368 }
369
370 void WebProcessProxy::didClearPluginSiteData(uint64_t callbackID)
371 {
372     m_context->pluginSiteDataManager()->didClearSiteData(callbackID);
373 }
374
375 #endif
376
377 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
378 {
379     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
380         didReceiveWebProcessProxyMessage(connection, messageID, arguments);
381         return;
382     }
383
384     if (messageID.is<CoreIPC::MessageClassWebContext>()
385         || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
386         || messageID.is<CoreIPC::MessageClassDownloadProxy>()
387         || messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>()
388 #if ENABLE(BATTERY_STATUS)
389         || messageID.is<CoreIPC::MessageClassWebBatteryManagerProxy>()
390 #endif
391         || messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>()
392         || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()
393         || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()
394         || messageID.is<CoreIPC::MessageClassWebIconDatabase>()
395         || messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>()
396         || messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>()
397 #if ENABLE(NETWORK_INFO)
398         || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
399 #endif
400         || messageID.is<CoreIPC::MessageClassWebNotificationManagerProxy>()
401 #if USE(SOUP)
402         || messageID.is<CoreIPC::MessageClassWebSoupRequestManagerProxy>()
403 #endif
404 #if ENABLE(VIBRATION)
405         || messageID.is<CoreIPC::MessageClassWebVibrationProxy>()
406 #endif
407         || messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) {
408         m_context->didReceiveMessage(this, messageID, arguments);
409         return;
410     }
411
412     uint64_t pageID = arguments->destinationID();
413     if (!pageID)
414         return;
415
416     WebPageProxy* pageProxy = webPage(pageID);
417     if (!pageProxy)
418         return;
419     
420     pageProxy->didReceiveMessage(connection, messageID, arguments);
421 }
422
423 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply)
424 {
425     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
426         didReceiveSyncWebProcessProxyMessage(connection, messageID, arguments, reply);
427         return;
428     }
429
430     if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
431 #if ENABLE(NETWORK_INFO)
432         || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
433 #endif
434         || messageID.is<CoreIPC::MessageClassDownloadProxy>() || messageID.is<CoreIPC::MessageClassWebIconDatabase>()) {
435         m_context->didReceiveSyncMessage(this, messageID, arguments, reply);
436         return;
437     }
438
439     uint64_t pageID = arguments->destinationID();
440     if (!pageID)
441         return;
442     
443     WebPageProxy* pageProxy = webPage(pageID);
444     if (!pageProxy)
445         return;
446     
447     pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply);
448 }
449
450 void WebProcessProxy::didReceiveMessageOnConnectionWorkQueue(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, bool& didHandleMessage)
451 {
452     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>())
453         didReceiveWebProcessProxyMessageOnConnectionWorkQueue(connection, messageID, arguments, didHandleMessage);
454 }
455
456 void WebProcessProxy::didClose(CoreIPC::Connection*)
457 {
458     // Protect ourselves, as the call to disconnect() below may otherwise cause us
459     // to be deleted before we can finish our work.
460     RefPtr<WebProcessProxy> protect(this);
461
462     Vector<RefPtr<WebPageProxy> > pages;
463     copyValuesToVector(m_pageMap, pages);
464
465     disconnect();
466
467     for (size_t i = 0, size = pages.size(); i < size; ++i)
468         pages[i]->processDidCrash();
469 }
470
471 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID)
472 {
473     WTFLogAlways("Received an invalid message from the web process with message ID %x\n", messageID.toInt());
474
475     // Terminate the WebProcesses.
476     terminate();
477 }
478
479 void WebProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*)
480 {
481 }
482
483 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
484 {
485     Vector<RefPtr<WebPageProxy> > pages;
486     copyValuesToVector(m_pageMap, pages);
487     for (size_t i = 0, size = pages.size(); i < size; ++i)
488         pages[i]->processDidBecomeUnresponsive();
489 }
490
491 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
492 {
493     Vector<RefPtr<WebPageProxy> > pages;
494     copyValuesToVector(m_pageMap, pages);
495     for (size_t i = 0, size = pages.size(); i < size; ++i)
496         pages[i]->interactionOccurredWhileProcessUnresponsive();
497 }
498
499 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
500 {
501     Vector<RefPtr<WebPageProxy> > pages;
502     copyValuesToVector(m_pageMap, pages);
503     for (size_t i = 0, size = pages.size(); i < size; ++i)
504         pages[i]->processDidBecomeResponsive();
505 }
506
507 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
508 {
509     didFinishLaunching(connectionIdentifier);
510 }
511
512 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
513 {
514     ASSERT(!m_connection);
515     
516     m_connection = WebConnectionToWebProcess::create(this, connectionIdentifier, RunLoop::main());
517     m_connection->connection()->addQueueClient(this);
518     m_connection->connection()->open();
519
520     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
521         CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first;
522         unsigned messageSendFlags = m_pendingMessages[i].second;
523         connection()->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags);
524     }
525
526     m_pendingMessages.clear();
527
528     // Tell the context that we finished launching.
529     m_context->processDidFinishLaunching(this);
530 }
531
532 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
533 {
534     return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
535 }
536
537 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
538 {
539     return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
540 }
541
542 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
543 {
544     ASSERT(canCreateFrame(frameID));
545     m_frameMap.set(frameID, frameProxy);
546 }
547
548 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
549 {
550     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
551     // back to the UIProcess, then the frameDestroyed message will still be received because it
552     // gets sent directly to the WebProcessProxy.
553     ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
554     m_frameMap.remove(frameID);
555 }
556
557 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
558 {
559     Vector<RefPtr<WebFrameProxy> > frames;
560     copyValuesToVector(m_frameMap, frames);
561     for (size_t i = 0, size = frames.size(); i < size; ++i) {
562         if (frames[i]->page() == page)
563             frames[i]->disconnect();
564     }
565 }
566
567 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
568 {
569     size_t result = 0;
570     for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
571         if (iter->second->page() == page)
572             ++result;
573     }
574     return result;
575 }
576
577 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
578 {
579     if (!m_pageMap.isEmpty() || !m_context->shouldTerminate(this)) {
580         shouldTerminate = false;
581         return;
582     }
583
584     shouldTerminate = true;
585
586     // We know that the web process is going to terminate so disconnect it from the context.
587     disconnect();
588 }
589
590 void WebProcessProxy::updateTextCheckerState()
591 {
592     if (!isValid())
593         return;
594
595     send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
596 }
597
598 void WebProcessProxy::didNavigateWithNavigationData(uint64_t pageID, const WebNavigationDataStore& store, uint64_t frameID) 
599 {
600     WebPageProxy* page = webPage(pageID);
601     if (!page)
602         return;
603     
604     WebFrameProxy* frame = webFrame(frameID);
605     MESSAGE_CHECK(frame);
606     MESSAGE_CHECK(frame->page() == page);
607     
608     m_context->historyClient().didNavigateWithNavigationData(m_context.get(), page, store, frame);
609 }
610
611 void WebProcessProxy::didPerformClientRedirect(uint64_t pageID, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
612 {
613     WebPageProxy* page = webPage(pageID);
614     if (!page)
615         return;
616
617     if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
618         return;
619     
620     WebFrameProxy* frame = webFrame(frameID);
621     MESSAGE_CHECK(frame);
622     MESSAGE_CHECK(frame->page() == page);
623     MESSAGE_CHECK_URL(sourceURLString);
624     MESSAGE_CHECK_URL(destinationURLString);
625
626     m_context->historyClient().didPerformClientRedirect(m_context.get(), page, sourceURLString, destinationURLString, frame);
627 }
628
629 void WebProcessProxy::didPerformServerRedirect(uint64_t pageID, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
630 {
631     WebPageProxy* page = webPage(pageID);
632     if (!page)
633         return;
634     
635     if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
636         return;
637     
638     WebFrameProxy* frame = webFrame(frameID);
639     MESSAGE_CHECK(frame);
640     MESSAGE_CHECK(frame->page() == page);
641     MESSAGE_CHECK_URL(sourceURLString);
642     MESSAGE_CHECK_URL(destinationURLString);
643
644     m_context->historyClient().didPerformServerRedirect(m_context.get(), page, sourceURLString, destinationURLString, frame);
645 }
646
647 void WebProcessProxy::didUpdateHistoryTitle(uint64_t pageID, const String& title, const String& url, uint64_t frameID)
648 {
649     WebPageProxy* page = webPage(pageID);
650     if (!page)
651         return;
652
653     WebFrameProxy* frame = webFrame(frameID);
654     MESSAGE_CHECK(frame);
655     MESSAGE_CHECK(frame->page() == page);
656     MESSAGE_CHECK_URL(url);
657
658     m_context->historyClient().didUpdateHistoryTitle(m_context.get(), page, title, url, frame);
659 }
660
661 } // namespace WebKit