fd18e128849d72cc4e2b55392e3d2b6c59029675
[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 "WebPageProxy.h"
38 #include "WebProcessManager.h"
39 #include "WebProcessMessages.h"
40 #include "WebProcessProxyMessages.h"
41 #include "WebProcessProxyMessageKinds.h"
42 #include <WebCore/KURL.h>
43 #include <wtf/text/CString.h>
44 #include <wtf/text/WTFString.h>
45
46 using namespace WebCore;
47 using namespace std;
48
49 namespace WebKit {
50
51 template<typename HashMap>
52 static inline bool isGoodKey(const typename HashMap::KeyType& key)
53 {
54     return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key);
55 }
56
57 static uint64_t generatePageID()
58 {
59     static uint64_t uniquePageID = 1;
60     return uniquePageID++;
61 }
62
63 PassRefPtr<WebProcessProxy> WebProcessProxy::create(WebContext* context)
64 {
65     return adoptRef(new WebProcessProxy(context));
66 }
67
68 WebProcessProxy::WebProcessProxy(WebContext* context)
69     : m_responsivenessTimer(this)
70     , m_context(context)
71 {
72     connect();
73 }
74
75 WebProcessProxy::~WebProcessProxy()
76 {
77     if (m_connection)
78         m_connection->invalidate();
79     
80     for (size_t i = 0; i < m_pendingMessages.size(); ++i)
81         m_pendingMessages[i].first.releaseArguments();
82
83     if (m_processLauncher) {
84         m_processLauncher->invalidate();
85         m_processLauncher = 0;
86     }
87
88     if (m_threadLauncher) {
89         m_threadLauncher->invalidate();
90         m_threadLauncher = 0;
91     }
92 }
93
94 void WebProcessProxy::connect()
95 {
96     if (m_context->processModel() == ProcessModelSharedSecondaryThread) {
97         ASSERT(!m_threadLauncher);
98         m_threadLauncher = ThreadLauncher::create(this);
99     } else {
100         ASSERT(!m_processLauncher);
101
102         ProcessLauncher::LaunchOptions launchOptions;
103         launchOptions.processType = ProcessLauncher::WebProcess;
104 #if PLATFORM(MAC)
105         // We want the web process to match the architecture of the UI process.
106         launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture;
107 #endif
108         m_processLauncher = ProcessLauncher::create(this, launchOptions);
109     }
110 }
111
112 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags)
113 {
114     // 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
115     // a CoreIPC connection.
116     if (isLaunching()) {
117         m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags));
118         return true;
119     }
120
121     // If the web process has exited, m_connection will be null here.
122     if (!m_connection)
123         return false;
124
125     return m_connection->sendMessage(messageID, arguments, messageSendFlags);
126 }
127
128 bool WebProcessProxy::isLaunching() const
129 {
130     if (m_processLauncher)
131         return m_processLauncher->isLaunching();
132     if (m_threadLauncher)
133         return m_threadLauncher->isLaunching();
134
135     return false;
136 }
137
138 void WebProcessProxy::terminate()
139 {
140     if (m_processLauncher)
141         m_processLauncher->terminateProcess();
142 }
143
144 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
145 {
146     return m_pageMap.get(pageID).get();
147 }
148
149 WebPageProxy* WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup)
150 {
151     ASSERT(context->process() == this);
152
153     unsigned pageID = generatePageID();
154     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, context, pageGroup, pageID);
155     m_pageMap.set(pageID, webPage);
156     return webPage.get();
157 }
158
159 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
160 {
161     m_pageMap.set(pageID, webPage);
162 }
163
164 void WebProcessProxy::removeWebPage(uint64_t pageID)
165 {
166     m_pageMap.remove(pageID);
167 }
168
169 WebProcessProxy::pages_const_iterator WebProcessProxy::pages_begin()
170 {
171     return m_pageMap.begin().values();
172 }
173
174 WebProcessProxy::pages_const_iterator WebProcessProxy::pages_end()
175 {
176     return m_pageMap.end().values();
177 }
178
179 size_t WebProcessProxy::numberOfPages()
180 {
181     return m_pageMap.size();
182 }
183
184 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
185 {
186     return m_backForwardListItemMap.get(itemID).get();
187 }
188
189 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
190 {
191     // This item was just created by the UIProcess and is being added to the map for the first time
192     // so we should not already have an item for this ID.
193     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
194
195     m_backForwardListItemMap.set(item->itemID(), item);
196 }
197
198 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
199 {
200     std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0);
201     if (result.second) {
202         // New item.
203         result.first->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
204         return;
205     }
206
207     // Update existing item.
208     result.first->second->setOriginalURL(originalURL);
209     result.first->second->setURL(url);
210     result.first->second->setTitle(title);
211     result.first->second->setBackForwardData(backForwardData.data(), backForwardData.size());
212 }
213
214 #if ENABLE(PLUGIN_PROCESS)
215 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, CoreIPC::ArgumentEncoder* reply)
216 {
217     PluginProcessManager::shared().getPluginProcessConnection(pluginPath, this, reply);
218 }
219 #endif
220
221 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
222 {
223     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
224         didReceiveWebProcessProxyMessage(connection, messageID, arguments);
225         return;
226     }
227
228     if (messageID.is<CoreIPC::MessageClassWebContext>()
229         || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
230         || messageID.is<CoreIPC::MessageClassDownloadProxy>()
231         || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()
232         || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()) {
233         m_context->didReceiveMessage(connection, messageID, arguments);
234         return;
235     }
236
237     uint64_t pageID = arguments->destinationID();
238     if (!pageID)
239         return;
240
241     WebPageProxy* pageProxy = webPage(pageID);
242     if (!pageProxy)
243         return;
244     
245     pageProxy->didReceiveMessage(connection, messageID, arguments);
246 }
247
248 CoreIPC::SyncReplyMode WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
249 {
250 #if ENABLE(PLUGIN_PROCESS)
251     if (messageID.is<CoreIPC::MessageClassWebProcessProxyLegacy>()) {
252         switch (messageID.get<WebProcessProxyLegacyMessage::Kind>()) {
253             case WebProcessProxyLegacyMessage::GetPluginProcessConnection: {
254                 String pluginPath;
255                 
256                 if (!arguments->decode(CoreIPC::Out(pluginPath)))
257                     return CoreIPC::AutomaticReply;
258
259                 getPluginProcessConnection(pluginPath, reply);
260                 return CoreIPC::ManualReply;
261             }
262         }
263     }
264 #endif
265
266     if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>()  || messageID.is<CoreIPC::MessageClassDownloadProxy>())
267         return m_context->didReceiveSyncMessage(connection, messageID, arguments, reply);
268
269     uint64_t pageID = arguments->destinationID();
270     if (!pageID)
271         return CoreIPC::AutomaticReply;
272     
273     WebPageProxy* pageProxy = webPage(pageID);
274     if (!pageProxy)
275         return CoreIPC::AutomaticReply;
276     
277     pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply);
278     return CoreIPC::AutomaticReply;
279 }
280
281 void WebProcessProxy::didClose(CoreIPC::Connection*)
282 {
283     // Protect ourselves, as the call to the shared WebProcessManager's processDidClose()
284     // below may otherwise cause us to be deleted before we can finish our work.
285     RefPtr<WebProcessProxy> protect(this);
286     
287     m_connection = nullptr;
288     m_responsivenessTimer.stop();
289
290     Vector<RefPtr<WebFrameProxy> > frames;
291     copyValuesToVector(m_frameMap, frames);
292
293     for (size_t i = 0, size = frames.size(); i < size; ++i)
294         frames[i]->disconnect();
295     m_frameMap.clear();
296
297     Vector<RefPtr<WebPageProxy> > pages;
298     copyValuesToVector(m_pageMap, pages);
299
300     m_context->processDidClose(this);
301
302     WebProcessManager::shared().processDidClose(this, m_context);
303
304     for (size_t i = 0, size = pages.size(); i < size; ++i)
305         pages[i]->processDidCrash();
306 }
307
308 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID)
309 {
310     // We received an invalid message from the web process, invalidate our connection and kill it.
311     m_connection->invalidate();
312
313     terminate();
314 }
315
316 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
317 {
318     Vector<RefPtr<WebPageProxy> > pages;
319     copyValuesToVector(m_pageMap, pages);
320     for (size_t i = 0, size = pages.size(); i < size; ++i)
321         pages[i]->processDidBecomeUnresponsive();
322 }
323
324 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
325 {
326     Vector<RefPtr<WebPageProxy> > pages;
327     copyValuesToVector(m_pageMap, pages);
328     for (size_t i = 0, size = pages.size(); i < size; ++i)
329         pages[i]->processDidBecomeResponsive();
330 }
331
332 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
333 {
334     didFinishLaunching(connectionIdentifier);
335 }
336
337 void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
338 {
339     didFinishLaunching(connectionIdentifier);
340 }
341
342 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
343 {
344     ASSERT(!m_connection);
345     
346     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
347 #if PLATFORM(MAC)
348     m_connection->setShouldCloseConnectionOnMachExceptions();
349 #elif PLATFORM(QT)
350     m_connection->setShouldCloseConnectionOnProcessTermination(processIdentifier());
351 #endif
352
353     m_connection->open();
354     
355     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
356         CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first;
357         unsigned messageSendFlags = m_pendingMessages[i].second;
358         m_connection->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags);
359     }
360
361     m_pendingMessages.clear();
362
363     // Tell the context that we finished launching.
364     m_context->processDidFinishLaunching(this);
365 }
366
367 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
368 {
369     return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
370 }
371
372 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
373 {
374     return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
375 }
376
377 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
378 {
379     ASSERT(canCreateFrame(frameID));
380     m_frameMap.set(frameID, frameProxy);
381 }
382
383 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
384 {
385     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
386     // back to the UIProcess, then the frameDestroyed message will still be received because it
387     // gets sent directly to the WebProcessProxy.
388     ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
389     m_frameMap.remove(frameID);
390 }
391
392 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
393 {
394     Vector<RefPtr<WebFrameProxy> > frames;
395     copyValuesToVector(m_frameMap, frames);
396     for (size_t i = 0, size = frames.size(); i < size; ++i) {
397         if (frames[i]->page() == page)
398             frames[i]->disconnect();
399     }
400 }
401
402 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
403 {
404     size_t result = 0;
405     for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
406         if (iter->second->page() == page)
407             ++result;
408     }
409     return result;
410 }
411
412 void WebProcessProxy::updateTextCheckerState()
413 {
414     if (!isValid())
415         return;
416
417     send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
418 }
419
420 } // namespace WebKit