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