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