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