Upstream version 9.37.195.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / chrome_extension_message_filter.cc
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 "chrome/browser/renderer_host/chrome_extension_message_filter.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
14 #include "chrome/browser/extensions/activity_log/activity_actions.h"
15 #include "chrome/browser/extensions/activity_log/activity_log.h"
16 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
17 #include "chrome/browser/extensions/api/messaging/message_service.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/common/extensions/api/i18n/default_locale_handler.h"
21 #include "chrome/common/render_messages.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/constants.h"
26 #include "extensions/common/extension_messages.h"
27 #include "extensions/common/file_util.h"
28 #include "extensions/common/message_bundle.h"
29
30 using content::BrowserThread;
31 using extensions::APIPermission;
32
33 namespace {
34
35 const uint32 kFilteredMessageClasses[] = {
36   ChromeMsgStart,
37   ExtensionMsgStart,
38 };
39
40 // Logs an action to the extension activity log for the specified profile.  Can
41 // be called from any thread.
42 void AddActionToExtensionActivityLog(
43     Profile* profile,
44     scoped_refptr<extensions::Action> action) {
45   // The ActivityLog can only be accessed from the main (UI) thread.  If we're
46   // running on the wrong thread, re-dispatch from the main thread.
47   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
48     BrowserThread::PostTask(
49         BrowserThread::UI, FROM_HERE,
50         base::Bind(&AddActionToExtensionActivityLog, profile, action));
51   } else {
52     if (!g_browser_process->profile_manager()->IsValidProfile(profile))
53       return;
54     // If the action included a URL, check whether it is for an incognito
55     // profile.  The check is performed here so that it can safely be done from
56     // the UI thread.
57     if (action->page_url().is_valid() || !action->page_title().empty())
58       action->set_page_incognito(profile->IsOffTheRecord());
59     extensions::ActivityLog* activity_log =
60         extensions::ActivityLog::GetInstance(profile);
61     activity_log->LogAction(action);
62   }
63 }
64
65 }  // namespace
66
67 ChromeExtensionMessageFilter::ChromeExtensionMessageFilter(
68     int render_process_id,
69     Profile* profile)
70     : BrowserMessageFilter(kFilteredMessageClasses,
71                            arraysize(kFilteredMessageClasses)),
72       render_process_id_(render_process_id),
73       profile_(profile),
74       extension_info_map_(
75           extensions::ExtensionSystem::Get(profile)->info_map()) {
76   DCHECK_CURRENTLY_ON(BrowserThread::UI);
77   notification_registrar_.Add(this,
78                               chrome::NOTIFICATION_PROFILE_DESTROYED,
79                               content::Source<Profile>(profile));
80 }
81
82 ChromeExtensionMessageFilter::~ChromeExtensionMessageFilter() {
83   DCHECK_CURRENTLY_ON(BrowserThread::UI);
84 }
85
86 bool ChromeExtensionMessageFilter::OnMessageReceived(
87     const IPC::Message& message) {
88   bool handled = true;
89   IPC_BEGIN_MESSAGE_MAP(ChromeExtensionMessageFilter, message)
90     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardRead,
91                         OnCanTriggerClipboardRead)
92     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardWrite,
93                         OnCanTriggerClipboardWrite)
94     IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToExtension,
95                         OnOpenChannelToExtension)
96     IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab)
97     IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToNativeApp,
98                         OnOpenChannelToNativeApp)
99     IPC_MESSAGE_HANDLER_DELAY_REPLY(ExtensionHostMsg_GetMessageBundle,
100                                     OnGetExtMessageBundle)
101     IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel)
102     IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddAPIActionToActivityLog,
103                         OnAddAPIActionToExtensionActivityLog);
104     IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddDOMActionToActivityLog,
105                         OnAddDOMActionToExtensionActivityLog);
106     IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddEventToActivityLog,
107                         OnAddEventToExtensionActivityLog);
108     IPC_MESSAGE_UNHANDLED(handled = false)
109   IPC_END_MESSAGE_MAP()
110
111   return handled;
112 }
113
114 void ChromeExtensionMessageFilter::OverrideThreadForMessage(
115     const IPC::Message& message, BrowserThread::ID* thread) {
116   switch (message.type()) {
117     case ExtensionHostMsg_CloseChannel::ID:
118       *thread = BrowserThread::UI;
119       break;
120     default:
121       break;
122   }
123 }
124
125 void ChromeExtensionMessageFilter::OnDestruct() const {
126   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
127     delete this;
128   } else {
129     BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
130   }
131 }
132
133 void ChromeExtensionMessageFilter::OnCanTriggerClipboardRead(
134     const GURL& origin, bool* allowed) {
135   *allowed = extension_info_map_->SecurityOriginHasAPIPermission(
136       origin, render_process_id_, APIPermission::kClipboardRead);
137 }
138
139 void ChromeExtensionMessageFilter::OnCanTriggerClipboardWrite(
140     const GURL& origin, bool* allowed) {
141   // Since all extensions could historically write to the clipboard, preserve it
142   // for compatibility.
143   *allowed = (origin.SchemeIs(extensions::kExtensionScheme) ||
144       extension_info_map_->SecurityOriginHasAPIPermission(
145           origin, render_process_id_, APIPermission::kClipboardWrite));
146 }
147
148 void ChromeExtensionMessageFilter::OnOpenChannelToExtension(
149     int routing_id,
150     const ExtensionMsg_ExternalConnectionInfo& info,
151     const std::string& channel_name,
152     bool include_tls_channel_id,
153     int* port_id) {
154   int port2_id;
155   extensions::MessageService::AllocatePortIdPair(port_id, &port2_id);
156
157   BrowserThread::PostTask(
158       BrowserThread::UI, FROM_HERE,
159       base::Bind(
160           &ChromeExtensionMessageFilter::OpenChannelToExtensionOnUIThread,
161           this, render_process_id_, routing_id, port2_id, info,
162           channel_name, include_tls_channel_id));
163 }
164
165 void ChromeExtensionMessageFilter::OpenChannelToExtensionOnUIThread(
166     int source_process_id, int source_routing_id,
167     int receiver_port_id,
168     const ExtensionMsg_ExternalConnectionInfo& info,
169     const std::string& channel_name,
170     bool include_tls_channel_id) {
171   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172   if (profile_) {
173     extensions::MessageService::Get(profile_)
174         ->OpenChannelToExtension(source_process_id,
175                                  source_routing_id,
176                                  receiver_port_id,
177                                  info.source_id,
178                                  info.target_id,
179                                  info.source_url,
180                                  channel_name,
181                                  include_tls_channel_id);
182   }
183 }
184
185 void ChromeExtensionMessageFilter::OnOpenChannelToNativeApp(
186     int routing_id,
187     const std::string& source_extension_id,
188     const std::string& native_app_name,
189     int* port_id) {
190   int port2_id;
191   extensions::MessageService::AllocatePortIdPair(port_id, &port2_id);
192
193   BrowserThread::PostTask(
194       BrowserThread::UI, FROM_HERE,
195       base::Bind(
196           &ChromeExtensionMessageFilter::OpenChannelToNativeAppOnUIThread,
197           this, routing_id, port2_id, source_extension_id, native_app_name));
198 }
199
200 void ChromeExtensionMessageFilter::OpenChannelToNativeAppOnUIThread(
201     int source_routing_id,
202     int receiver_port_id,
203     const std::string& source_extension_id,
204     const std::string& native_app_name) {
205   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
206   if (profile_) {
207     extensions::MessageService::Get(profile_)
208         ->OpenChannelToNativeApp(render_process_id_,
209                                  source_routing_id,
210                                  receiver_port_id,
211                                  source_extension_id,
212                                  native_app_name);
213   }
214 }
215
216 void ChromeExtensionMessageFilter::OnOpenChannelToTab(
217     int routing_id, int tab_id, const std::string& extension_id,
218     const std::string& channel_name, int* port_id) {
219   int port2_id;
220   extensions::MessageService::AllocatePortIdPair(port_id, &port2_id);
221
222   BrowserThread::PostTask(
223       BrowserThread::UI, FROM_HERE,
224       base::Bind(&ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread,
225                  this, render_process_id_, routing_id, port2_id, tab_id,
226                  extension_id, channel_name));
227 }
228
229 void ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread(
230     int source_process_id, int source_routing_id,
231     int receiver_port_id,
232     int tab_id,
233     const std::string& extension_id,
234     const std::string& channel_name) {
235   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236   if (profile_) {
237     extensions::MessageService::Get(profile_)
238         ->OpenChannelToTab(source_process_id,
239                            source_routing_id,
240                            receiver_port_id,
241                            tab_id,
242                            extension_id,
243                            channel_name);
244   }
245 }
246
247 void ChromeExtensionMessageFilter::OnGetExtMessageBundle(
248     const std::string& extension_id, IPC::Message* reply_msg) {
249   const extensions::Extension* extension =
250       extension_info_map_->extensions().GetByID(extension_id);
251   base::FilePath extension_path;
252   std::string default_locale;
253   if (extension) {
254     extension_path = extension->path();
255     default_locale = extensions::LocaleInfo::GetDefaultLocale(extension);
256   }
257
258   BrowserThread::PostBlockingPoolTask(
259       FROM_HERE,
260       base::Bind(
261           &ChromeExtensionMessageFilter::OnGetExtMessageBundleOnBlockingPool,
262           this, extension_path, extension_id, default_locale, reply_msg));
263 }
264
265 void ChromeExtensionMessageFilter::OnGetExtMessageBundleOnBlockingPool(
266     const base::FilePath& extension_path,
267     const std::string& extension_id,
268     const std::string& default_locale,
269     IPC::Message* reply_msg) {
270   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
271
272   scoped_ptr<extensions::MessageBundle::SubstitutionMap> dictionary_map(
273       extensions::file_util::LoadMessageBundleSubstitutionMap(
274           extension_path, extension_id, default_locale));
275
276   ExtensionHostMsg_GetMessageBundle::WriteReplyParams(reply_msg,
277                                                       *dictionary_map);
278   Send(reply_msg);
279 }
280
281 void ChromeExtensionMessageFilter::OnExtensionCloseChannel(
282     int port_id,
283     const std::string& error_message) {
284   if (!content::RenderProcessHost::FromID(render_process_id_))
285     return;  // To guard against crash in browser_tests shutdown.
286
287   extensions::MessageService* message_service =
288       extensions::MessageService::Get(profile_);
289   if (message_service)
290     message_service->CloseChannel(port_id, error_message);
291 }
292
293 void ChromeExtensionMessageFilter::OnAddAPIActionToExtensionActivityLog(
294     const std::string& extension_id,
295     const ExtensionHostMsg_APIActionOrEvent_Params& params) {
296   scoped_refptr<extensions::Action> action = new extensions::Action(
297       extension_id, base::Time::Now(), extensions::Action::ACTION_API_CALL,
298       params.api_call);
299   action->set_args(make_scoped_ptr(params.arguments.DeepCopy()));
300   if (!params.extra.empty()) {
301     action->mutable_other()->SetString(
302         activity_log_constants::kActionExtra, params.extra);
303   }
304   AddActionToExtensionActivityLog(profile_, action);
305 }
306
307 void ChromeExtensionMessageFilter::OnAddDOMActionToExtensionActivityLog(
308     const std::string& extension_id,
309     const ExtensionHostMsg_DOMAction_Params& params) {
310   scoped_refptr<extensions::Action> action = new extensions::Action(
311       extension_id, base::Time::Now(), extensions::Action::ACTION_DOM_ACCESS,
312       params.api_call);
313   action->set_args(make_scoped_ptr(params.arguments.DeepCopy()));
314   action->set_page_url(params.url);
315   action->set_page_title(base::UTF16ToUTF8(params.url_title));
316   action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
317                                       params.call_type);
318   AddActionToExtensionActivityLog(profile_, action);
319 }
320
321 void ChromeExtensionMessageFilter::OnAddEventToExtensionActivityLog(
322     const std::string& extension_id,
323     const ExtensionHostMsg_APIActionOrEvent_Params& params) {
324   scoped_refptr<extensions::Action> action = new extensions::Action(
325       extension_id, base::Time::Now(), extensions::Action::ACTION_API_EVENT,
326       params.api_call);
327   action->set_args(make_scoped_ptr(params.arguments.DeepCopy()));
328   if (!params.extra.empty()) {
329     action->mutable_other()->SetString(activity_log_constants::kActionExtra,
330                                        params.extra);
331   }
332   AddActionToExtensionActivityLog(profile_, action);
333 }
334
335 void ChromeExtensionMessageFilter::Observe(
336     int type,
337     const content::NotificationSource& source,
338     const content::NotificationDetails& details) {
339   DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
340   profile_ = NULL;
341 }