OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/common/npobject_proxy.h" | |
6 | |
7 #include "content/common/np_channel_base.h" | |
8 #include "content/common/npobject_util.h" | |
9 #include "content/common/plugin_messages.h" | |
10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" | |
11 #include "webkit/glue/webkit_glue.h" | |
12 #include "webkit/plugins/npapi/plugin_instance.h" | |
13 #include "webkit/plugins/npapi/plugin_host.h" | |
14 | |
15 using WebKit::WebBindings; | |
16 | |
17 namespace content { | |
18 | |
19 struct NPObjectWrapper { | |
20 NPObject object; | |
21 NPObjectProxy* proxy; | |
22 }; | |
23 | |
24 NPClass NPObjectProxy::npclass_proxy_ = { | |
25 NP_CLASS_STRUCT_VERSION, | |
26 NPObjectProxy::NPAllocate, | |
27 NPObjectProxy::NPDeallocate, | |
28 NPObjectProxy::NPPInvalidate, | |
29 NPObjectProxy::NPHasMethod, | |
30 NPObjectProxy::NPInvoke, | |
31 NPObjectProxy::NPInvokeDefault, | |
32 NPObjectProxy::NPHasProperty, | |
33 NPObjectProxy::NPGetProperty, | |
34 NPObjectProxy::NPSetProperty, | |
35 NPObjectProxy::NPRemoveProperty, | |
36 NPObjectProxy::NPNEnumerate, | |
37 NPObjectProxy::NPNConstruct | |
38 }; | |
39 | |
40 NPObjectProxy* NPObjectProxy::GetProxy(NPObject* object) { | |
41 NPObjectProxy* proxy = NULL; | |
42 | |
43 // Wrapper exists only for NPObjects that we had created. | |
44 if (&npclass_proxy_ == object->_class) { | |
45 NPObjectWrapper* wrapper = reinterpret_cast<NPObjectWrapper*>(object); | |
46 proxy = wrapper->proxy; | |
47 } | |
48 | |
49 return proxy; | |
50 } | |
51 | |
52 NPObject* NPObjectProxy::GetUnderlyingNPObject() { | |
53 return NULL; | |
54 } | |
55 | |
56 IPC::Listener* NPObjectProxy::GetChannelListener() { | |
57 return static_cast<IPC::Listener*>(this); | |
58 } | |
59 | |
60 NPObjectProxy::NPObjectProxy( | |
61 NPChannelBase* channel, | |
62 int route_id, | |
63 int render_view_id, | |
64 const GURL& page_url) | |
65 : channel_(channel), | |
66 route_id_(route_id), | |
67 render_view_id_(render_view_id), | |
68 page_url_(page_url) { | |
69 channel_->AddRoute(route_id, this, this); | |
70 } | |
71 | |
72 NPObjectProxy::~NPObjectProxy() { | |
73 if (channel_) { | |
74 // This NPObjectProxy instance is now invalid and should not be reused for | |
75 // requests initiated by plugins. We may receive requests for the | |
76 // same NPObject in the context of the outgoing NPObjectMsg_Release call. | |
77 // We should be creating new NPObjectProxy instances to wrap these | |
78 // NPObjects. | |
79 channel_->RemoveMappingForNPObjectProxy(route_id_); | |
80 channel_->RemoveRoute(route_id_); | |
81 Send(new NPObjectMsg_Release(route_id_)); | |
82 } | |
83 } | |
84 | |
85 NPObject* NPObjectProxy::Create(NPChannelBase* channel, | |
86 int route_id, | |
87 int render_view_id, | |
88 const GURL& page_url) { | |
89 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>( | |
90 WebBindings::createObject(0, &npclass_proxy_)); | |
91 obj->proxy = new NPObjectProxy(channel, route_id, render_view_id, page_url); | |
92 channel->AddMappingForNPObjectProxy(route_id, &obj->object); | |
93 return reinterpret_cast<NPObject*>(obj); | |
94 } | |
95 | |
96 bool NPObjectProxy::Send(IPC::Message* msg) { | |
97 if (channel_) | |
98 return channel_->Send(msg); | |
99 | |
100 delete msg; | |
101 return false; | |
102 } | |
103 | |
104 NPObject* NPObjectProxy::NPAllocate(NPP, NPClass*) { | |
105 return reinterpret_cast<NPObject*>(new NPObjectWrapper); | |
106 } | |
107 | |
108 void NPObjectProxy::NPDeallocate(NPObject* npObj) { | |
109 NPObjectWrapper* obj = reinterpret_cast<NPObjectWrapper*>(npObj); | |
110 delete obj->proxy; | |
111 delete obj; | |
112 } | |
113 | |
114 bool NPObjectProxy::OnMessageReceived(const IPC::Message& msg) { | |
115 NOTREACHED(); | |
116 return false; | |
117 } | |
118 | |
119 void NPObjectProxy::OnChannelError() { | |
120 // Release our ref count of the plugin channel object, as it addrefs the | |
121 // process. | |
122 channel_ = NULL; | |
123 } | |
124 | |
125 bool NPObjectProxy::NPHasMethod(NPObject *obj, | |
126 NPIdentifier name) { | |
127 if (obj == NULL) | |
128 return false; | |
129 | |
130 bool result = false; | |
131 NPObjectProxy* proxy = GetProxy(obj); | |
132 | |
133 if (!proxy) { | |
134 return obj->_class->hasMethod(obj, name); | |
135 } | |
136 | |
137 NPIdentifier_Param name_param; | |
138 CreateNPIdentifierParam(name, &name_param); | |
139 | |
140 proxy->Send(new NPObjectMsg_HasMethod(proxy->route_id(), name_param, | |
141 &result)); | |
142 return result; | |
143 } | |
144 | |
145 bool NPObjectProxy::NPInvoke(NPObject *obj, | |
146 NPIdentifier name, | |
147 const NPVariant *args, | |
148 uint32_t arg_count, | |
149 NPVariant *result) { | |
150 return NPInvokePrivate(0, obj, false, name, args, arg_count, result); | |
151 } | |
152 | |
153 bool NPObjectProxy::NPInvokeDefault(NPObject *npobj, | |
154 const NPVariant *args, | |
155 uint32_t arg_count, | |
156 NPVariant *result) { | |
157 return NPInvokePrivate(0, npobj, true, 0, args, arg_count, result); | |
158 } | |
159 | |
160 bool NPObjectProxy::NPInvokePrivate(NPP npp, | |
161 NPObject *obj, | |
162 bool is_default, | |
163 NPIdentifier name, | |
164 const NPVariant *args, | |
165 uint32_t arg_count, | |
166 NPVariant *np_result) { | |
167 if (obj == NULL) | |
168 return false; | |
169 | |
170 NPObjectProxy* proxy = GetProxy(obj); | |
171 if (!proxy) { | |
172 if (is_default) { | |
173 return obj->_class->invokeDefault(obj, args, arg_count, np_result); | |
174 } else { | |
175 return obj->_class->invoke(obj, name, args, arg_count, np_result); | |
176 } | |
177 } | |
178 | |
179 bool result = false; | |
180 int render_view_id = proxy->render_view_id_; | |
181 NPIdentifier_Param name_param; | |
182 if (is_default) { | |
183 // The data won't actually get used, but set it so we don't send random | |
184 // data. | |
185 name_param.identifier = NULL; | |
186 } else { | |
187 CreateNPIdentifierParam(name, &name_param); | |
188 } | |
189 | |
190 // Note: This instance can get destroyed in the context of | |
191 // Send so addref the channel in this scope. | |
192 scoped_refptr<NPChannelBase> channel_copy = proxy->channel_; | |
193 std::vector<NPVariant_Param> args_param; | |
194 for (unsigned int i = 0; i < arg_count; ++i) { | |
195 NPVariant_Param param; | |
196 CreateNPVariantParam( | |
197 args[i], channel_copy, ¶m, false, render_view_id, | |
198 proxy->page_url_); | |
199 args_param.push_back(param); | |
200 } | |
201 | |
202 NPVariant_Param param_result; | |
203 NPObjectMsg_Invoke* msg = new NPObjectMsg_Invoke( | |
204 proxy->route_id_, is_default, name_param, args_param, ¶m_result, | |
205 &result); | |
206 | |
207 // If we're in the plugin process and this invoke leads to a dialog box, the | |
208 // plugin will hang the window hierarchy unless we pump the window message | |
209 // queue while waiting for a reply. We need to do this to simulate what | |
210 // happens when everything runs in-process (while calling MessageBox window | |
211 // messages are pumped). | |
212 if (IsPluginProcess() && proxy->channel()) { | |
213 msg->set_pump_messages_event( | |
214 proxy->channel()->GetModalDialogEvent(render_view_id)); | |
215 } | |
216 | |
217 GURL page_url = proxy->page_url_; | |
218 proxy->Send(msg); | |
219 | |
220 // Send may delete proxy. | |
221 proxy = NULL; | |
222 | |
223 if (!result) | |
224 return false; | |
225 | |
226 CreateNPVariant( | |
227 param_result, channel_copy, np_result, render_view_id, page_url); | |
228 return true; | |
229 } | |
230 | |
231 bool NPObjectProxy::NPHasProperty(NPObject *obj, | |
232 NPIdentifier name) { | |
233 if (obj == NULL) | |
234 return false; | |
235 | |
236 bool result = false; | |
237 NPObjectProxy* proxy = GetProxy(obj); | |
238 if (!proxy) { | |
239 return obj->_class->hasProperty(obj, name); | |
240 } | |
241 | |
242 NPIdentifier_Param name_param; | |
243 CreateNPIdentifierParam(name, &name_param); | |
244 | |
245 NPVariant_Param param; | |
246 proxy->Send(new NPObjectMsg_HasProperty( | |
247 proxy->route_id(), name_param, &result)); | |
248 | |
249 // Send may delete proxy. | |
250 proxy = NULL; | |
251 | |
252 return result; | |
253 } | |
254 | |
255 bool NPObjectProxy::NPGetProperty(NPObject *obj, | |
256 NPIdentifier name, | |
257 NPVariant *np_result) { | |
258 // Please refer to http://code.google.com/p/chromium/issues/detail?id=2556, | |
259 // which was a crash in the XStandard plugin during plugin shutdown. The | |
260 // crash occured because the plugin requests the plugin script object, | |
261 // which fails. The plugin does not check the result of the operation and | |
262 // invokes NPN_GetProperty on a NULL object which lead to the crash. If | |
263 // we observe similar crashes in other methods in the future, these null | |
264 // checks may have to be replicated in the other methods in this class. | |
265 if (obj == NULL) | |
266 return false; | |
267 | |
268 NPObjectProxy* proxy = GetProxy(obj); | |
269 if (!proxy) { | |
270 return obj->_class->getProperty(obj, name, np_result); | |
271 } | |
272 | |
273 bool result = false; | |
274 int render_view_id = proxy->render_view_id_; | |
275 NPIdentifier_Param name_param; | |
276 CreateNPIdentifierParam(name, &name_param); | |
277 | |
278 NPVariant_Param param; | |
279 scoped_refptr<NPChannelBase> channel(proxy->channel_); | |
280 | |
281 GURL page_url = proxy->page_url_; | |
282 proxy->Send(new NPObjectMsg_GetProperty( | |
283 proxy->route_id(), name_param, ¶m, &result)); | |
284 // Send may delete proxy. | |
285 proxy = NULL; | |
286 if (!result) | |
287 return false; | |
288 | |
289 CreateNPVariant( | |
290 param, channel.get(), np_result, render_view_id, page_url); | |
291 | |
292 return true; | |
293 } | |
294 | |
295 bool NPObjectProxy::NPSetProperty(NPObject *obj, | |
296 NPIdentifier name, | |
297 const NPVariant *value) { | |
298 if (obj == NULL) | |
299 return false; | |
300 | |
301 NPObjectProxy* proxy = GetProxy(obj); | |
302 if (!proxy) { | |
303 return obj->_class->setProperty(obj, name, value); | |
304 } | |
305 | |
306 bool result = false; | |
307 int render_view_id = proxy->render_view_id_; | |
308 NPIdentifier_Param name_param; | |
309 CreateNPIdentifierParam(name, &name_param); | |
310 | |
311 NPVariant_Param value_param; | |
312 CreateNPVariantParam( | |
313 *value, proxy->channel(), &value_param, false, render_view_id, | |
314 proxy->page_url_); | |
315 | |
316 proxy->Send(new NPObjectMsg_SetProperty( | |
317 proxy->route_id(), name_param, value_param, &result)); | |
318 // Send may delete proxy. | |
319 proxy = NULL; | |
320 | |
321 return result; | |
322 } | |
323 | |
324 bool NPObjectProxy::NPRemoveProperty(NPObject *obj, | |
325 NPIdentifier name) { | |
326 if (obj == NULL) | |
327 return false; | |
328 | |
329 bool result = false; | |
330 NPObjectProxy* proxy = GetProxy(obj); | |
331 if (!proxy) { | |
332 return obj->_class->removeProperty(obj, name); | |
333 } | |
334 | |
335 NPIdentifier_Param name_param; | |
336 CreateNPIdentifierParam(name, &name_param); | |
337 | |
338 NPVariant_Param param; | |
339 proxy->Send(new NPObjectMsg_RemoveProperty( | |
340 proxy->route_id(), name_param, &result)); | |
341 // Send may delete proxy. | |
342 proxy = NULL; | |
343 | |
344 return result; | |
345 } | |
346 | |
347 void NPObjectProxy::NPPInvalidate(NPObject *obj) { | |
348 if (obj == NULL) | |
349 return; | |
350 | |
351 NPObjectProxy* proxy = GetProxy(obj); | |
352 if (!proxy) { | |
353 obj->_class->invalidate(obj); | |
354 return; | |
355 } | |
356 | |
357 proxy->Send(new NPObjectMsg_Invalidate(proxy->route_id())); | |
358 // Send may delete proxy. | |
359 proxy = NULL; | |
360 } | |
361 | |
362 bool NPObjectProxy::NPNEnumerate(NPObject *obj, | |
363 NPIdentifier **value, | |
364 uint32_t *count) { | |
365 if (obj == NULL) | |
366 return false; | |
367 | |
368 bool result = false; | |
369 NPObjectProxy* proxy = GetProxy(obj); | |
370 if (!proxy) { | |
371 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_ENUM) { | |
372 return obj->_class->enumerate(obj, value, count); | |
373 } else { | |
374 return false; | |
375 } | |
376 } | |
377 | |
378 std::vector<NPIdentifier_Param> value_param; | |
379 proxy->Send(new NPObjectMsg_Enumeration( | |
380 proxy->route_id(), &value_param, &result)); | |
381 // Send may delete proxy. | |
382 proxy = NULL; | |
383 | |
384 if (!result) | |
385 return false; | |
386 | |
387 *count = static_cast<unsigned int>(value_param.size()); | |
388 *value = static_cast<NPIdentifier *>( | |
389 webkit::npapi::PluginHost::Singleton()->host_functions()->memalloc( | |
390 sizeof(NPIdentifier) * *count)); | |
391 for (unsigned int i = 0; i < *count; ++i) | |
392 (*value)[i] = CreateNPIdentifier(value_param[i]); | |
393 | |
394 return true; | |
395 } | |
396 | |
397 bool NPObjectProxy::NPNConstruct(NPObject *obj, | |
398 const NPVariant *args, | |
399 uint32_t arg_count, | |
400 NPVariant *np_result) { | |
401 if (obj == NULL) | |
402 return false; | |
403 | |
404 NPObjectProxy* proxy = GetProxy(obj); | |
405 if (!proxy) { | |
406 if (obj->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR) { | |
407 return obj->_class->construct(obj, args, arg_count, np_result); | |
408 } else { | |
409 return false; | |
410 } | |
411 } | |
412 | |
413 bool result = false; | |
414 int render_view_id = proxy->render_view_id_; | |
415 | |
416 // Note: This instance can get destroyed in the context of | |
417 // Send so addref the channel in this scope. | |
418 scoped_refptr<NPChannelBase> channel_copy = proxy->channel_; | |
419 std::vector<NPVariant_Param> args_param; | |
420 for (unsigned int i = 0; i < arg_count; ++i) { | |
421 NPVariant_Param param; | |
422 CreateNPVariantParam( | |
423 args[i], channel_copy, ¶m, false, render_view_id, | |
424 proxy->page_url_); | |
425 args_param.push_back(param); | |
426 } | |
427 | |
428 NPVariant_Param param_result; | |
429 NPObjectMsg_Construct* msg = new NPObjectMsg_Construct( | |
430 proxy->route_id_, args_param, ¶m_result, &result); | |
431 | |
432 // See comment in NPObjectProxy::NPInvokePrivate. | |
433 if (IsPluginProcess() && proxy->channel()) { | |
434 msg->set_pump_messages_event( | |
435 proxy->channel()->GetModalDialogEvent(proxy->render_view_id_)); | |
436 } | |
437 | |
438 GURL page_url = proxy->page_url_; | |
439 proxy->Send(msg); | |
440 | |
441 // Send may delete proxy. | |
442 proxy = NULL; | |
443 | |
444 if (!result) | |
445 return false; | |
446 | |
447 CreateNPVariant( | |
448 param_result, channel_copy, np_result, render_view_id, page_url); | |
449 return true; | |
450 } | |
451 | |
452 bool NPObjectProxy::NPNEvaluate(NPP npp, | |
453 NPObject *obj, | |
454 NPString *script, | |
455 NPVariant *result_var) { | |
456 NPObjectProxy* proxy = GetProxy(obj); | |
457 if (!proxy) { | |
458 return false; | |
459 } | |
460 | |
461 bool result = false; | |
462 int render_view_id = proxy->render_view_id_; | |
463 bool popups_allowed = false; | |
464 | |
465 if (npp) { | |
466 webkit::npapi::PluginInstance* plugin_instance = | |
467 reinterpret_cast<webkit::npapi::PluginInstance*>(npp->ndata); | |
468 if (plugin_instance) | |
469 popups_allowed = plugin_instance->popups_allowed(); | |
470 } | |
471 | |
472 NPVariant_Param result_param; | |
473 std::string script_str = std::string( | |
474 script->UTF8Characters, script->UTF8Length); | |
475 | |
476 NPObjectMsg_Evaluate* msg = new NPObjectMsg_Evaluate(proxy->route_id(), | |
477 script_str, | |
478 popups_allowed, | |
479 &result_param, | |
480 &result); | |
481 | |
482 // See comment in NPObjectProxy::NPInvokePrivate. | |
483 if (IsPluginProcess() && proxy->channel()) { | |
484 msg->set_pump_messages_event( | |
485 proxy->channel()->GetModalDialogEvent(render_view_id)); | |
486 } | |
487 scoped_refptr<NPChannelBase> channel(proxy->channel_); | |
488 | |
489 GURL page_url = proxy->page_url_; | |
490 proxy->Send(msg); | |
491 // Send may delete proxy. | |
492 proxy = NULL; | |
493 if (!result) | |
494 return false; | |
495 | |
496 CreateNPVariant( | |
497 result_param, channel.get(), result_var, render_view_id, page_url); | |
498 return true; | |
499 } | |
500 | |
501 } // namespace content | |
OLD | NEW |