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.
5 #include "chrome/browser/renderer_host/pepper/pepper_extensions_common_message_filter.h"
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"
30 class PepperExtensionsCommonMessageFilter::DispatcherOwner
31 : public content::WebContentsObserver,
32 public extensions::ExtensionFunctionDispatcher::Delegate {
34 DispatcherOwner(PepperExtensionsCommonMessageFilter* message_filter,
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) {}
43 virtual ~DispatcherOwner() { message_filter_->DetachDispatcherOwner(); }
45 // content::WebContentsObserver implementation.
46 virtual void RenderFrameDeleted(content::RenderFrameHost* render_frame_host)
48 if (render_frame_host == render_frame_host_)
52 // extensions::ExtensionFunctionDispatcher::Delegate implementation.
53 virtual extensions::WindowController* GetExtensionWindowController() const
59 virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE {
64 extensions::ExtensionFunctionDispatcher* dispatcher() { return &dispatcher_; }
65 content::RenderFrameHost* render_frame_host() { return render_frame_host_; }
68 content::RenderFrameHost* render_frame_host_;
69 scoped_refptr<PepperExtensionsCommonMessageFilter> message_filter_;
70 extensions::ExtensionFunctionDispatcher dispatcher_;
72 DISALLOW_COPY_AND_ASSIGN(DispatcherOwner);
76 PepperExtensionsCommonMessageFilter*
77 PepperExtensionsCommonMessageFilter::Create(content::BrowserPpapiHost* host,
78 PP_Instance instance) {
79 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
81 int render_process_id = 0;
82 int render_frame_id = 0;
83 if (!host->GetRenderFrameIDsForInstance(
84 instance, &render_process_id, &render_frame_id)) {
88 base::FilePath profile_directory = host->GetProfileDataDirectory();
89 GURL document_url = host->GetDocumentURLForInstance(instance);
91 return new PepperExtensionsCommonMessageFilter(
92 render_process_id, render_frame_id, profile_directory, document_url);
95 PepperExtensionsCommonMessageFilter::PepperExtensionsCommonMessageFilter(
96 int render_process_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) {}
107 PepperExtensionsCommonMessageFilter::~PepperExtensionsCommonMessageFilter() {}
109 scoped_refptr<base::TaskRunner>
110 PepperExtensionsCommonMessageFilter::OverrideTaskRunnerForMessage(
111 const IPC::Message& msg) {
112 return content::BrowserThread::GetMessageLoopProxyForThread(
113 content::BrowserThread::UI);
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;
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));
132 if (!EnsureDispatcherOwnerInitialized())
133 return PP_ERROR_FAILED;
135 ExtensionHostMsg_Request_Params params;
136 PopulateParams(request_name, &args, false, ¶ms);
138 dispatcher_owner_->dispatcher()->Dispatch(
139 params, dispatcher_owner_->render_frame_host()->GetRenderViewHost());
140 // There will be no callback so return PP_OK.
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));
150 if (!EnsureDispatcherOwnerInitialized())
151 return PP_ERROR_FAILED;
153 ExtensionHostMsg_Request_Params params;
154 PopulateParams(request_name, &args, true, ¶ms);
156 dispatcher_owner_->dispatcher()->DispatchWithCallback(
158 dispatcher_owner_->render_frame_host(),
159 base::Bind(&PepperExtensionsCommonMessageFilter::OnCallCompleted,
161 context->MakeReplyMessageContext()));
162 return PP_OK_COMPLETIONPENDING;
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;
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);
177 if (!document_url_.SchemeIs(extensions::kExtensionScheme))
180 ProfileManager* profile_manager = g_browser_process->profile_manager();
181 if (!profile_manager)
183 Profile* profile = profile_manager->GetProfile(profile_directory_);
185 // It will be automatically destroyed when |view_host| goes away.
187 new DispatcherOwner(this, profile, frame_host, web_contents);
191 void PepperExtensionsCommonMessageFilter::DetachDispatcherOwner() {
192 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
193 dispatcher_owner_ = NULL;
196 void PepperExtensionsCommonMessageFilter::PopulateParams(
197 const std::string& request_name,
198 base::ListValue* args,
200 ExtensionHostMsg_Request_Params* params) {
201 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
203 params->name = request_name;
204 params->arguments.Swap(args);
206 params->extension_id = document_url_.host();
207 params->source_url = document_url_;
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;
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));
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;
229 reply_context.params.set_result(
230 type == ExtensionFunction::SUCCEEDED ? PP_OK : PP_ERROR_FAILED);
231 SendReply(reply_context, PpapiPluginMsg_ExtensionsCommon_CallReply(results));
234 } // namespace chrome