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