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