1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "extensions/browser/extension_message_filter.h"
6
7#include "components/crx_file/id_util.h"
8#include "content/public/browser/browser_thread.h"
9#include "content/public/browser/render_frame_host.h"
10#include "content/public/browser/render_process_host.h"
11#include "content/public/browser/render_view_host.h"
12#include "content/public/browser/resource_dispatcher_host.h"
13#include "extensions/browser/blob_holder.h"
14#include "extensions/browser/event_router.h"
15#include "extensions/browser/extension_function_dispatcher.h"
16#include "extensions/browser/extension_system.h"
17#include "extensions/browser/guest_view/guest_view_base.h"
18#include "extensions/browser/guest_view/guest_view_manager.h"
19#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h"
20#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
21#include "extensions/browser/info_map.h"
22#include "extensions/browser/process_manager.h"
23#include "extensions/common/extension.h"
24#include "extensions/common/extension_messages.h"
25#include "ipc/ipc_message_macros.h"
26
27using content::BrowserThread;
28using content::RenderProcessHost;
29
30namespace extensions {
31
32ExtensionMessageFilter::ExtensionMessageFilter(int render_process_id,
33                                               content::BrowserContext* context)
34    : BrowserMessageFilter(ExtensionMsgStart),
35      render_process_id_(render_process_id),
36      browser_context_(context),
37      extension_info_map_(ExtensionSystem::Get(context)->info_map()),
38      weak_ptr_factory_(this) {
39  DCHECK_CURRENTLY_ON(BrowserThread::UI);
40}
41
42ExtensionMessageFilter::~ExtensionMessageFilter() {
43  DCHECK_CURRENTLY_ON(BrowserThread::IO);
44}
45
46void ExtensionMessageFilter::OverrideThreadForMessage(
47    const IPC::Message& message,
48    BrowserThread::ID* thread) {
49  switch (message.type()) {
50    case ExtensionHostMsg_AddListener::ID:
51    case ExtensionHostMsg_AttachGuest::ID:
52    case ExtensionHostMsg_RemoveListener::ID:
53    case ExtensionHostMsg_AddLazyListener::ID:
54    case ExtensionHostMsg_CreateMimeHandlerViewGuest::ID:
55    case ExtensionHostMsg_RemoveLazyListener::ID:
56    case ExtensionHostMsg_AddFilteredListener::ID:
57    case ExtensionHostMsg_RemoveFilteredListener::ID:
58    case ExtensionHostMsg_ShouldSuspendAck::ID:
59    case ExtensionHostMsg_SuspendAck::ID:
60    case ExtensionHostMsg_TransferBlobsAck::ID:
61      *thread = BrowserThread::UI;
62      break;
63    default:
64      break;
65  }
66}
67
68void ExtensionMessageFilter::OnDestruct() const {
69  // Destroy the filter on the IO thread since that's where its weak pointers
70  // are being used.
71  BrowserThread::DeleteOnIOThread::Destruct(this);
72}
73
74bool ExtensionMessageFilter::OnMessageReceived(const IPC::Message& message) {
75  bool handled = true;
76  IPC_BEGIN_MESSAGE_MAP(ExtensionMessageFilter, message)
77    IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddListener,
78                        OnExtensionAddListener)
79    IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveListener,
80                        OnExtensionRemoveListener)
81    IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddLazyListener,
82                        OnExtensionAddLazyListener)
83    IPC_MESSAGE_HANDLER(ExtensionHostMsg_AttachGuest,
84                        OnExtensionAttachGuest)
85    IPC_MESSAGE_HANDLER(ExtensionHostMsg_CreateMimeHandlerViewGuest,
86                        OnExtensionCreateMimeHandlerViewGuest)
87    IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveLazyListener,
88                        OnExtensionRemoveLazyListener)
89    IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddFilteredListener,
90                        OnExtensionAddFilteredListener)
91    IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveFilteredListener,
92                        OnExtensionRemoveFilteredListener)
93    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ShouldSuspendAck,
94                        OnExtensionShouldSuspendAck)
95    IPC_MESSAGE_HANDLER(ExtensionHostMsg_SuspendAck,
96                        OnExtensionSuspendAck)
97    IPC_MESSAGE_HANDLER(ExtensionHostMsg_TransferBlobsAck,
98                        OnExtensionTransferBlobsAck)
99    IPC_MESSAGE_HANDLER(ExtensionHostMsg_GenerateUniqueID,
100                        OnExtensionGenerateUniqueID)
101    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ResumeRequests,
102                        OnExtensionResumeRequests);
103    IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestForIOThread,
104                        OnExtensionRequestForIOThread)
105    IPC_MESSAGE_UNHANDLED(handled = false)
106  IPC_END_MESSAGE_MAP()
107  return handled;
108}
109
110void ExtensionMessageFilter::OnExtensionAddListener(
111    const std::string& extension_id,
112    const GURL& listener_url,
113    const std::string& event_name) {
114  RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
115  if (!process)
116    return;
117  EventRouter* router = EventRouter::Get(browser_context_);
118  if (!router)
119    return;
120
121  if (crx_file::id_util::IdIsValid(extension_id)) {
122    router->AddEventListener(event_name, process, extension_id);
123  } else if (listener_url.is_valid()) {
124    router->AddEventListenerForURL(event_name, process, listener_url);
125  } else {
126    NOTREACHED() << "Tried to add an event listener without a valid "
127                 << "extension ID nor listener URL";
128  }
129}
130
131void ExtensionMessageFilter::OnExtensionRemoveListener(
132    const std::string& extension_id,
133    const GURL& listener_url,
134    const std::string& event_name) {
135  RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
136  if (!process)
137    return;
138  EventRouter* router = EventRouter::Get(browser_context_);
139  if (!router)
140    return;
141
142  if (crx_file::id_util::IdIsValid(extension_id)) {
143    router->RemoveEventListener(event_name, process, extension_id);
144  } else if (listener_url.is_valid()) {
145    router->RemoveEventListenerForURL(event_name, process, listener_url);
146  } else {
147    NOTREACHED() << "Tried to remove an event listener without a valid "
148                 << "extension ID nor listener URL";
149  }
150}
151
152void ExtensionMessageFilter::OnExtensionAddLazyListener(
153    const std::string& extension_id, const std::string& event_name) {
154  EventRouter* router = EventRouter::Get(browser_context_);
155  if (!router)
156    return;
157  router->AddLazyEventListener(event_name, extension_id);
158}
159
160void ExtensionMessageFilter::OnExtensionAttachGuest(
161    int routing_id,
162    int element_instance_id,
163    int guest_instance_id,
164    const base::DictionaryValue& params) {
165  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166  GuestViewManager* manager =
167      GuestViewManager::FromBrowserContext(browser_context_);
168  if (!manager)
169    return;
170
171  manager->AttachGuest(render_process_id_,
172                       routing_id,
173                       element_instance_id,
174                       guest_instance_id,
175                       params);
176}
177
178void ExtensionMessageFilter::OnExtensionCreateMimeHandlerViewGuest(
179    int render_frame_id,
180    const std::string& src,
181    const std::string& mime_type,
182    int element_instance_id) {
183  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
184  GuestViewManager* manager =
185      GuestViewManager::FromBrowserContext(browser_context_);
186  if (!manager)
187    return;
188
189  content::RenderFrameHost* rfh =
190      content::RenderFrameHost::FromID(render_process_id_, render_frame_id);
191  content::WebContents* embedder_web_contents =
192      content::WebContents::FromRenderFrameHost(rfh);
193  if (!embedder_web_contents)
194    return;
195
196  GuestViewManager::WebContentsCreatedCallback callback =
197      base::Bind(&ExtensionMessageFilter::MimeHandlerViewGuestCreatedCallback,
198                 this,
199                 element_instance_id,
200                 render_process_id_,
201                 render_frame_id,
202                 src);
203  base::DictionaryValue create_params;
204  create_params.SetString(mime_handler_view::kMimeType, mime_type);
205  create_params.SetString(mime_handler_view::kSrc, src);
206  manager->CreateGuest(MimeHandlerViewGuest::Type,
207                       "",
208                       embedder_web_contents,
209                       create_params,
210                       callback);
211}
212
213void ExtensionMessageFilter::OnExtensionRemoveLazyListener(
214    const std::string& extension_id, const std::string& event_name) {
215  EventRouter* router = EventRouter::Get(browser_context_);
216  if (!router)
217    return;
218  router->RemoveLazyEventListener(event_name, extension_id);
219}
220
221void ExtensionMessageFilter::OnExtensionAddFilteredListener(
222    const std::string& extension_id,
223    const std::string& event_name,
224    const base::DictionaryValue& filter,
225    bool lazy) {
226  RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
227  if (!process)
228    return;
229  EventRouter* router = EventRouter::Get(browser_context_);
230  if (!router)
231    return;
232  router->AddFilteredEventListener(
233      event_name, process, extension_id, filter, lazy);
234}
235
236void ExtensionMessageFilter::OnExtensionRemoveFilteredListener(
237    const std::string& extension_id,
238    const std::string& event_name,
239    const base::DictionaryValue& filter,
240    bool lazy) {
241  RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
242  if (!process)
243    return;
244  EventRouter* router = EventRouter::Get(browser_context_);
245  if (!router)
246    return;
247  router->RemoveFilteredEventListener(
248      event_name, process, extension_id, filter, lazy);
249}
250
251void ExtensionMessageFilter::OnExtensionShouldSuspendAck(
252     const std::string& extension_id, int sequence_id) {
253  ProcessManager* process_manager =
254      ExtensionSystem::Get(browser_context_)->process_manager();
255  if (process_manager)
256    process_manager->OnShouldSuspendAck(extension_id, sequence_id);
257}
258
259void ExtensionMessageFilter::OnExtensionSuspendAck(
260     const std::string& extension_id) {
261  ProcessManager* process_manager =
262      ExtensionSystem::Get(browser_context_)->process_manager();
263  if (process_manager)
264    process_manager->OnSuspendAck(extension_id);
265}
266
267void ExtensionMessageFilter::OnExtensionTransferBlobsAck(
268    const std::vector<std::string>& blob_uuids) {
269  RenderProcessHost* process = RenderProcessHost::FromID(render_process_id_);
270  if (!process)
271    return;
272  BlobHolder::FromRenderProcessHost(process)->DropBlobs(blob_uuids);
273}
274
275void ExtensionMessageFilter::OnExtensionGenerateUniqueID(int* unique_id) {
276  static int next_unique_id = 0;
277  *unique_id = ++next_unique_id;
278}
279
280void ExtensionMessageFilter::OnExtensionResumeRequests(int route_id) {
281  content::ResourceDispatcherHost::Get()->ResumeBlockedRequestsForRoute(
282      render_process_id_, route_id);
283}
284
285void ExtensionMessageFilter::OnExtensionRequestForIOThread(
286    int routing_id,
287    const ExtensionHostMsg_Request_Params& params) {
288  DCHECK_CURRENTLY_ON(BrowserThread::IO);
289  ExtensionFunctionDispatcher::DispatchOnIOThread(
290      extension_info_map_.get(),
291      browser_context_,
292      render_process_id_,
293      weak_ptr_factory_.GetWeakPtr(),
294      routing_id,
295      params);
296}
297
298void ExtensionMessageFilter::MimeHandlerViewGuestCreatedCallback(
299    int element_instance_id,
300    int embedder_render_process_id,
301    int embedder_render_frame_id,
302    const std::string& src,
303    content::WebContents* web_contents) {
304  GuestViewManager* manager =
305      GuestViewManager::FromBrowserContext(browser_context_);
306  if (!manager)
307    return;
308
309  MimeHandlerViewGuest* guest_view =
310      MimeHandlerViewGuest::FromWebContents(web_contents);
311  if (!guest_view)
312    return;
313  int guest_instance_id = guest_view->guest_instance_id();
314
315  content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
316      embedder_render_process_id, embedder_render_frame_id);
317  if (!rfh)
318    return;
319
320  base::DictionaryValue attach_params;
321  attach_params.SetString(mime_handler_view::kSrc, src);
322  manager->AttachGuest(embedder_render_process_id,
323                       rfh->GetRenderViewHost()->GetRoutingID(),
324                       element_instance_id,
325                       guest_instance_id,
326                       attach_params);
327
328  IPC::Message* msg =
329      new ExtensionMsg_CreateMimeHandlerViewGuestACK(element_instance_id);
330  msg->set_routing_id(rfh->GetRoutingID());
331  rfh->Send(msg);
332}
333
334}  // namespace extensions
335