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