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 <WebKitLegacy/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, std::unique_ptr<Reply> reply) 252 { 253 ASSERT(!m_replies.contains(requestID)); 254 m_replies.add(requestID, WTF::move(reply)); 255 } 256 257 template <typename T> 258 std::unique_ptr<T> waitForReply(uint32_t requestID) 259 { 260 Ref<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 auto 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 return nullptr; 276 } 277 278 return std::unique_ptr<T>(static_cast<T*>(reply.release())); 279 } 280 281 void webFrameDidFinishLoadWithReason(WebFrame*, NPReason); 282 283private: 284 NetscapePluginInstanceProxy(NetscapePluginHostProxy*, WebHostedNetscapePluginView*, bool fullFramePlugin); 285 286 NPError loadRequest(NSURLRequest*, const char* cTarget, bool currentEventIsUserGesture, uint32_t& streamID); 287 288 class PluginRequest; 289 void performRequest(PluginRequest*); 290 void evaluateJavaScript(PluginRequest*); 291 292 void stopAllStreams(); 293 std::unique_ptr<Reply> processRequestsAndWaitForReply(uint32_t requestID); 294 295 NetscapePluginHostProxy* m_pluginHostProxy; 296 WebHostedNetscapePluginView *m_pluginView; 297 298 void requestTimerFired(WebCore::Timer<NetscapePluginInstanceProxy>*); 299 WebCore::Timer<NetscapePluginInstanceProxy> m_requestTimer; 300 Deque<RefPtr<PluginRequest>> m_pluginRequests; 301 302 HashMap<uint32_t, RefPtr<HostedNetscapePluginStream>> m_streams; 303 304 uint32_t m_currentURLRequestID; 305 306 uint32_t m_pluginID; 307 uint32_t m_renderContextID; 308 RendererType m_rendererType; 309 310 bool m_waitingForReply; 311 HashMap<uint32_t, std::unique_ptr<Reply>> m_replies; 312 313 // NPRuntime 314 315 void addValueToArray(NSMutableArray *, JSC::ExecState* exec, JSC::JSValue value); 316 317 bool demarshalValueFromArray(JSC::ExecState*, NSArray *array, NSUInteger& index, JSC::JSValue& result); 318 void demarshalValues(JSC::ExecState*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result); 319 320 class LocalObjectMap { 321 WTF_MAKE_NONCOPYABLE(LocalObjectMap); 322 public: 323 LocalObjectMap(); 324 ~LocalObjectMap(); 325 uint32_t idForObject(JSC::VM&, JSC::JSObject*); 326 void retain(JSC::JSObject*); 327 void release(JSC::JSObject*); 328 void clear(); 329 bool forget(uint32_t); 330 bool contains(uint32_t) const; 331 JSC::JSObject* get(uint32_t) const; 332 333 private: 334 HashMap<uint32_t, JSC::Strong<JSC::JSObject>> m_idToJSObjectMap; 335 // The pair consists of object ID and a reference count. One reference belongs to remote plug-in, 336 // and the proxy will add transient references for arguments that are being sent out. 337 HashMap<JSC::JSObject*, std::pair<uint32_t, uint32_t>> m_jsObjectToIDMap; 338 uint32_t m_objectIDCounter; 339 }; 340 341 LocalObjectMap m_localObjects; 342 343 typedef HashSet<ProxyInstance*> ProxyInstanceSet; 344 ProxyInstanceSet m_instances; 345 346 uint32_t m_urlCheckCounter; 347 typedef HashMap<uint32_t, RetainPtr<id>> URLCheckMap; 348 URLCheckMap m_urlChecks; 349 350 unsigned m_pluginFunctionCallDepth; 351 bool m_shouldStopSoon; 352 uint32_t m_currentRequestID; 353 354 // All NPRuntime functions will return false when destroying a plug-in. This is necessary because there may be unhandled messages waiting, 355 // and spinning in processRequests() will unexpectedly execute them from inside destroy(). That's not a good time to execute arbitrary JavaScript, 356 // since both loading and rendering data structures may be in inconsistent state. 357 // 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. 358 // 359 // FIXME: Plug-ins can execute arbitrary JS from destroy() in same process case, and other browsers also support that. 360 // A better fix may be to make sure that unrelated messages are postponed until after destroy() returns. 361 // Another possible fix may be to send destroy message at a time when internal structures are consistent. 362 // 363 // FIXME: We lack similar message suppression in other cases - resize() is also triggered by layout, so executing arbitrary JS is also problematic. 364 static bool m_inDestroy; 365 366 bool m_pluginIsWaitingForDraw; 367 368 RefPtr<HostedNetscapePluginStream> m_manualStream; 369 370 typedef HashMap<WebFrame*, RefPtr<PluginRequest>> FrameLoadMap; 371 FrameLoadMap m_pendingFrameLoads; 372}; 373 374} // namespace WebKit 375 376#endif // NetscapePluginInstanceProxy_h 377#endif // USE(PLUGIN_HOST_PROCESS) 378