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