Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / pepper / pepper_extensions_common_message_filter.cc
1 // Copyright (c) 2013 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/pepper/pepper_extensions_common_message_filter.h"
6
7 #include "base/logging.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/values.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_manager.h"
13 #include "content/public/browser/browser_ppapi_host.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_observer.h"
18 #include "extensions/browser/extension_function_dispatcher.h"
19 #include "extensions/common/constants.h"
20 #include "extensions/common/extension_messages.h"
21 #include "ipc/ipc_message.h"
22 #include "ipc/ipc_message_macros.h"
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/host/dispatch_host_message.h"
25 #include "ppapi/host/host_message_context.h"
26 #include "ppapi/proxy/ppapi_messages.h"
27
28 namespace chrome {
29
30 class PepperExtensionsCommonMessageFilter::DispatcherOwner
31     : public content::WebContentsObserver,
32       public extensions::ExtensionFunctionDispatcher::Delegate {
33  public:
34   DispatcherOwner(PepperExtensionsCommonMessageFilter* message_filter,
35                   Profile* profile,
36                   content::RenderFrameHost* frame_host,
37                   content::WebContents* web_contents)
38       : content::WebContentsObserver(web_contents),
39         render_frame_host_(frame_host),
40         message_filter_(message_filter),
41         dispatcher_(profile, this) {}
42
43   virtual ~DispatcherOwner() { message_filter_->DetachDispatcherOwner(); }
44
45   // content::WebContentsObserver implementation.
46   virtual void RenderFrameDeleted(content::RenderFrameHost* render_frame_host)
47       OVERRIDE {
48     if (render_frame_host == render_frame_host_)
49       delete this;
50   }
51
52   // extensions::ExtensionFunctionDispatcher::Delegate implementation.
53   virtual extensions::WindowController* GetExtensionWindowController() const
54       OVERRIDE {
55     NOTREACHED();
56     return NULL;
57   }
58
59   virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE {
60     NOTREACHED();
61     return NULL;
62   }
63
64   extensions::ExtensionFunctionDispatcher* dispatcher() { return &dispatcher_; }
65   content::RenderFrameHost* render_frame_host() { return render_frame_host_; }
66
67  private:
68   content::RenderFrameHost* render_frame_host_;
69   scoped_refptr<PepperExtensionsCommonMessageFilter> message_filter_;
70   extensions::ExtensionFunctionDispatcher dispatcher_;
71
72   DISALLOW_COPY_AND_ASSIGN(DispatcherOwner);
73 };
74
75 // static
76 PepperExtensionsCommonMessageFilter*
77 PepperExtensionsCommonMessageFilter::Create(content::BrowserPpapiHost* host,
78                                             PP_Instance instance) {
79   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
80
81   int render_process_id = 0;
82   int render_frame_id = 0;
83   if (!host->GetRenderFrameIDsForInstance(
84           instance, &render_process_id, &render_frame_id)) {
85     return NULL;
86   }
87
88   base::FilePath profile_directory = host->GetProfileDataDirectory();
89   GURL document_url = host->GetDocumentURLForInstance(instance);
90
91   return new PepperExtensionsCommonMessageFilter(
92       render_process_id, render_frame_id, profile_directory, document_url);
93 }
94
95 PepperExtensionsCommonMessageFilter::PepperExtensionsCommonMessageFilter(
96     int render_process_id,
97     int render_frame_id,
98     const base::FilePath& profile_directory,
99     const GURL& document_url)
100     : render_process_id_(render_process_id),
101       render_frame_id_(render_frame_id),
102       profile_directory_(profile_directory),
103       document_url_(document_url),
104       dispatcher_owner_(NULL),
105       dispatcher_owner_initialized_(false) {}
106
107 PepperExtensionsCommonMessageFilter::~PepperExtensionsCommonMessageFilter() {}
108
109 scoped_refptr<base::TaskRunner>
110 PepperExtensionsCommonMessageFilter::OverrideTaskRunnerForMessage(
111     const IPC::Message& msg) {
112   return content::BrowserThread::GetMessageLoopProxyForThread(
113       content::BrowserThread::UI);
114 }
115
116 int32_t PepperExtensionsCommonMessageFilter::OnResourceMessageReceived(
117     const IPC::Message& msg,
118     ppapi::host::HostMessageContext* context) {
119   IPC_BEGIN_MESSAGE_MAP(PepperExtensionsCommonMessageFilter, msg)
120   PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_ExtensionsCommon_Post, OnPost)
121   PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_ExtensionsCommon_Call, OnCall)
122   IPC_END_MESSAGE_MAP()
123   return PP_ERROR_FAILED;
124 }
125
126 int32_t PepperExtensionsCommonMessageFilter::OnPost(
127     ppapi::host::HostMessageContext* context,
128     const std::string& request_name,
129     base::ListValue& args) {
130   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
131
132   if (!EnsureDispatcherOwnerInitialized())
133     return PP_ERROR_FAILED;
134
135   ExtensionHostMsg_Request_Params params;
136   PopulateParams(request_name, &args, false, &params);
137
138   dispatcher_owner_->dispatcher()->Dispatch(
139       params, dispatcher_owner_->render_frame_host()->GetRenderViewHost());
140   // There will be no callback so return PP_OK.
141   return PP_OK;
142 }
143
144 int32_t PepperExtensionsCommonMessageFilter::OnCall(
145     ppapi::host::HostMessageContext* context,
146     const std::string& request_name,
147     base::ListValue& args) {
148   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
149
150   if (!EnsureDispatcherOwnerInitialized())
151     return PP_ERROR_FAILED;
152
153   ExtensionHostMsg_Request_Params params;
154   PopulateParams(request_name, &args, true, &params);
155
156   dispatcher_owner_->dispatcher()->DispatchWithCallback(
157       params,
158       dispatcher_owner_->render_frame_host(),
159       base::Bind(&PepperExtensionsCommonMessageFilter::OnCallCompleted,
160                  this,
161                  context->MakeReplyMessageContext()));
162   return PP_OK_COMPLETIONPENDING;
163 }
164
165 bool PepperExtensionsCommonMessageFilter::EnsureDispatcherOwnerInitialized() {
166   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
167   if (dispatcher_owner_initialized_)
168     return (!!dispatcher_owner_);
169   dispatcher_owner_initialized_ = true;
170
171   DCHECK(!dispatcher_owner_);
172   content::RenderFrameHost* frame_host =
173       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
174   content::WebContents* web_contents =
175       content::WebContents::FromRenderFrameHost(frame_host);
176
177   if (!document_url_.SchemeIs(extensions::kExtensionScheme))
178     return false;
179
180   ProfileManager* profile_manager = g_browser_process->profile_manager();
181   if (!profile_manager)
182     return false;
183   Profile* profile = profile_manager->GetProfile(profile_directory_);
184
185   // It will be automatically destroyed when |view_host| goes away.
186   dispatcher_owner_ =
187       new DispatcherOwner(this, profile, frame_host, web_contents);
188   return true;
189 }
190
191 void PepperExtensionsCommonMessageFilter::DetachDispatcherOwner() {
192   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
193   dispatcher_owner_ = NULL;
194 }
195
196 void PepperExtensionsCommonMessageFilter::PopulateParams(
197     const std::string& request_name,
198     base::ListValue* args,
199     bool has_callback,
200     ExtensionHostMsg_Request_Params* params) {
201   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
202
203   params->name = request_name;
204   params->arguments.Swap(args);
205
206   params->extension_id = document_url_.host();
207   params->source_url = document_url_;
208
209   // We don't need an ID to map a response to the corresponding request.
210   params->request_id = 0;
211   params->has_callback = has_callback;
212   params->user_gesture = false;
213 }
214
215 void PepperExtensionsCommonMessageFilter::OnCallCompleted(
216     ppapi::host::ReplyMessageContext reply_context,
217     ExtensionFunction::ResponseType type,
218     const base::ListValue& results,
219     const std::string& /* error */) {
220   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
221
222   if (type == ExtensionFunction::BAD_MESSAGE) {
223     // The input arguments were not validated at the plugin side, so don't kill
224     // the plugin process when we see a message with invalid arguments.
225     // TODO(yzshen): It is nicer to also do the validation at the plugin side.
226     type = ExtensionFunction::FAILED;
227   }
228
229   reply_context.params.set_result(
230       type == ExtensionFunction::SUCCEEDED ? PP_OK : PP_ERROR_FAILED);
231   SendReply(reply_context, PpapiPluginMsg_ExtensionsCommon_CallReply(results));
232 }
233
234 }  // namespace chrome