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(PLUGIN_PROCESS)
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 <WebCore/RunLoop.h>
39#include <wtf/MainThread.h>
40
41using namespace WebCore;
42
43namespace WebKit {
44
45NPObjectProxy* NPObjectProxy::create(NPRemoteObjectMap* npRemoteObjectMap, Plugin* plugin, uint64_t npObjectID)
46{
47    NPObjectProxy* npObjectProxy = toNPObjectProxy(createNPObject(0, npClass()));
48    npObjectProxy->initialize(npRemoteObjectMap, plugin, npObjectID);
49
50    return npObjectProxy;
51}
52
53NPObjectProxy::NPObjectProxy()
54    : m_npRemoteObjectMap(0)
55    , m_plugin(0)
56    , m_npObjectID(0)
57{
58}
59
60NPObjectProxy::~NPObjectProxy()
61{
62    ASSERT(isMainThread());
63
64    if (!m_npRemoteObjectMap)
65        return;
66
67    m_npRemoteObjectMap->npObjectProxyDestroyed(this);
68    m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Deallocate(), Messages::NPObjectMessageReceiver::Deallocate::Reply(), m_npObjectID);
69}
70
71bool NPObjectProxy::isNPObjectProxy(NPObject* npObject)
72{
73    return npObject->_class == npClass();
74}
75
76void NPObjectProxy::invalidate()
77{
78    ASSERT(m_npRemoteObjectMap);
79    ASSERT(m_plugin);
80
81    m_npRemoteObjectMap = 0;
82    m_plugin = 0;
83}
84
85void NPObjectProxy::initialize(NPRemoteObjectMap* npRemoteObjectMap, Plugin* plugin, uint64_t npObjectID)
86{
87    ASSERT(!m_npRemoteObjectMap);
88    ASSERT(!m_plugin);
89    ASSERT(!m_npObjectID);
90
91    ASSERT(npRemoteObjectMap);
92    ASSERT(plugin);
93    ASSERT(npObjectID);
94
95    m_npRemoteObjectMap = npRemoteObjectMap;
96    m_plugin = plugin;
97    m_npObjectID = npObjectID;
98}
99
100bool NPObjectProxy::hasMethod(NPIdentifier methodName)
101{
102    if (!m_npRemoteObjectMap)
103        return false;
104
105    NPIdentifierData methodNameData = NPIdentifierData::fromNPIdentifier(methodName);
106
107    bool returnValue = false;
108
109    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::HasMethod(methodNameData), Messages::NPObjectMessageReceiver::HasMethod::Reply(returnValue), m_npObjectID))
110        return false;
111
112    return returnValue;
113}
114
115bool NPObjectProxy::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
116{
117    if (!m_npRemoteObjectMap)
118        return false;
119
120    NPIdentifierData methodNameData = NPIdentifierData::fromNPIdentifier(methodName);
121    Vector<NPVariantData> argumentsData;
122    for (uint32_t i = 0; i < argumentCount; ++i)
123        argumentsData.append(m_npRemoteObjectMap->npVariantToNPVariantData(arguments[i], m_plugin));
124
125    bool returnValue = false;
126    NPVariantData resultData;
127
128    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Invoke(methodNameData, argumentsData), Messages::NPObjectMessageReceiver::Invoke::Reply(returnValue, resultData), m_npObjectID))
129        return false;
130
131    if (!returnValue)
132        return false;
133
134    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
135    return true;
136}
137
138bool NPObjectProxy::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
139{
140    if (!m_npRemoteObjectMap)
141        return false;
142
143    Vector<NPVariantData> argumentsData;
144    for (uint32_t i = 0; i < argumentCount; ++i)
145        argumentsData.append(m_npRemoteObjectMap->npVariantToNPVariantData(arguments[i], m_plugin));
146
147    bool returnValue = false;
148    NPVariantData resultData;
149
150    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::InvokeDefault(argumentsData), Messages::NPObjectMessageReceiver::InvokeDefault::Reply(returnValue, resultData), m_npObjectID))
151        return false;
152
153    if (!returnValue)
154        return false;
155
156    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
157    return true;
158}
159
160bool NPObjectProxy::hasProperty(NPIdentifier propertyName)
161{
162    if (!m_npRemoteObjectMap)
163        return false;
164
165    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
166
167    bool returnValue = false;
168
169    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::HasProperty(propertyNameData), Messages::NPObjectMessageReceiver::HasProperty::Reply(returnValue), m_npObjectID))
170        return false;
171
172    return returnValue;
173}
174
175bool NPObjectProxy::getProperty(NPIdentifier propertyName, NPVariant* result)
176{
177    if (!m_npRemoteObjectMap)
178        return false;
179
180    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
181
182    bool returnValue = false;
183    NPVariantData resultData;
184
185    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::GetProperty(propertyNameData), Messages::NPObjectMessageReceiver::GetProperty::Reply(returnValue, resultData), m_npObjectID))
186        return false;
187
188    if (!returnValue)
189        return false;
190
191    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
192    return true;
193}
194
195bool NPObjectProxy::setProperty(NPIdentifier propertyName, const NPVariant* value)
196{
197    if (!m_npRemoteObjectMap)
198        return false;
199
200    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
201    NPVariantData propertyValueData = m_npRemoteObjectMap->npVariantToNPVariantData(*value, m_plugin);
202
203    bool returnValue = false;
204
205    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::SetProperty(propertyNameData, propertyValueData), Messages::NPObjectMessageReceiver::SetProperty::Reply(returnValue), m_npObjectID))
206        return false;
207
208    return returnValue;
209}
210
211bool NPObjectProxy::removeProperty(NPIdentifier propertyName)
212{
213    if (!m_npRemoteObjectMap)
214        return false;
215
216    NPIdentifierData propertyNameData = NPIdentifierData::fromNPIdentifier(propertyName);
217
218    bool returnValue = false;
219
220    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::RemoveProperty(propertyNameData), Messages::NPObjectMessageReceiver::RemoveProperty::Reply(returnValue), m_npObjectID))
221        return false;
222
223    return returnValue;
224}
225
226bool NPObjectProxy::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount)
227{
228    if (!m_npRemoteObjectMap)
229        return false;
230
231    bool returnValue;
232    Vector<NPIdentifierData> identifiersData;
233
234    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Enumerate(), Messages::NPObjectMessageReceiver::Enumerate::Reply(returnValue, identifiersData), m_npObjectID))
235        return false;
236
237    if (!returnValue)
238        return false;
239
240    NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(identifiersData.size());
241
242    for (size_t i = 0; i < identifiersData.size(); ++i)
243        nameIdentifiers[i] = identifiersData[i].createNPIdentifier();
244
245    *identifiers = nameIdentifiers;
246    *identifierCount = identifiersData.size();
247    return true;
248}
249
250bool NPObjectProxy::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
251{
252    if (!m_npRemoteObjectMap)
253        return false;
254
255    Vector<NPVariantData> argumentsData;
256    for (uint32_t i = 0; i < argumentCount; ++i)
257        argumentsData.append(m_npRemoteObjectMap->npVariantToNPVariantData(arguments[i], m_plugin));
258
259    bool returnValue = false;
260    NPVariantData resultData;
261
262    if (!m_npRemoteObjectMap->connection()->sendSync(Messages::NPObjectMessageReceiver::Construct(argumentsData), Messages::NPObjectMessageReceiver::Construct::Reply(returnValue, resultData), m_npObjectID))
263        return false;
264
265    if (!returnValue)
266        return false;
267
268    *result = m_npRemoteObjectMap->npVariantDataToNPVariant(resultData, m_plugin);
269    return true;
270}
271
272NPClass* NPObjectProxy::npClass()
273{
274    static NPClass npClass = {
275        NP_CLASS_STRUCT_VERSION,
276        NP_Allocate,
277        NP_Deallocate,
278        0,
279        NP_HasMethod,
280        NP_Invoke,
281        NP_InvokeDefault,
282        NP_HasProperty,
283        NP_GetProperty,
284        NP_SetProperty,
285        NP_RemoveProperty,
286        NP_Enumerate,
287        NP_Construct
288    };
289
290    return &npClass;
291}
292
293NPObject* NPObjectProxy::NP_Allocate(NPP npp, NPClass*)
294{
295    ASSERT_UNUSED(npp, !npp);
296
297    return new NPObjectProxy;
298}
299
300void NPObjectProxy::NP_Deallocate(NPObject* npObject)
301{
302    // http://webkit.org/b/118535 - The Java Netscape Plug-in has a background thread do some of their NPP_Destroy work.
303    // That background thread can call NP_Deallocate, and this leads to a WebProcess <-> PluginProcess deadlock.
304    // Since NPAPI behavior on a background thread is undefined, it is okay to limit this workaround to the one API
305    // that is known to be misused during plugin teardown, and to not be concerned about change in behavior if this
306    // occured at any other time.
307    if (!isMainThread()) {
308        RunLoop::main()->dispatch(bind(&NPObjectProxy::NP_Deallocate, npObject));
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(PLUGIN_PROCESS)
364