/* * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if USE(PLUGIN_HOST_PROCESS) #ifndef NetscapePluginInstanceProxy_h #define NetscapePluginInstanceProxy_h #include #include #include #include #include #include #include #include #include #include #include "WebKitPluginHostTypes.h" namespace JSC { namespace Bindings { class Instance; class RootObject; } class ArgList; } @class WebHostedNetscapePluginView; @class WebFrame; namespace WebKit { class HostedNetscapePluginStream; class NetscapePluginHostProxy; class PluginRequest; class ProxyInstance; class NetscapePluginInstanceProxy : public RefCounted { public: static PassRefPtr create(NetscapePluginHostProxy*, WebHostedNetscapePluginView *, bool fullFramePlugin); ~NetscapePluginInstanceProxy(); uint32_t pluginID() const { ASSERT(m_pluginID); return m_pluginID; } uint32_t renderContextID() const { ASSERT(fastMallocSize(this)); return m_renderContextID; } void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; } RendererType rendererType() const { return m_rendererType; } void setRendererType(RendererType rendererType) { m_rendererType = rendererType; } WebHostedNetscapePluginView *pluginView() const { ASSERT(fastMallocSize(this)); return m_pluginView; } NetscapePluginHostProxy* hostProxy() const { ASSERT(fastMallocSize(this)); return m_pluginHostProxy; } bool cancelStreamLoad(uint32_t streamID, NPReason); void disconnectStream(HostedNetscapePluginStream*); void setManualStream(PassRefPtr); HostedNetscapePluginStream* manualStream() const { return m_manualStream.get(); } void pluginHostDied(); void resize(NSRect size, NSRect clipRect); void destroy(); void focusChanged(bool hasFocus); void windowFocusChanged(bool hasFocus); void windowFrameChanged(NSRect frame); void mouseEvent(NSView *pluginView, NSEvent *, NPCocoaEventType); void keyEvent(NSView *pluginView, NSEvent *, NPCocoaEventType); void insertText(NSString *); bool wheelEvent(NSView *pluginView, NSEvent *); void syntheticKeyDownWithCommandModifier(int keyCode, char character); void flagsChanged(NSEvent *); void print(CGContextRef, unsigned width, unsigned height); void snapshot(CGContextRef, unsigned width, unsigned height); void startTimers(bool throttleTimers); void stopTimers(); void invalidateRect(double x, double y, double width, double height); // NPRuntime bool getWindowNPObject(uint32_t& objectID); bool getPluginElementNPObject(uint32_t& objectID); 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). bool evaluate(uint32_t objectID, const WTF::String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups); 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); bool invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); bool construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); bool enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength); bool getProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t &resultData, mach_msg_type_number_t& resultLength); bool getProperty(uint32_t objectID, unsigned propertyName, data_t &resultData, mach_msg_type_number_t& resultLength); bool setProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength); bool setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength); bool removeProperty(uint32_t objectID, const JSC::Identifier& propertyName); bool removeProperty(uint32_t objectID, unsigned propertyName); bool hasProperty(uint32_t objectID, const JSC::Identifier& propertyName); bool hasProperty(uint32_t objectID, unsigned propertyName); bool hasMethod(uint32_t objectID, const JSC::Identifier& methodName); void status(const char* message); NPError loadURL(const char* url, const char* target, const char* postData, uint32_t postDataLength, LoadURLFlags, uint32_t& requestID); bool getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength); bool setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength); bool getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength); bool getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData, data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength); bool convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double& destX, double& destY, NPCoordinateSpace destSpace); PassRefPtr createBindingsInstance(PassRefPtr); RetainPtr marshalValues(JSC::ExecState*, const JSC::ArgList& args); void marshalValue(JSC::ExecState*, JSC::JSValue, data_t& resultData, mach_msg_type_number_t& resultLength); JSC::JSValue demarshalValue(JSC::ExecState*, const char* valueData, mach_msg_type_number_t valueLength); // No-op if the value does not contain a local object. void retainLocalObject(JSC::JSValue); void releaseLocalObject(JSC::JSValue); void addInstance(ProxyInstance*); void removeInstance(ProxyInstance*); void cleanup(); void invalidate(); void willCallPluginFunction(); void didCallPluginFunction(bool& stopped); bool shouldStop(); uint32_t nextRequestID(); uint32_t checkIfAllowedToLoadURL(const char* url, const char* target); void cancelCheckIfAllowedToLoadURL(uint32_t checkID); void checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed); void resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength); void didDraw(); void privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled); static void setGlobalException(const WTF::String&); static void moveGlobalExceptionToExecState(JSC::ExecState*); // Reply structs struct Reply { enum Type { InstantiatePlugin, GetScriptableNPObject, BooleanAndData, Boolean }; Reply(Type type) : m_type(type) { } virtual ~Reply() { } Type m_type; }; struct InstantiatePluginReply : public Reply { static const int ReplyType = InstantiatePlugin; InstantiatePluginReply(kern_return_t resultCode, uint32_t renderContextID, RendererType rendererType) : Reply(InstantiatePlugin) , m_resultCode(resultCode) , m_renderContextID(renderContextID) , m_rendererType(rendererType) { } kern_return_t m_resultCode; uint32_t m_renderContextID; RendererType m_rendererType; }; struct GetScriptableNPObjectReply : public Reply { static const Reply::Type ReplyType = GetScriptableNPObject; GetScriptableNPObjectReply(uint32_t objectID) : Reply(ReplyType) , m_objectID(objectID) { } uint32_t m_objectID; }; struct BooleanReply : public Reply { static const Reply::Type ReplyType = Boolean; BooleanReply(boolean_t result) : Reply(ReplyType) , m_result(result) { } boolean_t m_result; }; struct BooleanAndDataReply : public Reply { static const Reply::Type ReplyType = BooleanAndData; BooleanAndDataReply(boolean_t returnValue, RetainPtr result) : Reply(ReplyType) , m_returnValue(returnValue) , m_result(result) { } boolean_t m_returnValue; RetainPtr m_result; }; void setCurrentReply(uint32_t requestID, Reply* reply) { ASSERT(!m_replies.contains(requestID)); m_replies.set(requestID, reply); } template std::auto_ptr waitForReply(uint32_t requestID) { RefPtr protect(this); // Plug-in host may crash while we are waiting for reply, releasing all instances to the instance proxy. willCallPluginFunction(); m_waitingForReply = true; Reply* reply = processRequestsAndWaitForReply(requestID); if (reply) ASSERT(reply->m_type == T::ReplyType); m_waitingForReply = false; bool stopped = false; didCallPluginFunction(stopped); if (stopped) { // The instance proxy may have been deleted from didCallPluginFunction(), so a null reply needs to be returned. delete static_cast(reply); return std::auto_ptr(); } return std::auto_ptr(static_cast(reply)); } void webFrameDidFinishLoadWithReason(WebFrame*, NPReason); private: NetscapePluginInstanceProxy(NetscapePluginHostProxy*, WebHostedNetscapePluginView*, bool fullFramePlugin); NPError loadRequest(NSURLRequest*, const char* cTarget, bool currentEventIsUserGesture, uint32_t& streamID); class PluginRequest; void performRequest(PluginRequest*); void evaluateJavaScript(PluginRequest*); void stopAllStreams(); Reply* processRequestsAndWaitForReply(uint32_t requestID); NetscapePluginHostProxy* m_pluginHostProxy; WebHostedNetscapePluginView *m_pluginView; void requestTimerFired(WebCore::Timer*); WebCore::Timer m_requestTimer; Deque > m_pluginRequests; HashMap > m_streams; uint32_t m_currentURLRequestID; uint32_t m_pluginID; uint32_t m_renderContextID; RendererType m_rendererType; bool m_waitingForReply; HashMap m_replies; // NPRuntime void addValueToArray(NSMutableArray *, JSC::ExecState* exec, JSC::JSValue value); bool demarshalValueFromArray(JSC::ExecState*, NSArray *array, NSUInteger& index, JSC::JSValue& result); void demarshalValues(JSC::ExecState*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result); class LocalObjectMap { WTF_MAKE_NONCOPYABLE(LocalObjectMap); public: LocalObjectMap(); ~LocalObjectMap(); uint32_t idForObject(JSC::JSGlobalData&, JSC::JSObject*); void retain(JSC::JSObject*); void release(JSC::JSObject*); void clear(); bool forget(uint32_t); bool contains(uint32_t) const; JSC::JSObject* get(uint32_t) const; private: HashMap > m_idToJSObjectMap; // The pair consists of object ID and a reference count. One reference belongs to remote plug-in, // and the proxy will add transient references for arguments that are being sent out. HashMap > m_jsObjectToIDMap; uint32_t m_objectIDCounter; }; LocalObjectMap m_localObjects; typedef HashSet ProxyInstanceSet; ProxyInstanceSet m_instances; uint32_t m_urlCheckCounter; typedef HashMap > URLCheckMap; URLCheckMap m_urlChecks; unsigned m_pluginFunctionCallDepth; bool m_shouldStopSoon; uint32_t m_currentRequestID; // All NPRuntime functions will return false when destroying a plug-in. This is necessary because there may be unhandled messages waiting, // and spinning in processRequests() will unexpectedly execute them from inside destroy(). That's not a good time to execute arbitrary JavaScript, // since both loading and rendering data structures may be in inconsistent state. // 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. // // FIXME: Plug-ins can execute arbitrary JS from destroy() in same process case, and other browsers also support that. // A better fix may be to make sure that unrelated messages are postponed until after destroy() returns. // Another possible fix may be to send destroy message at a time when internal structures are consistent. // // FIXME: We lack similar message suppression in other cases - resize() is also triggered by layout, so executing arbitrary JS is also problematic. static bool m_inDestroy; bool m_pluginIsWaitingForDraw; RefPtr m_manualStream; typedef HashMap > FrameLoadMap; FrameLoadMap m_pendingFrameLoads; }; } // namespace WebKit #endif // NetscapePluginInstanceProxy_h #endif // USE(PLUGIN_HOST_PROCESS)