1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Sean Echevarria <sean@beatnik.com>
24 : * HÃ¥kan Waara <hwaara@chello.se>
25 : * Josh Aas <josh@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /* nsPluginHost.cpp - top-level plugin management code */
42 :
43 : #include "nscore.h"
44 : #include "nsPluginHost.h"
45 :
46 : #include <stdio.h>
47 : #include "prio.h"
48 : #include "prmem.h"
49 : #include "nsIComponentManager.h"
50 : #include "nsNPAPIPlugin.h"
51 : #include "nsNPAPIPluginStreamListener.h"
52 : #include "nsNPAPIPluginInstance.h"
53 : #include "nsIPluginStreamListener.h"
54 : #include "nsIHTTPHeaderListener.h"
55 : #include "nsIHttpHeaderVisitor.h"
56 : #include "nsIObserverService.h"
57 : #include "nsIHttpProtocolHandler.h"
58 : #include "nsIHttpChannel.h"
59 : #include "nsIHttpChannelInternal.h"
60 : #include "nsIUploadChannel.h"
61 : #include "nsIByteRangeRequest.h"
62 : #include "nsIStreamListener.h"
63 : #include "nsIInputStream.h"
64 : #include "nsIOutputStream.h"
65 : #include "nsIURL.h"
66 : #include "nsXPIDLString.h"
67 : #include "nsReadableUtils.h"
68 : #include "nsIProtocolProxyService.h"
69 : #include "nsIStreamConverterService.h"
70 : #include "nsIFile.h"
71 : #if defined(XP_MACOSX)
72 : #include "nsILocalFileMac.h"
73 : #endif
74 : #include "nsIInputStream.h"
75 : #include "nsIIOService.h"
76 : #include "nsIURL.h"
77 : #include "nsIChannel.h"
78 : #include "nsISeekableStream.h"
79 : #include "nsNetUtil.h"
80 : #include "nsIProgressEventSink.h"
81 : #include "nsIDocument.h"
82 : #include "nsICachingChannel.h"
83 : #include "nsHashtable.h"
84 : #include "nsIProxyInfo.h"
85 : #include "nsPluginLogging.h"
86 : #include "nsIPrefBranch.h"
87 : #include "nsIScriptChannel.h"
88 : #include "nsIBlocklistService.h"
89 : #include "nsVersionComparator.h"
90 : #include "nsIPrivateBrowsingService.h"
91 : #include "nsIObjectLoadingContent.h"
92 : #include "nsIWritablePropertyBag2.h"
93 : #include "nsPluginStreamListenerPeer.h"
94 :
95 : #include "nsEnumeratorUtils.h"
96 : #include "nsXPCOM.h"
97 : #include "nsXPCOMCID.h"
98 : #include "nsISupportsPrimitives.h"
99 :
100 : #include "nsXULAppAPI.h"
101 : #include "nsIXULRuntime.h"
102 :
103 : // for the dialog
104 : #include "nsIStringBundle.h"
105 : #include "nsIWindowWatcher.h"
106 : #include "nsPIDOMWindow.h"
107 :
108 : #include "nsIScriptGlobalObject.h"
109 : #include "nsIScriptGlobalObjectOwner.h"
110 : #include "nsIPrincipal.h"
111 :
112 : #include "nsNetCID.h"
113 : #include "nsIDOMPlugin.h"
114 : #include "nsIDOMMimeType.h"
115 : #include "nsMimeTypes.h"
116 : #include "prprf.h"
117 : #include "nsThreadUtils.h"
118 : #include "nsIInputStreamTee.h"
119 : #include "nsIInterfaceInfoManager.h"
120 : #include "xptinfo.h"
121 :
122 : #include "nsIMIMEService.h"
123 : #include "nsCExternalHandlerService.h"
124 : #include "nsILocalFile.h"
125 : #include "nsIFileChannel.h"
126 :
127 : #include "nsPluginSafety.h"
128 :
129 : #include "nsICharsetConverterManager.h"
130 : #include "nsIPlatformCharset.h"
131 :
132 : #include "nsIDirectoryService.h"
133 : #include "nsDirectoryServiceDefs.h"
134 : #include "nsXULAppAPI.h"
135 : #include "nsAppDirectoryServiceDefs.h"
136 : #include "nsIFile.h"
137 : #include "nsPluginDirServiceProvider.h"
138 : #include "nsPluginError.h"
139 :
140 : #include "nsUnicharUtils.h"
141 : #include "nsPluginManifestLineReader.h"
142 :
143 : #include "nsIWeakReferenceUtils.h"
144 : #include "nsIDOMElement.h"
145 : #include "nsIDOMHTMLObjectElement.h"
146 : #include "nsIDOMHTMLEmbedElement.h"
147 : #include "nsIPresShell.h"
148 : #include "nsIWebNavigation.h"
149 : #include "nsISupportsArray.h"
150 : #include "nsIDocShell.h"
151 : #include "nsPluginNativeWindow.h"
152 : #include "nsIScriptSecurityManager.h"
153 : #include "nsIContentPolicy.h"
154 : #include "nsContentPolicyUtils.h"
155 : #include "nsContentErrors.h"
156 : #include "mozilla/TimeStamp.h"
157 : #include "mozilla/Telemetry.h"
158 : #include "nsIImageLoadingContent.h"
159 : #include "mozilla/Preferences.h"
160 :
161 : #if defined(XP_WIN)
162 : #include "nsIWindowMediator.h"
163 : #include "nsIBaseWindow.h"
164 : #include "windows.h"
165 : #include "winbase.h"
166 : #endif
167 :
168 : #ifdef ANDROID
169 : #include <android/log.h>
170 : #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
171 : #endif
172 :
173 : using namespace mozilla;
174 : using mozilla::TimeStamp;
175 :
176 : // Null out a strong ref to a linked list iteratively to avoid
177 : // exhausting the stack (bug 486349).
178 : #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_) \
179 : { \
180 : while (list_) { \
181 : type_ temp = list_->mNext_; \
182 : list_->mNext_ = nsnull; \
183 : list_ = temp; \
184 : } \
185 : }
186 :
187 : // this is the name of the directory which will be created
188 : // to cache temporary files.
189 : #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
190 :
191 : // Version of cached plugin info
192 : // 0.01 first implementation
193 : // 0.02 added caching of CanUnload to fix bug 105935
194 : // 0.03 changed name, description and mime desc from string to bytes, bug 108246
195 : // 0.04 added new mime entry point on Mac, bug 113464
196 : // 0.05 added new entry point check for the default plugin, bug 132430
197 : // 0.06 strip off suffixes in mime description strings, bug 53895
198 : // 0.07 changed nsIRegistry to flat file support for caching plugins info
199 : // 0.08 mime entry point on MachO, bug 137535
200 : // 0.09 the file encoding is changed to UTF-8, bug 420285
201 : // 0.10 added plugin versions on appropriate platforms, bug 427743
202 : // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
203 : // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
204 : // 0.13 add architecture and list of invalid plugins, bug 616271
205 : // 0.14 force refresh due to locale comparison fix, bug 611296
206 : // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
207 : // The current plugin registry version (and the maximum version we know how to read)
208 : static const char *kPluginRegistryVersion = "0.15";
209 : // The minimum registry version we know how to read
210 : static const char *kMinimumRegistryVersion = "0.9";
211 :
212 : static NS_DEFINE_IID(kIPluginTagInfoIID, NS_IPLUGINTAGINFO_IID);
213 : static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
214 :
215 : // Registry keys for caching plugin info
216 : static const char kPluginsRootKey[] = "software/plugins";
217 : static const char kPluginsNameKey[] = "name";
218 : static const char kPluginsDescKey[] = "description";
219 : static const char kPluginsFilenameKey[] = "filename";
220 : static const char kPluginsFullpathKey[] = "fullpath";
221 : static const char kPluginsModTimeKey[] = "lastModTimeStamp";
222 : static const char kPluginsCanUnload[] = "canUnload";
223 : static const char kPluginsVersionKey[] = "version";
224 : static const char kPluginsMimeTypeKey[] = "mimetype";
225 : static const char kPluginsMimeDescKey[] = "description";
226 : static const char kPluginsMimeExtKey[] = "extension";
227 :
228 : #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
229 :
230 : #ifdef PLUGIN_LOGGING
231 : PRLogModuleInfo* nsPluginLogging::gNPNLog = nsnull;
232 : PRLogModuleInfo* nsPluginLogging::gNPPLog = nsnull;
233 : PRLogModuleInfo* nsPluginLogging::gPluginLog = nsnull;
234 : #endif
235 :
236 : #define BRAND_PROPERTIES_URL "chrome://branding/locale/brand.properties"
237 : #define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
238 :
239 : // #defines for plugin cache and prefs
240 : #define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
241 : // Raise this from '10' to '50' to work around a bug in Apple's current Java
242 : // plugins on OS X Lion and SnowLeopard. See bug 705931.
243 : #define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
244 :
245 : #ifdef CALL_SAFETY_ON
246 : // By default we run OOPP, so we don't want to cover up crashes.
247 : bool gSkipPluginSafeCalls = true;
248 : #endif
249 :
250 : nsIFile *nsPluginHost::sPluginTempDir;
251 : nsPluginHost *nsPluginHost::sInst;
252 :
253 0 : NS_IMPL_ISUPPORTS0(nsInvalidPluginTag)
254 :
255 0 : nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath, PRInt64 aLastModifiedTime)
256 : : mFullPath(aFullPath),
257 : mLastModifiedTime(aLastModifiedTime),
258 0 : mSeen(false)
259 : {
260 :
261 0 : }
262 :
263 0 : nsInvalidPluginTag::~nsInvalidPluginTag()
264 : {
265 :
266 0 : }
267 :
268 : // flat file reg funcs
269 : static
270 29 : bool ReadSectionHeader(nsPluginManifestLineReader& reader, const char *token)
271 : {
272 15 : do {
273 29 : if (*reader.LinePtr() == '[') {
274 14 : char* p = reader.LinePtr() + (reader.LineLength() - 1);
275 14 : if (*p != ']')
276 0 : break;
277 14 : *p = 0;
278 :
279 : char* values[1];
280 14 : if (1 != reader.ParseLine(values, 1))
281 0 : break;
282 : // ignore the leading '['
283 14 : if (PL_strcmp(values[0]+1, token)) {
284 0 : break; // it's wrong token
285 : }
286 14 : return true;
287 : }
288 : } while (reader.NextLine());
289 0 : return false;
290 : }
291 :
292 : // Little helper struct to asynchronously reframe any presentations (embedded)
293 : // or reload any documents (full-page), that contained plugins
294 : // which were shutdown as a result of a plugins.refresh(1)
295 0 : class nsPluginDocReframeEvent: public nsRunnable {
296 : public:
297 0 : nsPluginDocReframeEvent(nsISupportsArray* aDocs) { mDocs = aDocs; }
298 :
299 : NS_DECL_NSIRUNNABLE
300 :
301 : nsCOMPtr<nsISupportsArray> mDocs;
302 : };
303 :
304 0 : NS_IMETHODIMP nsPluginDocReframeEvent::Run() {
305 0 : NS_ENSURE_TRUE(mDocs, NS_ERROR_FAILURE);
306 :
307 : PRUint32 c;
308 0 : mDocs->Count(&c);
309 :
310 : // for each document (which previously had a running instance), tell
311 : // the frame constructor to rebuild
312 0 : for (PRUint32 i = 0; i < c; i++) {
313 0 : nsCOMPtr<nsIDocument> doc (do_QueryElementAt(mDocs, i));
314 0 : if (doc) {
315 0 : nsIPresShell *shell = doc->GetShell();
316 :
317 : // if this document has a presentation shell, then it has frames and can be reframed
318 0 : if (shell) {
319 : /* A reframe will cause a fresh object frame, instance owner, and instance
320 : * to be created. Reframing of the entire document is necessary as we may have
321 : * recently found new plugins and we want a shot at trying to use them instead
322 : * of leaving alternate renderings.
323 : * We do not want to completely reload all the documents that had running plugins
324 : * because we could possibly trigger a script to run in the unload event handler
325 : * which may want to access our defunct plugin and cause us to crash.
326 : */
327 :
328 0 : shell->ReconstructFrames(); // causes reframe of document
329 : } else { // no pres shell --> full-page plugin
330 :
331 0 : NS_NOTREACHED("all plugins should have a pres shell!");
332 :
333 : }
334 : }
335 : }
336 :
337 0 : return mDocs->Clear();
338 : }
339 :
340 173 : static bool UnloadPluginsASAP()
341 : {
342 : nsresult rv;
343 346 : nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
344 173 : if (NS_SUCCEEDED(rv)) {
345 173 : bool unloadPluginsASAP = false;
346 173 : rv = pref->GetBoolPref("dom.ipc.plugins.unloadASAP", &unloadPluginsASAP);
347 173 : if (NS_SUCCEEDED(rv)) {
348 0 : return unloadPluginsASAP;
349 : }
350 : }
351 :
352 173 : return false;
353 : }
354 :
355 173 : nsPluginHost::nsPluginHost()
356 : // No need to initialize members to nsnull, false etc because this class
357 : // has a zeroing operator new.
358 : {
359 : // check to see if pref is set at startup to let plugins take over in
360 : // full page mode for certain image mime types that we handle internally
361 173 : mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
362 173 : if (mPrefService) {
363 : bool tmp;
364 173 : nsresult rv = mPrefService->GetBoolPref("plugin.override_internal_types",
365 173 : &tmp);
366 173 : if (NS_SUCCEEDED(rv)) {
367 173 : mOverrideInternalTypes = tmp;
368 : }
369 :
370 173 : rv = mPrefService->GetBoolPref("plugin.disable", &tmp);
371 173 : if (NS_SUCCEEDED(rv)) {
372 0 : mPluginsDisabled = tmp;
373 : }
374 : }
375 :
376 : nsCOMPtr<nsIObserverService> obsService =
377 346 : mozilla::services::GetObserverService();
378 173 : if (obsService) {
379 173 : obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
380 173 : obsService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
381 : #ifdef MOZ_WIDGET_ANDROID
382 : obsService->AddObserver(this, "application-foreground", false);
383 : obsService->AddObserver(this, "application-background", false);
384 : #endif
385 : }
386 :
387 : #ifdef PLUGIN_LOGGING
388 173 : nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME);
389 173 : nsPluginLogging::gNPPLog = PR_NewLogModule(NPP_LOG_NAME);
390 173 : nsPluginLogging::gPluginLog = PR_NewLogModule(PLUGIN_LOG_NAME);
391 :
392 173 : PR_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
393 173 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
394 173 : PR_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
395 :
396 173 : PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n"));
397 173 : PR_LogFlush();
398 : #endif
399 :
400 : #ifdef MAC_CARBON_PLUGINS
401 : mVisiblePluginTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
402 : mHiddenPluginTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
403 : #endif
404 173 : }
405 :
406 519 : nsPluginHost::~nsPluginHost()
407 : {
408 173 : PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::dtor\n"));
409 :
410 173 : Destroy();
411 173 : sInst = nsnull;
412 346 : }
413 :
414 12452 : NS_IMPL_ISUPPORTS4(nsPluginHost,
415 : nsIPluginHost,
416 : nsIObserver,
417 : nsITimerCallback,
418 : nsISupportsWeakReference)
419 :
420 : nsPluginHost*
421 173 : nsPluginHost::GetInst()
422 : {
423 173 : if (!sInst) {
424 173 : sInst = new nsPluginHost();
425 173 : if (!sInst)
426 0 : return nsnull;
427 173 : NS_ADDREF(sInst);
428 : }
429 :
430 173 : NS_ADDREF(sInst);
431 173 : return sInst;
432 : }
433 :
434 0 : bool nsPluginHost::IsRunningPlugin(nsPluginTag * plugin)
435 : {
436 0 : if (!plugin || !plugin->mEntryPoint) {
437 0 : return false;
438 : }
439 :
440 0 : for (PRUint32 i = 0; i < mInstances.Length(); i++) {
441 0 : nsNPAPIPluginInstance *instance = mInstances[i].get();
442 0 : if (instance &&
443 0 : instance->GetPlugin() == plugin->mEntryPoint &&
444 0 : instance->IsRunning()) {
445 0 : return true;
446 : }
447 : }
448 :
449 0 : return false;
450 : }
451 :
452 0 : nsresult nsPluginHost::ReloadPlugins(bool reloadPages)
453 : {
454 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
455 : ("nsPluginHost::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
456 : reloadPages, mInstances.Length()));
457 :
458 0 : nsresult rv = NS_OK;
459 :
460 : // this will create the initial plugin list out of cache
461 : // if it was not created yet
462 0 : if (!mPluginsLoaded)
463 0 : return LoadPlugins();
464 :
465 : // we are re-scanning plugins. New plugins may have been added, also some
466 : // plugins may have been removed, so we should probably shut everything down
467 : // but don't touch running (active and not stopped) plugins
468 :
469 : // check if plugins changed, no need to do anything else
470 : // if no changes to plugins have been made
471 : // false instructs not to touch the plugin list, just to
472 : // look for possible changes
473 0 : bool pluginschanged = true;
474 0 : FindPlugins(false, &pluginschanged);
475 :
476 : // if no changed detected, return an appropriate error code
477 0 : if (!pluginschanged)
478 0 : return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
479 :
480 0 : nsCOMPtr<nsISupportsArray> instsToReload;
481 0 : if (reloadPages) {
482 0 : NS_NewISupportsArray(getter_AddRefs(instsToReload));
483 :
484 : // Then stop any running plugin instances but hold on to the documents in the array
485 : // We are going to need to restart the instances in these documents later
486 0 : DestroyRunningInstances(instsToReload, nsnull);
487 : }
488 :
489 : // shutdown plugins and kill the list if there are no running plugins
490 0 : nsRefPtr<nsPluginTag> prev;
491 0 : nsRefPtr<nsPluginTag> next;
492 :
493 0 : for (nsRefPtr<nsPluginTag> p = mPlugins; p != nsnull;) {
494 0 : next = p->mNext;
495 :
496 : // only remove our plugin from the list if it's not running.
497 0 : if (!IsRunningPlugin(p)) {
498 0 : if (p == mPlugins)
499 0 : mPlugins = next;
500 : else
501 0 : prev->mNext = next;
502 :
503 0 : p->mNext = nsnull;
504 :
505 : // attempt to unload plugins whenever they are removed from the list
506 0 : p->TryUnloadPlugin(false);
507 :
508 0 : p = next;
509 0 : continue;
510 : }
511 :
512 0 : prev = p;
513 0 : p = next;
514 : }
515 :
516 : // set flags
517 0 : mPluginsLoaded = false;
518 :
519 : // load them again
520 0 : rv = LoadPlugins();
521 :
522 : // If we have shut down any plugin instances, we've now got to restart them.
523 : // Post an event to do the rest as we are going to be destroying the frame tree and we also want
524 : // any posted unload events to finish
525 : PRUint32 c;
526 0 : if (reloadPages &&
527 0 : instsToReload &&
528 0 : NS_SUCCEEDED(instsToReload->Count(&c)) &&
529 : c > 0) {
530 0 : nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
531 0 : if (ev)
532 0 : NS_DispatchToCurrentThread(ev);
533 : }
534 :
535 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
536 : ("nsPluginHost::ReloadPlugins End active_instance_count=%d\n",
537 : mInstances.Length()));
538 :
539 0 : return rv;
540 : }
541 :
542 : #define NS_RETURN_UASTRING_SIZE 128
543 :
544 0 : nsresult nsPluginHost::UserAgent(const char **retstring)
545 : {
546 : static char resultString[NS_RETURN_UASTRING_SIZE];
547 : nsresult res;
548 :
549 0 : nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
550 0 : if (NS_FAILED(res))
551 0 : return res;
552 :
553 0 : nsCAutoString uaString;
554 0 : res = http->GetUserAgent(uaString);
555 :
556 0 : if (NS_SUCCEEDED(res)) {
557 0 : if (NS_RETURN_UASTRING_SIZE > uaString.Length()) {
558 0 : PL_strcpy(resultString, uaString.get());
559 : } else {
560 : // Copy as much of UA string as we can (terminate at right-most space).
561 0 : PL_strncpy(resultString, uaString.get(), NS_RETURN_UASTRING_SIZE);
562 0 : for (int i = NS_RETURN_UASTRING_SIZE - 1; i >= 0; i--) {
563 0 : if (i == 0) {
564 0 : resultString[NS_RETURN_UASTRING_SIZE - 1] = '\0';
565 : }
566 0 : else if (resultString[i] == ' ') {
567 0 : resultString[i] = '\0';
568 0 : break;
569 : }
570 : }
571 : }
572 0 : *retstring = resultString;
573 : }
574 : else {
575 0 : *retstring = nsnull;
576 : }
577 :
578 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::UserAgent return=%s\n", *retstring));
579 :
580 0 : return res;
581 : }
582 :
583 0 : nsresult nsPluginHost::GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt)
584 : {
585 : nsresult rv;
586 0 : nsCOMPtr<nsIPrompt> prompt;
587 0 : nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
588 :
589 0 : if (wwatch) {
590 0 : nsCOMPtr<nsIDOMWindow> domWindow;
591 0 : if (aOwner) {
592 0 : nsCOMPtr<nsIDocument> document;
593 0 : aOwner->GetDocument(getter_AddRefs(document));
594 0 : if (document) {
595 0 : domWindow = document->GetWindow();
596 : }
597 : }
598 :
599 0 : if (!domWindow) {
600 0 : wwatch->GetWindowByName(NS_LITERAL_STRING("_content").get(), nsnull, getter_AddRefs(domWindow));
601 : }
602 0 : rv = wwatch->GetNewPrompter(domWindow, getter_AddRefs(prompt));
603 : }
604 :
605 0 : NS_IF_ADDREF(*aPrompt = prompt);
606 0 : return rv;
607 : }
608 :
609 0 : nsresult nsPluginHost::GetURL(nsISupports* pluginInst,
610 : const char* url,
611 : const char* target,
612 : nsIPluginStreamListener* streamListener,
613 : const char* altHost,
614 : const char* referrer,
615 : bool forceJSEnabled)
616 : {
617 : return GetURLWithHeaders(static_cast<nsNPAPIPluginInstance*>(pluginInst),
618 : url, target, streamListener, altHost, referrer,
619 0 : forceJSEnabled, nsnull, nsnull);
620 : }
621 :
622 0 : nsresult nsPluginHost::GetURLWithHeaders(nsNPAPIPluginInstance* pluginInst,
623 : const char* url,
624 : const char* target,
625 : nsIPluginStreamListener* streamListener,
626 : const char* altHost,
627 : const char* referrer,
628 : bool forceJSEnabled,
629 : PRUint32 getHeadersLength,
630 : const char* getHeaders)
631 : {
632 : // we can only send a stream back to the plugin (as specified by a
633 : // null target) if we also have a nsIPluginStreamListener to talk to
634 0 : if (!target && !streamListener)
635 0 : return NS_ERROR_ILLEGAL_VALUE;
636 :
637 0 : nsresult rv = DoURLLoadSecurityCheck(pluginInst, url);
638 0 : if (NS_FAILED(rv))
639 0 : return rv;
640 :
641 0 : if (target) {
642 0 : nsCOMPtr<nsIPluginInstanceOwner> owner;
643 0 : rv = pluginInst->GetOwner(getter_AddRefs(owner));
644 0 : if (owner) {
645 0 : if ((0 == PL_strcmp(target, "newwindow")) ||
646 0 : (0 == PL_strcmp(target, "_new")))
647 0 : target = "_blank";
648 0 : else if (0 == PL_strcmp(target, "_current"))
649 0 : target = "_self";
650 :
651 0 : rv = owner->GetURL(url, target, nsnull, nsnull, 0);
652 : }
653 : }
654 :
655 0 : if (streamListener)
656 0 : rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), pluginInst,
657 : streamListener, nsnull,
658 0 : getHeaders, getHeadersLength);
659 :
660 0 : return rv;
661 : }
662 :
663 0 : nsresult nsPluginHost::PostURL(nsISupports* pluginInst,
664 : const char* url,
665 : PRUint32 postDataLen,
666 : const char* postData,
667 : bool isFile,
668 : const char* target,
669 : nsIPluginStreamListener* streamListener,
670 : const char* altHost,
671 : const char* referrer,
672 : bool forceJSEnabled,
673 : PRUint32 postHeadersLength,
674 : const char* postHeaders)
675 : {
676 : nsresult rv;
677 :
678 : // we can only send a stream back to the plugin (as specified
679 : // by a null target) if we also have a nsIPluginStreamListener
680 : // to talk to also
681 0 : if (!target && !streamListener)
682 0 : return NS_ERROR_ILLEGAL_VALUE;
683 :
684 0 : nsNPAPIPluginInstance* instance = static_cast<nsNPAPIPluginInstance*>(pluginInst);
685 :
686 0 : rv = DoURLLoadSecurityCheck(instance, url);
687 0 : if (NS_FAILED(rv))
688 0 : return rv;
689 :
690 0 : nsCOMPtr<nsIInputStream> postStream;
691 0 : if (isFile) {
692 0 : nsCOMPtr<nsIFile> file;
693 0 : rv = CreateTempFileToPost(postData, getter_AddRefs(file));
694 0 : if (NS_FAILED(rv))
695 0 : return rv;
696 :
697 0 : nsCOMPtr<nsIInputStream> fileStream;
698 0 : rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream),
699 : file,
700 : PR_RDONLY,
701 : 0600,
702 : nsIFileInputStream::DELETE_ON_CLOSE |
703 0 : nsIFileInputStream::CLOSE_ON_EOF);
704 0 : if (NS_FAILED(rv))
705 0 : return rv;
706 :
707 0 : rv = NS_NewBufferedInputStream(getter_AddRefs(postStream), fileStream, 8192);
708 0 : if (NS_FAILED(rv))
709 0 : return rv;
710 : } else {
711 : char *dataToPost;
712 : PRUint32 newDataToPostLen;
713 0 : ParsePostBufferToFixHeaders(postData, postDataLen, &dataToPost, &newDataToPostLen);
714 0 : if (!dataToPost)
715 0 : return NS_ERROR_UNEXPECTED;
716 :
717 0 : nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
718 0 : if (!sis) {
719 0 : NS_Free(dataToPost);
720 0 : return rv;
721 : }
722 :
723 : // data allocated by ParsePostBufferToFixHeaders() is managed and
724 : // freed by the string stream.
725 0 : postDataLen = newDataToPostLen;
726 0 : sis->AdoptData(dataToPost, postDataLen);
727 0 : postStream = sis;
728 : }
729 :
730 0 : if (target) {
731 0 : nsCOMPtr<nsIPluginInstanceOwner> owner;
732 0 : rv = instance->GetOwner(getter_AddRefs(owner));
733 0 : if (owner) {
734 0 : if ((0 == PL_strcmp(target, "newwindow")) ||
735 0 : (0 == PL_strcmp(target, "_new"))) {
736 0 : target = "_blank";
737 0 : } else if (0 == PL_strcmp(target, "_current")) {
738 0 : target = "_self";
739 : }
740 0 : rv = owner->GetURL(url, target, postStream,
741 0 : (void*)postHeaders, postHeadersLength);
742 : }
743 : }
744 :
745 : // if we don't have a target, just create a stream. This does
746 : // NS_OpenURI()!
747 0 : if (streamListener)
748 0 : rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), instance,
749 : streamListener,
750 0 : postStream, postHeaders, postHeadersLength);
751 :
752 0 : return rv;
753 : }
754 :
755 : /* This method queries the prefs for proxy information.
756 : * It has been tested and is known to work in the following three cases
757 : * when no proxy host or port is specified
758 : * when only the proxy host is specified
759 : * when only the proxy port is specified
760 : * This method conforms to the return code specified in
761 : * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
762 : * with the exception that multiple values are not implemented.
763 : */
764 :
765 0 : nsresult nsPluginHost::FindProxyForURL(const char* url, char* *result)
766 : {
767 0 : if (!url || !result) {
768 0 : return NS_ERROR_INVALID_ARG;
769 : }
770 : nsresult res;
771 :
772 0 : nsCOMPtr<nsIURI> uriIn;
773 0 : nsCOMPtr<nsIProtocolProxyService> proxyService;
774 0 : nsCOMPtr<nsIIOService> ioService;
775 :
776 0 : proxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &res);
777 0 : if (NS_FAILED(res) || !proxyService)
778 0 : return res;
779 :
780 0 : ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &res);
781 0 : if (NS_FAILED(res) || !ioService)
782 0 : return res;
783 :
784 : // make an nsURI from the argument url
785 0 : res = ioService->NewURI(nsDependentCString(url), nsnull, nsnull, getter_AddRefs(uriIn));
786 0 : if (NS_FAILED(res))
787 0 : return res;
788 :
789 0 : nsCOMPtr<nsIProxyInfo> pi;
790 :
791 0 : res = proxyService->Resolve(uriIn, 0, getter_AddRefs(pi));
792 0 : if (NS_FAILED(res))
793 0 : return res;
794 :
795 0 : nsCAutoString host, type;
796 0 : PRInt32 port = -1;
797 :
798 : // These won't fail, and even if they do... we'll be ok.
799 0 : if (pi) {
800 0 : pi->GetType(type);
801 0 : pi->GetHost(host);
802 0 : pi->GetPort(&port);
803 : }
804 :
805 0 : if (!pi || host.IsEmpty() || port <= 0 || host.EqualsLiteral("direct")) {
806 0 : *result = PL_strdup("DIRECT");
807 0 : } else if (type.EqualsLiteral("http")) {
808 0 : *result = PR_smprintf("PROXY %s:%d", host.get(), port);
809 0 : } else if (type.EqualsLiteral("socks4")) {
810 0 : *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
811 0 : } else if (type.EqualsLiteral("socks")) {
812 : // XXX - this is socks5, but there is no API for us to tell the
813 : // plugin that fact. SOCKS for now, in case the proxy server
814 : // speaks SOCKS4 as well. See bug 78176
815 : // For a long time this was returning an http proxy type, so
816 : // very little is probably broken by this
817 0 : *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
818 : } else {
819 0 : NS_ASSERTION(false, "Unknown proxy type!");
820 0 : *result = PL_strdup("DIRECT");
821 : }
822 :
823 0 : if (nsnull == *result)
824 0 : res = NS_ERROR_OUT_OF_MEMORY;
825 :
826 0 : return res;
827 : }
828 :
829 0 : nsresult nsPluginHost::Init()
830 : {
831 0 : return NS_OK;
832 : }
833 :
834 346 : nsresult nsPluginHost::Destroy()
835 : {
836 346 : PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::Destroy Called\n"));
837 :
838 346 : if (mIsDestroyed)
839 173 : return NS_OK;
840 :
841 173 : mIsDestroyed = true;
842 :
843 : // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
844 : // for those plugins who want it
845 173 : DestroyRunningInstances(nsnull, nsnull);
846 :
847 : nsPluginTag *pluginTag;
848 346 : for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
849 173 : pluginTag->TryUnloadPlugin(true);
850 : }
851 :
852 173 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mPlugins, mNext);
853 173 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
854 173 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
855 :
856 : // Lets remove any of the temporary files that we created.
857 173 : if (sPluginTempDir) {
858 0 : sPluginTempDir->Remove(true);
859 0 : NS_RELEASE(sPluginTempDir);
860 : }
861 :
862 : #ifdef XP_WIN
863 : if (mPrivateDirServiceProvider) {
864 : nsCOMPtr<nsIDirectoryService> dirService =
865 : do_GetService(kDirectoryServiceContractID);
866 : if (dirService)
867 : dirService->UnregisterProvider(mPrivateDirServiceProvider);
868 : mPrivateDirServiceProvider = nsnull;
869 : }
870 : #endif /* XP_WIN */
871 :
872 173 : mPrefService = nsnull; // release prefs service to avoid leaks!
873 :
874 173 : return NS_OK;
875 : }
876 :
877 0 : void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
878 : {
879 0 : bool hasInstance = false;
880 0 : for (PRUint32 i = 0; i < mInstances.Length(); i++) {
881 0 : if (TagForPlugin(mInstances[i]->GetPlugin()) == aPluginTag) {
882 0 : hasInstance = true;
883 0 : break;
884 : }
885 : }
886 :
887 : // We have some options for unloading plugins if they have no instances.
888 : //
889 : // Unloading plugins immediately can be bad - some plugins retain state
890 : // between instances even when there are none. This is largely limited to
891 : // going from one page to another, so state is retained without an instance
892 : // for only a very short period of time. In order to allow this to work
893 : // we don't unload plugins immediately by default. This is supported
894 : // via a hidden user pref though.
895 : //
896 : // Another reason not to unload immediately is that loading is expensive,
897 : // and it is better to leave popular plugins loaded.
898 : //
899 : // Our default behavior is to try to unload a plugin three minutes after
900 : // its last instance is destroyed. This seems like a reasonable compromise
901 : // that allows us to reclaim memory while allowing short state retention
902 : // and avoid perf hits for loading popular plugins.
903 0 : if (!hasInstance) {
904 0 : if (UnloadPluginsASAP()) {
905 0 : aPluginTag->TryUnloadPlugin(false);
906 : } else {
907 0 : if (aPluginTag->mUnloadTimer) {
908 0 : aPluginTag->mUnloadTimer->Cancel();
909 : } else {
910 0 : aPluginTag->mUnloadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
911 : }
912 0 : aPluginTag->mUnloadTimer->InitWithCallback(this, 1000 * 60 * 3, nsITimer::TYPE_ONE_SHOT);
913 : }
914 : }
915 0 : }
916 :
917 : nsresult
918 0 : nsPluginHost::GetPluginTempDir(nsIFile **aDir)
919 : {
920 0 : if (!sPluginTempDir) {
921 0 : nsCOMPtr<nsIFile> tmpDir;
922 : nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
923 0 : getter_AddRefs(tmpDir));
924 0 : NS_ENSURE_SUCCESS(rv, rv);
925 :
926 0 : rv = tmpDir->AppendNative(kPluginTmpDirName);
927 :
928 : // make it unique, and mode == 0700, not world-readable
929 0 : rv = tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
930 0 : NS_ENSURE_SUCCESS(rv, rv);
931 :
932 0 : tmpDir.swap(sPluginTempDir);
933 : }
934 :
935 0 : return sPluginTempDir->Clone(aDir);
936 : }
937 :
938 0 : nsresult nsPluginHost::CreateListenerForChannel(nsIChannel* aChannel,
939 : nsObjectLoadingContent* aContent,
940 : nsIStreamListener** aListener)
941 : {
942 0 : NS_PRECONDITION(aChannel && aContent,
943 : "Invalid arguments to InstantiatePluginForChannel");
944 0 : nsCOMPtr<nsIURI> uri;
945 0 : nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
946 0 : if (NS_FAILED(rv))
947 0 : return rv;
948 :
949 : #ifdef PLUGIN_LOGGING
950 0 : if (PR_LOG_TEST(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL)) {
951 0 : nsCAutoString urlSpec;
952 0 : uri->GetAsciiSpec(urlSpec);
953 :
954 0 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
955 : ("nsPluginHost::InstantiatePluginForChannel Begin content=%p, url=%s\n",
956 : aContent, urlSpec.get()));
957 :
958 0 : PR_LogFlush();
959 : }
960 : #endif
961 :
962 : // Note that we're not setting up a plugin instance here; the stream
963 : // listener's OnStartRequest will handle doing that.
964 :
965 0 : return NewEmbeddedPluginStreamListener(uri, aContent, nsnull, aListener);
966 : }
967 :
968 : nsresult
969 0 : nsPluginHost::InstantiateEmbeddedPlugin(const char *aMimeType, nsIURI* aURL,
970 : nsObjectLoadingContent *aContent,
971 : nsPluginInstanceOwner** aOwner)
972 : {
973 0 : NS_ENSURE_ARG_POINTER(aOwner);
974 :
975 : #ifdef PLUGIN_LOGGING
976 0 : nsCAutoString urlSpec;
977 0 : if (aURL)
978 0 : aURL->GetAsciiSpec(urlSpec);
979 :
980 0 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
981 : ("nsPluginHost::InstantiateEmbeddedPlugin Begin mime=%s, url=%s\n",
982 : aMimeType, urlSpec.get()));
983 :
984 0 : PR_LogFlush();
985 : #endif
986 :
987 0 : nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
988 0 : if (!instanceOwner) {
989 0 : return NS_ERROR_OUT_OF_MEMORY;
990 : }
991 :
992 0 : nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
993 0 : nsresult rv = instanceOwner->Init(ourContent);
994 0 : if (NS_FAILED(rv)) {
995 0 : return rv;
996 : }
997 :
998 0 : nsCOMPtr<nsIPluginTagInfo> pti;
999 0 : rv = instanceOwner->QueryInterface(kIPluginTagInfoIID, getter_AddRefs(pti));
1000 0 : if (NS_FAILED(rv)) {
1001 0 : return rv;
1002 : }
1003 :
1004 : nsPluginTagType tagType;
1005 0 : rv = pti->GetTagType(&tagType);
1006 0 : if (NS_FAILED(rv)) {
1007 0 : return rv;
1008 : }
1009 :
1010 0 : if (tagType != nsPluginTagType_Embed &&
1011 : tagType != nsPluginTagType_Applet &&
1012 : tagType != nsPluginTagType_Object) {
1013 0 : return NS_ERROR_FAILURE;
1014 : }
1015 :
1016 : // Security checks. Can't do security checks without a URI - hopefully the plugin
1017 : // will take care of that.
1018 0 : if (aURL) {
1019 : nsCOMPtr<nsIScriptSecurityManager> secMan =
1020 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
1021 0 : if (NS_FAILED(rv))
1022 0 : return rv; // Better fail if we can't do security checks
1023 :
1024 0 : nsCOMPtr<nsIDocument> doc;
1025 0 : instanceOwner->GetDocument(getter_AddRefs(doc));
1026 0 : if (!doc)
1027 0 : return NS_ERROR_NULL_POINTER;
1028 :
1029 0 : rv = secMan->CheckLoadURIWithPrincipal(doc->NodePrincipal(), aURL, 0);
1030 0 : if (NS_FAILED(rv))
1031 0 : return rv;
1032 :
1033 0 : nsCOMPtr<nsIDOMElement> elem;
1034 0 : pti->GetDOMElement(getter_AddRefs(elem));
1035 :
1036 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; // default permit
1037 : nsresult rv =
1038 : NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT,
1039 : aURL,
1040 0 : doc->NodePrincipal(),
1041 : elem,
1042 0 : nsDependentCString(aMimeType ? aMimeType : ""),
1043 : nsnull, //extra
1044 0 : &shouldLoad);
1045 0 : if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad))
1046 0 : return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
1047 : }
1048 :
1049 0 : bool isJava = false;
1050 0 : nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
1051 0 : if (pluginTag) {
1052 0 : isJava = pluginTag->mIsJavaPlugin;
1053 : }
1054 :
1055 : // Determine if the scheme of this URL is one we can handle internally because we should
1056 : // only open the initial stream if it's one that we can handle internally. Otherwise
1057 : // |NS_OpenURI| in |InstantiateEmbeddedPlugin| may open up a OS protocal registered helper app
1058 : // Also set bCanHandleInternally to true if aAllowOpeningStreams is
1059 : // false; we don't want to do any network traffic in that case.
1060 0 : bool bCanHandleInternally = false;
1061 0 : nsCAutoString scheme;
1062 0 : if (aURL && NS_SUCCEEDED(aURL->GetScheme(scheme))) {
1063 0 : nsCAutoString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
1064 0 : contractID += scheme;
1065 0 : ToLowerCase(contractID);
1066 0 : nsCOMPtr<nsIProtocolHandler> handler = do_GetService(contractID.get());
1067 0 : if (handler)
1068 0 : bCanHandleInternally = true;
1069 : }
1070 :
1071 : // if we don't have a MIME type at this point, we still have one more chance by
1072 : // opening the stream and seeing if the server hands one back
1073 0 : if (!aMimeType) {
1074 0 : if (bCanHandleInternally && !aContent->SrcStreamLoading()) {
1075 0 : NewEmbeddedPluginStream(aURL, aContent, nsnull);
1076 : }
1077 0 : return NS_ERROR_FAILURE;
1078 : }
1079 :
1080 0 : rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
1081 0 : if (NS_FAILED(rv)) {
1082 0 : return NS_ERROR_FAILURE;
1083 : }
1084 :
1085 0 : nsRefPtr<nsNPAPIPluginInstance> instance;
1086 0 : rv = instanceOwner->GetInstance(getter_AddRefs(instance));
1087 0 : if (NS_FAILED(rv)) {
1088 0 : return rv;
1089 : }
1090 :
1091 0 : if (instance) {
1092 0 : instanceOwner->CreateWidget();
1093 :
1094 : // If we've got a native window, the let the plugin know about it.
1095 0 : instanceOwner->CallSetWindow();
1096 :
1097 : // create an initial stream with data
1098 : // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
1099 : // no need to check for "data" as it would have been converted to "src"
1100 : const char *value;
1101 0 : bool havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
1102 0 : if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoading()) {
1103 0 : NewEmbeddedPluginStream(aURL, aContent, instance.get());
1104 : }
1105 : }
1106 :
1107 : // At this point we consider instantiation to be successful. Do not return an error.
1108 0 : instanceOwner.forget(aOwner);
1109 :
1110 : #ifdef PLUGIN_LOGGING
1111 0 : nsCAutoString urlSpec2;
1112 0 : if (aURL != nsnull) aURL->GetAsciiSpec(urlSpec2);
1113 :
1114 0 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
1115 : ("nsPluginHost::InstantiateEmbeddedPlugin Finished mime=%s, rv=%d, url=%s\n",
1116 : aMimeType, rv, urlSpec2.get()));
1117 :
1118 0 : PR_LogFlush();
1119 : #endif
1120 :
1121 0 : return NS_OK;
1122 : }
1123 :
1124 0 : nsresult nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
1125 : nsIURI* aURI,
1126 : nsObjectLoadingContent *aContent,
1127 : nsPluginInstanceOwner **aOwner,
1128 : nsIStreamListener **aStreamListener)
1129 : {
1130 : #ifdef PLUGIN_LOGGING
1131 0 : nsCAutoString urlSpec;
1132 0 : aURI->GetSpec(urlSpec);
1133 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1134 : ("nsPluginHost::InstantiateFullPagePlugin Begin mime=%s, url=%s\n",
1135 : aMimeType, urlSpec.get()));
1136 : #endif
1137 :
1138 0 : nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
1139 0 : if (!instanceOwner) {
1140 0 : return NS_ERROR_OUT_OF_MEMORY;
1141 : }
1142 :
1143 0 : nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
1144 0 : nsresult rv = instanceOwner->Init(ourContent);
1145 0 : if (NS_FAILED(rv)) {
1146 0 : return rv;
1147 : }
1148 :
1149 0 : rv = SetUpPluginInstance(aMimeType, aURI, instanceOwner);
1150 0 : if (NS_FAILED(rv)) {
1151 0 : return rv;
1152 : }
1153 :
1154 0 : nsRefPtr<nsNPAPIPluginInstance> instance;
1155 0 : instanceOwner->GetInstance(getter_AddRefs(instance));
1156 0 : if (!instance) {
1157 0 : return NS_ERROR_FAILURE;
1158 : }
1159 :
1160 0 : NPWindow* win = nsnull;
1161 0 : instanceOwner->GetWindow(win);
1162 0 : if (!win) {
1163 0 : return NS_ERROR_FAILURE;
1164 : }
1165 :
1166 : // Set up any widget that might be required.
1167 0 : instanceOwner->CreateWidget();
1168 0 : instanceOwner->CallSetWindow();
1169 :
1170 0 : rv = NewFullPagePluginStream(aURI, instance.get(), aStreamListener);
1171 0 : if (NS_FAILED(rv)) {
1172 0 : return rv;
1173 : }
1174 :
1175 : // Call SetWindow again in case something changed.
1176 0 : instanceOwner->CallSetWindow();
1177 :
1178 0 : instanceOwner.forget(aOwner);
1179 :
1180 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1181 : ("nsPluginHost::InstantiateFullPagePlugin End mime=%s, rv=%d, url=%s\n",
1182 : aMimeType, rv, urlSpec.get()));
1183 :
1184 0 : return NS_OK;
1185 : }
1186 :
1187 : nsPluginTag*
1188 0 : nsPluginHost::FindTagForLibrary(PRLibrary* aLibrary)
1189 : {
1190 : nsPluginTag* pluginTag;
1191 0 : for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
1192 0 : if (pluginTag->mLibrary == aLibrary) {
1193 0 : return pluginTag;
1194 : }
1195 : }
1196 0 : return nsnull;
1197 : }
1198 :
1199 : nsPluginTag*
1200 0 : nsPluginHost::TagForPlugin(nsNPAPIPlugin* aPlugin)
1201 : {
1202 : nsPluginTag* pluginTag;
1203 0 : for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
1204 0 : if (pluginTag->mEntryPoint == aPlugin) {
1205 0 : return pluginTag;
1206 : }
1207 : }
1208 : // a plugin should never exist without a corresponding tag
1209 0 : NS_ERROR("TagForPlugin has failed");
1210 0 : return nsnull;
1211 : }
1212 :
1213 0 : nsresult nsPluginHost::SetUpPluginInstance(const char *aMimeType,
1214 : nsIURI *aURL,
1215 : nsIPluginInstanceOwner *aOwner)
1216 : {
1217 0 : NS_ENSURE_ARG_POINTER(aOwner);
1218 :
1219 0 : nsresult rv = NS_OK;
1220 :
1221 0 : rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
1222 :
1223 : // if we fail, refresh plugin list just in case the plugin has been
1224 : // just added and try to instantiate plugin instance again, see bug 143178
1225 0 : if (NS_FAILED(rv)) {
1226 : // we should also make sure not to do this more than once per page
1227 : // so if there are a few embed tags with unknown plugins,
1228 : // we don't get unnecessary overhead
1229 : // let's cache document to decide whether this is the same page or not
1230 0 : nsCOMPtr<nsIDocument> document;
1231 0 : aOwner->GetDocument(getter_AddRefs(document));
1232 :
1233 0 : nsCOMPtr<nsIDocument> currentdocument = do_QueryReferent(mCurrentDocument);
1234 0 : if (document == currentdocument)
1235 0 : return rv;
1236 :
1237 0 : mCurrentDocument = do_GetWeakReference(document);
1238 :
1239 : // ReloadPlugins will do the job smartly: nothing will be done
1240 : // if no changes detected, in such a case just return
1241 0 : if (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED == ReloadPlugins(false))
1242 0 : return rv;
1243 :
1244 : // other failure return codes may be not fatal, so we can still try
1245 0 : aOwner->SetInstance(nsnull); // avoid assert about setting it twice
1246 0 : rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
1247 : }
1248 :
1249 0 : return rv;
1250 : }
1251 :
1252 : nsresult
1253 0 : nsPluginHost::TrySetUpPluginInstance(const char *aMimeType,
1254 : nsIURI *aURL,
1255 : nsIPluginInstanceOwner *aOwner)
1256 : {
1257 : #ifdef PLUGIN_LOGGING
1258 0 : nsCAutoString urlSpec;
1259 0 : if (aURL != nsnull) aURL->GetSpec(urlSpec);
1260 :
1261 0 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
1262 : ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
1263 : aMimeType, aOwner, urlSpec.get()));
1264 :
1265 0 : PR_LogFlush();
1266 : #endif
1267 :
1268 0 : nsresult rv = NS_ERROR_FAILURE;
1269 :
1270 0 : const char* mimetype = nsnull;
1271 :
1272 : // if don't have a mimetype or no plugin can handle this mimetype
1273 : // check by file extension
1274 0 : nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
1275 0 : if (!pluginTag) {
1276 0 : nsCOMPtr<nsIURL> url = do_QueryInterface(aURL);
1277 0 : if (!url) return NS_ERROR_FAILURE;
1278 :
1279 0 : nsCAutoString fileExtension;
1280 0 : url->GetFileExtension(fileExtension);
1281 :
1282 : // if we don't have an extension or no plugin for this extension,
1283 : // return failure as there is nothing more we can do
1284 0 : if (fileExtension.IsEmpty() ||
1285 : !(pluginTag = FindPluginEnabledForExtension(fileExtension.get(),
1286 0 : mimetype))) {
1287 0 : return NS_ERROR_FAILURE;
1288 : }
1289 : }
1290 : else {
1291 0 : mimetype = aMimeType;
1292 : }
1293 :
1294 0 : NS_ASSERTION(pluginTag, "Must have plugin tag here!");
1295 :
1296 0 : nsRefPtr<nsNPAPIPlugin> plugin;
1297 0 : GetPlugin(mimetype, getter_AddRefs(plugin));
1298 :
1299 0 : nsRefPtr<nsNPAPIPluginInstance> instance;
1300 :
1301 0 : if (plugin) {
1302 : #if defined(XP_WIN)
1303 : static BOOL firstJavaPlugin = FALSE;
1304 : BOOL restoreOrigDir = FALSE;
1305 : WCHAR origDir[_MAX_PATH];
1306 : if (pluginTag->mIsJavaPlugin && !firstJavaPlugin) {
1307 : DWORD dw = GetCurrentDirectoryW(_MAX_PATH, origDir);
1308 : NS_ASSERTION(dw <= _MAX_PATH, "Failed to obtain the current directory, which may lead to incorrect class loading");
1309 : nsCOMPtr<nsIFile> binDirectory;
1310 : rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
1311 : getter_AddRefs(binDirectory));
1312 :
1313 : if (NS_SUCCEEDED(rv)) {
1314 : nsAutoString path;
1315 : binDirectory->GetPath(path);
1316 : restoreOrigDir = SetCurrentDirectoryW(path.get());
1317 : }
1318 : }
1319 : #endif
1320 :
1321 0 : rv = plugin->CreatePluginInstance(getter_AddRefs(instance));
1322 :
1323 : #if defined(XP_WIN)
1324 : if (!firstJavaPlugin && restoreOrigDir) {
1325 : BOOL bCheck = SetCurrentDirectoryW(origDir);
1326 : NS_ASSERTION(bCheck, "Error restoring directory");
1327 : firstJavaPlugin = TRUE;
1328 : }
1329 : #endif
1330 : }
1331 :
1332 0 : if (NS_FAILED(rv))
1333 0 : return rv;
1334 :
1335 : // it is adreffed here
1336 0 : aOwner->SetInstance(instance.get());
1337 :
1338 : // this should not addref the instance or owner
1339 : // except in some cases not Java, see bug 140931
1340 : // our COM pointer will free the peer
1341 0 : rv = instance->Initialize(aOwner, mimetype);
1342 0 : if (NS_FAILED(rv)) {
1343 0 : aOwner->SetInstance(nsnull);
1344 0 : return rv;
1345 : }
1346 :
1347 : // Cancel the plugin unload timer since we are creating
1348 : // an instance for it.
1349 0 : if (pluginTag->mUnloadTimer) {
1350 0 : pluginTag->mUnloadTimer->Cancel();
1351 : }
1352 :
1353 0 : mInstances.AppendElement(instance.get());
1354 :
1355 : #ifdef PLUGIN_LOGGING
1356 0 : nsCAutoString urlSpec2;
1357 0 : if (aURL)
1358 0 : aURL->GetSpec(urlSpec2);
1359 :
1360 0 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
1361 : ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
1362 : aMimeType, rv, aOwner, urlSpec2.get()));
1363 :
1364 0 : PR_LogFlush();
1365 : #endif
1366 :
1367 0 : return rv;
1368 : }
1369 :
1370 : nsresult
1371 0 : nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
1372 : {
1373 0 : nsPluginTag *plugin = FindPluginForType(aMimeType, true);
1374 0 : if (plugin)
1375 0 : return NS_OK;
1376 :
1377 : // Pass false as the second arg so we can return NS_ERROR_PLUGIN_DISABLED
1378 : // for disabled plug-ins.
1379 0 : plugin = FindPluginForType(aMimeType, false);
1380 0 : if (!plugin)
1381 0 : return NS_ERROR_FAILURE;
1382 :
1383 0 : if (!plugin->IsEnabled()) {
1384 0 : if (plugin->HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED))
1385 0 : return NS_ERROR_PLUGIN_BLOCKLISTED;
1386 : else
1387 0 : return NS_ERROR_PLUGIN_DISABLED;
1388 : }
1389 :
1390 0 : return NS_OK;
1391 : }
1392 :
1393 : // check comma delimitered extensions
1394 43 : static int CompareExtensions(const char *aExtensionList, const char *aExtension)
1395 : {
1396 43 : if (!aExtensionList || !aExtension)
1397 0 : return -1;
1398 :
1399 43 : const char *pExt = aExtensionList;
1400 43 : const char *pComma = strchr(pExt, ',');
1401 43 : if (!pComma)
1402 43 : return PL_strcasecmp(pExt, aExtension);
1403 :
1404 0 : int extlen = strlen(aExtension);
1405 0 : while (pComma) {
1406 0 : int length = pComma - pExt;
1407 0 : if (length == extlen && 0 == PL_strncasecmp(aExtension, pExt, length))
1408 0 : return 0;
1409 0 : pComma++;
1410 0 : pExt = pComma;
1411 0 : pComma = strchr(pExt, ',');
1412 : }
1413 :
1414 : // the last one
1415 0 : return PL_strcasecmp(pExt, aExtension);
1416 : }
1417 :
1418 : nsresult
1419 43 : nsPluginHost::IsPluginEnabledForExtension(const char* aExtension,
1420 : const char* &aMimeType)
1421 : {
1422 43 : nsPluginTag *plugin = FindPluginEnabledForExtension(aExtension, aMimeType);
1423 43 : if (plugin)
1424 0 : return NS_OK;
1425 :
1426 43 : return NS_ERROR_FAILURE;
1427 : }
1428 :
1429 : class DOMMimeTypeImpl : public nsIDOMMimeType {
1430 : public:
1431 : NS_DECL_ISUPPORTS
1432 :
1433 0 : DOMMimeTypeImpl(nsPluginTag* aTag, PRUint32 aMimeTypeIndex)
1434 0 : {
1435 0 : if (!aTag)
1436 0 : return;
1437 0 : CopyUTF8toUTF16(aTag->mMimeDescriptions[aMimeTypeIndex], mDescription);
1438 0 : CopyUTF8toUTF16(aTag->mExtensions[aMimeTypeIndex], mSuffixes);
1439 0 : CopyUTF8toUTF16(aTag->mMimeTypes[aMimeTypeIndex], mType);
1440 : }
1441 :
1442 0 : virtual ~DOMMimeTypeImpl() {
1443 0 : }
1444 :
1445 0 : NS_METHOD GetDescription(nsAString& aDescription)
1446 : {
1447 0 : aDescription.Assign(mDescription);
1448 0 : return NS_OK;
1449 : }
1450 :
1451 0 : NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin)
1452 : {
1453 : // this has to be implemented by the DOM version.
1454 0 : *aEnabledPlugin = nsnull;
1455 0 : return NS_OK;
1456 : }
1457 :
1458 0 : NS_METHOD GetSuffixes(nsAString& aSuffixes)
1459 : {
1460 0 : aSuffixes.Assign(mSuffixes);
1461 0 : return NS_OK;
1462 : }
1463 :
1464 0 : NS_METHOD GetType(nsAString& aType)
1465 : {
1466 0 : aType.Assign(mType);
1467 0 : return NS_OK;
1468 : }
1469 :
1470 : private:
1471 : nsString mDescription;
1472 : nsString mSuffixes;
1473 : nsString mType;
1474 : };
1475 :
1476 0 : NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType)
1477 :
1478 : class DOMPluginImpl : public nsIDOMPlugin {
1479 : public:
1480 : NS_DECL_ISUPPORTS
1481 :
1482 0 : DOMPluginImpl(nsPluginTag* aPluginTag) : mPluginTag(aPluginTag)
1483 : {
1484 0 : }
1485 :
1486 0 : virtual ~DOMPluginImpl() {
1487 0 : }
1488 :
1489 0 : NS_METHOD GetDescription(nsAString& aDescription)
1490 : {
1491 0 : CopyUTF8toUTF16(mPluginTag.mDescription, aDescription);
1492 0 : return NS_OK;
1493 : }
1494 :
1495 0 : NS_METHOD GetFilename(nsAString& aFilename)
1496 : {
1497 : bool bShowPath;
1498 0 : nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
1499 0 : if (prefService &&
1500 0 : NS_SUCCEEDED(prefService->GetBoolPref("plugin.expose_full_path", &bShowPath)) &&
1501 : bShowPath) {
1502 0 : CopyUTF8toUTF16(mPluginTag.mFullPath, aFilename);
1503 : } else {
1504 0 : CopyUTF8toUTF16(mPluginTag.mFileName, aFilename);
1505 : }
1506 :
1507 0 : return NS_OK;
1508 : }
1509 :
1510 0 : NS_METHOD GetVersion(nsAString& aVersion)
1511 : {
1512 0 : CopyUTF8toUTF16(mPluginTag.mVersion, aVersion);
1513 0 : return NS_OK;
1514 : }
1515 :
1516 0 : NS_METHOD GetName(nsAString& aName)
1517 : {
1518 0 : CopyUTF8toUTF16(mPluginTag.mName, aName);
1519 0 : return NS_OK;
1520 : }
1521 :
1522 0 : NS_METHOD GetLength(PRUint32* aLength)
1523 : {
1524 0 : *aLength = mPluginTag.mMimeTypes.Length();
1525 0 : return NS_OK;
1526 : }
1527 :
1528 0 : NS_METHOD Item(PRUint32 aIndex, nsIDOMMimeType** aReturn)
1529 : {
1530 0 : nsIDOMMimeType* mimeType = new DOMMimeTypeImpl(&mPluginTag, aIndex);
1531 0 : NS_IF_ADDREF(mimeType);
1532 0 : *aReturn = mimeType;
1533 0 : return NS_OK;
1534 : }
1535 :
1536 0 : NS_METHOD NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn)
1537 : {
1538 0 : for (int i = mPluginTag.mMimeTypes.Length() - 1; i >= 0; --i) {
1539 0 : if (aName.Equals(NS_ConvertUTF8toUTF16(mPluginTag.mMimeTypes[i])))
1540 0 : return Item(i, aReturn);
1541 : }
1542 0 : return NS_OK;
1543 : }
1544 :
1545 : private:
1546 : nsPluginTag mPluginTag;
1547 : };
1548 :
1549 0 : NS_IMPL_ISUPPORTS1(DOMPluginImpl, nsIDOMPlugin)
1550 :
1551 : nsresult
1552 0 : nsPluginHost::GetPluginCount(PRUint32* aPluginCount)
1553 : {
1554 0 : LoadPlugins();
1555 :
1556 0 : PRUint32 count = 0;
1557 :
1558 0 : nsPluginTag* plugin = mPlugins;
1559 0 : while (plugin != nsnull) {
1560 0 : if (plugin->IsEnabled()) {
1561 0 : ++count;
1562 : }
1563 0 : plugin = plugin->mNext;
1564 : }
1565 :
1566 0 : *aPluginCount = count;
1567 :
1568 0 : return NS_OK;
1569 : }
1570 :
1571 : nsresult
1572 0 : nsPluginHost::GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray)
1573 : {
1574 0 : LoadPlugins();
1575 :
1576 0 : nsPluginTag* plugin = mPlugins;
1577 0 : for (PRUint32 i = 0; i < aPluginCount && plugin; plugin = plugin->mNext) {
1578 0 : if (plugin->IsEnabled()) {
1579 0 : nsIDOMPlugin* domPlugin = new DOMPluginImpl(plugin);
1580 0 : NS_IF_ADDREF(domPlugin);
1581 0 : aPluginArray[i++] = domPlugin;
1582 : }
1583 : }
1584 :
1585 0 : return NS_OK;
1586 : }
1587 :
1588 : NS_IMETHODIMP
1589 815 : nsPluginHost::GetPluginTags(PRUint32* aPluginCount, nsIPluginTag*** aResults)
1590 : {
1591 815 : LoadPlugins();
1592 :
1593 815 : PRUint32 count = 0;
1594 1630 : nsRefPtr<nsPluginTag> plugin = mPlugins;
1595 2444 : while (plugin != nsnull) {
1596 814 : count++;
1597 814 : plugin = plugin->mNext;
1598 : }
1599 :
1600 : *aResults = static_cast<nsIPluginTag**>
1601 815 : (nsMemory::Alloc(count * sizeof(**aResults)));
1602 815 : if (!*aResults)
1603 0 : return NS_ERROR_OUT_OF_MEMORY;
1604 :
1605 815 : *aPluginCount = count;
1606 :
1607 815 : plugin = mPlugins;
1608 1629 : for (PRUint32 i = 0; i < count; i++) {
1609 814 : (*aResults)[i] = plugin;
1610 814 : NS_ADDREF((*aResults)[i]);
1611 814 : plugin = plugin->mNext;
1612 : }
1613 :
1614 815 : return NS_OK;
1615 : }
1616 :
1617 : nsPluginTag*
1618 0 : nsPluginHost::FindPluginForType(const char* aMimeType,
1619 : bool aCheckEnabled)
1620 : {
1621 0 : if (!aMimeType) {
1622 0 : return nsnull;
1623 : }
1624 :
1625 0 : LoadPlugins();
1626 :
1627 0 : nsPluginTag *plugin = mPlugins;
1628 0 : while (plugin) {
1629 0 : if (!aCheckEnabled || plugin->IsEnabled()) {
1630 0 : PRInt32 mimeCount = plugin->mMimeTypes.Length();
1631 0 : for (PRInt32 i = 0; i < mimeCount; i++) {
1632 0 : if (0 == PL_strcasecmp(plugin->mMimeTypes[i].get(), aMimeType)) {
1633 0 : return plugin;
1634 : }
1635 : }
1636 : }
1637 0 : plugin = plugin->mNext;
1638 : }
1639 :
1640 0 : return nsnull;
1641 : }
1642 :
1643 : nsPluginTag*
1644 43 : nsPluginHost::FindPluginEnabledForExtension(const char* aExtension,
1645 : const char*& aMimeType)
1646 : {
1647 43 : if (!aExtension) {
1648 0 : return nsnull;
1649 : }
1650 :
1651 43 : LoadPlugins();
1652 :
1653 43 : nsPluginTag *plugin = mPlugins;
1654 129 : while (plugin) {
1655 43 : if (plugin->IsEnabled()) {
1656 43 : PRInt32 variants = plugin->mExtensions.Length();
1657 86 : for (PRInt32 i = 0; i < variants; i++) {
1658 : // mExtensionsArray[cnt] is a list of extensions separated by commas
1659 43 : if (0 == CompareExtensions(plugin->mExtensions[i].get(), aExtension)) {
1660 0 : aMimeType = plugin->mMimeTypes[i].get();
1661 0 : return plugin;
1662 : }
1663 : }
1664 : }
1665 43 : plugin = plugin->mNext;
1666 : }
1667 :
1668 43 : return nsnull;
1669 : }
1670 :
1671 0 : static nsresult CreateNPAPIPlugin(nsPluginTag *aPluginTag,
1672 : nsNPAPIPlugin **aOutNPAPIPlugin)
1673 : {
1674 : // If this is an in-process plugin we'll need to load it here if we haven't already.
1675 0 : if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
1676 0 : if (aPluginTag->mFullPath.IsEmpty())
1677 0 : return NS_ERROR_FAILURE;
1678 0 : nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
1679 0 : file->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag->mFullPath));
1680 0 : nsPluginFile pluginFile(file);
1681 0 : PRLibrary* pluginLibrary = NULL;
1682 :
1683 0 : if (NS_FAILED(pluginFile.LoadPlugin(&pluginLibrary)) || !pluginLibrary)
1684 0 : return NS_ERROR_FAILURE;
1685 :
1686 0 : aPluginTag->mLibrary = pluginLibrary;
1687 : }
1688 :
1689 : nsresult rv;
1690 0 : rv = nsNPAPIPlugin::CreatePlugin(aPluginTag, aOutNPAPIPlugin);
1691 :
1692 0 : return rv;
1693 : }
1694 :
1695 0 : nsresult nsPluginHost::EnsurePluginLoaded(nsPluginTag* plugin)
1696 : {
1697 0 : nsRefPtr<nsNPAPIPlugin> entrypoint = plugin->mEntryPoint;
1698 0 : if (!entrypoint) {
1699 0 : nsresult rv = CreateNPAPIPlugin(plugin, getter_AddRefs(entrypoint));
1700 0 : if (NS_FAILED(rv)) {
1701 0 : return rv;
1702 : }
1703 0 : plugin->mEntryPoint = entrypoint;
1704 : }
1705 0 : return NS_OK;
1706 : }
1707 :
1708 0 : nsresult nsPluginHost::GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin)
1709 : {
1710 0 : nsresult rv = NS_ERROR_FAILURE;
1711 0 : *aPlugin = NULL;
1712 :
1713 0 : if (!aMimeType)
1714 0 : return NS_ERROR_ILLEGAL_VALUE;
1715 :
1716 : // If plugins haven't been scanned yet, do so now
1717 0 : LoadPlugins();
1718 :
1719 0 : nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
1720 0 : if (pluginTag) {
1721 0 : rv = NS_OK;
1722 0 : PLUGIN_LOG(PLUGIN_LOG_BASIC,
1723 : ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
1724 : aMimeType, pluginTag->mFileName.get()));
1725 :
1726 : #ifdef NS_DEBUG
1727 0 : if (aMimeType && !pluginTag->mFileName.IsEmpty())
1728 0 : printf("For %s found plugin %s\n", aMimeType, pluginTag->mFileName.get());
1729 : #endif
1730 :
1731 0 : rv = EnsurePluginLoaded(pluginTag);
1732 0 : if (NS_FAILED(rv)) {
1733 0 : return rv;
1734 : }
1735 :
1736 0 : NS_ADDREF(*aPlugin = pluginTag->mEntryPoint);
1737 0 : return NS_OK;
1738 : }
1739 :
1740 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
1741 : ("nsPluginHost::GetPlugin End mime=%s, rv=%d, plugin=%p name=%s\n",
1742 : aMimeType, rv, *aPlugin,
1743 : (pluginTag ? pluginTag->mFileName.get() : "(not found)")));
1744 :
1745 0 : return rv;
1746 : }
1747 :
1748 : // Normalize 'host' to ACE.
1749 : nsresult
1750 0 : nsPluginHost::NormalizeHostname(nsCString& host)
1751 : {
1752 0 : if (IsASCII(host)) {
1753 0 : ToLowerCase(host);
1754 0 : return NS_OK;
1755 : }
1756 :
1757 0 : if (!mIDNService) {
1758 : nsresult rv;
1759 0 : mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
1760 0 : NS_ENSURE_SUCCESS(rv, rv);
1761 : }
1762 :
1763 0 : return mIDNService->ConvertUTF8toACE(host, host);
1764 : }
1765 :
1766 : // Enumerate a 'sites' array returned by GetSitesWithData and determine if
1767 : // any of them have a base domain in common with 'domain'; if so, append them
1768 : // to the 'result' array. If 'firstMatchOnly' is true, return after finding the
1769 : // first match.
1770 : nsresult
1771 0 : nsPluginHost::EnumerateSiteData(const nsACString& domain,
1772 : const nsTArray<nsCString>& sites,
1773 : InfallibleTArray<nsCString>& result,
1774 : bool firstMatchOnly)
1775 : {
1776 0 : NS_ASSERTION(!domain.IsVoid(), "null domain string");
1777 :
1778 : nsresult rv;
1779 0 : if (!mTLDService) {
1780 0 : mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
1781 0 : NS_ENSURE_SUCCESS(rv, rv);
1782 : }
1783 :
1784 : // Get the base domain from the domain.
1785 0 : nsCString baseDomain;
1786 0 : rv = mTLDService->GetBaseDomainFromHost(domain, 0, baseDomain);
1787 0 : bool isIP = rv == NS_ERROR_HOST_IS_IP_ADDRESS;
1788 0 : if (isIP || rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
1789 : // The base domain is the site itself. However, we must be careful to
1790 : // normalize.
1791 0 : baseDomain = domain;
1792 0 : rv = NormalizeHostname(baseDomain);
1793 0 : NS_ENSURE_SUCCESS(rv, rv);
1794 0 : } else if (NS_FAILED(rv)) {
1795 0 : return rv;
1796 : }
1797 :
1798 : // Enumerate the array of sites with data.
1799 0 : for (PRUint32 i = 0; i < sites.Length(); ++i) {
1800 0 : const nsCString& site = sites[i];
1801 :
1802 : // Check if the site is an IP address.
1803 : bool siteIsIP =
1804 0 : site.Length() >= 2 && site.First() == '[' && site.Last() == ']';
1805 0 : if (siteIsIP != isIP)
1806 0 : continue;
1807 :
1808 0 : nsCString siteBaseDomain;
1809 0 : if (siteIsIP) {
1810 : // Strip the '[]'.
1811 0 : siteBaseDomain = Substring(site, 1, site.Length() - 2);
1812 : } else {
1813 : // Determine the base domain of the site.
1814 0 : rv = mTLDService->GetBaseDomainFromHost(site, 0, siteBaseDomain);
1815 0 : if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
1816 : // The base domain is the site itself. However, we must be careful to
1817 : // normalize.
1818 0 : siteBaseDomain = site;
1819 0 : rv = NormalizeHostname(siteBaseDomain);
1820 0 : NS_ENSURE_SUCCESS(rv, rv);
1821 0 : } else if (NS_FAILED(rv)) {
1822 0 : return rv;
1823 : }
1824 : }
1825 :
1826 : // At this point, we can do an exact comparison of the two domains.
1827 0 : if (baseDomain != siteBaseDomain) {
1828 0 : continue;
1829 : }
1830 :
1831 : // Append the site to the result array.
1832 0 : result.AppendElement(site);
1833 :
1834 : // If we're supposed to return early, do so.
1835 0 : if (firstMatchOnly) {
1836 : break;
1837 : }
1838 : }
1839 :
1840 0 : return NS_OK;
1841 : }
1842 :
1843 : NS_IMETHODIMP
1844 49 : nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
1845 : PRUint64 flags, PRInt64 maxAge)
1846 : {
1847 : // maxAge must be either a nonnegative integer or -1.
1848 49 : NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
1849 :
1850 : // Caller may give us a tag object that is no longer live.
1851 49 : if (!IsLiveTag(plugin)) {
1852 0 : return NS_ERROR_NOT_AVAILABLE;
1853 : }
1854 :
1855 49 : nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
1856 :
1857 : // We only ensure support for clearing Flash site data for now.
1858 : // We will also attempt to clear data for any plugin that happens
1859 : // to be loaded already.
1860 49 : if (!tag->mIsFlashPlugin && !tag->mEntryPoint) {
1861 49 : return NS_ERROR_FAILURE;
1862 : }
1863 :
1864 : // Make sure the plugin is loaded.
1865 0 : nsresult rv = EnsurePluginLoaded(tag);
1866 0 : if (NS_FAILED(rv)) {
1867 0 : return rv;
1868 : }
1869 :
1870 0 : PluginLibrary* library = tag->mEntryPoint->GetLibrary();
1871 :
1872 : // If 'domain' is the null string, clear everything.
1873 0 : if (domain.IsVoid()) {
1874 0 : return library->NPP_ClearSiteData(NULL, flags, maxAge);
1875 : }
1876 :
1877 : // Get the list of sites from the plugin.
1878 0 : InfallibleTArray<nsCString> sites;
1879 0 : rv = library->NPP_GetSitesWithData(sites);
1880 0 : NS_ENSURE_SUCCESS(rv, rv);
1881 :
1882 : // Enumerate the sites and build a list of matches.
1883 0 : InfallibleTArray<nsCString> matches;
1884 0 : rv = EnumerateSiteData(domain, sites, matches, false);
1885 0 : NS_ENSURE_SUCCESS(rv, rv);
1886 :
1887 : // Clear the matches.
1888 0 : for (PRUint32 i = 0; i < matches.Length(); ++i) {
1889 0 : const nsCString& match = matches[i];
1890 0 : rv = library->NPP_ClearSiteData(match.get(), flags, maxAge);
1891 0 : NS_ENSURE_SUCCESS(rv, rv);
1892 : }
1893 :
1894 0 : return NS_OK;
1895 : }
1896 :
1897 : NS_IMETHODIMP
1898 0 : nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
1899 : bool* result)
1900 : {
1901 : // Caller may give us a tag object that is no longer live.
1902 0 : if (!IsLiveTag(plugin)) {
1903 0 : return NS_ERROR_NOT_AVAILABLE;
1904 : }
1905 :
1906 0 : nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
1907 :
1908 : // We only ensure support for clearing Flash site data for now.
1909 : // We will also attempt to clear data for any plugin that happens
1910 : // to be loaded already.
1911 0 : if (!tag->mIsFlashPlugin && !tag->mEntryPoint) {
1912 0 : return NS_ERROR_FAILURE;
1913 : }
1914 :
1915 : // Make sure the plugin is loaded.
1916 0 : nsresult rv = EnsurePluginLoaded(tag);
1917 0 : if (NS_FAILED(rv)) {
1918 0 : return rv;
1919 : }
1920 :
1921 0 : PluginLibrary* library = tag->mEntryPoint->GetLibrary();
1922 :
1923 : // Get the list of sites from the plugin.
1924 0 : InfallibleTArray<nsCString> sites;
1925 0 : rv = library->NPP_GetSitesWithData(sites);
1926 0 : NS_ENSURE_SUCCESS(rv, rv);
1927 :
1928 : // If there's no data, we're done.
1929 0 : if (sites.IsEmpty()) {
1930 0 : *result = false;
1931 0 : return NS_OK;
1932 : }
1933 :
1934 : // If 'domain' is the null string, and there's data for at least one site,
1935 : // we're done.
1936 0 : if (domain.IsVoid()) {
1937 0 : *result = true;
1938 0 : return NS_OK;
1939 : }
1940 :
1941 : // Enumerate the sites and determine if there's a match.
1942 0 : InfallibleTArray<nsCString> matches;
1943 0 : rv = EnumerateSiteData(domain, sites, matches, true);
1944 0 : NS_ENSURE_SUCCESS(rv, rv);
1945 :
1946 0 : *result = !matches.IsEmpty();
1947 0 : return NS_OK;
1948 : }
1949 :
1950 178 : bool nsPluginHost::IsJavaMIMEType(const char* aType)
1951 : {
1952 : return aType &&
1953 : ((0 == PL_strncasecmp(aType, "application/x-java-vm",
1954 178 : sizeof("application/x-java-vm") - 1)) ||
1955 : (0 == PL_strncasecmp(aType, "application/x-java-applet",
1956 178 : sizeof("application/x-java-applet") - 1)) ||
1957 : (0 == PL_strncasecmp(aType, "application/x-java-bean",
1958 534 : sizeof("application/x-java-bean") - 1)));
1959 : }
1960 :
1961 : // Check whether or not a tag is a live, valid tag, and that it's loaded.
1962 : bool
1963 49 : nsPluginHost::IsLiveTag(nsIPluginTag* aPluginTag)
1964 : {
1965 : nsPluginTag* tag;
1966 49 : for (tag = mPlugins; tag; tag = tag->mNext) {
1967 49 : if (tag == aPluginTag) {
1968 49 : return true;
1969 : }
1970 : }
1971 0 : return false;
1972 : }
1973 :
1974 346 : nsPluginTag * nsPluginHost::HaveSamePlugin(nsPluginTag * aPluginTag)
1975 : {
1976 346 : for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
1977 0 : if (tag->Equals(aPluginTag))
1978 0 : return tag;
1979 : }
1980 346 : return nsnull;
1981 : }
1982 :
1983 173 : bool nsPluginHost::IsDuplicatePlugin(nsPluginTag * aPluginTag)
1984 : {
1985 173 : nsPluginTag * tag = HaveSamePlugin(aPluginTag);
1986 173 : if (tag) {
1987 : // if we got the same plugin, check the full path to see if this is a dup;
1988 :
1989 : // mFileName contains full path on Windows and Unix and leaf name on Mac
1990 : // if those are not equal, we have the same plugin with different path,
1991 : // i.e. duplicate, return true
1992 0 : if (!tag->mFileName.Equals(aPluginTag->mFileName))
1993 0 : return true;
1994 :
1995 : // if they are equal, compare mFullPath fields just in case
1996 : // mFileName contained leaf name only, and if not equal, return true
1997 0 : if (!tag->mFullPath.Equals(aPluginTag->mFullPath))
1998 0 : return true;
1999 : }
2000 :
2001 : // we do not have it at all, return false
2002 173 : return false;
2003 : }
2004 :
2005 : typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
2006 :
2007 346 : nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
2008 : bool aCreatePluginList,
2009 : bool *aPluginsChanged)
2010 : {
2011 346 : NS_ENSURE_ARG_POINTER(aPluginsChanged);
2012 : nsresult rv;
2013 :
2014 346 : *aPluginsChanged = false;
2015 :
2016 : #ifdef PLUGIN_LOGGING
2017 692 : nsCAutoString dirPath;
2018 346 : pluginsDir->GetNativePath(dirPath);
2019 346 : PLUGIN_LOG(PLUGIN_LOG_BASIC,
2020 : ("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath.get()));
2021 : #endif
2022 :
2023 692 : nsCOMPtr<nsISimpleEnumerator> iter;
2024 346 : rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
2025 346 : if (NS_FAILED(rv))
2026 0 : return rv;
2027 :
2028 692 : nsAutoTArray<nsCOMPtr<nsILocalFile>, 6> pluginFiles;
2029 :
2030 : bool hasMore;
2031 865 : while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
2032 346 : nsCOMPtr<nsISupports> supports;
2033 173 : rv = iter->GetNext(getter_AddRefs(supports));
2034 173 : if (NS_FAILED(rv))
2035 0 : continue;
2036 346 : nsCOMPtr<nsILocalFile> dirEntry(do_QueryInterface(supports, &rv));
2037 173 : if (NS_FAILED(rv))
2038 0 : continue;
2039 :
2040 : // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
2041 : // See bug 197855.
2042 173 : dirEntry->Normalize();
2043 :
2044 173 : if (nsPluginsDir::IsPluginFile(dirEntry)) {
2045 173 : pluginFiles.AppendElement(dirEntry);
2046 : }
2047 : }
2048 :
2049 346 : bool warnOutdated = false;
2050 :
2051 519 : for (PRUint32 i = 0; i < pluginFiles.Length(); i++) {
2052 173 : nsCOMPtr<nsILocalFile>& localfile = pluginFiles[i];
2053 :
2054 346 : nsString utf16FilePath;
2055 173 : rv = localfile->GetPath(utf16FilePath);
2056 173 : if (NS_FAILED(rv))
2057 0 : continue;
2058 :
2059 173 : PRInt64 fileModTime = LL_ZERO;
2060 : #if defined(XP_MACOSX)
2061 : // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
2062 : // is a much better guide to when it was last modified than the date of
2063 : // its package directory. See bug 313700.
2064 : nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
2065 : if (localFileMac) {
2066 : localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
2067 : } else {
2068 : localfile->GetLastModifiedTime(&fileModTime);
2069 : }
2070 : #else
2071 173 : localfile->GetLastModifiedTime(&fileModTime);
2072 : #endif
2073 :
2074 : // Look for it in our cache
2075 346 : NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
2076 346 : nsRefPtr<nsPluginTag> pluginTag;
2077 : RemoveCachedPluginsInfo(filePath.get(),
2078 173 : getter_AddRefs(pluginTag));
2079 :
2080 173 : bool enabled = true;
2081 173 : bool seenBefore = false;
2082 173 : if (pluginTag) {
2083 1 : seenBefore = true;
2084 : // If plugin changed, delete cachedPluginTag and don't use cache
2085 1 : if (LL_NE(fileModTime, pluginTag->mLastModifiedTime)) {
2086 : // Plugins has changed. Don't use cached plugin info.
2087 1 : enabled = (pluginTag->Flags() & NS_PLUGIN_FLAG_ENABLED) != 0;
2088 1 : pluginTag = nsnull;
2089 :
2090 : // plugin file changed, flag this fact
2091 1 : *aPluginsChanged = true;
2092 : }
2093 : else {
2094 : // if it is unwanted plugin we are checking for, get it back to the cache info list
2095 : // if this is a duplicate plugin, too place it back in the cache info list marking unwantedness
2096 0 : if (IsDuplicatePlugin(pluginTag)) {
2097 0 : if (!pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED)) {
2098 : // Plugin switched from wanted to unwanted
2099 0 : *aPluginsChanged = true;
2100 : }
2101 0 : pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
2102 0 : pluginTag->mNext = mCachedPlugins;
2103 0 : mCachedPlugins = pluginTag;
2104 0 : } else if (pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED)) {
2105 0 : pluginTag->UnMark(NS_PLUGIN_FLAG_UNWANTED);
2106 : // Plugin switched from unwanted to wanted
2107 0 : *aPluginsChanged = true;
2108 : }
2109 : }
2110 :
2111 : // If we're not creating a list and we already know something changed then
2112 : // we're done.
2113 1 : if (!aCreatePluginList) {
2114 0 : if (*aPluginsChanged) {
2115 0 : return NS_OK;
2116 : }
2117 0 : continue;
2118 : }
2119 : }
2120 :
2121 173 : bool isKnownInvalidPlugin = false;
2122 346 : for (nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
2123 173 : invalidPlugins; invalidPlugins = invalidPlugins->mNext) {
2124 : // If already marked as invalid, ignore it
2125 0 : if (invalidPlugins->mFullPath.Equals(filePath.get()) &&
2126 0 : invalidPlugins->mLastModifiedTime == fileModTime) {
2127 0 : if (aCreatePluginList) {
2128 0 : invalidPlugins->mSeen = true;
2129 : }
2130 0 : isKnownInvalidPlugin = true;
2131 0 : break;
2132 : }
2133 : }
2134 173 : if (isKnownInvalidPlugin) {
2135 0 : continue;
2136 : }
2137 :
2138 : // if it is not found in cache info list or has been changed, create a new one
2139 173 : if (!pluginTag) {
2140 346 : nsPluginFile pluginFile(localfile);
2141 :
2142 : // create a tag describing this plugin.
2143 173 : PRLibrary *library = nsnull;
2144 : nsPluginInfo info;
2145 173 : memset(&info, 0, sizeof(info));
2146 173 : nsresult res = pluginFile.GetPluginInfo(info, &library);
2147 : // if we don't have mime type don't proceed, this is not a plugin
2148 173 : if (NS_FAILED(res) || !info.fMimeTypeArray) {
2149 : nsRefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(filePath.get(),
2150 0 : fileModTime);
2151 0 : pluginFile.FreePluginInfo(info);
2152 :
2153 0 : if (aCreatePluginList) {
2154 0 : invalidTag->mSeen = true;
2155 : }
2156 0 : invalidTag->mNext = mInvalidPlugins;
2157 0 : if (mInvalidPlugins) {
2158 0 : mInvalidPlugins->mPrev = invalidTag;
2159 : }
2160 0 : mInvalidPlugins = invalidTag;
2161 :
2162 : // Mark aPluginsChanged so pluginreg is rewritten
2163 0 : *aPluginsChanged = true;
2164 0 : continue;
2165 : }
2166 :
2167 173 : pluginTag = new nsPluginTag(&info);
2168 173 : pluginFile.FreePluginInfo(info);
2169 173 : if (!pluginTag)
2170 0 : return NS_ERROR_OUT_OF_MEMORY;
2171 :
2172 173 : pluginTag->mLibrary = library;
2173 173 : pluginTag->mLastModifiedTime = fileModTime;
2174 :
2175 519 : nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
2176 173 : if (blocklist) {
2177 : PRUint32 state;
2178 346 : rv = blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
2179 346 : EmptyString(), &state);
2180 :
2181 173 : if (NS_SUCCEEDED(rv)) {
2182 : // If the blocklist says so then block the plugin. If the blocklist says
2183 : // it is risky and we have never seen this plugin before then disable it
2184 151 : if (state == nsIBlocklistService::STATE_BLOCKED)
2185 0 : pluginTag->Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
2186 151 : else if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore)
2187 0 : enabled = false;
2188 151 : else if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore)
2189 2 : warnOutdated = true;
2190 : }
2191 : }
2192 :
2193 173 : if (!enabled)
2194 1 : pluginTag->UnMark(NS_PLUGIN_FLAG_ENABLED);
2195 :
2196 : // if this is unwanted plugin we are checkin for, or this is a duplicate plugin,
2197 : // add it to our cache info list so we can cache the unwantedness of this plugin
2198 : // when we sync cached plugins to registry
2199 173 : NS_ASSERTION(!pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED),
2200 : "Brand-new tags should not be unwanted");
2201 173 : if (IsDuplicatePlugin(pluginTag)) {
2202 0 : pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
2203 0 : pluginTag->mNext = mCachedPlugins;
2204 0 : mCachedPlugins = pluginTag;
2205 : }
2206 :
2207 : // Plugin unloading is tag-based. If we created a new tag and loaded
2208 : // the library in the process then we want to attempt to unload it here.
2209 : // Only do this if the pref is set for aggressive unloading.
2210 173 : if (UnloadPluginsASAP()) {
2211 0 : pluginTag->TryUnloadPlugin(false);
2212 : }
2213 : }
2214 :
2215 : // set the flag that we want to add this plugin to the list for now
2216 : // and see if it remains after we check several reasons not to do so
2217 173 : bool bAddIt = true;
2218 :
2219 173 : if (HaveSamePlugin(pluginTag)) {
2220 : // we cannot get here if the plugin has just been added
2221 : // and thus |pluginTag| is not from cache, because otherwise
2222 : // it would not be present in the list;
2223 0 : bAddIt = false;
2224 : }
2225 :
2226 : // do it if we still want it
2227 173 : if (bAddIt) {
2228 173 : if (!seenBefore) {
2229 : // We have a valid new plugin so report that plugins have changed.
2230 172 : *aPluginsChanged = true;
2231 : }
2232 :
2233 : // If we're not creating a plugin list, simply looking for changes,
2234 : // then we're done.
2235 173 : if (!aCreatePluginList) {
2236 0 : return NS_OK;
2237 : }
2238 :
2239 173 : pluginTag->SetHost(this);
2240 :
2241 : // Add plugin tags such that the list is ordered by modification date,
2242 : // newest to oldest. This is ugly, it'd be easier with just about anything
2243 : // other than a single-directional linked list.
2244 173 : if (mPlugins) {
2245 0 : nsPluginTag *prev = nsnull;
2246 0 : nsPluginTag *next = mPlugins;
2247 0 : while (next) {
2248 0 : if (pluginTag->mLastModifiedTime >= next->mLastModifiedTime) {
2249 0 : pluginTag->mNext = next;
2250 0 : if (prev) {
2251 0 : prev->mNext = pluginTag;
2252 : } else {
2253 0 : mPlugins = pluginTag;
2254 : }
2255 0 : break;
2256 : }
2257 0 : prev = next;
2258 0 : next = prev->mNext;
2259 0 : if (!next) {
2260 0 : prev->mNext = pluginTag;
2261 : }
2262 : }
2263 : } else {
2264 173 : mPlugins = pluginTag;
2265 : }
2266 :
2267 173 : if (pluginTag->IsEnabled()) {
2268 172 : pluginTag->RegisterWithCategoryManager(mOverrideInternalTypes);
2269 : }
2270 : }
2271 : }
2272 :
2273 346 : if (warnOutdated) {
2274 2 : mPrefService->SetBoolPref("plugins.update.notifyUser", true);
2275 : }
2276 :
2277 346 : return NS_OK;
2278 : }
2279 :
2280 173 : nsresult nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator *dirEnum,
2281 : bool aCreatePluginList,
2282 : bool *aPluginsChanged)
2283 : {
2284 : bool hasMore;
2285 692 : while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
2286 692 : nsCOMPtr<nsISupports> supports;
2287 346 : nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
2288 346 : if (NS_FAILED(rv))
2289 0 : continue;
2290 692 : nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
2291 346 : if (NS_FAILED(rv))
2292 0 : continue;
2293 :
2294 : // don't pass aPluginsChanged directly to prevent it from been reset
2295 346 : bool pluginschanged = false;
2296 346 : ScanPluginsDirectory(nextDir, aCreatePluginList, &pluginschanged);
2297 :
2298 346 : if (pluginschanged)
2299 173 : *aPluginsChanged = true;
2300 :
2301 : // if changes are detected and we are not creating the list, do not proceed
2302 346 : if (!aCreatePluginList && *aPluginsChanged)
2303 : break;
2304 : }
2305 173 : return NS_OK;
2306 : }
2307 :
2308 858 : nsresult nsPluginHost::LoadPlugins()
2309 : {
2310 : #ifdef ANDROID
2311 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
2312 : return NS_OK;
2313 : }
2314 : #endif
2315 : // do not do anything if it is already done
2316 : // use ReloadPlugins() to enforce loading
2317 858 : if (mPluginsLoaded)
2318 684 : return NS_OK;
2319 :
2320 174 : if (mPluginsDisabled)
2321 0 : return NS_OK;
2322 :
2323 : bool pluginschanged;
2324 174 : nsresult rv = FindPlugins(true, &pluginschanged);
2325 174 : if (NS_FAILED(rv))
2326 0 : return rv;
2327 :
2328 : // only if plugins have changed will we notify plugin-change observers
2329 174 : if (pluginschanged) {
2330 : nsCOMPtr<nsIObserverService> obsService =
2331 346 : mozilla::services::GetObserverService();
2332 173 : if (obsService)
2333 173 : obsService->NotifyObservers(nsnull, "plugins-list-updated", nsnull);
2334 : }
2335 :
2336 174 : return NS_OK;
2337 : }
2338 :
2339 : // if aCreatePluginList is false we will just scan for plugins
2340 : // and see if any changes have been made to the plugins.
2341 : // This is needed in ReloadPlugins to prevent possible recursive reloads
2342 174 : nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChanged)
2343 : {
2344 348 : Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
2345 :
2346 : #ifdef CALL_SAFETY_ON
2347 : // check preferences on whether or not we want to try safe calls to plugins
2348 : NS_INIT_PLUGIN_SAFE_CALLS;
2349 : #endif
2350 :
2351 174 : NS_ENSURE_ARG_POINTER(aPluginsChanged);
2352 :
2353 174 : *aPluginsChanged = false;
2354 : nsresult rv;
2355 :
2356 : // Read cached plugins info. If the profile isn't yet available then don't
2357 : // scan for plugins
2358 174 : if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE)
2359 1 : return NS_OK;
2360 :
2361 : #ifdef XP_WIN
2362 : // Failure here is not a show-stopper so just warn.
2363 : rv = EnsurePrivateDirServiceProvider();
2364 : NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
2365 : #endif /* XP_WIN */
2366 :
2367 346 : nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
2368 173 : if (NS_FAILED(rv))
2369 0 : return rv;
2370 :
2371 346 : nsCOMPtr<nsISimpleEnumerator> dirList;
2372 :
2373 : // Scan plugins directories;
2374 : // don't pass aPluginsChanged directly, to prevent its
2375 : // possible reset in subsequent ScanPluginsDirectory calls
2376 173 : bool pluginschanged = false;
2377 :
2378 : // Scan the app-defined list of plugin dirs.
2379 173 : rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
2380 173 : if (NS_SUCCEEDED(rv)) {
2381 173 : ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
2382 :
2383 173 : if (pluginschanged)
2384 173 : *aPluginsChanged = true;
2385 :
2386 : // if we are just looking for possible changes,
2387 : // no need to proceed if changes are detected
2388 173 : if (!aCreatePluginList && *aPluginsChanged) {
2389 0 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
2390 0 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
2391 0 : return NS_OK;
2392 : }
2393 : } else {
2394 : #ifdef ANDROID
2395 : LOG("getting plugins dir failed");
2396 : #endif
2397 : }
2398 :
2399 173 : mPluginsLoaded = true; // at this point 'some' plugins have been loaded,
2400 : // the rest is optional
2401 :
2402 : #ifdef XP_WIN
2403 : bool bScanPLIDs = false;
2404 :
2405 : if (mPrefService)
2406 : mPrefService->GetBoolPref("plugin.scan.plid.all", &bScanPLIDs);
2407 :
2408 : // Now lets scan any PLID directories
2409 : if (bScanPLIDs && mPrivateDirServiceProvider) {
2410 : rv = mPrivateDirServiceProvider->GetPLIDDirectories(getter_AddRefs(dirList));
2411 : if (NS_SUCCEEDED(rv)) {
2412 : ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
2413 :
2414 : if (pluginschanged)
2415 : *aPluginsChanged = true;
2416 :
2417 : // if we are just looking for possible changes,
2418 : // no need to proceed if changes are detected
2419 : if (!aCreatePluginList && *aPluginsChanged) {
2420 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
2421 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
2422 : return NS_OK;
2423 : }
2424 : }
2425 : }
2426 :
2427 :
2428 : // Scan the installation paths of our popular plugins if the prefs are enabled
2429 :
2430 : // This table controls the order of scanning
2431 : const char* const prefs[] = {NS_WIN_JRE_SCAN_KEY,
2432 : NS_WIN_ACROBAT_SCAN_KEY,
2433 : NS_WIN_QUICKTIME_SCAN_KEY,
2434 : NS_WIN_WMP_SCAN_KEY};
2435 :
2436 : PRUint32 size = sizeof(prefs) / sizeof(prefs[0]);
2437 :
2438 : for (PRUint32 i = 0; i < size; i+=1) {
2439 : nsCOMPtr<nsIFile> dirToScan;
2440 : bool bExists;
2441 : if (NS_SUCCEEDED(dirService->Get(prefs[i], NS_GET_IID(nsIFile), getter_AddRefs(dirToScan))) &&
2442 : dirToScan &&
2443 : NS_SUCCEEDED(dirToScan->Exists(&bExists)) &&
2444 : bExists) {
2445 :
2446 : ScanPluginsDirectory(dirToScan, aCreatePluginList, &pluginschanged);
2447 :
2448 : if (pluginschanged)
2449 : *aPluginsChanged = true;
2450 :
2451 : // if we are just looking for possible changes,
2452 : // no need to proceed if changes are detected
2453 : if (!aCreatePluginList && *aPluginsChanged) {
2454 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
2455 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
2456 : return NS_OK;
2457 : }
2458 : }
2459 : }
2460 : #endif
2461 :
2462 : // if get to this point and did not detect changes in plugins
2463 : // that means no plugins got updated or added
2464 : // let's see if plugins have been removed
2465 173 : if (!*aPluginsChanged) {
2466 : // count plugins remained in cache, if there are some, that means some plugins were removed;
2467 : // while counting, we should ignore unwanted plugins which are also present in cache
2468 0 : PRUint32 cachecount = 0;
2469 0 : for (nsPluginTag * cachetag = mCachedPlugins; cachetag; cachetag = cachetag->mNext) {
2470 0 : if (!cachetag->HasFlag(NS_PLUGIN_FLAG_UNWANTED))
2471 0 : cachecount++;
2472 : }
2473 : // if there is something left in cache, some plugins got removed from the directory
2474 : // and therefor their info did not get removed from the cache info list during directory scan;
2475 : // flag this fact
2476 0 : if (cachecount > 0)
2477 0 : *aPluginsChanged = true;
2478 : }
2479 :
2480 : // Remove unseen invalid plugins
2481 346 : nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
2482 346 : while (invalidPlugins) {
2483 0 : if (!invalidPlugins->mSeen) {
2484 0 : nsRefPtr<nsInvalidPluginTag> invalidPlugin = invalidPlugins;
2485 :
2486 0 : if (invalidPlugin->mPrev) {
2487 0 : invalidPlugin->mPrev->mNext = invalidPlugin->mNext;
2488 : }
2489 : else {
2490 0 : mInvalidPlugins = invalidPlugin->mNext;
2491 : }
2492 0 : if (invalidPlugin->mNext) {
2493 0 : invalidPlugin->mNext->mPrev = invalidPlugin->mPrev;
2494 : }
2495 :
2496 0 : invalidPlugins = invalidPlugin->mNext;
2497 :
2498 0 : invalidPlugin->mPrev = NULL;
2499 0 : invalidPlugin->mNext = NULL;
2500 : }
2501 : else {
2502 0 : invalidPlugins->mSeen = false;
2503 0 : invalidPlugins = invalidPlugins->mNext;
2504 : }
2505 : }
2506 :
2507 : // if we are not creating the list, there is no need to proceed
2508 173 : if (!aCreatePluginList) {
2509 0 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
2510 0 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
2511 0 : return NS_OK;
2512 : }
2513 :
2514 : // if we are creating the list, it is already done;
2515 : // update the plugins info cache if changes are detected
2516 173 : if (*aPluginsChanged)
2517 173 : WritePluginInfo();
2518 :
2519 : // No more need for cached plugins. Clear it up.
2520 173 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
2521 173 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
2522 :
2523 173 : return NS_OK;
2524 : }
2525 :
2526 : nsresult
2527 4 : nsPluginHost::UpdatePluginInfo(nsPluginTag* aPluginTag)
2528 : {
2529 4 : ReadPluginInfo();
2530 4 : WritePluginInfo();
2531 4 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
2532 4 : NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
2533 :
2534 4 : if (!aPluginTag || aPluginTag->IsEnabled())
2535 2 : return NS_OK;
2536 :
2537 4 : nsCOMPtr<nsISupportsArray> instsToReload;
2538 2 : NS_NewISupportsArray(getter_AddRefs(instsToReload));
2539 2 : DestroyRunningInstances(instsToReload, aPluginTag);
2540 :
2541 : PRUint32 c;
2542 2 : if (instsToReload && NS_SUCCEEDED(instsToReload->Count(&c)) && c > 0) {
2543 0 : nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
2544 0 : if (ev)
2545 0 : NS_DispatchToCurrentThread(ev);
2546 : }
2547 :
2548 2 : return NS_OK;
2549 : }
2550 :
2551 : nsresult
2552 177 : nsPluginHost::WritePluginInfo()
2553 : {
2554 :
2555 177 : nsresult rv = NS_OK;
2556 354 : nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
2557 177 : if (NS_FAILED(rv))
2558 0 : return rv;
2559 :
2560 177 : directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
2561 177 : getter_AddRefs(mPluginRegFile));
2562 :
2563 177 : if (!mPluginRegFile)
2564 15 : return NS_ERROR_FAILURE;
2565 :
2566 162 : PRFileDesc* fd = nsnull;
2567 :
2568 324 : nsCOMPtr<nsIFile> pluginReg;
2569 :
2570 162 : rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
2571 162 : if (NS_FAILED(rv))
2572 0 : return rv;
2573 :
2574 324 : nsCAutoString filename(kPluginRegistryFilename);
2575 162 : filename.Append(".tmp");
2576 162 : rv = pluginReg->AppendNative(filename);
2577 162 : if (NS_FAILED(rv))
2578 0 : return rv;
2579 :
2580 324 : nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(pluginReg, &rv);
2581 162 : if (NS_FAILED(rv))
2582 0 : return rv;
2583 :
2584 162 : rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2585 162 : if (NS_FAILED(rv))
2586 0 : return rv;
2587 :
2588 324 : nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
2589 162 : if (!runtime) {
2590 0 : return NS_ERROR_FAILURE;
2591 : }
2592 :
2593 324 : nsCAutoString arch;
2594 162 : rv = runtime->GetXPCOMABI(arch);
2595 162 : if (NS_FAILED(rv)) {
2596 0 : return rv;
2597 : }
2598 :
2599 162 : PR_fprintf(fd, "Generated File. Do not edit.\n");
2600 :
2601 : PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c\nArch%c%s%c%c\n",
2602 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2603 : kPluginRegistryVersion,
2604 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2605 : PLUGIN_REGISTRY_END_OF_LINE_MARKER,
2606 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2607 : arch.get(),
2608 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2609 162 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2610 :
2611 : // Store all plugins in the mPlugins list - all plugins currently in use.
2612 162 : PR_fprintf(fd, "\n[PLUGINS]\n");
2613 :
2614 162 : nsPluginTag *taglist[] = {mPlugins, mCachedPlugins};
2615 486 : for (int i=0; i<(int)(sizeof(taglist)/sizeof(nsPluginTag *)); i++) {
2616 490 : for (nsPluginTag *tag = taglist[i]; tag; tag=tag->mNext) {
2617 : // from mCachedPlugins list write down only unwanted plugins
2618 166 : if ((taglist[i] == mCachedPlugins) && !tag->HasFlag(NS_PLUGIN_FLAG_UNWANTED))
2619 4 : continue;
2620 : // store each plugin info into the registry
2621 : // filename & fullpath are on separate line
2622 : // because they can contain field delimiter char
2623 : PR_fprintf(fd, "%s%c%c\n%s%c%c\n%s%c%c\n",
2624 : (tag->mFileName.get()),
2625 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2626 : PLUGIN_REGISTRY_END_OF_LINE_MARKER,
2627 : (tag->mFullPath.get()),
2628 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2629 : PLUGIN_REGISTRY_END_OF_LINE_MARKER,
2630 : (tag->mVersion.get()),
2631 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2632 162 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2633 :
2634 : // lastModifiedTimeStamp|canUnload|tag->mFlags
2635 : PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
2636 : tag->mLastModifiedTime,
2637 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2638 : false, // did store whether or not to unload in-process plugins
2639 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2640 : tag->Flags(),
2641 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2642 162 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2643 :
2644 : //description, name & mtypecount are on separate line
2645 : PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
2646 : (tag->mDescription.get()),
2647 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2648 : PLUGIN_REGISTRY_END_OF_LINE_MARKER,
2649 : (tag->mName.get()),
2650 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2651 : PLUGIN_REGISTRY_END_OF_LINE_MARKER,
2652 162 : tag->mMimeTypes.Length() + (tag->mIsNPRuntimeEnabledJavaPlugin ? 1 : 0));
2653 :
2654 : // Add in each mimetype this plugin supports
2655 324 : for (PRUint32 i = 0; i < tag->mMimeTypes.Length(); i++) {
2656 : PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
2657 : i,PLUGIN_REGISTRY_FIELD_DELIMITER,
2658 162 : (tag->mMimeTypes[i].get()),
2659 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2660 162 : (tag->mMimeDescriptions[i].get()),
2661 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2662 162 : (tag->mExtensions[i].get()),
2663 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2664 486 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2665 : }
2666 :
2667 162 : if (tag->mIsNPRuntimeEnabledJavaPlugin) {
2668 : PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
2669 : tag->mMimeTypes.Length(), PLUGIN_REGISTRY_FIELD_DELIMITER,
2670 : "application/x-java-vm-npruntime",
2671 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2672 : "",
2673 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2674 : "",
2675 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2676 0 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2677 : }
2678 : }
2679 : }
2680 :
2681 162 : PR_fprintf(fd, "\n[INVALID]\n");
2682 :
2683 324 : nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
2684 324 : while (invalidPlugins) {
2685 : // fullPath
2686 : PR_fprintf(fd, "%s%c%c\n",
2687 0 : (!invalidPlugins->mFullPath.IsEmpty() ? invalidPlugins->mFullPath.get() : ""),
2688 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2689 0 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2690 :
2691 : // lastModifiedTimeStamp
2692 : PR_fprintf(fd, "%lld%c%c\n",
2693 0 : invalidPlugins->mLastModifiedTime,
2694 : PLUGIN_REGISTRY_FIELD_DELIMITER,
2695 0 : PLUGIN_REGISTRY_END_OF_LINE_MARKER);
2696 :
2697 0 : invalidPlugins = invalidPlugins->mNext;
2698 : }
2699 :
2700 162 : PR_Close(fd);
2701 324 : nsCOMPtr<nsIFile> parent;
2702 162 : rv = localFile->GetParent(getter_AddRefs(parent));
2703 162 : NS_ENSURE_SUCCESS(rv, rv);
2704 162 : rv = localFile->MoveToNative(parent, kPluginRegistryFilename);
2705 162 : return rv;
2706 : }
2707 :
2708 : #define PLUGIN_REG_MIMETYPES_ARRAY_SIZE 12
2709 : nsresult
2710 178 : nsPluginHost::ReadPluginInfo()
2711 : {
2712 : nsresult rv;
2713 :
2714 356 : nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
2715 178 : if (NS_FAILED(rv))
2716 0 : return rv;
2717 :
2718 178 : directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
2719 178 : getter_AddRefs(mPluginRegFile));
2720 :
2721 178 : if (!mPluginRegFile) {
2722 : // There is no profile yet, this will tell us if there is going to be one
2723 : // in the future.
2724 16 : directoryService->Get(NS_APP_PROFILE_DIR_STARTUP, NS_GET_IID(nsIFile),
2725 16 : getter_AddRefs(mPluginRegFile));
2726 16 : if (!mPluginRegFile)
2727 15 : return NS_ERROR_FAILURE;
2728 : else
2729 1 : return NS_ERROR_NOT_AVAILABLE;
2730 : }
2731 :
2732 162 : PRFileDesc* fd = nsnull;
2733 :
2734 324 : nsCOMPtr<nsIFile> pluginReg;
2735 :
2736 162 : rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
2737 162 : if (NS_FAILED(rv))
2738 0 : return rv;
2739 :
2740 162 : rv = pluginReg->AppendNative(kPluginRegistryFilename);
2741 162 : if (NS_FAILED(rv))
2742 0 : return rv;
2743 :
2744 324 : nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(pluginReg, &rv);
2745 162 : if (NS_FAILED(rv))
2746 0 : return rv;
2747 :
2748 : PRInt64 fileSize;
2749 162 : rv = localFile->GetFileSize(&fileSize);
2750 162 : if (NS_FAILED(rv))
2751 157 : return rv;
2752 :
2753 5 : PRInt32 flen = PRInt64(fileSize);
2754 5 : if (flen == 0) {
2755 0 : NS_WARNING("Plugins Registry Empty!");
2756 0 : return NS_OK; // ERROR CONDITION
2757 : }
2758 :
2759 10 : nsPluginManifestLineReader reader;
2760 5 : char* registry = reader.Init(flen);
2761 5 : if (!registry)
2762 0 : return NS_ERROR_OUT_OF_MEMORY;
2763 :
2764 5 : rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
2765 5 : if (NS_FAILED(rv))
2766 0 : return rv;
2767 :
2768 : // set rv to return an error on goto out
2769 5 : rv = NS_ERROR_FAILURE;
2770 :
2771 5 : PRInt32 bread = PR_Read(fd, registry, flen);
2772 5 : PR_Close(fd);
2773 :
2774 5 : if (flen > bread)
2775 0 : return rv;
2776 :
2777 5 : if (!ReadSectionHeader(reader, "HEADER"))
2778 0 : return rv;;
2779 :
2780 5 : if (!reader.NextLine())
2781 0 : return rv;
2782 :
2783 : char* values[6];
2784 :
2785 : // VersionLiteral, kPluginRegistryVersion
2786 5 : if (2 != reader.ParseLine(values, 2))
2787 0 : return rv;
2788 :
2789 : // VersionLiteral
2790 5 : if (PL_strcmp(values[0], "Version"))
2791 0 : return rv;
2792 :
2793 : // kPluginRegistryVersion
2794 5 : PRInt32 vdiff = NS_CompareVersions(values[1], kPluginRegistryVersion);
2795 : // If this is a registry from some future version then don't attempt to read it
2796 5 : if (vdiff > 0)
2797 0 : return rv;
2798 : // If this is a registry from before the minimum then don't attempt to read it
2799 5 : if (NS_CompareVersions(values[1], kMinimumRegistryVersion) < 0)
2800 0 : return rv;
2801 :
2802 : // Registry v0.10 and upwards includes the plugin version field
2803 5 : bool regHasVersion = NS_CompareVersions(values[1], "0.10") >= 0;
2804 :
2805 : // Registry v0.13 and upwards includes the architecture
2806 5 : if (NS_CompareVersions(values[1], "0.13") >= 0) {
2807 : char* archValues[6];
2808 :
2809 4 : if (!reader.NextLine()) {
2810 0 : return rv;
2811 : }
2812 :
2813 : // ArchLiteral, Architecture
2814 4 : if (2 != reader.ParseLine(archValues, 2)) {
2815 0 : return rv;
2816 : }
2817 :
2818 : // ArchLiteral
2819 4 : if (PL_strcmp(archValues[0], "Arch")) {
2820 0 : return rv;
2821 : }
2822 :
2823 8 : nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
2824 4 : if (!runtime) {
2825 0 : return rv;
2826 : }
2827 :
2828 8 : nsCAutoString arch;
2829 4 : if (NS_FAILED(runtime->GetXPCOMABI(arch))) {
2830 0 : return rv;
2831 : }
2832 :
2833 : // If this is a registry from a different architecture then don't attempt to read it
2834 4 : if (PL_strcmp(archValues[1], arch.get())) {
2835 0 : return rv;
2836 : }
2837 : }
2838 :
2839 : // Registry v0.13 and upwards includes the list of invalid plugins
2840 5 : bool hasInvalidPlugins = (NS_CompareVersions(values[1], "0.13") >= 0);
2841 :
2842 5 : if (!ReadSectionHeader(reader, "PLUGINS"))
2843 0 : return rv;
2844 :
2845 : #if defined(XP_MACOSX)
2846 : bool hasFullPathInFileNameField = false;
2847 : #else
2848 5 : bool hasFullPathInFileNameField = (NS_CompareVersions(values[1], "0.11") < 0);
2849 : #endif
2850 :
2851 15 : while (reader.NextLine()) {
2852 : const char *filename;
2853 : const char *fullpath;
2854 18 : nsCAutoString derivedFileName;
2855 :
2856 9 : if (hasInvalidPlugins && *reader.LinePtr() == '[') {
2857 : break;
2858 : }
2859 :
2860 5 : if (hasFullPathInFileNameField) {
2861 1 : fullpath = reader.LinePtr();
2862 1 : if (!reader.NextLine())
2863 0 : return rv;
2864 : // try to derive a file name from the full path
2865 1 : if (fullpath) {
2866 2 : nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
2867 1 : file->InitWithNativePath(nsDependentCString(fullpath));
2868 1 : file->GetNativeLeafName(derivedFileName);
2869 1 : filename = derivedFileName.get();
2870 : } else {
2871 0 : filename = NULL;
2872 : }
2873 :
2874 : // skip the next line, useless in this version
2875 1 : if (!reader.NextLine())
2876 0 : return rv;
2877 : } else {
2878 4 : filename = reader.LinePtr();
2879 4 : if (!reader.NextLine())
2880 0 : return rv;
2881 :
2882 4 : fullpath = reader.LinePtr();
2883 4 : if (!reader.NextLine())
2884 0 : return rv;
2885 : }
2886 :
2887 : const char *version;
2888 5 : if (regHasVersion) {
2889 4 : version = reader.LinePtr();
2890 4 : if (!reader.NextLine())
2891 0 : return rv;
2892 : } else {
2893 1 : version = "0";
2894 : }
2895 :
2896 : // lastModifiedTimeStamp|canUnload|tag.mFlag
2897 5 : if (reader.ParseLine(values, 3) != 3)
2898 0 : return rv;
2899 :
2900 : // If this is an old plugin registry mark this plugin tag to be refreshed
2901 5 : PRInt64 lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
2902 5 : PRUint32 tagflag = atoi(values[2]);
2903 5 : if (!reader.NextLine())
2904 0 : return rv;
2905 :
2906 5 : const char *description = reader.LinePtr();
2907 5 : if (!reader.NextLine())
2908 0 : return rv;
2909 :
2910 5 : const char *name = reader.LinePtr();
2911 5 : if (!reader.NextLine())
2912 0 : return rv;
2913 :
2914 5 : int mimetypecount = atoi(reader.LinePtr());
2915 :
2916 : char *stackalloced[PLUGIN_REG_MIMETYPES_ARRAY_SIZE * 3];
2917 : char **mimetypes;
2918 : char **mimedescriptions;
2919 : char **extensions;
2920 5 : char **heapalloced = 0;
2921 5 : if (mimetypecount > PLUGIN_REG_MIMETYPES_ARRAY_SIZE - 1) {
2922 0 : heapalloced = new char *[mimetypecount * 3];
2923 0 : mimetypes = heapalloced;
2924 : } else {
2925 5 : mimetypes = stackalloced;
2926 : }
2927 5 : mimedescriptions = mimetypes + mimetypecount;
2928 5 : extensions = mimedescriptions + mimetypecount;
2929 :
2930 5 : int mtr = 0; //mimetype read
2931 10 : for (; mtr < mimetypecount; mtr++) {
2932 5 : if (!reader.NextLine())
2933 0 : break;
2934 :
2935 : //line number|mimetype|description|extension
2936 5 : if (4 != reader.ParseLine(values, 4))
2937 0 : break;
2938 5 : int line = atoi(values[0]);
2939 5 : if (line != mtr)
2940 0 : break;
2941 5 : mimetypes[mtr] = values[1];
2942 5 : mimedescriptions[mtr] = values[2];
2943 5 : extensions[mtr] = values[3];
2944 : }
2945 :
2946 5 : if (mtr != mimetypecount) {
2947 0 : if (heapalloced) {
2948 0 : delete [] heapalloced;
2949 : }
2950 0 : return rv;
2951 : }
2952 :
2953 : nsRefPtr<nsPluginTag> tag = new nsPluginTag(name,
2954 : description,
2955 : filename,
2956 : fullpath,
2957 : version,
2958 : (const char* const*)mimetypes,
2959 : (const char* const*)mimedescriptions,
2960 : (const char* const*)extensions,
2961 10 : mimetypecount, lastmod, true);
2962 5 : if (heapalloced)
2963 0 : delete [] heapalloced;
2964 :
2965 5 : if (!tag)
2966 0 : continue;
2967 :
2968 : // Mark plugin as loaded from cache
2969 5 : tag->Mark(tagflag | NS_PLUGIN_FLAG_FROMCACHE);
2970 5 : PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
2971 : ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->mFileName.get()));
2972 5 : tag->mNext = mCachedPlugins;
2973 10 : mCachedPlugins = tag;
2974 : }
2975 :
2976 5 : if (hasInvalidPlugins) {
2977 4 : if (!ReadSectionHeader(reader, "INVALID")) {
2978 0 : return rv;
2979 : }
2980 :
2981 8 : while (reader.NextLine()) {
2982 0 : const char *fullpath = reader.LinePtr();
2983 0 : if (!reader.NextLine()) {
2984 0 : return rv;
2985 : }
2986 :
2987 0 : const char *lastModifiedTimeStamp = reader.LinePtr();
2988 0 : PRInt64 lastmod = (vdiff == 0) ? nsCRT::atoll(lastModifiedTimeStamp) : -1;
2989 :
2990 0 : nsRefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(fullpath, lastmod);
2991 :
2992 0 : invalidTag->mNext = mInvalidPlugins;
2993 0 : if (mInvalidPlugins) {
2994 0 : mInvalidPlugins->mPrev = invalidTag;
2995 : }
2996 0 : mInvalidPlugins = invalidTag;
2997 : }
2998 : }
2999 5 : return NS_OK;
3000 : }
3001 :
3002 : void
3003 173 : nsPluginHost::RemoveCachedPluginsInfo(const char *filePath, nsPluginTag **result)
3004 : {
3005 346 : nsRefPtr<nsPluginTag> prev;
3006 346 : nsRefPtr<nsPluginTag> tag = mCachedPlugins;
3007 346 : while (tag)
3008 : {
3009 1 : if (tag->mFullPath.Equals(filePath)) {
3010 : // Found it. Remove it from our list
3011 1 : if (prev)
3012 0 : prev->mNext = tag->mNext;
3013 : else
3014 1 : mCachedPlugins = tag->mNext;
3015 1 : tag->mNext = nsnull;
3016 1 : *result = tag;
3017 1 : NS_ADDREF(*result);
3018 1 : break;
3019 : }
3020 0 : prev = tag;
3021 0 : tag = tag->mNext;
3022 : }
3023 173 : }
3024 :
3025 : #ifdef XP_WIN
3026 : nsresult
3027 : nsPluginHost::EnsurePrivateDirServiceProvider()
3028 : {
3029 : if (!mPrivateDirServiceProvider) {
3030 : nsresult rv;
3031 : mPrivateDirServiceProvider = new nsPluginDirServiceProvider();
3032 : if (!mPrivateDirServiceProvider)
3033 : return NS_ERROR_OUT_OF_MEMORY;
3034 : nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
3035 : if (NS_FAILED(rv))
3036 : return rv;
3037 : rv = dirService->RegisterProvider(mPrivateDirServiceProvider);
3038 : if (NS_FAILED(rv))
3039 : return rv;
3040 : }
3041 : return NS_OK;
3042 : }
3043 : #endif /* XP_WIN */
3044 :
3045 0 : nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL,
3046 : nsNPAPIPluginInstance *aInstance,
3047 : nsIPluginStreamListener* aListener,
3048 : nsIInputStream *aPostStream,
3049 : const char *aHeadersData,
3050 : PRUint32 aHeadersDataLen)
3051 : {
3052 0 : nsCOMPtr<nsIURI> url;
3053 0 : nsAutoString absUrl;
3054 : nsresult rv;
3055 :
3056 0 : if (aURL.Length() <= 0)
3057 0 : return NS_OK;
3058 :
3059 : // get the full URL of the document that the plugin is embedded
3060 : // in to create an absolute url in case aURL is relative
3061 0 : nsCOMPtr<nsIDocument> doc;
3062 0 : nsCOMPtr<nsIPluginInstanceOwner> owner;
3063 0 : aInstance->GetOwner(getter_AddRefs(owner));
3064 0 : if (owner) {
3065 0 : rv = owner->GetDocument(getter_AddRefs(doc));
3066 0 : if (NS_SUCCEEDED(rv) && doc) {
3067 : // Create an absolute URL
3068 0 : rv = NS_MakeAbsoluteURI(absUrl, aURL, doc->GetDocBaseURI());
3069 : }
3070 : }
3071 :
3072 0 : if (absUrl.IsEmpty())
3073 0 : absUrl.Assign(aURL);
3074 :
3075 0 : rv = NS_NewURI(getter_AddRefs(url), absUrl);
3076 0 : if (NS_FAILED(rv))
3077 0 : return rv;
3078 :
3079 0 : nsCOMPtr<nsIPluginTagInfo> pti = do_QueryInterface(owner);
3080 0 : nsCOMPtr<nsIDOMElement> element;
3081 0 : if (pti)
3082 0 : pti->GetDOMElement(getter_AddRefs(element));
3083 :
3084 0 : PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
3085 : rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
3086 : url,
3087 0 : (doc ? doc->NodePrincipal() : nsnull),
3088 : element,
3089 0 : EmptyCString(), //mime guess
3090 : nsnull, //extra
3091 0 : &shouldLoad);
3092 0 : if (NS_FAILED(rv))
3093 0 : return rv;
3094 0 : if (NS_CP_REJECTED(shouldLoad)) {
3095 : // Disallowed by content policy
3096 0 : return NS_ERROR_CONTENT_BLOCKED;
3097 : }
3098 :
3099 0 : nsRefPtr<nsPluginStreamListenerPeer> listenerPeer = new nsPluginStreamListenerPeer();
3100 0 : if (!listenerPeer)
3101 0 : return NS_ERROR_OUT_OF_MEMORY;
3102 :
3103 0 : rv = listenerPeer->Initialize(url, aInstance, aListener);
3104 0 : if (NS_FAILED(rv))
3105 0 : return rv;
3106 :
3107 0 : nsCOMPtr<nsIChannel> channel;
3108 0 : rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull,
3109 : nsnull, /* do not add this internal plugin's channel
3110 : on the load group otherwise this channel could be canceled
3111 : form |nsDocShell::OnLinkClickSync| bug 166613 */
3112 0 : listenerPeer);
3113 0 : if (NS_FAILED(rv))
3114 0 : return rv;
3115 :
3116 0 : if (doc) {
3117 : // Set the owner of channel to the document principal...
3118 0 : channel->SetOwner(doc->NodePrincipal());
3119 :
3120 : // And if it's a script allow it to execute against the
3121 : // document's script context.
3122 0 : nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
3123 0 : if (scriptChannel) {
3124 0 : scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
3125 : // Plug-ins seem to depend on javascript: URIs running synchronously
3126 0 : scriptChannel->SetExecuteAsync(false);
3127 : }
3128 : }
3129 :
3130 : // deal with headers and post data
3131 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
3132 0 : if (httpChannel) {
3133 0 : if (!aPostStream) {
3134 : // Only set the Referer header for GET requests because IIS throws
3135 : // errors about malformed requests if we include it in POSTs. See
3136 : // bug 724465.
3137 0 : nsCOMPtr<nsIURI> referer;
3138 :
3139 0 : nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(element);
3140 0 : if (olc)
3141 0 : olc->GetSrcURI(getter_AddRefs(referer));
3142 :
3143 :
3144 0 : if (!referer)
3145 0 : referer = doc->GetDocumentURI();
3146 :
3147 0 : rv = httpChannel->SetReferrer(referer);
3148 0 : NS_ENSURE_SUCCESS(rv,rv);
3149 : }
3150 :
3151 0 : if (aPostStream) {
3152 : // XXX it's a bit of a hack to rewind the postdata stream
3153 : // here but it has to be done in case the post data is
3154 : // being reused multiple times.
3155 : nsCOMPtr<nsISeekableStream>
3156 0 : postDataSeekable(do_QueryInterface(aPostStream));
3157 0 : if (postDataSeekable)
3158 0 : postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
3159 :
3160 0 : nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
3161 0 : NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
3162 :
3163 0 : uploadChannel->SetUploadStream(aPostStream, EmptyCString(), -1);
3164 : }
3165 :
3166 0 : if (aHeadersData) {
3167 0 : rv = AddHeadersToChannel(aHeadersData, aHeadersDataLen, httpChannel);
3168 0 : NS_ENSURE_SUCCESS(rv,rv);
3169 : }
3170 : }
3171 0 : rv = channel->AsyncOpen(listenerPeer, nsnull);
3172 0 : if (NS_SUCCEEDED(rv))
3173 0 : listenerPeer->TrackRequest(channel);
3174 0 : return rv;
3175 : }
3176 :
3177 : // Called by GetURL and PostURL
3178 : nsresult
3179 0 : nsPluginHost::DoURLLoadSecurityCheck(nsNPAPIPluginInstance *aInstance,
3180 : const char* aURL)
3181 : {
3182 0 : if (!aURL || *aURL == '\0')
3183 0 : return NS_OK;
3184 :
3185 : // get the URL of the document that loaded the plugin
3186 0 : nsCOMPtr<nsIPluginInstanceOwner> owner;
3187 0 : aInstance->GetOwner(getter_AddRefs(owner));
3188 0 : if (!owner)
3189 0 : return NS_ERROR_FAILURE;
3190 :
3191 0 : nsCOMPtr<nsIDocument> doc;
3192 0 : owner->GetDocument(getter_AddRefs(doc));
3193 0 : if (!doc)
3194 0 : return NS_ERROR_FAILURE;
3195 :
3196 : // Create an absolute URL for the target in case the target is relative
3197 0 : nsCOMPtr<nsIURI> targetURL;
3198 0 : NS_NewURI(getter_AddRefs(targetURL), aURL, doc->GetDocBaseURI());
3199 0 : if (!targetURL)
3200 0 : return NS_ERROR_FAILURE;
3201 :
3202 : nsresult rv;
3203 : nsCOMPtr<nsIScriptSecurityManager> secMan(
3204 0 : do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
3205 0 : if (NS_FAILED(rv))
3206 0 : return rv;
3207 :
3208 0 : return secMan->CheckLoadURIWithPrincipal(doc->NodePrincipal(), targetURL,
3209 0 : nsIScriptSecurityManager::STANDARD);
3210 :
3211 : }
3212 :
3213 : nsresult
3214 0 : nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
3215 : PRUint32 aHeadersDataLen,
3216 : nsIChannel *aGenericChannel)
3217 : {
3218 0 : nsresult rv = NS_OK;
3219 :
3220 0 : nsCOMPtr<nsIHttpChannel> aChannel = do_QueryInterface(aGenericChannel);
3221 0 : if (!aChannel) {
3222 0 : return NS_ERROR_NULL_POINTER;
3223 : }
3224 :
3225 : // used during the manipulation of the String from the aHeadersData
3226 0 : nsCAutoString headersString;
3227 0 : nsCAutoString oneHeader;
3228 0 : nsCAutoString headerName;
3229 0 : nsCAutoString headerValue;
3230 0 : PRInt32 crlf = 0;
3231 0 : PRInt32 colon = 0;
3232 :
3233 : // Turn the char * buffer into an nsString.
3234 0 : headersString = aHeadersData;
3235 :
3236 : // Iterate over the nsString: for each "\r\n" delimited chunk,
3237 : // add the value as a header to the nsIHTTPChannel
3238 0 : while (true) {
3239 0 : crlf = headersString.Find("\r\n", true);
3240 0 : if (-1 == crlf) {
3241 0 : rv = NS_OK;
3242 0 : return rv;
3243 : }
3244 0 : headersString.Mid(oneHeader, 0, crlf);
3245 0 : headersString.Cut(0, crlf + 2);
3246 0 : oneHeader.StripWhitespace();
3247 0 : colon = oneHeader.Find(":");
3248 0 : if (-1 == colon) {
3249 0 : rv = NS_ERROR_NULL_POINTER;
3250 0 : return rv;
3251 : }
3252 0 : oneHeader.Left(headerName, colon);
3253 0 : colon++;
3254 0 : oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
3255 :
3256 : // FINALLY: we can set the header!
3257 :
3258 0 : rv = aChannel->SetRequestHeader(headerName, headerValue, true);
3259 0 : if (NS_FAILED(rv)) {
3260 0 : rv = NS_ERROR_NULL_POINTER;
3261 0 : return rv;
3262 : }
3263 : }
3264 : return rv;
3265 : }
3266 :
3267 : nsresult
3268 0 : nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance)
3269 : {
3270 0 : if (PluginDestructionGuard::DelayDestroy(aInstance)) {
3271 0 : return NS_OK;
3272 : }
3273 :
3274 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
3275 : ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
3276 :
3277 0 : if (aInstance->HasStartedDestroying()) {
3278 0 : return NS_OK;
3279 : }
3280 :
3281 0 : Telemetry::AutoTimer<Telemetry::PLUGIN_SHUTDOWN_MS> timer;
3282 0 : aInstance->Stop();
3283 :
3284 : // if the instance does not want to be 'cached' just remove it
3285 0 : bool doCache = aInstance->ShouldCache();
3286 0 : if (doCache) {
3287 : // try to get the max cached instances from a pref or use default
3288 : PRUint32 cachedInstanceLimit;
3289 0 : nsresult rv = NS_ERROR_FAILURE;
3290 0 : if (mPrefService)
3291 0 : rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_INSTANCES, (int*)&cachedInstanceLimit);
3292 0 : if (NS_FAILED(rv))
3293 0 : cachedInstanceLimit = DEFAULT_NUMBER_OF_STOPPED_INSTANCES;
3294 :
3295 0 : if (StoppedInstanceCount() >= cachedInstanceLimit) {
3296 0 : nsNPAPIPluginInstance *oldestInstance = FindOldestStoppedInstance();
3297 0 : if (oldestInstance) {
3298 0 : nsPluginTag* pluginTag = TagForPlugin(oldestInstance->GetPlugin());
3299 0 : oldestInstance->Destroy();
3300 0 : mInstances.RemoveElement(oldestInstance);
3301 0 : OnPluginInstanceDestroyed(pluginTag);
3302 : }
3303 : }
3304 : } else {
3305 0 : nsPluginTag* pluginTag = TagForPlugin(aInstance->GetPlugin());
3306 0 : aInstance->Destroy();
3307 0 : mInstances.RemoveElement(aInstance);
3308 0 : OnPluginInstanceDestroyed(pluginTag);
3309 : }
3310 :
3311 0 : return NS_OK;
3312 : }
3313 :
3314 0 : nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
3315 : nsObjectLoadingContent *aContent,
3316 : nsNPAPIPluginInstance* aInstance,
3317 : nsIStreamListener** aListener)
3318 : {
3319 0 : if (!aURL)
3320 0 : return NS_OK;
3321 :
3322 0 : nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
3323 0 : if (!listener)
3324 0 : return NS_ERROR_OUT_OF_MEMORY;
3325 :
3326 : nsresult rv;
3327 :
3328 : // if we have an instance, everything has been set up
3329 : // if we only have an owner, then we need to pass it in
3330 : // so the listener can set up the instance later after
3331 : // we've determined the mimetype of the stream
3332 0 : if (aInstance)
3333 0 : rv = listener->InitializeEmbedded(aURL, aInstance, nsnull);
3334 0 : else if (aContent)
3335 0 : rv = listener->InitializeEmbedded(aURL, nsnull, aContent);
3336 : else
3337 0 : rv = NS_ERROR_ILLEGAL_VALUE;
3338 :
3339 0 : if (NS_SUCCEEDED(rv))
3340 0 : NS_ADDREF(*aListener = listener);
3341 :
3342 0 : return rv;
3343 : }
3344 :
3345 : // Called by InstantiateEmbeddedPlugin()
3346 0 : nsresult nsPluginHost::NewEmbeddedPluginStream(nsIURI* aURL,
3347 : nsObjectLoadingContent *aContent,
3348 : nsNPAPIPluginInstance* aInstance)
3349 : {
3350 0 : nsCOMPtr<nsIStreamListener> listener;
3351 : nsresult rv = NewEmbeddedPluginStreamListener(aURL, aContent, aInstance,
3352 0 : getter_AddRefs(listener));
3353 0 : if (NS_SUCCEEDED(rv)) {
3354 0 : nsCOMPtr<nsIDocument> doc;
3355 0 : nsCOMPtr<nsILoadGroup> loadGroup;
3356 0 : if (aContent) {
3357 0 : nsCOMPtr<nsIContent> aIContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
3358 0 : doc = aIContent->GetDocument();
3359 0 : if (doc) {
3360 0 : loadGroup = doc->GetDocumentLoadGroup();
3361 : }
3362 : }
3363 0 : nsCOMPtr<nsIChannel> channel;
3364 0 : rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull, loadGroup, nsnull);
3365 0 : if (NS_SUCCEEDED(rv)) {
3366 : // if this is http channel, set referrer, some servers are configured
3367 : // to reject requests without referrer set, see bug 157796
3368 0 : nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
3369 0 : if (httpChannel && doc)
3370 0 : httpChannel->SetReferrer(doc->GetDocumentURI());
3371 :
3372 0 : rv = channel->AsyncOpen(listener, nsnull);
3373 0 : if (NS_SUCCEEDED(rv))
3374 0 : return NS_OK;
3375 : }
3376 : }
3377 :
3378 0 : return rv;
3379 : }
3380 :
3381 : // Called by InstantiateFullPagePlugin()
3382 0 : nsresult nsPluginHost::NewFullPagePluginStream(nsIURI* aURI,
3383 : nsNPAPIPluginInstance *aInstance,
3384 : nsIStreamListener **aStreamListener)
3385 : {
3386 0 : NS_ASSERTION(aStreamListener, "Stream listener out param cannot be null");
3387 :
3388 0 : nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
3389 0 : if (!listener)
3390 0 : return NS_ERROR_OUT_OF_MEMORY;
3391 :
3392 0 : nsresult rv = listener->InitializeFullPage(aURI, aInstance);
3393 0 : if (NS_FAILED(rv)) {
3394 0 : return rv;
3395 : }
3396 :
3397 0 : listener.forget(aStreamListener);
3398 :
3399 0 : return NS_OK;
3400 : }
3401 :
3402 173 : NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
3403 : const char *aTopic,
3404 : const PRUnichar *someData)
3405 : {
3406 173 : if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
3407 173 : OnShutdown();
3408 173 : Destroy();
3409 173 : sInst->Release();
3410 : }
3411 173 : if (!nsCRT::strcmp(NS_PRIVATE_BROWSING_SWITCH_TOPIC, aTopic)) {
3412 : // inform all active plugins of changed private mode state
3413 0 : for (PRUint32 i = 0; i < mInstances.Length(); i++) {
3414 0 : mInstances[i]->PrivateModeStateChanged();
3415 : }
3416 : }
3417 : #ifdef MOZ_WIDGET_ANDROID
3418 : if (!nsCRT::strcmp("application-background", aTopic)) {
3419 : for(PRUint32 i = 0; i < mInstances.Length(); i++) {
3420 : mInstances[i]->NotifyForeground(false);
3421 : }
3422 : }
3423 : if (!nsCRT::strcmp("application-foreground", aTopic)) {
3424 : for(PRUint32 i = 0; i < mInstances.Length(); i++) {
3425 : if (mInstances[i]->IsOnScreen())
3426 : mInstances[i]->NotifyForeground(true);
3427 : }
3428 : }
3429 : if (!nsCRT::strcmp("memory-pressure", aTopic)) {
3430 : for(PRUint32 i = 0; i < mInstances.Length(); i++) {
3431 : mInstances[i]->MemoryPressure();
3432 : }
3433 : }
3434 : #endif
3435 173 : return NS_OK;
3436 : }
3437 :
3438 : nsresult
3439 0 : nsPluginHost::HandleBadPlugin(PRLibrary* aLibrary, nsNPAPIPluginInstance *aInstance)
3440 : {
3441 : // the |aLibrary| parameter is not needed anymore, after we added |aInstance| which
3442 : // can also be used to look up the plugin name, but we cannot get rid of it because
3443 : // the |nsIPluginHost| interface is deprecated which in fact means 'frozen'
3444 :
3445 0 : NS_ERROR("Plugin performed illegal operation");
3446 0 : NS_ENSURE_ARG_POINTER(aInstance);
3447 :
3448 0 : if (mDontShowBadPluginMessage)
3449 0 : return NS_OK;
3450 :
3451 0 : nsCOMPtr<nsIPluginInstanceOwner> owner;
3452 0 : aInstance->GetOwner(getter_AddRefs(owner));
3453 :
3454 0 : nsCOMPtr<nsIPrompt> prompt;
3455 0 : GetPrompt(owner, getter_AddRefs(prompt));
3456 0 : if (!prompt)
3457 0 : return NS_OK;
3458 :
3459 : nsCOMPtr<nsIStringBundleService> strings =
3460 0 : mozilla::services::GetStringBundleService();
3461 0 : if (!strings)
3462 0 : return NS_ERROR_FAILURE;
3463 :
3464 0 : nsCOMPtr<nsIStringBundle> bundle;
3465 0 : nsresult rv = strings->CreateBundle(BRAND_PROPERTIES_URL, getter_AddRefs(bundle));
3466 0 : if (NS_FAILED(rv))
3467 0 : return rv;
3468 :
3469 0 : nsXPIDLString brandName;
3470 0 : rv = bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
3471 0 : getter_Copies(brandName));
3472 0 : if (NS_FAILED(rv))
3473 0 : return rv;
3474 :
3475 0 : rv = strings->CreateBundle(PLUGIN_PROPERTIES_URL, getter_AddRefs(bundle));
3476 0 : if (NS_FAILED(rv))
3477 0 : return rv;
3478 :
3479 0 : nsXPIDLString title, message, checkboxMessage;
3480 0 : rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginTitle").get(),
3481 0 : getter_Copies(title));
3482 0 : if (NS_FAILED(rv))
3483 0 : return rv;
3484 :
3485 0 : const PRUnichar *formatStrings[] = { brandName.get() };
3486 0 : if (NS_FAILED(rv = bundle->FormatStringFromName(NS_LITERAL_STRING("BadPluginMessage").get(),
3487 : formatStrings, 1, getter_Copies(message))))
3488 0 : return rv;
3489 :
3490 0 : rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
3491 0 : getter_Copies(checkboxMessage));
3492 0 : if (NS_FAILED(rv))
3493 0 : return rv;
3494 :
3495 0 : nsNPAPIPlugin *plugin = aInstance->GetPlugin();
3496 0 : if (!plugin)
3497 0 : return NS_ERROR_FAILURE;
3498 :
3499 0 : nsPluginTag *pluginTag = TagForPlugin(plugin);
3500 :
3501 : // add plugin name to the message
3502 0 : nsCString pluginname;
3503 0 : if (pluginTag) {
3504 0 : if (!pluginTag->mName.IsEmpty()) {
3505 0 : pluginname = pluginTag->mName;
3506 : } else {
3507 0 : pluginname = pluginTag->mFileName;
3508 : }
3509 : } else {
3510 0 : pluginname.AppendLiteral("???");
3511 : }
3512 :
3513 0 : NS_ConvertUTF8toUTF16 msg(pluginname);
3514 0 : msg.AppendLiteral("\n\n");
3515 0 : msg.Append(message);
3516 :
3517 : PRInt32 buttonPressed;
3518 0 : bool checkboxState = false;
3519 0 : rv = prompt->ConfirmEx(title, msg.get(),
3520 : nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0,
3521 : nsnull, nsnull, nsnull,
3522 0 : checkboxMessage, &checkboxState, &buttonPressed);
3523 :
3524 :
3525 0 : if (NS_SUCCEEDED(rv) && checkboxState)
3526 0 : mDontShowBadPluginMessage = true;
3527 :
3528 0 : return rv;
3529 : }
3530 :
3531 : nsresult
3532 0 : nsPluginHost::ParsePostBufferToFixHeaders(const char *inPostData, PRUint32 inPostDataLen,
3533 : char **outPostData, PRUint32 *outPostDataLen)
3534 : {
3535 0 : if (!inPostData || !outPostData || !outPostDataLen)
3536 0 : return NS_ERROR_NULL_POINTER;
3537 :
3538 0 : *outPostData = 0;
3539 0 : *outPostDataLen = 0;
3540 :
3541 0 : const char CR = '\r';
3542 0 : const char LF = '\n';
3543 0 : const char CRLFCRLF[] = {CR,LF,CR,LF,'\0'}; // C string"\r\n\r\n"
3544 0 : const char ContentLenHeader[] = "Content-length";
3545 :
3546 0 : nsAutoTArray<const char*, 8> singleLF;
3547 0 : const char *pSCntlh = 0;// pointer to start of ContentLenHeader in inPostData
3548 0 : const char *pSod = 0; // pointer to start of data in inPostData
3549 0 : const char *pEoh = 0; // pointer to end of headers in inPostData
3550 0 : const char *pEod = inPostData + inPostDataLen; // pointer to end of inPostData
3551 0 : if (*inPostData == LF) {
3552 : // If no custom headers are required, simply add a blank
3553 : // line ('\n') to the beginning of the file or buffer.
3554 : // so *inPostData == '\n' is valid
3555 0 : pSod = inPostData + 1;
3556 : } else {
3557 0 : const char *s = inPostData; //tmp pointer to sourse inPostData
3558 0 : while (s < pEod) {
3559 0 : if (!pSCntlh &&
3560 : (*s == 'C' || *s == 'c') &&
3561 0 : (s + sizeof(ContentLenHeader) - 1 < pEod) &&
3562 0 : (!PL_strncasecmp(s, ContentLenHeader, sizeof(ContentLenHeader) - 1)))
3563 : {
3564 : // lets assume this is ContentLenHeader for now
3565 0 : const char *p = pSCntlh = s;
3566 0 : p += sizeof(ContentLenHeader) - 1;
3567 : // search for first CR or LF == end of ContentLenHeader
3568 0 : for (; p < pEod; p++) {
3569 0 : if (*p == CR || *p == LF) {
3570 : // got delimiter,
3571 : // one more check; if previous char is a digit
3572 : // most likely pSCntlh points to the start of ContentLenHeader
3573 0 : if (*(p-1) >= '0' && *(p-1) <= '9') {
3574 0 : s = p;
3575 : }
3576 0 : break; //for loop
3577 : }
3578 : }
3579 0 : if (pSCntlh == s) { // curret ptr is the same
3580 0 : pSCntlh = 0; // that was not ContentLenHeader
3581 0 : break; // there is nothing to parse, break *WHILE LOOP* here
3582 : }
3583 : }
3584 :
3585 0 : if (*s == CR) {
3586 0 : if (pSCntlh && // only if ContentLenHeader is found we are looking for end of headers
3587 0 : ((s + sizeof(CRLFCRLF)-1) <= pEod) &&
3588 0 : !memcmp(s, CRLFCRLF, sizeof(CRLFCRLF)-1))
3589 : {
3590 0 : s += sizeof(CRLFCRLF)-1;
3591 0 : pEoh = pSod = s; // data stars here
3592 0 : break;
3593 : }
3594 0 : } else if (*s == LF) {
3595 0 : if (*(s-1) != CR) {
3596 0 : singleLF.AppendElement(s);
3597 : }
3598 0 : if (pSCntlh && (s+1 < pEod) && (*(s+1) == LF)) {
3599 0 : s++;
3600 0 : singleLF.AppendElement(s);
3601 0 : s++;
3602 0 : pEoh = pSod = s; // data stars here
3603 0 : break;
3604 : }
3605 : }
3606 0 : s++;
3607 : }
3608 : }
3609 :
3610 : // deal with output buffer
3611 0 : if (!pSod) { // lets assume whole buffer is a data
3612 0 : pSod = inPostData;
3613 : }
3614 :
3615 0 : PRUint32 newBufferLen = 0;
3616 0 : PRUint32 dataLen = pEod - pSod;
3617 0 : PRUint32 headersLen = pEoh ? pSod - inPostData : 0;
3618 :
3619 : char *p; // tmp ptr into new output buf
3620 0 : if (headersLen) { // we got a headers
3621 : // this function does not make any assumption on correctness
3622 : // of ContentLenHeader value in this case.
3623 :
3624 0 : newBufferLen = dataLen + headersLen;
3625 : // in case there were single LFs in headers
3626 : // reserve an extra space for CR will be added before each single LF
3627 0 : int cntSingleLF = singleLF.Length();
3628 0 : newBufferLen += cntSingleLF;
3629 :
3630 0 : if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
3631 0 : return NS_ERROR_OUT_OF_MEMORY;
3632 :
3633 : // deal with single LF
3634 0 : const char *s = inPostData;
3635 0 : if (cntSingleLF) {
3636 0 : for (int i=0; i<cntSingleLF; i++) {
3637 0 : const char *plf = singleLF.ElementAt(i); // ptr to single LF in headers
3638 0 : int n = plf - s; // bytes to copy
3639 0 : if (n) { // for '\n\n' there is nothing to memcpy
3640 0 : memcpy(p, s, n);
3641 0 : p += n;
3642 : }
3643 0 : *p++ = CR;
3644 0 : s = plf;
3645 0 : *p++ = *s++;
3646 : }
3647 : }
3648 : // are we done with headers?
3649 0 : headersLen = pEoh - s;
3650 0 : if (headersLen) { // not yet
3651 0 : memcpy(p, s, headersLen); // copy the rest
3652 0 : p += headersLen;
3653 : }
3654 0 : } else if (dataLen) { // no ContentLenHeader is found but there is a data
3655 : // make new output buffer big enough
3656 : // to keep ContentLenHeader+value followed by data
3657 0 : PRUint32 l = sizeof(ContentLenHeader) + sizeof(CRLFCRLF) + 32;
3658 0 : newBufferLen = dataLen + l;
3659 0 : if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
3660 0 : return NS_ERROR_OUT_OF_MEMORY;
3661 0 : headersLen = PR_snprintf(p, l,"%s: %ld%s", ContentLenHeader, dataLen, CRLFCRLF);
3662 0 : if (headersLen == l) { // if PR_snprintf has ate all extra space consider this as an error
3663 0 : nsMemory::Free(p);
3664 0 : *outPostData = 0;
3665 0 : return NS_ERROR_FAILURE;
3666 : }
3667 0 : p += headersLen;
3668 0 : newBufferLen = headersLen + dataLen;
3669 : }
3670 : // at this point we've done with headers.
3671 : // there is a possibility that input buffer has only headers info in it
3672 : // which already parsed and copied into output buffer.
3673 : // copy the data
3674 0 : if (dataLen) {
3675 0 : memcpy(p, pSod, dataLen);
3676 : }
3677 :
3678 0 : *outPostDataLen = newBufferLen;
3679 :
3680 0 : return NS_OK;
3681 : }
3682 :
3683 : nsresult
3684 0 : nsPluginHost::CreateTempFileToPost(const char *aPostDataURL, nsIFile **aTmpFile)
3685 : {
3686 : nsresult rv;
3687 : PRInt64 fileSize;
3688 0 : nsCAutoString filename;
3689 :
3690 : // stat file == get size & convert file:///c:/ to c: if needed
3691 0 : nsCOMPtr<nsIFile> inFile;
3692 0 : rv = NS_GetFileFromURLSpec(nsDependentCString(aPostDataURL),
3693 0 : getter_AddRefs(inFile));
3694 0 : if (NS_FAILED(rv)) {
3695 0 : nsCOMPtr<nsILocalFile> localFile;
3696 0 : rv = NS_NewNativeLocalFile(nsDependentCString(aPostDataURL), false,
3697 0 : getter_AddRefs(localFile));
3698 0 : if (NS_FAILED(rv)) return rv;
3699 0 : inFile = localFile;
3700 : }
3701 0 : rv = inFile->GetFileSize(&fileSize);
3702 0 : if (NS_FAILED(rv)) return rv;
3703 0 : rv = inFile->GetNativePath(filename);
3704 0 : if (NS_FAILED(rv)) return rv;
3705 :
3706 0 : if (!LL_IS_ZERO(fileSize)) {
3707 0 : nsCOMPtr<nsIInputStream> inStream;
3708 0 : rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), inFile);
3709 0 : if (NS_FAILED(rv)) return rv;
3710 :
3711 : // Create a temporary file to write the http Content-length:
3712 : // %ld\r\n\" header and "\r\n" == end of headers for post data to
3713 :
3714 0 : nsCOMPtr<nsIFile> tempFile;
3715 0 : rv = GetPluginTempDir(getter_AddRefs(tempFile));
3716 0 : if (NS_FAILED(rv))
3717 0 : return rv;
3718 :
3719 0 : nsCAutoString inFileName;
3720 0 : inFile->GetNativeLeafName(inFileName);
3721 : // XXX hack around bug 70083
3722 0 : inFileName.Insert(NS_LITERAL_CSTRING("post-"), 0);
3723 0 : rv = tempFile->AppendNative(inFileName);
3724 :
3725 0 : if (NS_FAILED(rv))
3726 0 : return rv;
3727 :
3728 : // make it unique, and mode == 0600, not world-readable
3729 0 : rv = tempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
3730 0 : if (NS_FAILED(rv))
3731 0 : return rv;
3732 :
3733 0 : nsCOMPtr<nsIOutputStream> outStream;
3734 0 : if (NS_SUCCEEDED(rv)) {
3735 0 : rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
3736 : tempFile,
3737 : (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
3738 0 : 0600); // 600 so others can't read our form data
3739 : }
3740 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Post data file couldn't be created!");
3741 0 : if (NS_FAILED(rv))
3742 0 : return rv;
3743 :
3744 : char buf[1024];
3745 : PRUint32 br, bw;
3746 0 : bool firstRead = true;
3747 0 : while (1) {
3748 : // Read() mallocs if buffer is null
3749 0 : rv = inStream->Read(buf, 1024, &br);
3750 0 : if (NS_FAILED(rv) || (PRInt32)br <= 0)
3751 0 : break;
3752 0 : if (firstRead) {
3753 : //"For protocols in which the headers must be distinguished from the body,
3754 : // such as HTTP, the buffer or file should contain the headers, followed by
3755 : // a blank line, then the body. If no custom headers are required, simply
3756 : // add a blank line ('\n') to the beginning of the file or buffer.
3757 :
3758 : char *parsedBuf;
3759 : // assuming first 1K (or what we got) has all headers in,
3760 : // lets parse it through nsPluginHost::ParsePostBufferToFixHeaders()
3761 0 : ParsePostBufferToFixHeaders((const char *)buf, br, &parsedBuf, &bw);
3762 0 : rv = outStream->Write(parsedBuf, bw, &br);
3763 0 : nsMemory::Free(parsedBuf);
3764 0 : if (NS_FAILED(rv) || (bw != br))
3765 0 : break;
3766 :
3767 0 : firstRead = false;
3768 0 : continue;
3769 : }
3770 0 : bw = br;
3771 0 : rv = outStream->Write(buf, bw, &br);
3772 0 : if (NS_FAILED(rv) || (bw != br))
3773 0 : break;
3774 : }
3775 :
3776 0 : inStream->Close();
3777 0 : outStream->Close();
3778 0 : if (NS_SUCCEEDED(rv))
3779 0 : *aTmpFile = tempFile.forget().get();
3780 : }
3781 0 : return rv;
3782 : }
3783 :
3784 : nsresult
3785 0 : nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
3786 : {
3787 0 : return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
3788 : }
3789 :
3790 : nsresult
3791 0 : nsPluginHost::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner)
3792 : {
3793 : // Pass false as the second arg, we want the answer to be the
3794 : // same here whether the Java plugin is enabled or not.
3795 0 : nsPluginTag *plugin = FindPluginForType("application/x-java-vm", false);
3796 :
3797 0 : if (!plugin || !plugin->mIsNPRuntimeEnabledJavaPlugin) {
3798 : // No NPRuntime enabled Java plugin found, no point in
3799 : // instantiating a dummy plugin then.
3800 :
3801 0 : return NS_OK;
3802 : }
3803 :
3804 0 : nsresult rv = SetUpPluginInstance("application/x-java-vm", nsnull, aOwner);
3805 0 : NS_ENSURE_SUCCESS(rv, rv);
3806 :
3807 0 : nsRefPtr<nsNPAPIPluginInstance> instance;
3808 0 : aOwner->GetInstance(getter_AddRefs(instance));
3809 0 : if (!instance)
3810 0 : return NS_OK;
3811 :
3812 0 : instance->DefineJavaProperties();
3813 :
3814 0 : return NS_OK;
3815 : }
3816 :
3817 : nsresult
3818 0 : nsPluginHost::GetPluginName(nsNPAPIPluginInstance *aPluginInstance,
3819 : const char** aPluginName)
3820 : {
3821 0 : nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aPluginInstance);
3822 0 : if (!instance)
3823 0 : return NS_ERROR_FAILURE;
3824 :
3825 0 : nsNPAPIPlugin* plugin = instance->GetPlugin();
3826 0 : if (!plugin)
3827 0 : return NS_ERROR_FAILURE;
3828 :
3829 0 : *aPluginName = TagForPlugin(plugin)->mName.get();
3830 :
3831 0 : return NS_OK;
3832 : }
3833 :
3834 : nsresult
3835 0 : nsPluginHost::GetPluginTagForInstance(nsNPAPIPluginInstance *aPluginInstance,
3836 : nsIPluginTag **aPluginTag)
3837 : {
3838 0 : NS_ENSURE_ARG_POINTER(aPluginInstance);
3839 0 : NS_ENSURE_ARG_POINTER(aPluginTag);
3840 :
3841 0 : nsNPAPIPlugin *plugin = aPluginInstance->GetPlugin();
3842 0 : if (!plugin)
3843 0 : return NS_ERROR_FAILURE;
3844 :
3845 0 : *aPluginTag = TagForPlugin(plugin);
3846 :
3847 0 : NS_ADDREF(*aPluginTag);
3848 0 : return NS_OK;
3849 : }
3850 :
3851 : #ifdef MAC_CARBON_PLUGINS
3852 : // Flash requires a minimum of 8 events per second to avoid audio skipping.
3853 : // Since WebKit uses a hidden plugin event rate of 4 events per second Flash
3854 : // uses a Carbon timer for WebKit which fires at 8 events per second.
3855 : #define HIDDEN_PLUGIN_DELAY 125
3856 : #define VISIBLE_PLUGIN_DELAY 20
3857 : #endif
3858 :
3859 0 : void nsPluginHost::AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, bool isVisible)
3860 : {
3861 : #ifdef MAC_CARBON_PLUGINS
3862 : nsTObserverArray<nsIPluginInstanceOwner*> *targetArray;
3863 : if (isVisible) {
3864 : targetArray = &mVisibleTimerTargets;
3865 : } else {
3866 : targetArray = &mHiddenTimerTargets;
3867 : }
3868 :
3869 : if (targetArray->Contains(objectFrame)) {
3870 : return;
3871 : }
3872 :
3873 : targetArray->AppendElement(objectFrame);
3874 : if (targetArray->Length() == 1) {
3875 : if (isVisible) {
3876 : mVisiblePluginTimer->InitWithCallback(this, VISIBLE_PLUGIN_DELAY, nsITimer::TYPE_REPEATING_SLACK);
3877 : } else {
3878 : mHiddenPluginTimer->InitWithCallback(this, HIDDEN_PLUGIN_DELAY, nsITimer::TYPE_REPEATING_SLACK);
3879 : }
3880 : }
3881 : #endif
3882 0 : }
3883 :
3884 0 : void nsPluginHost::RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame)
3885 : {
3886 : #ifdef MAC_CARBON_PLUGINS
3887 : bool visibleRemoved = mVisibleTimerTargets.RemoveElement(objectFrame);
3888 : if (visibleRemoved && mVisibleTimerTargets.IsEmpty()) {
3889 : mVisiblePluginTimer->Cancel();
3890 : }
3891 :
3892 : bool hiddenRemoved = mHiddenTimerTargets.RemoveElement(objectFrame);
3893 : if (hiddenRemoved && mHiddenTimerTargets.IsEmpty()) {
3894 : mHiddenPluginTimer->Cancel();
3895 : }
3896 :
3897 : NS_ASSERTION(!(hiddenRemoved && visibleRemoved), "Plugin instance received visible and hidden idle event notifications");
3898 : #endif
3899 0 : }
3900 :
3901 0 : NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer)
3902 : {
3903 : #ifdef MAC_CARBON_PLUGINS
3904 : if (timer == mVisiblePluginTimer) {
3905 : nsTObserverArray<nsIPluginInstanceOwner*>::ForwardIterator iter(mVisibleTimerTargets);
3906 : while (iter.HasMore()) {
3907 : iter.GetNext()->SendIdleEvent();
3908 : }
3909 : return NS_OK;
3910 : } else if (timer == mHiddenPluginTimer) {
3911 : nsTObserverArray<nsIPluginInstanceOwner*>::ForwardIterator iter(mHiddenTimerTargets);
3912 : while (iter.HasMore()) {
3913 : iter.GetNext()->SendIdleEvent();
3914 : }
3915 : return NS_OK;
3916 : }
3917 : #endif
3918 :
3919 0 : nsRefPtr<nsPluginTag> pluginTag = mPlugins;
3920 0 : while (pluginTag) {
3921 0 : if (pluginTag->mUnloadTimer == timer) {
3922 0 : if (!IsRunningPlugin(pluginTag)) {
3923 0 : pluginTag->TryUnloadPlugin(false);
3924 : }
3925 0 : return NS_OK;
3926 : }
3927 0 : pluginTag = pluginTag->mNext;
3928 : }
3929 :
3930 0 : return NS_ERROR_FAILURE;
3931 : }
3932 :
3933 : #ifdef XP_WIN
3934 : // Re-enable any top level browser windows that were disabled by modal dialogs
3935 : // displayed by the crashed plugin.
3936 : static void
3937 : CheckForDisabledWindows()
3938 : {
3939 : nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
3940 : if (!wm)
3941 : return;
3942 :
3943 : nsCOMPtr<nsISimpleEnumerator> windowList;
3944 : wm->GetXULWindowEnumerator(nsnull, getter_AddRefs(windowList));
3945 : if (!windowList)
3946 : return;
3947 :
3948 : bool haveWindows;
3949 : do {
3950 : windowList->HasMoreElements(&haveWindows);
3951 : if (!haveWindows)
3952 : return;
3953 :
3954 : nsCOMPtr<nsISupports> supportsWindow;
3955 : windowList->GetNext(getter_AddRefs(supportsWindow));
3956 : nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
3957 : if (baseWin) {
3958 : bool aFlag;
3959 : nsCOMPtr<nsIWidget> widget;
3960 : baseWin->GetMainWidget(getter_AddRefs(widget));
3961 : if (widget && !widget->GetParent() &&
3962 : NS_SUCCEEDED(widget->IsVisible(aFlag)) && aFlag == true &&
3963 : NS_SUCCEEDED(widget->IsEnabled(&aFlag)) && aFlag == false) {
3964 : nsIWidget * child = widget->GetFirstChild();
3965 : bool enable = true;
3966 : while (child) {
3967 : nsWindowType aType;
3968 : if (NS_SUCCEEDED(child->GetWindowType(aType)) &&
3969 : aType == eWindowType_dialog) {
3970 : enable = false;
3971 : break;
3972 : }
3973 : child = child->GetNextSibling();
3974 : }
3975 : if (enable) {
3976 : widget->Enable(true);
3977 : }
3978 : }
3979 : }
3980 : } while (haveWindows);
3981 : }
3982 : #endif
3983 :
3984 : void
3985 0 : nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin,
3986 : const nsAString& pluginDumpID,
3987 : const nsAString& browserDumpID)
3988 : {
3989 0 : nsPluginTag* crashedPluginTag = TagForPlugin(aPlugin);
3990 :
3991 : // Notify the app's observer that a plugin crashed so it can submit
3992 : // a crashreport.
3993 0 : bool submittedCrashReport = false;
3994 : nsCOMPtr<nsIObserverService> obsService =
3995 0 : mozilla::services::GetObserverService();
3996 : nsCOMPtr<nsIWritablePropertyBag2> propbag =
3997 0 : do_CreateInstance("@mozilla.org/hash-property-bag;1");
3998 0 : if (obsService && propbag) {
3999 0 : propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
4000 0 : pluginDumpID);
4001 0 : propbag->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),
4002 0 : browserDumpID);
4003 0 : propbag->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
4004 0 : submittedCrashReport);
4005 0 : obsService->NotifyObservers(propbag, "plugin-crashed", nsnull);
4006 : // see if an observer submitted a crash report.
4007 0 : propbag->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
4008 0 : &submittedCrashReport);
4009 : }
4010 :
4011 : // Invalidate each nsPluginInstanceTag for the crashed plugin
4012 :
4013 0 : for (PRUint32 i = mInstances.Length(); i > 0; i--) {
4014 0 : nsNPAPIPluginInstance* instance = mInstances[i - 1];
4015 0 : if (instance->GetPlugin() == aPlugin) {
4016 : // notify the content node (nsIObjectLoadingContent) that the
4017 : // plugin has crashed
4018 0 : nsCOMPtr<nsIDOMElement> domElement;
4019 0 : instance->GetDOMElement(getter_AddRefs(domElement));
4020 0 : nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
4021 0 : if (objectContent) {
4022 0 : objectContent->PluginCrashed(crashedPluginTag, pluginDumpID, browserDumpID,
4023 0 : submittedCrashReport);
4024 : }
4025 :
4026 0 : instance->Destroy();
4027 0 : mInstances.RemoveElement(instance);
4028 0 : OnPluginInstanceDestroyed(crashedPluginTag);
4029 : }
4030 : }
4031 :
4032 : // Only after all instances have been invalidated is it safe to null
4033 : // out nsPluginTag.mEntryPoint. The next time we try to create an
4034 : // instance of this plugin we reload it (launch a new plugin process).
4035 :
4036 0 : crashedPluginTag->mEntryPoint = nsnull;
4037 :
4038 : #ifdef XP_WIN
4039 : CheckForDisabledWindows();
4040 : #endif
4041 0 : }
4042 :
4043 : nsNPAPIPluginInstance*
4044 0 : nsPluginHost::FindInstance(const char *mimetype)
4045 : {
4046 0 : for (PRUint32 i = 0; i < mInstances.Length(); i++) {
4047 0 : nsNPAPIPluginInstance* instance = mInstances[i];
4048 :
4049 : const char* mt;
4050 0 : nsresult rv = instance->GetMIMEType(&mt);
4051 0 : if (NS_FAILED(rv))
4052 0 : continue;
4053 :
4054 0 : if (PL_strcasecmp(mt, mimetype) == 0)
4055 0 : return instance;
4056 : }
4057 :
4058 0 : return nsnull;
4059 : }
4060 :
4061 : nsNPAPIPluginInstance*
4062 0 : nsPluginHost::FindOldestStoppedInstance()
4063 : {
4064 0 : nsNPAPIPluginInstance *oldestInstance = nsnull;
4065 0 : TimeStamp oldestTime = TimeStamp::Now();
4066 0 : for (PRUint32 i = 0; i < mInstances.Length(); i++) {
4067 0 : nsNPAPIPluginInstance *instance = mInstances[i];
4068 0 : if (instance->IsRunning())
4069 0 : continue;
4070 :
4071 0 : TimeStamp time = instance->StopTime();
4072 0 : if (time < oldestTime) {
4073 0 : oldestTime = time;
4074 0 : oldestInstance = instance;
4075 : }
4076 : }
4077 :
4078 0 : return oldestInstance;
4079 : }
4080 :
4081 : PRUint32
4082 0 : nsPluginHost::StoppedInstanceCount()
4083 : {
4084 0 : PRUint32 stoppedCount = 0;
4085 0 : for (PRUint32 i = 0; i < mInstances.Length(); i++) {
4086 0 : nsNPAPIPluginInstance *instance = mInstances[i];
4087 0 : if (!instance->IsRunning())
4088 0 : stoppedCount++;
4089 : }
4090 0 : return stoppedCount;
4091 : }
4092 :
4093 : nsTArray< nsRefPtr<nsNPAPIPluginInstance> >*
4094 0 : nsPluginHost::InstanceArray()
4095 : {
4096 0 : return &mInstances;
4097 : }
4098 :
4099 : void
4100 175 : nsPluginHost::DestroyRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag)
4101 : {
4102 175 : for (PRInt32 i = mInstances.Length(); i > 0; i--) {
4103 0 : nsNPAPIPluginInstance *instance = mInstances[i - 1];
4104 0 : if (instance->IsRunning() && (!aPluginTag || aPluginTag == TagForPlugin(instance->GetPlugin()))) {
4105 0 : instance->SetWindow(nsnull);
4106 0 : instance->Stop();
4107 :
4108 : // If we've been passed an array to return, lets collect all our documents,
4109 : // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
4110 : // to kickstart our instances.
4111 0 : if (aReloadDocs) {
4112 0 : nsCOMPtr<nsIPluginInstanceOwner> owner;
4113 0 : instance->GetOwner(getter_AddRefs(owner));
4114 0 : if (owner) {
4115 0 : nsCOMPtr<nsIDocument> doc;
4116 0 : owner->GetDocument(getter_AddRefs(doc));
4117 0 : if (doc && aReloadDocs->IndexOf(doc) == -1) // don't allow for duplicates
4118 0 : aReloadDocs->AppendElement(doc);
4119 : }
4120 : }
4121 :
4122 : // Get rid of all the instances without the possibility of caching.
4123 0 : nsPluginTag* pluginTag = TagForPlugin(instance->GetPlugin());
4124 0 : instance->SetWindow(nsnull);
4125 0 : instance->Destroy();
4126 0 : mInstances.RemoveElement(instance);
4127 0 : OnPluginInstanceDestroyed(pluginTag);
4128 : }
4129 : }
4130 175 : }
4131 :
4132 : // Runnable that does an async destroy of a plugin.
4133 :
4134 : class nsPluginDestroyRunnable : public nsRunnable,
4135 : public PRCList
4136 : {
4137 : public:
4138 0 : nsPluginDestroyRunnable(nsNPAPIPluginInstance *aInstance)
4139 0 : : mInstance(aInstance)
4140 : {
4141 0 : PR_INIT_CLIST(this);
4142 0 : PR_APPEND_LINK(this, &sRunnableListHead);
4143 0 : }
4144 :
4145 0 : virtual ~nsPluginDestroyRunnable()
4146 0 : {
4147 0 : PR_REMOVE_LINK(this);
4148 0 : }
4149 :
4150 0 : NS_IMETHOD Run()
4151 : {
4152 0 : nsRefPtr<nsNPAPIPluginInstance> instance;
4153 :
4154 : // Null out mInstance to make sure this code in another runnable
4155 : // will do the right thing even if someone was holding on to this
4156 : // runnable longer than we expect.
4157 0 : instance.swap(mInstance);
4158 :
4159 0 : if (PluginDestructionGuard::DelayDestroy(instance)) {
4160 : // It's still not safe to destroy the plugin, it's now up to the
4161 : // outermost guard on the stack to take care of the destruction.
4162 0 : return NS_OK;
4163 : }
4164 :
4165 : nsPluginDestroyRunnable *r =
4166 0 : static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(&sRunnableListHead));
4167 :
4168 0 : while (r != &sRunnableListHead) {
4169 0 : if (r != this && r->mInstance == instance) {
4170 : // There's another runnable scheduled to tear down
4171 : // instance. Let it do the job.
4172 0 : return NS_OK;
4173 : }
4174 0 : r = static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(r));
4175 : }
4176 :
4177 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
4178 : ("Doing delayed destroy of instance %p\n", instance.get()));
4179 :
4180 0 : nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
4181 0 : if (host)
4182 0 : host->StopPluginInstance(instance);
4183 :
4184 0 : PLUGIN_LOG(PLUGIN_LOG_NORMAL,
4185 : ("Done with delayed destroy of instance %p\n", instance.get()));
4186 :
4187 0 : return NS_OK;
4188 : }
4189 :
4190 : protected:
4191 : nsRefPtr<nsNPAPIPluginInstance> mInstance;
4192 :
4193 : static PRCList sRunnableListHead;
4194 : };
4195 :
4196 : PRCList nsPluginDestroyRunnable::sRunnableListHead =
4197 : PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead);
4198 :
4199 : PRCList PluginDestructionGuard::sListHead =
4200 : PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead);
4201 :
4202 0 : PluginDestructionGuard::~PluginDestructionGuard()
4203 : {
4204 0 : NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
4205 :
4206 0 : PR_REMOVE_LINK(this);
4207 :
4208 0 : if (mDelayedDestroy) {
4209 : // We've attempted to destroy the plugin instance we're holding on
4210 : // to while we were guarding it. Do the actual destroy now, off of
4211 : // a runnable.
4212 : nsRefPtr<nsPluginDestroyRunnable> evt =
4213 0 : new nsPluginDestroyRunnable(mInstance);
4214 :
4215 0 : NS_DispatchToMainThread(evt);
4216 : }
4217 0 : }
4218 :
4219 : // static
4220 : bool
4221 0 : PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance *aInstance)
4222 : {
4223 0 : NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
4224 0 : NS_ASSERTION(aInstance, "Uh, I need an instance!");
4225 :
4226 : // Find the first guard on the stack and make it do a delayed
4227 : // destroy upon destruction.
4228 :
4229 : PluginDestructionGuard *g =
4230 0 : static_cast<PluginDestructionGuard*>(PR_LIST_HEAD(&sListHead));
4231 :
4232 0 : while (g != &sListHead) {
4233 0 : if (g->mInstance == aInstance) {
4234 0 : g->mDelayedDestroy = true;
4235 :
4236 0 : return true;
4237 : }
4238 0 : g = static_cast<PluginDestructionGuard*>(PR_NEXT_LINK(g));
4239 : }
4240 :
4241 0 : return false;
4242 : }
|