FireBreath  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Pages
NpapiPlugin.cpp
1 /**********************************************************\
2 Original Author: Richard Bateman (taxilian)
3 
4 Created: Oct 19, 2009
5 License: Dual license model; choose one of two:
6  New BSD License
7  http://www.opensource.org/licenses/bsd-license.php
8  - or -
9  GNU Lesser General Public License, version 2.1
10  http://www.gnu.org/licenses/lgpl-2.1.html
11 
12 Copyright 2009 Richard Bateman, Firebreath development team
13 \**********************************************************/
14 
15 #include "NpapiStream.h"
16 #include "FactoryBase.h"
17 #include "PluginCore.h"
18 #include "PluginInfo.h"
19 #include "BrowserHost.h"
20 #include "precompiled_headers.h" // On windows, everything above this line in PCH
21 
22 #include "BrowserStreamRequest.h"
23 #include "NpapiPlugin.h"
24 #include "PluginEventSink.h"
25 using namespace FB::Npapi;
26 
27 NpapiPlugin::NpapiPlugin(const NpapiBrowserHostPtr& host, const std::string& mimetype)
28  : FB::BrowserPlugin(mimetype),
29  m_obj(NULL),
30  m_npHost(host),
31  m_retainReturnedNPObject(true),
32  m_isReady(false),
33  m_mimetype(mimetype),
34  m_pluginName(getFactoryInstance()->getPluginName(mimetype)),
35  m_pluginDesc(getFactoryInstance()->getPluginDescription(mimetype))
36 {
37  pluginMain->SetHost(host);
38 }
39 
40 NpapiPlugin::~NpapiPlugin(void)
41 {
42  if (m_obj != NULL) {
43  m_npHost->ReleaseObject(m_obj);
44  }
45 }
46 
47 bool NpapiPlugin::setReady()
48 {
49  bool rval = false;
50  if (!m_isReady)
51  rval = m_isReady = pluginMain->setReady();
52  return rval;
53 }
54 
55 NPObject *NpapiPlugin::getScriptableObject()
56 {
57  if (m_obj == NULL) {
58  m_obj = NPJavascriptObject::NewObject(m_npHost, pluginMain->getRootJSAPI());
59  }
60  /* Bugfix from Facebook: Certain older versions of webkit do a retain when
61  * you return an NPObject from NPP_GetValue instead of assuming that we do
62  * it before returninglike the NPAPI spec instructs; this results in a memory
63  * leak if we don't fix it.
64  */
65  if (m_retainReturnedNPObject)
66  m_npHost->RetainObject(m_obj);
67 
68  return m_obj;
69 }
70 
71 void NpapiPlugin::shutdown(void)
72 {
73  pluginMain->ClearWindow();
74  pluginMain->shutdown();
75 }
76 
77 void NpapiPlugin::init(NPMIMEType pluginType, int16_t argc, char* argn[], char *argv[])
78 {
79  FB::VariantMap paramList;
80  for (int16_t i = 0; i < argc; i++) {
81  if (argv[i] != NULL) {
82  paramList[argn[i]] = std::string(argv[i]);
83  }
84  }
85  pluginMain->setParams(paramList);
86  setReady();
87 }
88 
89 NPError NpapiPlugin::SetWindow(NPWindow* window)
90 {
91  return NPERR_NO_ERROR;
92 }
93 
94 /*
95 NPP_GetValue retrieves instance variables, among them whether a plug-in is windowed or windowless.
96 
97 You can use this method as an optional entry point that the browser can call to determine the
98 plug-in name and description. It returns the requested values, specified by the variable and
99 value parameters, to the plug-in.
100 
101 - This also is responsible for returning the core NPObject for the plugin
102 */
103 NPError NpapiPlugin::GetValue(NPPVariable variable, void *value)
104 {
105 
106  switch (variable) {
107  case NPPVpluginNameString:
108  *((const char **)value) = m_pluginName.c_str();
109  FBLOG_TRACE("PluginCore", "GetValue(NPPVpluginNameString)");
110  break;
111  case NPPVpluginDescriptionString:
112  *((const char **)value) = m_pluginDesc.c_str();
113  FBLOG_TRACE("PluginCore", "GetValue(NPPVpluginDescriptionString)");
114  break;
115  case NPPVpluginScriptableNPObject:
116  *(NPObject **)value = getScriptableObject();
117  FBLOG_TRACE("PluginCore", "GetValue(NPPVpluginScriptableNPObject)");
118  break;
119  default:
120  FBLOG_TRACE("PluginCore", "GetValue(Unknown)");
121  return NPERR_GENERIC_ERROR;
122  }
123  return NPERR_NO_ERROR;
124 }
125 
126 /*
127 This call is used to inform plugins of variable information controlled by the browser.
128 
129 I don't know of any time that this is actually used, but I'm sure there are uses =]
130 */
131 NPError NpapiPlugin::SetValue(NPNVariable variable, void *value)
132 {
133  return NPERR_NO_ERROR;
134 }
135 
136 /*
137 The browser calls NPP_WriteReady before each call to NPP_Write to determine whether a plug-in can
138 receive data and how many bytes it can receive. This function allows the browser to send only as
139 much data to the instance as it can handle at one time, making resource use more efficient for
140 both the browser and plug-in.
141 
142 The NPP_Write function may pass a larger buffer, but the plug-in is required to consume only the
143 amount of data returned by NPP_WriteReady.
144 
145 The browser can write a smaller amount of data if desired or necessary; for example, if only 8K of
146 data is available in a network buffer. If the plug-in is allocating memory for the entire stream
147 at once (an AS_FILE stream), it can return a very large number. Because it is not processing
148 streaming data, the browser can pass as much data to the instance as necessary in a single
149 NPP_Write.
150 
151 If the plug-in receives a value of zero, the data flow temporarily stops. The browser checks to
152 see if the plug-in can receive data again by resending the data at regular intervals.
153 */
154 int32_t NpapiPlugin::WriteReady(NPStream* stream)
155 {
156  NpapiStream* s = static_cast<NpapiStream*>( stream->pdata );
157  // check for streams we did not request or create
158  if ( !s ) return -1;
159 
160  return s->getInternalBufferSize();
161 }
162 
163 /*
164 The browser calls the NPP_Write function to deliver the data specified in a previous
165 NPP_WriteReady call to the plug-in. A plug-in must consume at least as many bytes as indicated in
166 the NPP_WriteReady call.
167 
168 After a stream is created by a call to NPP_NewStream, the browser calls NPP_Write either:
169 
170  * If the plug-in requested a normal-mode stream, the data in the stream is delivered to the
171  plug-in instance in a series of calls to NPP_WriteReady and NPP_Write.
172  * If the plug-in requested a seekable stream, the NPN_RequestRead function requests reads of
173  a specified byte range that results in a series of calls to NPP_WriteReady and NPP_Write.
174 
175 The plug-in can use the offset parameter to track the bytes that are written. This gives you
176 different information depending in the type of stream. In a normal-mode stream., the parameter
177 value increases as the each buffer is written. The buf parameter is not persistent, so the plug-in
178 must process data immediately or allocate memory and save a copy of it. In a seekable stream with
179 byte range requests, you can use this parameter to track NPN_RequestRead requests.
180 */
181 int32_t NpapiPlugin::Write(NPStream* stream, int32_t offset, int32_t len, void* buffer)
182 {
183  NpapiStream* s = static_cast<NpapiStream*>( stream->pdata );
184  // check for streams we did not request or create
185  if ( !s ) return -1;
186 
187  return s->signalDataArrived( buffer, len, offset );
188 }
189 
190 /*
191 When the stream is complete, the browser calls NPP_StreamAsFile to provide the instance with a
192 full path name for a local file for the stream. NPP_StreamAsFile is called for streams whose mode
193 is set to NP_ASFILEONLY or NP_ASFILE only in a previous call to NPP_NewStream.
194 
195 If an error occurs while retrieving the data or writing the file, the file name (fname) is null.
196 */
197 void NpapiPlugin::StreamAsFile(NPStream* stream, const char* fname)
198 {
199  NpapiStream* s = static_cast<NpapiStream*>( stream->pdata );
200  // check for streams we did not request or create
201  if ( !s ) return;
202 
203  std::string cacheFilename( fname );
204  s->signalCacheFilename( std::wstring( cacheFilename.begin(), cacheFilename.end() ) );
205 }
206 
207 
208 /*
209 The browser calls NPP_URLNotify after the completion of a NPN_GetURLNotify or NPN_PostURLNotify
210 request to inform the plug-in that the request was completed and supply a reason code for the
211 completion.
212 
213 The most common reason code is NPRES_DONE, indicating simply that the request completed normally.
214 Other possible reason codes are NPRES_USER_BREAK, indicating that the request was halted due to a
215 user action (for example, clicking the Stop button), and NPRES_NETWORK_ERR, indicating that the
216 request could not be completed, perhaps because the URL could not be found.
217 
218 The parameter notifyData is the plug-in-private value passed as an argument by a previous
219 NPN_GetURLNotify or NPN_PostURLNotify call, and can be used as an identifier for the request.
220 */
221 void NpapiPlugin::URLNotify(const char* url, NPReason reason, void* notifyData)
222 {
223  NpapiStream* s = static_cast<NpapiStream*>( notifyData );
224  // check for streams we did not request or create
225  if ( !s ) return;
226 
227  s->signalCompleted( reason == NPRES_DONE );
228  s->setNotified();
229 }
230 
231 /*
232 NPP_Print is called when the user requests printing for a web page that contains a visible plug-in
233 (either embedded or full-page). It uses the print mode set in the NPPrint structure in its
234 printInfo parameter to determine whether the plug-in should print as an embedded plug-in or as a
235 full-page plug-in.
236 
237  * An embedded plug-in shares printing with the browser; the plug-in prints the part of the
238  page it occupies, and the browser handles everything else, including displaying print dialog
239  boxes, getting the printer device context, and any other tasks involved in printing, as well
240  as printing the rest of the page. For an embedded plug-in, set the printInfo field to
241  NPEmbedPrint.
242  * A full-page plug-in handles all aspects of printing itself. For a full-page plug-in, set the
243  printInfo field to NPFullPrint or null.
244 
245 For information about printing on your platform, see your platform documentation.
246 MS Windows
247 
248 On MS Windows printInfo->print.embedPrint.platformPrint is the device context (DC) handle. Be sure
249 to cast this to type HDC.
250 
251 The coordinates for the window rectangle are in TWIPS format. This means that you need to convert
252 the x-y coordinates using the Windows API call DPtoLP when you output text.
253 */
254 void NpapiPlugin::Print(NPPrint* platformPrint)
255 {
256 }
257 
258 /*
259 The browser calls NPP_HandleEvent to tell the plug-in when events take place in the plug-in's
260 window or drawable area. The plug-in either handles or ignores the event, depending on the value
261 given in the event parameter of this function. For a list of event types the application is
262 responsible for delivering to the plug-in, see the NPEvent structure.
263 
264 MS Windows
265 ----------
266 The browser gives each windowed plug-in its own native window, often a child window of the browser
267 window, to draw into. The plug-in has complete control over drawing and event handling within that
268 window.
269 
270 Mac OS
271 ------
272 The browser does not give a windowed plug-in a native window, because the Mac OS platform does not
273 support child windows. Instead, the windowed plug-in draws into the graphics port associated with
274 the the browser window, at the offset that the browser specifies. For this reason, NPP_HandleEvent
275 is only way the plug-in can receive events from its host application on Mac OS. When
276 NPP_HandleEvent is called, the current port is set up so that its origin matches the top-left
277 corner of the plug-in. A plug-in does not need to set up the current port for mouse coordinate
278 translation.
279 */
280 int16_t NpapiPlugin::HandleEvent(void* event)
281 {
282  return 0; // 0, false, indicates that the event was not handled
283 }
284 
285 
286 /*
287 see https://developer.mozilla.org/en/NPP_NewStream
288 
289 NPP_NewStream notifies the plug-in when a new stream is created. The NPStream* pointer is valid
290 until the stream is destroyed. The plug-in can store plug-in-private data associated with the
291 stream in stream->pdata. The MIME type of the stream is provided by the type parameter.
292 
293 The data in the stream can be the file specified in the SRC attribute of the EMBED tag, for an
294 embedded instance, or the file itself, for a full-page instance. A plug-in can also request a
295 stream with the function NPN_GetURL. The browser calls NPP_DestroyStream when the stream completes
296 (either successfully or abnormally). The plug-in can terminate the stream itself by calling
297 NPN_DestroyStream.
298 */
299 NPError NpapiPlugin::NewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
300 {
301  if (stream->notifyData && !stream->pdata) stream->pdata = stream->notifyData;
302 
303  NpapiStream* s = static_cast<NpapiStream*>( stream->pdata );
304  // check for streams we did not request or create
305  if ( !s )
306  {
307  // Create a BrowserStreamRequest; only GET is supported
308  BrowserStreamRequest streamReq(stream->url, "GET", false);
309  streamReq.setLastModified(stream->lastmodified);
310  if (stream->headers) {
311  streamReq.setHeaders(stream->headers);
312  }
313  streamReq.setSeekable(seekable != 0);
314 
315  pluginMain->handleUnsolicitedStream(streamReq);
316 
317  FB::BrowserStreamPtr newstream;
318  if (streamReq.wasAccepted()) {
319  newstream = m_npHost->createUnsolicitedStream(streamReq);
320  PluginEventSinkPtr sink(streamReq.getEventSink());
321  if (sink) {
322  newstream->AttachObserver(sink);
323  } else {
324  HttpCallback callback(streamReq.getCallback());
325  if (callback) {
326  SimpleStreamHelper::AsyncRequest(m_npHost, newstream, streamReq);
327  } else {
328  FBLOG_WARN("NpapiPlugin", "Unsolicited request accepted but no callback or sink provided");
329  }
330  }
331  // continue function using the newly created stream object
332  s = dynamic_cast<NpapiStream*> ( newstream.get() );
333  stream->pdata = static_cast<void*>( s );
334  }
335  }
336 
337  if ( !s ) return NPERR_NO_ERROR;
338 
339  s->setMimeType( type );
340  s->setStream( stream );
341  s->setLength( stream->end );
342  s->setUrl( stream->url );
343  if( stream->headers ) s->setHeaders( stream->headers );
344  s->setSeekableByServer( seekable ? true : false );
345 
346  if ( s->isSeekableRequested() && !s->isSeekableByServer() ) // requested seekable stream, but stream was not seekable
347  { // stream can only be made seekable by downloading the entire file
348  // which we don't want to happen automatically.
349  s->signalFailedOpen();
350  // If unsuccessful, the function should return one of the NPError Error Codes.
351  // This will cause the browser to destroy the stream without calling NPP_DestroyStream.
352  s->setStream( 0 );
353  return NPERR_STREAM_NOT_SEEKABLE;
354  }
355 
356  if ( s->isSeekable() ) *stype = NP_SEEK;
357  else if ( s->isCached() ) *stype = NP_ASFILE;
358  else *stype = NP_NORMAL;
359 
360  // first npp_newstream has to finish before the user may perform a RequestRead in the opened handler
361  if ( s->isSeekable() ) signalStreamOpened( s ); //m_npHost->ScheduleAsyncCall( signalStreamOpened, s );
362  else signalStreamOpened( s );
363 
364  return NPERR_NO_ERROR;
365 }
366 
367 void NpapiPlugin::signalStreamOpened(FB::BrowserStream* stream)
368 {
369  NpapiStream* s = dynamic_cast<NpapiStream*>(stream);
370  if ( s != NULL && !s->isCompleted() ) s->signalOpened();
371 }
372 
373 
374 /*
375 The browser calls the NPP_DestroyStream function when a data stream sent to the plug-in is
376 finished, either because it has completed successfully or terminated abnormally. After this, the
377 browser deletes the NPStream object.
378 
379 You should delete any private data allocated in stream->pdata at this time, and should not make
380 any further references to the stream object.
381 */
382 NPError NpapiPlugin::DestroyStream(NPStream* stream, NPReason reason)
383 {
384  NpapiStream* s = static_cast<NpapiStream*>( stream->pdata );
385  // check for streams we did not request or create
386  if ( !s || !s->getStream() ) return NPERR_NO_ERROR;
387 
388  s->setStream( 0 );
389  stream->pdata = 0;
390  stream->notifyData = 0;
391 
392  if ( !s->isCompleted() ) s->signalCompleted( reason == NPRES_DONE );
393  s->setDestroyed();
394 
395  return NPERR_NO_ERROR;
396 }
397 
398 
static FB::SimpleStreamHelperPtr AsyncRequest(const BrowserHostConstPtr &host, const BrowserStreamRequest &req)
Creates an asynchronous HTTP request from the provided BrowserStreamRequest.
This is the abstract base class (interface class) for a browser stream.
Definition: BrowserStream.h:41
std::map< std::string, variant > VariantMap
Defines an alias representing a string -> variant map.
Definition: APITypes.h:72