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