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
26namespace base {
27class MessageLoop;
28}
29
30namespace content {
31
32class PluginLib;
33class PluginHost;
34class PluginStream;
35class PluginStreamUrl;
36class WebPlugin;
37class WebPluginResourceClient;
38
39#if defined(OS_MACOSX)
40class ScopedCurrentPluginEvent;
41#endif
42
43// A PluginInstance is an active, running instance of a Plugin.
44// A single plugin may have many PluginInstances.
45class 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
76  NPP npp() { return npp_; }
77
78  // Get/Set for the instance's window handle.
79  gfx::PluginWindowHandle window_handle() const { return window_handle_; }
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.
86  bool windowless() { return windowless_; }
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.
94  bool transparent() { return transparent_; }
95  void set_transparent(bool value) { transparent_ = value; }
96
97  // Get/Set the WebPlugin associated with this instance
98  WebPlugin* webplugin() { return webplugin_; }
99  void set_web_plugin(WebPlugin* webplugin) {
100    webplugin_ = webplugin;
101  }
102
103  // Get the mimeType for this plugin stream
104  const std::string &mime_type() { return mime_type_; }
105
106  PluginLib* plugin_lib() { return plugin_.get(); }
107
108#if defined(OS_MACOSX)
109  // Get/Set the Mac NPAPI drawing and event models
110  NPDrawingModel drawing_model() { return drawing_model_; }
111  void set_drawing_model(NPDrawingModel value) { drawing_model_ = value; }
112  NPEventModel event_model() { return event_model_; }
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.
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.
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.
163  bool use_mozilla_user_agent() { return 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
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
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.
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.
359class 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