1/*
2 * Copyright (C) 2008, 2009, 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#if USE(PLUGIN_HOST_PROCESS)
27
28#ifndef NetscapePluginInstanceProxy_h
29#define NetscapePluginInstanceProxy_h
30
31#include <JavaScriptCore/Identifier.h>
32#include <JavaScriptCore/VM.h>
33#include <JavaScriptCore/Strong.h>
34#include <WebCore/Timer.h>
35#include <WebKit/npapi.h>
36#include <wtf/Deque.h>
37#include <wtf/Forward.h>
38#include <wtf/HashMap.h>
39#include <wtf/PassRefPtr.h>
40#include <wtf/RefCounted.h>
41#include <wtf/RetainPtr.h>
42#include "WebKitPluginHostTypes.h"
43
44namespace JSC {
45    namespace Bindings {
46        class Instance;
47        class RootObject;
48    }
49    class ArgList;
50}
51@class WebHostedNetscapePluginView;
52@class WebFrame;
53
54namespace WebKit {
55
56class HostedNetscapePluginStream;
57class NetscapePluginHostProxy;
58class PluginRequest;
59class ProxyInstance;
60
61class NetscapePluginInstanceProxy : public RefCounted<NetscapePluginInstanceProxy> {
62public:
63    static PassRefPtr<NetscapePluginInstanceProxy> create(NetscapePluginHostProxy*, WebHostedNetscapePluginView *, bool fullFramePlugin);
64    ~NetscapePluginInstanceProxy();
65
66    uint32_t pluginID() const
67    {
68        ASSERT(m_pluginID);
69
70        return m_pluginID;
71    }
72    uint32_t renderContextID() const { ASSERT(fastMallocSize(this)); return m_renderContextID; }
73    void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; }
74
75    RendererType rendererType() const { return m_rendererType; }
76    void setRendererType(RendererType rendererType) { m_rendererType = rendererType; }
77
78    WebHostedNetscapePluginView *pluginView() const { ASSERT(fastMallocSize(this)); return m_pluginView; }
79    NetscapePluginHostProxy* hostProxy() const { ASSERT(fastMallocSize(this)); return m_pluginHostProxy; }
80
81    bool cancelStreamLoad(uint32_t streamID, NPReason);
82    void disconnectStream(HostedNetscapePluginStream*);
83
84    void setManualStream(PassRefPtr<HostedNetscapePluginStream>);
85    HostedNetscapePluginStream* manualStream() const { return m_manualStream.get(); }
86
87    void pluginHostDied();
88
89    void resize(NSRect size, NSRect clipRect);
90    void destroy();
91    void focusChanged(bool hasFocus);
92    void windowFocusChanged(bool hasFocus);
93    void windowFrameChanged(NSRect frame);
94
95    void setShouldHostLayersInWindowServer(bool);
96    void layerHostingModeChanged(bool hostsLayersInWindowServer, uint32_t renderContextID);
97
98    void mouseEvent(NSView *pluginView, NSEvent *, NPCocoaEventType);
99    void keyEvent(NSView *pluginView, NSEvent *, NPCocoaEventType);
100    void insertText(NSString *);
101    bool wheelEvent(NSView *pluginView, NSEvent *);
102    void syntheticKeyDownWithCommandModifier(int keyCode, char character);
103    void flagsChanged(NSEvent *);
104    void print(CGContextRef, unsigned width, unsigned height);
105    void snapshot(CGContextRef, unsigned width, unsigned height);
106
107    void startTimers(bool throttleTimers);
108    void stopTimers();
109
110    void invalidateRect(double x, double y, double width, double height);
111
112    // NPRuntime
113    bool getWindowNPObject(uint32_t& objectID);
114    bool getPluginElementNPObject(uint32_t& objectID);
115    bool forgetBrowserObjectID(uint32_t objectID); // Will fail if the ID is being sent to plug-in right now (i.e., retain/release calls aren't balanced).
116
117    bool evaluate(uint32_t objectID, const WTF::String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups);
118    bool invoke(uint32_t objectID, const JSC::Identifier& methodName, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength);
119    bool invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength);
120    bool construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength);
121    bool enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength);
122
123    bool getProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t &resultData, mach_msg_type_number_t& resultLength);
124    bool getProperty(uint32_t objectID, unsigned propertyName, data_t &resultData, mach_msg_type_number_t& resultLength);
125    bool setProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength);
126    bool setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength);
127    bool removeProperty(uint32_t objectID, const JSC::Identifier& propertyName);
128    bool removeProperty(uint32_t objectID, unsigned propertyName);
129    bool hasProperty(uint32_t objectID, const JSC::Identifier& propertyName);
130    bool hasProperty(uint32_t objectID, unsigned propertyName);
131    bool hasMethod(uint32_t objectID, const JSC::Identifier& methodName);
132
133    void status(const char* message);
134    NPError loadURL(const char* url, const char* target, const char* postData, uint32_t postDataLength, LoadURLFlags, uint32_t& requestID);
135
136    bool getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength);
137    bool setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength);
138
139    bool getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength);
140    bool getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData,
141                               data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength);
142    bool convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
143                      double& destX, double& destY, NPCoordinateSpace destSpace);
144
145    PassRefPtr<JSC::Bindings::Instance> createBindingsInstance(PassRefPtr<JSC::Bindings::RootObject>);
146    RetainPtr<NSData *> marshalValues(JSC::ExecState*, const JSC::ArgList& args);
147    void marshalValue(JSC::ExecState*, JSC::JSValue, data_t& resultData, mach_msg_type_number_t& resultLength);
148    JSC::JSValue demarshalValue(JSC::ExecState*, const char* valueData, mach_msg_type_number_t valueLength);
149
150    // No-op if the value does not contain a local object.
151    void retainLocalObject(JSC::JSValue);
152    void releaseLocalObject(JSC::JSValue);
153
154    void addInstance(ProxyInstance*);
155    void removeInstance(ProxyInstance*);
156
157    void cleanup();
158    void invalidate();
159
160    void willCallPluginFunction();
161    void didCallPluginFunction(bool& stopped);
162    bool shouldStop();
163
164    uint32_t nextRequestID();
165
166    uint32_t checkIfAllowedToLoadURL(const char* url, const char* target);
167    void cancelCheckIfAllowedToLoadURL(uint32_t checkID);
168    void checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed);
169
170    void resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength);
171
172    void didDraw();
173    void privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled);
174
175    static void setGlobalException(const WTF::String&);
176    static void moveGlobalExceptionToExecState(JSC::ExecState*);
177
178    // Reply structs
179    struct Reply {
180        enum Type {
181            InstantiatePlugin,
182            GetScriptableNPObject,
183            BooleanAndData,
184            Boolean
185        };
186
187        Reply(Type type)
188            : m_type(type)
189        {
190        }
191
192        virtual ~Reply() { }
193
194        Type m_type;
195    };
196
197    struct InstantiatePluginReply : public Reply {
198        static const int ReplyType = InstantiatePlugin;
199
200        InstantiatePluginReply(kern_return_t resultCode, uint32_t renderContextID, RendererType rendererType)
201            : Reply(InstantiatePlugin)
202            , m_resultCode(resultCode)
203            , m_renderContextID(renderContextID)
204            , m_rendererType(rendererType)
205        {
206        }
207
208        kern_return_t m_resultCode;
209        uint32_t m_renderContextID;
210        RendererType m_rendererType;
211    };
212
213    struct GetScriptableNPObjectReply : public Reply {
214        static const Reply::Type ReplyType = GetScriptableNPObject;
215
216        GetScriptableNPObjectReply(uint32_t objectID)
217            : Reply(ReplyType)
218            , m_objectID(objectID)
219        {
220        }
221
222        uint32_t m_objectID;
223    };
224
225    struct BooleanReply : public Reply {
226        static const Reply::Type ReplyType = Boolean;
227
228        BooleanReply(boolean_t result)
229            : Reply(ReplyType)
230            , m_result(result)
231        {
232        }
233
234        boolean_t m_result;
235    };
236
237    struct BooleanAndDataReply : public Reply {
238        static const Reply::Type ReplyType = BooleanAndData;
239
240        BooleanAndDataReply(boolean_t returnValue, RetainPtr<CFDataRef> result)
241            : Reply(ReplyType)
242            , m_returnValue(returnValue)
243            , m_result(result)
244        {
245        }
246
247        boolean_t m_returnValue;
248        RetainPtr<CFDataRef> m_result;
249    };
250
251    void setCurrentReply(uint32_t requestID, Reply* reply)
252    {
253        ASSERT(!m_replies.contains(requestID));
254        m_replies.set(requestID, reply);
255    }
256
257    template <typename T>
258    std::auto_ptr<T> waitForReply(uint32_t requestID)
259    {
260        RefPtr<NetscapePluginInstanceProxy> protect(this); // Plug-in host may crash while we are waiting for reply, releasing all instances to the instance proxy.
261
262        willCallPluginFunction();
263        m_waitingForReply = true;
264
265        Reply* reply = processRequestsAndWaitForReply(requestID);
266        if (reply)
267            ASSERT(reply->m_type == T::ReplyType);
268
269        m_waitingForReply = false;
270
271        bool stopped = false;
272        didCallPluginFunction(stopped);
273        if (stopped) {
274            // The instance proxy may have been deleted from didCallPluginFunction(), so a null reply needs to be returned.
275            delete static_cast<T*>(reply);
276            return std::auto_ptr<T>();
277        }
278
279        return std::auto_ptr<T>(static_cast<T*>(reply));
280    }
281
282    void webFrameDidFinishLoadWithReason(WebFrame*, NPReason);
283
284private:
285    NetscapePluginInstanceProxy(NetscapePluginHostProxy*, WebHostedNetscapePluginView*, bool fullFramePlugin);
286
287    NPError loadRequest(NSURLRequest*, const char* cTarget, bool currentEventIsUserGesture, uint32_t& streamID);
288
289    class PluginRequest;
290    void performRequest(PluginRequest*);
291    void evaluateJavaScript(PluginRequest*);
292
293    void stopAllStreams();
294    Reply* processRequestsAndWaitForReply(uint32_t requestID);
295
296    NetscapePluginHostProxy* m_pluginHostProxy;
297    WebHostedNetscapePluginView *m_pluginView;
298
299    void requestTimerFired(WebCore::Timer<NetscapePluginInstanceProxy>*);
300    WebCore::Timer<NetscapePluginInstanceProxy> m_requestTimer;
301    Deque<RefPtr<PluginRequest> > m_pluginRequests;
302
303    HashMap<uint32_t, RefPtr<HostedNetscapePluginStream> > m_streams;
304
305    uint32_t m_currentURLRequestID;
306
307    uint32_t m_pluginID;
308    uint32_t m_renderContextID;
309    RendererType m_rendererType;
310
311    bool m_waitingForReply;
312    HashMap<uint32_t, Reply*> m_replies;
313
314    // NPRuntime
315
316    void addValueToArray(NSMutableArray *, JSC::ExecState* exec, JSC::JSValue value);
317
318    bool demarshalValueFromArray(JSC::ExecState*, NSArray *array, NSUInteger& index, JSC::JSValue& result);
319    void demarshalValues(JSC::ExecState*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result);
320
321    class LocalObjectMap {
322        WTF_MAKE_NONCOPYABLE(LocalObjectMap);
323    public:
324        LocalObjectMap();
325        ~LocalObjectMap();
326        uint32_t idForObject(JSC::VM&, JSC::JSObject*);
327        void retain(JSC::JSObject*);
328        void release(JSC::JSObject*);
329        void clear();
330        bool forget(uint32_t);
331        bool contains(uint32_t) const;
332        JSC::JSObject* get(uint32_t) const;
333
334    private:
335        HashMap<uint32_t, JSC::Strong<JSC::JSObject> > m_idToJSObjectMap;
336        // The pair consists of object ID and a reference count. One reference belongs to remote plug-in,
337        // and the proxy will add transient references for arguments that are being sent out.
338        HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> > m_jsObjectToIDMap;
339        uint32_t m_objectIDCounter;
340    };
341
342    LocalObjectMap m_localObjects;
343
344    typedef HashSet<ProxyInstance*> ProxyInstanceSet;
345    ProxyInstanceSet m_instances;
346
347    uint32_t m_urlCheckCounter;
348    typedef HashMap<uint32_t, RetainPtr<id> > URLCheckMap;
349    URLCheckMap m_urlChecks;
350
351    unsigned m_pluginFunctionCallDepth;
352    bool m_shouldStopSoon;
353    uint32_t m_currentRequestID;
354
355    // All NPRuntime functions will return false when destroying a plug-in. This is necessary because there may be unhandled messages waiting,
356    // and spinning in processRequests() will unexpectedly execute them from inside destroy(). That's not a good time to execute arbitrary JavaScript,
357    // since both loading and rendering data structures may be in inconsistent state.
358    // This suppresses calls from all plug-ins, even those in different pages, since JS might affect the frame with plug-in that's being stopped.
359    //
360    // FIXME: Plug-ins can execute arbitrary JS from destroy() in same process case, and other browsers also support that.
361    // A better fix may be to make sure that unrelated messages are postponed until after destroy() returns.
362    // Another possible fix may be to send destroy message at a time when internal structures are consistent.
363    //
364    // FIXME: We lack similar message suppression in other cases - resize() is also triggered by layout, so executing arbitrary JS is also problematic.
365    static bool m_inDestroy;
366
367    bool m_pluginIsWaitingForDraw;
368
369    RefPtr<HostedNetscapePluginStream> m_manualStream;
370
371    typedef HashMap<WebFrame*, RefPtr<PluginRequest> > FrameLoadMap;
372    FrameLoadMap m_pendingFrameLoads;
373};
374
375} // namespace WebKit
376
377#endif // NetscapePluginInstanceProxy_h
378#endif // USE(PLUGIN_HOST_PROCESS)
379