Home | History | Annotate | Download | only in Hosted
      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 
     65     uint32_t pluginID() const
     66     {
     67         ASSERT(m_pluginID);
     68 
     69         return m_pluginID;
     70     }
     71     uint32_t renderContextID() const { ASSERT(fastMallocSize(this)); return m_renderContextID; }
     72     void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; }
     73 
     74     RendererType rendererType() const { return m_rendererType; }
     75     void setRendererType(RendererType rendererType) { m_rendererType = rendererType; }
     76 
     77     WebHostedNetscapePluginView *pluginView() const { ASSERT(fastMallocSize(this)); return m_pluginView; }
     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>);
     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 
    183         Reply(Type type)
    184             : m_type(type)
    185         {
    186         }
    187 
    188         virtual ~Reply() { }
    189 
    190         Type m_type;
    191     };
    192 
    193     struct InstantiatePluginReply : public Reply {
    194         static const int ReplyType = InstantiatePlugin;
    195 
    196         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 
    212         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 
    224         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 
    236         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 
    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>
    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