Home | History | Annotate | Download | only in pepper
      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, &params);
    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