Home | History | Annotate | Download | only in npapi
      1 // Copyright 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 "content/child/npapi/npobject_stub.h"
      6 
      7 #include "content/child/npapi/np_channel_base.h"
      8 #include "content/child/npapi/npobject_util.h"
      9 #include "content/child/plugin_messages.h"
     10 #include "content/public/common/content_client.h"
     11 #include "content/public/common/content_switches.h"
     12 #include "third_party/WebKit/public/web/WebBindings.h"
     13 #include "third_party/npapi/bindings/npapi.h"
     14 #include "third_party/npapi/bindings/npruntime.h"
     15 
     16 #if defined(OS_WIN)
     17 #include "base/command_line.h"
     18 #include "content/common/plugin_constants_win.h"
     19 #endif
     20 
     21 using blink::WebBindings;
     22 
     23 namespace content {
     24 
     25 NPObjectStub::NPObjectStub(
     26     NPObject* npobject,
     27     NPChannelBase* channel,
     28     int route_id,
     29     int render_view_id,
     30     const GURL& page_url)
     31     : npobject_(npobject),
     32       channel_(channel),
     33       route_id_(route_id),
     34       render_view_id_(render_view_id),
     35       page_url_(page_url) {
     36   channel_->AddMappingForNPObjectStub(route_id, npobject);
     37   channel_->AddRoute(route_id, this, this);
     38 
     39   // We retain the object just as PluginHost does if everything was in-process.
     40   WebBindings::retainObject(npobject_);
     41 }
     42 
     43 NPObjectStub::~NPObjectStub() {
     44   channel_->RemoveRoute(route_id_);
     45   DCHECK(!npobject_);
     46 }
     47 
     48 void NPObjectStub::DeleteSoon() {
     49   if (npobject_) {
     50     channel_->RemoveMappingForNPObjectStub(route_id_, npobject_);
     51 
     52     // We need to NULL npobject_ prior to calling releaseObject() to avoid
     53     // problems with re-entrancy. See http://crbug.com/94179#c17 for more
     54     // details on how this can happen.
     55     NPObject* npobject = npobject_;
     56     npobject_ = NULL;
     57 
     58     WebBindings::releaseObject(npobject);
     59 
     60     base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
     61   }
     62 }
     63 
     64 bool NPObjectStub::Send(IPC::Message* msg) {
     65   return channel_->Send(msg);
     66 }
     67 
     68 NPObject* NPObjectStub::GetUnderlyingNPObject() {
     69   return npobject_;
     70 }
     71 
     72 IPC::Listener* NPObjectStub::GetChannelListener() {
     73   return static_cast<IPC::Listener*>(this);
     74 }
     75 
     76 bool NPObjectStub::OnMessageReceived(const IPC::Message& msg) {
     77   GetContentClient()->SetActiveURL(page_url_);
     78   if (!npobject_) {
     79     if (msg.is_sync()) {
     80       // The object could be garbage because the frame has gone away, so
     81       // just send an error reply to the caller.
     82       IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
     83       reply->set_reply_error();
     84       Send(reply);
     85     }
     86 
     87     return true;
     88   }
     89 
     90   bool handled = true;
     91   IPC_BEGIN_MESSAGE_MAP(NPObjectStub, msg)
     92     IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release, OnRelease);
     93     IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod, OnHasMethod);
     94     IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke, OnInvoke);
     95     IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty, OnHasProperty);
     96     IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty, OnGetProperty);
     97     IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_SetProperty, OnSetProperty);
     98     IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty, OnRemoveProperty);
     99     IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate, OnInvalidate);
    100     IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration, OnEnumeration);
    101     IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Construct, OnConstruct);
    102     IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate, OnEvaluate);
    103     IPC_MESSAGE_UNHANDLED(handled = false)
    104   IPC_END_MESSAGE_MAP()
    105   DCHECK(handled);
    106   return handled;
    107 }
    108 
    109 void NPObjectStub::OnChannelError() {
    110   DeleteSoon();
    111 }
    112 
    113 void NPObjectStub::OnRelease(IPC::Message* reply_msg) {
    114   Send(reply_msg);
    115   DeleteSoon();
    116 }
    117 
    118 void NPObjectStub::OnHasMethod(const NPIdentifier_Param& name,
    119                                bool* result) {
    120   NPIdentifier id = CreateNPIdentifier(name);
    121   // If we're in the plugin process, then the stub is holding onto an NPObject
    122   // from the plugin, so all function calls on it need to go through the
    123   // functions in NPClass.  If we're in the renderer process, then we just call
    124   // the NPN_ functions.
    125   if (IsPluginProcess()) {
    126     if (npobject_->_class->hasMethod) {
    127       *result = npobject_->_class->hasMethod(npobject_, id);
    128     } else {
    129       *result = false;
    130     }
    131   } else {
    132     *result = WebBindings::hasMethod(0, npobject_, id);
    133   }
    134 }
    135 
    136 void NPObjectStub::OnInvoke(bool is_default,
    137                             const NPIdentifier_Param& method,
    138                             const std::vector<NPVariant_Param>& args,
    139                             IPC::Message* reply_msg) {
    140   bool return_value = false;
    141   NPVariant_Param result_param;
    142   NPVariant result_var;
    143 
    144   VOID_TO_NPVARIANT(result_var);
    145   result_param.type = NPVARIANT_PARAM_VOID;
    146 
    147   int arg_count = static_cast<int>(args.size());
    148   NPVariant* args_var = new NPVariant[arg_count];
    149   for (int i = 0; i < arg_count; ++i) {
    150     if (!CreateNPVariant(args[i],
    151                          channel_.get(),
    152                          &(args_var[i]),
    153                          render_view_id_,
    154                          page_url_)) {
    155       NPObjectMsg_Invoke::WriteReplyParams(
    156           reply_msg, result_param, return_value);
    157       channel_->Send(reply_msg);
    158       delete[] args_var;
    159       return;
    160     }
    161   }
    162 
    163   if (is_default) {
    164     if (IsPluginProcess()) {
    165       if (npobject_->_class->invokeDefault) {
    166         return_value = npobject_->_class->invokeDefault(
    167             npobject_, args_var, arg_count, &result_var);
    168       } else {
    169         return_value = false;
    170       }
    171     } else {
    172       return_value = WebBindings::invokeDefault(
    173           0, npobject_, args_var, arg_count, &result_var);
    174     }
    175   } else {
    176     NPIdentifier id = CreateNPIdentifier(method);
    177     if (IsPluginProcess()) {
    178       if (npobject_->_class->invoke) {
    179         return_value = npobject_->_class->invoke(
    180             npobject_, id, args_var, arg_count, &result_var);
    181       } else {
    182         return_value = false;
    183       }
    184     } else {
    185       return_value = WebBindings::invoke(
    186           0, npobject_, id, args_var, arg_count, &result_var);
    187     }
    188   }
    189 
    190   for (int i = 0; i < arg_count; ++i)
    191     WebBindings::releaseVariantValue(&(args_var[i]));
    192 
    193   delete[] args_var;
    194 
    195   CreateNPVariantParam(result_var,
    196                        channel_.get(),
    197                        &result_param,
    198                        true,
    199                        render_view_id_,
    200                        page_url_);
    201   NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
    202   channel_->Send(reply_msg);
    203 }
    204 
    205 void NPObjectStub::OnHasProperty(const NPIdentifier_Param& name,
    206                                  bool* result) {
    207   NPIdentifier id = CreateNPIdentifier(name);
    208   if (IsPluginProcess()) {
    209     if (npobject_->_class->hasProperty) {
    210       *result = npobject_->_class->hasProperty(npobject_, id);
    211     } else {
    212       *result = false;
    213     }
    214   } else {
    215     *result = WebBindings::hasProperty(0, npobject_, id);
    216   }
    217 }
    218 
    219 void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name,
    220                                  NPVariant_Param* property,
    221                                  bool* result) {
    222   NPVariant result_var;
    223   VOID_TO_NPVARIANT(result_var);
    224   NPIdentifier id = CreateNPIdentifier(name);
    225 
    226   if (IsPluginProcess()) {
    227     if (npobject_->_class->getProperty) {
    228       *result = npobject_->_class->getProperty(npobject_, id, &result_var);
    229     } else {
    230       *result = false;
    231     }
    232   } else {
    233     *result = WebBindings::getProperty(0, npobject_, id, &result_var);
    234   }
    235 
    236   CreateNPVariantParam(
    237       result_var, channel_.get(), property, true, render_view_id_, page_url_);
    238 }
    239 
    240 void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name,
    241                                  const NPVariant_Param& property,
    242                                  IPC::Message* reply_msg) {
    243   bool result = false;
    244   NPIdentifier id = CreateNPIdentifier(name);
    245   NPVariant property_var;
    246   if (!CreateNPVariant(property,
    247                        channel_.get(),
    248                        &property_var,
    249                        render_view_id_,
    250                        page_url_)) {
    251     NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result);
    252     channel_->Send(reply_msg);
    253     return;
    254   }
    255 
    256   if (IsPluginProcess()) {
    257     if (npobject_->_class->setProperty) {
    258 #if defined(OS_WIN)
    259       static base::FilePath plugin_path =
    260           CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    261               switches::kPluginPath);
    262       static std::wstring filename = StringToLowerASCII(
    263           plugin_path.BaseName().value());
    264       static NPIdentifier fullscreen =
    265           WebBindings::getStringIdentifier("fullScreen");
    266       if (filename == kNewWMPPlugin && id == fullscreen) {
    267         // Workaround for bug 15985, which is if Flash causes WMP to go
    268         // full screen a deadlock can occur when WMP calls SetFocus.
    269         NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, true);
    270         Send(reply_msg);
    271         reply_msg = NULL;
    272       }
    273 #endif
    274       result = npobject_->_class->setProperty(npobject_, id, &property_var);
    275     } else {
    276       result = false;
    277     }
    278   } else {
    279     result = WebBindings::setProperty(0, npobject_, id, &property_var);
    280   }
    281 
    282   WebBindings::releaseVariantValue(&property_var);
    283 
    284   if (reply_msg) {
    285     NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result);
    286     Send(reply_msg);
    287   }
    288 }
    289 
    290 void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param& name,
    291                                     bool* result) {
    292   NPIdentifier id = CreateNPIdentifier(name);
    293   if (IsPluginProcess()) {
    294     if (npobject_->_class->removeProperty) {
    295       *result = npobject_->_class->removeProperty(npobject_, id);
    296     } else {
    297       *result = false;
    298     }
    299   } else {
    300     *result = WebBindings::removeProperty(0, npobject_, id);
    301   }
    302 }
    303 
    304 void NPObjectStub::OnInvalidate() {
    305   if (!IsPluginProcess()) {
    306     NOTREACHED() << "Should only be called on NPObjects in the plugin";
    307     return;
    308   }
    309 
    310   if (!npobject_->_class->invalidate)
    311     return;
    312 
    313   npobject_->_class->invalidate(npobject_);
    314 }
    315 
    316 void NPObjectStub::OnEnumeration(std::vector<NPIdentifier_Param>* value,
    317                                  bool* result) {
    318   NPIdentifier* value_np = NULL;
    319   unsigned int count = 0;
    320   if (!IsPluginProcess()) {
    321     *result = WebBindings::enumerate(0, npobject_, &value_np, &count);
    322   } else {
    323     if (npobject_->_class->structVersion < NP_CLASS_STRUCT_VERSION_ENUM ||
    324         !npobject_->_class->enumerate) {
    325       *result = false;
    326       return;
    327     }
    328 
    329     *result = npobject_->_class->enumerate(npobject_, &value_np, &count);
    330   }
    331 
    332   if (!*result)
    333     return;
    334 
    335   for (unsigned int i = 0; i < count; ++i) {
    336     NPIdentifier_Param param;
    337     CreateNPIdentifierParam(value_np[i], &param);
    338     value->push_back(param);
    339   }
    340 
    341   free(value_np);
    342 }
    343 
    344 void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args,
    345                                IPC::Message* reply_msg) {
    346   bool return_value = false;
    347   NPVariant_Param result_param;
    348   NPVariant result_var;
    349 
    350   VOID_TO_NPVARIANT(result_var);
    351 
    352   int arg_count = static_cast<int>(args.size());
    353   NPVariant* args_var = new NPVariant[arg_count];
    354   for (int i = 0; i < arg_count; ++i) {
    355     if (!CreateNPVariant(args[i],
    356                          channel_.get(),
    357                          &(args_var[i]),
    358                          render_view_id_,
    359                          page_url_)) {
    360       NPObjectMsg_Invoke::WriteReplyParams(
    361           reply_msg, result_param, return_value);
    362       channel_->Send(reply_msg);
    363       delete[] args_var;
    364       return;
    365     }
    366   }
    367 
    368   if (IsPluginProcess()) {
    369     if (npobject_->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR &&
    370         npobject_->_class->construct) {
    371       return_value = npobject_->_class->construct(
    372           npobject_, args_var, arg_count, &result_var);
    373     } else {
    374       return_value = false;
    375     }
    376   } else {
    377     return_value = WebBindings::construct(
    378         0, npobject_, args_var, arg_count, &result_var);
    379   }
    380 
    381   for (int i = 0; i < arg_count; ++i)
    382     WebBindings::releaseVariantValue(&(args_var[i]));
    383 
    384   delete[] args_var;
    385 
    386   CreateNPVariantParam(result_var,
    387                        channel_.get(),
    388                        &result_param,
    389                        true,
    390                        render_view_id_,
    391                        page_url_);
    392   NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value);
    393   channel_->Send(reply_msg);
    394 }
    395 
    396 void NPObjectStub::OnEvaluate(const std::string& script,
    397                               bool popups_allowed,
    398                               IPC::Message* reply_msg) {
    399   if (IsPluginProcess()) {
    400     NOTREACHED() << "Should only be called on NPObjects in the renderer";
    401     return;
    402   }
    403 
    404   NPVariant result_var;
    405   NPString script_string;
    406   script_string.UTF8Characters = script.c_str();
    407   script_string.UTF8Length = static_cast<unsigned int>(script.length());
    408 
    409   bool return_value = WebBindings::evaluateHelper(0, popups_allowed, npobject_,
    410                                                   &script_string, &result_var);
    411 
    412   NPVariant_Param result_param;
    413   CreateNPVariantParam(result_var,
    414                        channel_.get(),
    415                        &result_param,
    416                        true,
    417                        render_view_id_,
    418                        page_url_);
    419   NPObjectMsg_Evaluate::WriteReplyParams(reply_msg, result_param, return_value);
    420   channel_->Send(reply_msg);
    421 }
    422 
    423 }  // namespace content
    424