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