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