• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NPObjectStub(NPObject * npobject,NPChannelBase * channel,int route_id,int render_view_id,const GURL & page_url)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 
~NPObjectStub()43 NPObjectStub::~NPObjectStub() {
44   channel_->RemoveRoute(route_id_);
45   DCHECK(!npobject_);
46 }
47 
DeleteSoon()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 
Send(IPC::Message * msg)64 bool NPObjectStub::Send(IPC::Message* msg) {
65   return channel_->Send(msg);
66 }
67 
GetUnderlyingNPObject()68 NPObject* NPObjectStub::GetUnderlyingNPObject() {
69   return npobject_;
70 }
71 
GetChannelListener()72 IPC::Listener* NPObjectStub::GetChannelListener() {
73   return static_cast<IPC::Listener*>(this);
74 }
75 
OnMessageReceived(const IPC::Message & msg)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 
OnChannelError()109 void NPObjectStub::OnChannelError() {
110   DeleteSoon();
111 }
112 
OnRelease(IPC::Message * reply_msg)113 void NPObjectStub::OnRelease(IPC::Message* reply_msg) {
114   Send(reply_msg);
115   DeleteSoon();
116 }
117 
OnHasMethod(const NPIdentifier_Param & name,bool * result)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 
OnInvoke(bool is_default,const NPIdentifier_Param & method,const std::vector<NPVariant_Param> & args,IPC::Message * reply_msg)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 
OnHasProperty(const NPIdentifier_Param & name,bool * result)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 
OnGetProperty(const NPIdentifier_Param & name,NPVariant_Param * property,bool * result)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 
OnSetProperty(const NPIdentifier_Param & name,const NPVariant_Param & property,IPC::Message * reply_msg)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           base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
261               switches::kPluginPath);
262       static std::wstring filename = base::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 
OnRemoveProperty(const NPIdentifier_Param & name,bool * result)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 
OnInvalidate()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 
OnEnumeration(std::vector<NPIdentifier_Param> * value,bool * result)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 
OnConstruct(const std::vector<NPVariant_Param> & args,IPC::Message * reply_msg)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 
OnEvaluate(const std::string & script,bool popups_allowed,IPC::Message * reply_msg)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