1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // TODO: Need to deal with NPAPI's NPSavedData. 6 // I haven't seen plugins use it yet. 7 8 #ifndef CONTENT_CHILD_NPAPI_PLUGIN_INSTANCE_H_ 9 #define CONTENT_CHILD_NPAPI_PLUGIN_INSTANCE_H_ 10 11 #include <map> 12 #include <stack> 13 #include <string> 14 #include <vector> 15 16 #include "base/basictypes.h" 17 #include "base/files/file_path.h" 18 #include "base/memory/ref_counted.h" 19 #include "third_party/npapi/bindings/npapi.h" 20 #include "third_party/npapi/bindings/nphostapi.h" 21 #include "ui/gfx/native_widget_types.h" 22 #include "ui/gfx/point.h" 23 #include "ui/gfx/rect.h" 24 #include "url/gurl.h" 25 26 namespace base { 27 class MessageLoop; 28 } 29 30 namespace content { 31 32 class PluginLib; 33 class PluginHost; 34 class PluginStream; 35 class PluginStreamUrl; 36 class WebPlugin; 37 class WebPluginResourceClient; 38 39 #if defined(OS_MACOSX) 40 class ScopedCurrentPluginEvent; 41 #endif 42 43 // A PluginInstance is an active, running instance of a Plugin. 44 // A single plugin may have many PluginInstances. 45 class PluginInstance : public base::RefCountedThreadSafe<PluginInstance> { 46 public: 47 // Create a new instance of a plugin. The PluginInstance 48 // will hold a reference to the plugin. 49 PluginInstance(PluginLib* plugin, const std::string &mime_type); 50 51 // Activates the instance by calling NPP_New. 52 // This should be called after our instance is all 53 // setup from the host side and we are ready to receive 54 // requests from the plugin. We must not call any 55 // functions on the plugin instance until start has 56 // been called. 57 // 58 // url: The instance URL. 59 // param_names: the list of names of attributes passed via the 60 // element. 61 // param_values: the list of values corresponding to param_names 62 // param_count: number of attributes 63 // load_manually: if true indicates that the plugin data would be passed 64 // from webkit. if false indicates that the plugin should 65 // download the data. 66 // This also controls whether the plugin is instantiated as 67 // a full page plugin (NP_FULL) or embedded (NP_EMBED) 68 // 69 bool Start(const GURL& url, 70 char** const param_names, 71 char** const param_values, 72 int param_count, 73 bool load_manually); 74 75 // NPAPI's instance identifier for this instance npp()76 NPP npp() { return npp_; } 77 78 // Get/Set for the instance's window handle. window_handle()79 gfx::PluginWindowHandle window_handle() const { return window_handle_; } set_window_handle(gfx::PluginWindowHandle value)80 void set_window_handle(gfx::PluginWindowHandle value) { 81 window_handle_ = value; 82 } 83 84 // Get/Set whether this instance is in Windowless mode. 85 // Default is false. windowless()86 bool windowless() { return windowless_; } set_windowless(bool value)87 void set_windowless(bool value) { windowless_ = value; } 88 89 // Get/Set whether this instance is transparent. This only applies to 90 // windowless plugins. Transparent plugins require that webkit paint the 91 // background. 92 // Default is true for all plugins other than Flash. For Flash, we default to 93 // opaque since it always tells us if it's transparent during NPP_New. transparent()94 bool transparent() { return transparent_; } set_transparent(bool value)95 void set_transparent(bool value) { transparent_ = value; } 96 97 // Get/Set the WebPlugin associated with this instance webplugin()98 WebPlugin* webplugin() { return webplugin_; } set_web_plugin(WebPlugin * webplugin)99 void set_web_plugin(WebPlugin* webplugin) { 100 webplugin_ = webplugin; 101 } 102 103 // Get the mimeType for this plugin stream mime_type()104 const std::string &mime_type() { return mime_type_; } 105 plugin_lib()106 PluginLib* plugin_lib() { return plugin_.get(); } 107 108 #if defined(OS_MACOSX) 109 // Get/Set the Mac NPAPI drawing and event models drawing_model()110 NPDrawingModel drawing_model() { return drawing_model_; } set_drawing_model(NPDrawingModel value)111 void set_drawing_model(NPDrawingModel value) { drawing_model_ = value; } event_model()112 NPEventModel event_model() { return event_model_; } set_event_model(NPEventModel value)113 void set_event_model(NPEventModel value) { event_model_ = value; } 114 // Updates the instance's tracking of the location of the plugin location 115 // relative to the upper left of the screen. set_plugin_origin(const gfx::Point & origin)116 void set_plugin_origin(const gfx::Point& origin) { plugin_origin_ = origin; } 117 // Updates the instance's tracking of the frame of the containing window 118 // relative to the upper left of the screen. set_window_frame(const gfx::Rect & frame)119 void set_window_frame(const gfx::Rect& frame) { 120 containing_window_frame_ = frame; 121 } 122 #endif 123 124 // Creates a stream for sending an URL. If notify_id is non-zero, it will 125 // send a notification to the plugin when the stream is complete; otherwise it 126 // will not. Set object_url to true if the load is for the object tag's url, 127 // or false if it's for a url that the plugin fetched through 128 // NPN_GetUrl[Notify]. 129 PluginStreamUrl* CreateStream(unsigned long resource_id, 130 const GURL& url, 131 const std::string& mime_type, 132 int notify_id); 133 134 // For each instance, we track all streams. When the 135 // instance closes, all remaining streams are also 136 // closed. All streams associated with this instance 137 // should call AddStream so that they can be cleaned 138 // up when the instance shuts down. 139 void AddStream(PluginStream* stream); 140 141 // This is called when a stream is closed. We remove the stream from the 142 // list, which releases the reference maintained to the stream. 143 void RemoveStream(PluginStream* stream); 144 145 // Closes all open streams on this instance. 146 void CloseStreams(); 147 148 // Returns the WebPluginResourceClient object for a stream that has become 149 // seekable. 150 WebPluginResourceClient* GetRangeRequest(int id); 151 152 // Have the plugin create its script object. 153 NPObject* GetPluginScriptableObject(); 154 155 // Returns the form value of this instance. 156 bool GetFormValue(base::string16* value); 157 158 // WebViewDelegate methods that we implement. This is for handling 159 // callbacks during getURLNotify. 160 void DidFinishLoadWithReason(const GURL& url, NPReason reason, int notify_id); 161 162 // If true, send the Mozilla user agent instead of Chrome's to the plugin. use_mozilla_user_agent()163 bool use_mozilla_user_agent() { return use_mozilla_user_agent_; } set_use_mozilla_user_agent()164 void set_use_mozilla_user_agent() { use_mozilla_user_agent_ = true; } 165 166 // If the plugin instance is backed by a texture, return its ID in the 167 // compositor's namespace. Otherwise return 0. Returns 0 by default. 168 unsigned GetBackingTextureId(); 169 170 // Helper that implements NPN_PluginThreadAsyncCall semantics 171 void PluginThreadAsyncCall(void (*func)(void *), 172 void* userData); 173 174 uint32 ScheduleTimer(uint32 interval, 175 NPBool repeat, 176 void (*func)(NPP id, uint32 timer_id)); 177 178 void UnscheduleTimer(uint32 timer_id); 179 180 bool ConvertPoint(double source_x, double source_y, 181 NPCoordinateSpace source_space, 182 double* dest_x, double* dest_y, 183 NPCoordinateSpace dest_space); 184 185 NPError PopUpContextMenu(NPMenu* menu); 186 187 // 188 // NPAPI methods for calling the Plugin Instance 189 // 190 NPError NPP_New(unsigned short, short, char *[], char *[]); 191 NPError NPP_SetWindow(NPWindow*); 192 NPError NPP_NewStream(NPMIMEType, NPStream*, NPBool, unsigned short*); 193 NPError NPP_DestroyStream(NPStream*, NPReason); 194 int NPP_WriteReady(NPStream*); 195 int NPP_Write(NPStream*, int, int, void*); 196 void NPP_StreamAsFile(NPStream*, const char*); 197 void NPP_URLNotify(const char*, NPReason, void*); 198 NPError NPP_GetValue(NPPVariable, void*); 199 NPError NPP_SetValue(NPNVariable, void*); 200 short NPP_HandleEvent(void*); 201 void NPP_Destroy(); 202 bool NPP_Print(NPPrint* platform_print); 203 void NPP_URLRedirectNotify(const char* url, int32_t status, 204 void* notify_data); 205 206 void SendJavaScriptStream(const GURL& url, 207 const std::string& result, 208 bool success, 209 int notify_id); 210 211 void DidReceiveManualResponse(const GURL& url, 212 const std::string& mime_type, 213 const std::string& headers, 214 uint32 expected_length, 215 uint32 last_modified); 216 void DidReceiveManualData(const char* buffer, int length); 217 void DidFinishManualLoading(); 218 void DidManualLoadFail(); 219 220 void PushPopupsEnabledState(bool enabled); 221 void PopPopupsEnabledState(); 222 popups_allowed()223 bool popups_allowed() const { 224 return popups_enabled_stack_.empty() ? false : popups_enabled_stack_.top(); 225 } 226 227 // Initiates byte range reads for plugins. 228 void RequestRead(NPStream* stream, NPByteRange* range_list); 229 230 // Handles GetURL/GetURLNotify/PostURL/PostURLNotify requests initiated 231 // by plugins. 232 void RequestURL(const char* url, 233 const char* method, 234 const char* target, 235 const char* buf, 236 unsigned int len, 237 bool notify, 238 void* notify_data); 239 240 // Handles NPN_URLRedirectResponse calls issued by plugins in response to 241 // HTTP URL redirect notifications. 242 void URLRedirectResponse(bool allow, void* notify_data); 243 handles_url_redirects()244 bool handles_url_redirects() const { return handles_url_redirects_; } 245 246 private: 247 friend class base::RefCountedThreadSafe<PluginInstance>; 248 249 #if defined(OS_MACOSX) 250 friend class ScopedCurrentPluginEvent; 251 // Sets the event that the plugin is currently handling. The object is not 252 // owned or copied, so the caller must call this again with NULL before the 253 // event pointer becomes invalid. Clients use ScopedCurrentPluginEvent rather 254 // than calling this directly. set_currently_handled_event(NPCocoaEvent * event)255 void set_currently_handled_event(NPCocoaEvent* event) { 256 currently_handled_event_ = event; 257 } 258 #endif 259 260 ~PluginInstance(); 261 void OnPluginThreadAsyncCall(void (*func)(void *), void* userData); 262 void OnTimerCall(void (*func)(NPP id, uint32 timer_id), 263 NPP id, uint32 timer_id); 264 bool IsValidStream(const NPStream* stream); 265 void GetNotifyData(int notify_id, bool* notify, void** notify_data); 266 267 // This is a hack to get the real player plugin to work with chrome 268 // The real player plugin dll(nppl3260) when loaded by firefox is loaded via 269 // the NS COM API which is analogous to win32 COM. So the NPAPI functions in 270 // the plugin are invoked via an interface by firefox. The plugin instance 271 // handle which is passed to every NPAPI method is owned by the real player 272 // plugin, i.e. it expects the ndata member to point to a structure which 273 // it knows about. Eventually it dereferences this structure and compares 274 // a member variable at offset 0x24(Version 6.0.11.2888) /2D (Version 275 // 6.0.11.3088) with 0 and on failing this check, takes a different code 276 // path which causes a crash. Safari and Opera work with version 6.0.11.2888 277 // by chance as their ndata structure contains a 0 at the location which real 278 // player checks:(. They crash with version 6.0.11.3088 as well. The 279 // following member just adds a 96 byte padding to our PluginInstance class 280 // which is passed in the ndata member. This magic number works correctly on 281 // Vista with UAC on or off :(. 282 // NOTE: Please dont change the ordering of the member variables 283 // New members should be added after this padding array. 284 // TODO(iyengar) : Disassemble the Realplayer ndata structure and look into 285 // the possiblity of conforming to it (http://b/issue?id=936667). We 286 // could also log a bug with Real, which would save the effort. 287 uint8 zero_padding_[96]; 288 scoped_refptr<PluginLib> plugin_; 289 NPP npp_; 290 scoped_refptr<PluginHost> host_; 291 NPPluginFuncs* npp_functions_; 292 std::vector<scoped_refptr<PluginStream> > open_streams_; 293 gfx::PluginWindowHandle window_handle_; 294 bool windowless_; 295 bool transparent_; 296 WebPlugin* webplugin_; 297 std::string mime_type_; 298 GURL get_url_; 299 intptr_t get_notify_data_; 300 bool use_mozilla_user_agent_; 301 #if defined(OS_MACOSX) 302 NPDrawingModel drawing_model_; 303 NPEventModel event_model_; 304 gfx::Point plugin_origin_; 305 gfx::Rect containing_window_frame_; 306 NPCocoaEvent* currently_handled_event_; // weak 307 #endif 308 base::MessageLoop* message_loop_; 309 scoped_refptr<PluginStreamUrl> plugin_data_stream_; 310 311 // This flag if true indicates that the plugin data would be passed from 312 // webkit. if false indicates that the plugin should download the data. 313 bool load_manually_; 314 315 // Stack indicating if popups are to be enabled for the outgoing 316 // NPN_GetURL/NPN_GetURLNotify calls. 317 std::stack<bool> popups_enabled_stack_; 318 319 // True if in CloseStreams(). 320 bool in_close_streams_; 321 322 // List of files created for the current plugin instance. File names are 323 // added to the list every time the NPP_StreamAsFile function is called. 324 std::vector<base::FilePath> files_created_; 325 326 // Next unusued timer id. 327 uint32 next_timer_id_; 328 329 // Map of timer id to settings for timer. 330 struct TimerInfo { 331 uint32 interval; 332 bool repeat; 333 }; 334 typedef std::map<uint32, TimerInfo> TimerMap; 335 TimerMap timers_; 336 337 // Tracks pending GET/POST requests so that the plugin-given data doesn't 338 // cross process boundaries to an untrusted process. 339 typedef std::map<int, void*> PendingRequestMap; 340 PendingRequestMap pending_requests_; 341 int next_notify_id_; 342 343 // Used to track pending range requests so that when WebPlugin replies to us 344 // we can match the reply to the stream. 345 typedef std::map<int, scoped_refptr<PluginStream> > PendingRangeRequestMap; 346 PendingRangeRequestMap pending_range_requests_; 347 int next_range_request_id_; 348 // The plugin handles the NPAPI URL redirect notification API. 349 // See here https://wiki.mozilla.org/NPAPI:HTTPRedirectHandling 350 bool handles_url_redirects_; 351 352 DISALLOW_COPY_AND_ASSIGN(PluginInstance); 353 }; 354 355 #if defined(OS_MACOSX) 356 // Helper to simplify correct usage of set_currently_handled_event. 357 // Instantiating will set |instance|'s currently handled to |event| for the 358 // lifetime of the object, then NULL when it goes out of scope. 359 class ScopedCurrentPluginEvent { 360 public: 361 ScopedCurrentPluginEvent(PluginInstance* instance, NPCocoaEvent* event); 362 ~ScopedCurrentPluginEvent(); 363 364 private: 365 scoped_refptr<PluginInstance> instance_; 366 DISALLOW_COPY_AND_ASSIGN(ScopedCurrentPluginEvent); 367 }; 368 #endif 369 370 } // namespace content 371 372 #endif // CONTENT_CHILD_NPAPI_PLUGIN_INSTANCE_H_ 373