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