1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "NPObjectProxy.h"
28
29#if ENABLE(NETSCAPE_PLUGIN_API)
30
31#include "ArgumentCoders.h"
32#include "Connection.h"
33#include "NPIdentifierData.h"
34#include "NPObjectMessageReceiverMessages.h"
35#include "NPRemoteObjectMap.h"
36#include "NPRuntimeUtilities.h"
37#include "NPVariantData.h"
38#include <wtf/MainThread.h>
39#include <wtf/RunLoop.h>
40
41namespace WebKit {
42
43NPObjectProxy* NPObjectProxy::create(NPRemoteObjectMap* npRemoteObjectMap, Plugin* plugin, uint64_t npObjectID)
44{
45    NPObjectProxy* npObjectProxy = toNPObjectProxy(createNPObject(0, npClass()));
46    npObjectProxy->initialize(npRemoteObjectMap, plugin, npObjectID);
47
48    return npObjectProxy;
49}
50
51NPObjectProxy::NPObjectProxy()
52    : m_npRemoteObjectMap(0)
53    , m_plugin(0)
54    , m_npObjectID(0)
55{
56}
57
58NPObjectProxy::~NPObjectProxy()
59{
60    ASSERT(RunLoop::isMain());
61
62    if (!m_npRemoteObjectMap)
63        return;
64
65    m_npRemoteObjectMap->npObjectProxyDestroyed(this);
66    m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Deallocate(), Messages::NPObjectMessageReceiver::Deallocate::Reply(), m_npObjectID);
67}
68
69bool NPObjectProxy::isNPObjectProxy(NPObject* npObject)
70{
71    return npObject->_class == npClass();
72}
73
74void NPObjectProxy::invalidate()
75{
76    ASSERT(m_npRemoteObjectMap);
77    ASSERT(m_plugin);
78
79    m_npRemoteObjectMap = 0;
80    m_plugin = 0;
81}
82
83void NPObjectProxy::initialize(NPRemoteObjectMap* npRemoteObjectMap, Plugin* plugin, uint64_t npObjectID)
84{
85    ASSERT(!m_npRemoteObjectMap);
86    ASSERT(!m_plugin);
87    ASSERT(!m_npObjectID);
88
89    ASSERT(npRemoteObjectMap);
90    ASSERT(plugin);
91    ASSERT(npObjectID);
92
93    m_npRemoteObjectMap = npRemoteObjectMap;
94    m_plugin = plugin;
95    m_npObjectID = npObjectID;
96}
97
98bool NPObjectProxy::hasMethod(NPIdentifier methodName)
99{
100    if (!m_npRemoteObjectMap)
101        return false;
102
103    NPIdentifierData methodNameData = NPIdentifierData::fromNPIdentifier(methodName);
104
105    bool returnValue = false;
106
107    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::HasMethod(methodNameData), Messages::NPObjectMessageReceiver::HasMethod::Reply(returnValue), m_npObjectID))
108        return false;
109
110    return returnValue;
111}
112
113bool NPObjectProxy::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
114{
115    if (!m_npRemoteObjectMap)
116        return false;
117
118    NPIdentifierData methodNameData = NPIdentifierData::fromNPIdentifier(methodName);
119    Vector<NPVariantData> argumentsData;
120    for (uint32_t i = 0; i < argumentCount; ++i)
121        argumentsData.append(m_npRemoteObjectMap->npVariantToNPVariantData(arguments[i], m_plugin));
122
123    bool returnValue = false;
124    NPVariantData resultData;
125
126    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Invoke(methodNameData, argumentsData), Messages::NPObjectMessageReceiver::Invoke::Reply(returnValue, resultData), m_npObjectID))
127        return false;
128
129    if (!returnValue)
130        return false;
131
132    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
133    return true;
134}
135
136bool NPObjectProxy::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
137{
138    if (!m_npRemoteObjectMap)
139        return false;
140
141    Vector<NPVariantData> argumentsData;
142    for (uint32_t i = 0; i < argumentCount; ++i)
143        argumentsData.append(m_npRemoteObjectMap->npVariantToNPVariantData(arguments[i], m_plugin));
144
145    bool returnValue = false;
146    NPVariantData resultData;
147
148    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::InvokeDefault(argumentsData), Messages::NPObjectMessageReceiver::InvokeDefault::Reply(returnValue, resultData), m_npObjectID))
149        return false;
150
151    if (!returnValue)
152        return false;
153
154    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
155    return true;
156}
157
158bool NPObjectProxy::hasProperty(NPIdentifier propertyName)
159{
160    if (!m_npRemoteObjectMap)
161        return false;
162
163    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
164
165    bool returnValue = false;
166
167    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::HasProperty(propertyNameData), Messages::NPObjectMessageReceiver::HasProperty::Reply(returnValue), m_npObjectID))
168        return false;
169
170    return returnValue;
171}
172
173bool NPObjectProxy::getProperty(NPIdentifier propertyName, NPVariant* result)
174{
175    if (!m_npRemoteObjectMap)
176        return false;
177
178    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
179
180    bool returnValue = false;
181    NPVariantData resultData;
182
183    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::GetProperty(propertyNameData), Messages::NPObjectMessageReceiver::GetProperty::Reply(returnValue, resultData), m_npObjectID))
184        return false;
185
186    if (!returnValue)
187        return false;
188
189    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
190    return true;
191}
192
193bool NPObjectProxy::setProperty(NPIdentifier propertyName, const NPVariant* value)
194{
195    if (!m_npRemoteObjectMap)
196        return false;
197
198    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
199    NPVariantData propertyValueData = m_npRemoteObjectMap->npVariantToNPVariantData(*value, m_plugin);
200
201    bool returnValue = false;
202
203    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::SetProperty(propertyNameData, propertyValueData), Messages::NPObjectMessageReceiver::SetProperty::Reply(returnValue), m_npObjectID))
204        return false;
205
206    return returnValue;
207}
208
209bool NPObjectProxy::removeProperty(NPIdentifier propertyName)
210{
211    if (!m_npRemoteObjectMap)
212        return false;
213
214    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
215
216    bool returnValue = false;
217
218    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::RemoveProperty(propertyNameData), Messages::NPObjectMessageReceiver::RemoveProperty::Reply(returnValue), m_npObjectID))
219        return false;
220
221    return returnValue;
222}
223
224bool NPObjectProxy::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount)
225{
226    if (!m_npRemoteObjectMap)
227        return false;
228
229    bool returnValue;
230    Vector<NPIdentifierData> identifiersData;
231
232    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Enumerate(), Messages::NPObjectMessageReceiver::Enumerate::Reply(returnValue, identifiersData), m_npObjectID))
233        return false;
234
235    if (!returnValue)
236        return false;
237
238    NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(identifiersData.size());
239
240    for (size_t i = 0; i < identifiersData.size(); ++i)
241        nameIdentifiers[i] = identifiersData[i].createNPIdentifier();
242
243    *identifiers = nameIdentifiers;
244    *identifierCount = identifiersData.size();
245    return true;
246}
247
248bool NPObjectProxy::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
249{
250    if (!m_npRemoteObjectMap)
251        return false;
252
253    Vector<NPVariantData> argumentsData;
254    for (uint32_t i = 0; i < argumentCount; ++i)
255        argumentsData.append(m_npRemoteObjectMap->npVariantToNPVariantData(arguments[i], m_plugin));
256
257    bool returnValue = false;
258    NPVariantData resultData;
259
260    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Construct(argumentsData), Messages::NPObjectMessageReceiver::Construct::Reply(returnValue, resultData), m_npObjectID))
261        return false;
262
263    if (!returnValue)
264        return false;
265
266    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
267    return true;
268}
269
270NPClass* NPObjectProxy::npClass()
271{
272    static NPClass npClass = {
273        NP_CLASS_STRUCT_VERSION,
274        NP_Allocate,
275        NP_Deallocate,
276        0,
277        NP_HasMethod,
278        NP_Invoke,
279        NP_InvokeDefault,
280        NP_HasProperty,
281        NP_GetProperty,
282        NP_SetProperty,
283        NP_RemoveProperty,
284        NP_Enumerate,
285        NP_Construct
286    };
287
288    return &npClass;
289}
290
291NPObject* NPObjectProxy::NP_Allocate(NPP npp, NPClass*)
292{
293    ASSERT_UNUSED(npp, !npp);
294
295    return new NPObjectProxy;
296}
297
298void NPObjectProxy::NP_Deallocate(NPObject* npObject)
299{
300    // http://webkit.org/b/118535 - The Java Netscape Plug-in has a background thread do some of their NPP_Destroy work.
301    // That background thread can call NP_Deallocate, and this leads to a WebProcess <-> PluginProcess deadlock.
302    // Since NPAPI behavior on a background thread is undefined, it is okay to limit this workaround to the one API
303    // that is known to be misused during plugin teardown, and to not be concerned about change in behavior if this
304    // occured at any other time.
305    if (!isMainThread()) {
306        RunLoop::main().dispatch([npObject] {
307            NP_Deallocate(npObject);
308        });
309        return;
310    }
311
312    NPObjectProxy* npObjectProxy = toNPObjectProxy(npObject);
313    delete npObjectProxy;
314}
315
316bool NPObjectProxy::NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
317{
318    return toNPObjectProxy(npObject)->hasMethod(methodName);
319}
320
321bool NPObjectProxy::NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
322{
323    return toNPObjectProxy(npObject)->invoke(methodName, arguments, argumentCount, result);
324}
325
326bool NPObjectProxy::NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
327{
328    return toNPObjectProxy(npObject)->invokeDefault(arguments, argumentCount, result);
329}
330
331bool NPObjectProxy::NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
332{
333    return toNPObjectProxy(npObject)->hasProperty(propertyName);
334}
335
336bool NPObjectProxy::NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
337{
338    return toNPObjectProxy(npObject)->getProperty(propertyName, result);
339}
340
341bool NPObjectProxy::NP_SetProperty(NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
342{
343    return toNPObjectProxy(npObject)->setProperty(propertyName, value);
344}
345
346bool NPObjectProxy::NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
347{
348    return toNPObjectProxy(npObject)->removeProperty(propertyName);
349}
350
351bool NPObjectProxy::NP_Enumerate(NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
352{
353    return toNPObjectProxy(npObject)->enumerate(identifiers, identifierCount);
354}
355
356bool NPObjectProxy::NP_Construct(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
357{
358    return toNPObjectProxy(npObject)->construct(arguments, argumentCount, result);
359}
360
361} // namespace WebKit
362
363#endif // ENABLE(NETSCAPE_PLUGIN_API)
364