2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
// vim:set et cin sw=2 sts=2:
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
/*
|
2007-07-18 14:48:18 -07:00
|
|
|
* A base class implementing nsIObjectLoadingContent for use by
|
2007-03-22 10:30:00 -07:00
|
|
|
* various content nodes that want to provide plugin/document/image
|
|
|
|
* loading functionality (eg <embed>, <object>, <applet>, etc).
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Interface headers
|
2012-10-03 13:17:40 -07:00
|
|
|
#include "imgLoader.h"
|
2010-02-09 17:05:31 -08:00
|
|
|
#include "nsEventDispatcher.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIDocument.h"
|
2010-02-09 17:05:31 -08:00
|
|
|
#include "nsIDOMDataContainerEvent.h"
|
2011-05-23 09:46:36 -07:00
|
|
|
#include "nsIDOMDocument.h"
|
2010-02-09 17:05:31 -08:00
|
|
|
#include "nsIDOMEventTarget.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIExternalProtocolHandler.h"
|
2011-04-21 10:35:52 -07:00
|
|
|
#include "nsEventStates.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIObjectFrame.h"
|
2012-04-18 11:40:55 -07:00
|
|
|
#include "nsIPermissionManager.h"
|
2011-05-17 18:48:34 -07:00
|
|
|
#include "nsPluginHost.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsIStreamConverterService.h"
|
|
|
|
#include "nsIURILoader.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsIWebNavigation.h"
|
|
|
|
#include "nsIWebNavigationInfo.h"
|
2007-12-03 13:57:17 -08:00
|
|
|
#include "nsIScriptChannel.h"
|
2009-10-02 04:26:04 -07:00
|
|
|
#include "nsIBlocklistService.h"
|
2010-08-04 19:15:55 -07:00
|
|
|
#include "nsIAsyncVerifyRedirectCallback.h"
|
2012-01-31 13:55:54 -08:00
|
|
|
#include "nsIAppShell.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-27 07:03:27 -07:00
|
|
|
#include "nsError.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Util headers
|
2012-07-25 21:44:11 -07:00
|
|
|
#include "prenv.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "prlog.h"
|
|
|
|
|
|
|
|
#include "nsAutoPtr.h"
|
|
|
|
#include "nsCURILoader.h"
|
|
|
|
#include "nsContentPolicyUtils.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsDocShellCID.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsNetUtil.h"
|
2007-08-20 20:26:12 -07:00
|
|
|
#include "nsMimeTypes.h"
|
2008-03-26 16:04:57 -07:00
|
|
|
#include "nsStyleUtil.h"
|
2010-02-09 17:05:31 -08:00
|
|
|
#include "nsGUIEvent.h"
|
2011-02-08 05:35:25 -08:00
|
|
|
#include "nsUnicharUtils.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Concrete classes
|
|
|
|
#include "nsFrameLoader.h"
|
|
|
|
|
|
|
|
#include "nsObjectLoadingContent.h"
|
2008-04-11 10:29:06 -07:00
|
|
|
#include "mozAutoDocUpdate.h"
|
2010-04-23 12:51:25 -07:00
|
|
|
#include "nsIContentSecurityPolicy.h"
|
|
|
|
#include "nsIChannelPolicy.h"
|
|
|
|
#include "nsChannelPolicy.h"
|
2011-07-20 12:18:54 -07:00
|
|
|
#include "mozilla/dom/Element.h"
|
2012-01-18 16:53:35 -08:00
|
|
|
#include "sampler.h"
|
2012-01-31 13:55:54 -08:00
|
|
|
#include "nsObjectFrame.h"
|
|
|
|
#include "nsDOMClassInfo.h"
|
|
|
|
|
|
|
|
#include "nsWidgetsCID.h"
|
|
|
|
#include "nsContentCID.h"
|
|
|
|
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
2012-10-29 16:32:10 -07:00
|
|
|
static PRLogModuleInfo*
|
|
|
|
GetObjectLog()
|
|
|
|
{
|
|
|
|
static PRLogModuleInfo *sLog;
|
|
|
|
if (!sLog)
|
|
|
|
sLog = PR_NewLogModule("objlc");
|
|
|
|
return sLog;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
2012-10-29 16:32:10 -07:00
|
|
|
#define LOG(args) PR_LOG(GetObjectLog(), PR_LOG_DEBUG, args)
|
|
|
|
#define LOG_ENABLED() PR_LOG_TEST(GetObjectLog(), PR_LOG_DEBUG)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-05 17:56:25 -07:00
|
|
|
static bool
|
|
|
|
InActiveDocument(nsIContent *aContent)
|
|
|
|
{
|
|
|
|
if (!aContent->IsInDoc()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsIDocument *doc = aContent->OwnerDoc();
|
|
|
|
return (doc && doc->IsActive());
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// Runnables and helper classes
|
|
|
|
///
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
class nsAsyncInstantiateEvent : public nsRunnable {
|
|
|
|
public:
|
2012-07-05 14:07:46 -07:00
|
|
|
nsAsyncInstantiateEvent(nsObjectLoadingContent *aContent)
|
|
|
|
: mContent(aContent) {}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
~nsAsyncInstantiateEvent() {}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_IMETHOD Run();
|
2012-07-05 14:07:46 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIObjectLoadingContent> mContent;
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAsyncInstantiateEvent::Run()
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
nsObjectLoadingContent *objLC =
|
|
|
|
static_cast<nsObjectLoadingContent *>(mContent.get());
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
// do nothing if we've been revoked
|
2012-07-05 14:07:46 -07:00
|
|
|
if (objLC->mPendingInstantiateEvent != this) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
objLC->mPendingInstantiateEvent = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
return objLC->SyncStartPluginInstance();
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
2011-08-29 00:09:22 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
// Checks to see if the content for a plugin instance has a parent.
|
|
|
|
// The plugin instance is stopped if there is no parent.
|
|
|
|
class InDocCheckEvent : public nsRunnable {
|
|
|
|
public:
|
2012-07-05 14:07:46 -07:00
|
|
|
InDocCheckEvent(nsObjectLoadingContent *aContent)
|
|
|
|
: mContent(aContent) {}
|
2012-01-31 13:55:54 -08:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
~InDocCheckEvent() {}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
NS_IMETHOD Run();
|
2012-07-05 14:07:46 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIObjectLoadingContent> mContent;
|
2012-01-31 13:55:54 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InDocCheckEvent::Run()
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
nsObjectLoadingContent *objLC =
|
|
|
|
static_cast<nsObjectLoadingContent *>(mContent.get());
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent *>(objLC));
|
|
|
|
|
2012-07-05 17:56:25 -07:00
|
|
|
if (!InActiveDocument(content)) {
|
2012-07-05 14:07:46 -07:00
|
|
|
nsObjectLoadingContent *objLC =
|
|
|
|
static_cast<nsObjectLoadingContent *>(mContent.get());
|
2012-07-05 13:47:39 -07:00
|
|
|
objLC->UnloadObject();
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-12-07 14:50:10 -08:00
|
|
|
* Helper task for firing simple events
|
2007-03-22 10:30:00 -07:00
|
|
|
*/
|
2012-12-07 14:50:10 -08:00
|
|
|
class nsSimplePluginEvent : public nsRunnable {
|
2007-03-22 10:30:00 -07:00
|
|
|
public:
|
2012-12-07 14:50:10 -08:00
|
|
|
nsSimplePluginEvent(nsIContent* aContent, const nsAString &aEvent)
|
|
|
|
: mContent(aContent),
|
|
|
|
mEvent(aEvent)
|
|
|
|
{}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-12-07 14:50:10 -08:00
|
|
|
~nsSimplePluginEvent() {}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_IMETHOD Run();
|
2012-07-05 13:47:39 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIContent> mContent;
|
2012-12-07 14:50:10 -08:00
|
|
|
nsString mEvent;
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-12-07 14:50:10 -08:00
|
|
|
nsSimplePluginEvent::Run()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-12-07 14:50:10 -08:00
|
|
|
LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mContent.get(),
|
|
|
|
mEvent.get()));
|
2008-09-09 08:43:21 -07:00
|
|
|
nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
|
2012-12-07 14:50:10 -08:00
|
|
|
mEvent, true, true);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-02-09 17:05:31 -08:00
|
|
|
/**
|
|
|
|
* A task for firing PluginCrashed DOM Events.
|
|
|
|
*/
|
|
|
|
class nsPluginCrashedEvent : public nsRunnable {
|
|
|
|
public:
|
|
|
|
nsCOMPtr<nsIContent> mContent;
|
2010-03-24 14:22:04 -07:00
|
|
|
nsString mPluginDumpID;
|
|
|
|
nsString mBrowserDumpID;
|
2010-02-09 17:05:31 -08:00
|
|
|
nsString mPluginName;
|
2010-04-08 00:45:00 -07:00
|
|
|
nsString mPluginFilename;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool mSubmittedCrashReport;
|
2010-02-09 17:05:31 -08:00
|
|
|
|
|
|
|
nsPluginCrashedEvent(nsIContent* aContent,
|
2010-03-24 14:22:04 -07:00
|
|
|
const nsAString& aPluginDumpID,
|
|
|
|
const nsAString& aBrowserDumpID,
|
2010-02-09 17:05:31 -08:00
|
|
|
const nsAString& aPluginName,
|
2010-04-08 00:45:00 -07:00
|
|
|
const nsAString& aPluginFilename,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool submittedCrashReport)
|
2010-02-09 17:05:31 -08:00
|
|
|
: mContent(aContent),
|
2010-03-24 14:22:04 -07:00
|
|
|
mPluginDumpID(aPluginDumpID),
|
|
|
|
mBrowserDumpID(aBrowserDumpID),
|
2010-02-09 17:05:31 -08:00
|
|
|
mPluginName(aPluginName),
|
2010-04-08 00:45:00 -07:00
|
|
|
mPluginFilename(aPluginFilename),
|
2010-02-09 17:05:31 -08:00
|
|
|
mSubmittedCrashReport(submittedCrashReport)
|
|
|
|
{}
|
|
|
|
|
|
|
|
~nsPluginCrashedEvent() {}
|
|
|
|
|
|
|
|
NS_IMETHOD Run();
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsPluginCrashedEvent::Run()
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: Firing plugin crashed event\n",
|
2010-02-09 17:05:31 -08:00
|
|
|
mContent.get()));
|
|
|
|
|
2011-05-23 09:46:36 -07:00
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc =
|
2010-02-09 17:05:31 -08:00
|
|
|
do_QueryInterface(mContent->GetDocument());
|
2011-05-23 09:46:36 -07:00
|
|
|
if (!domDoc) {
|
2010-02-09 17:05:31 -08:00
|
|
|
NS_WARNING("Couldn't get document for PluginCrashed event!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
2011-05-23 09:46:36 -07:00
|
|
|
domDoc->CreateEvent(NS_LITERAL_STRING("datacontainerevents"),
|
|
|
|
getter_AddRefs(event));
|
2010-02-09 17:05:31 -08:00
|
|
|
nsCOMPtr<nsIDOMDataContainerEvent> containerEvent(do_QueryInterface(event));
|
2012-06-10 11:14:30 -07:00
|
|
|
if (!containerEvent) {
|
2010-02-09 17:05:31 -08:00
|
|
|
NS_WARNING("Couldn't QI event for PluginCrashed event!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
event->InitEvent(NS_LITERAL_STRING("PluginCrashed"), true, true);
|
2012-06-10 11:14:30 -07:00
|
|
|
event->SetTrusted(true);
|
2012-12-15 17:26:05 -08:00
|
|
|
event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2010-02-09 17:05:31 -08:00
|
|
|
nsCOMPtr<nsIWritableVariant> variant;
|
|
|
|
|
2010-03-24 14:22:04 -07:00
|
|
|
// add a "pluginDumpID" property to this event
|
2010-03-16 22:10:08 -07:00
|
|
|
variant = do_CreateInstance("@mozilla.org/variant;1");
|
|
|
|
if (!variant) {
|
2010-03-24 14:22:04 -07:00
|
|
|
NS_WARNING("Couldn't create pluginDumpID variant for PluginCrashed event!");
|
2010-03-16 22:10:08 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-03-24 14:22:04 -07:00
|
|
|
variant->SetAsAString(mPluginDumpID);
|
|
|
|
containerEvent->SetData(NS_LITERAL_STRING("pluginDumpID"), variant);
|
|
|
|
|
|
|
|
// add a "browserDumpID" property to this event
|
|
|
|
variant = do_CreateInstance("@mozilla.org/variant;1");
|
|
|
|
if (!variant) {
|
|
|
|
NS_WARNING("Couldn't create browserDumpID variant for PluginCrashed event!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
variant->SetAsAString(mBrowserDumpID);
|
|
|
|
containerEvent->SetData(NS_LITERAL_STRING("browserDumpID"), variant);
|
2010-03-16 22:10:08 -07:00
|
|
|
|
2010-02-09 17:05:31 -08:00
|
|
|
// add a "pluginName" property to this event
|
|
|
|
variant = do_CreateInstance("@mozilla.org/variant;1");
|
|
|
|
if (!variant) {
|
|
|
|
NS_WARNING("Couldn't create pluginName variant for PluginCrashed event!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
variant->SetAsAString(mPluginName);
|
|
|
|
containerEvent->SetData(NS_LITERAL_STRING("pluginName"), variant);
|
|
|
|
|
2010-04-08 00:45:00 -07:00
|
|
|
// add a "pluginFilename" property to this event
|
|
|
|
variant = do_CreateInstance("@mozilla.org/variant;1");
|
|
|
|
if (!variant) {
|
|
|
|
NS_WARNING("Couldn't create pluginFilename variant for PluginCrashed event!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
variant->SetAsAString(mPluginFilename);
|
|
|
|
containerEvent->SetData(NS_LITERAL_STRING("pluginFilename"), variant);
|
|
|
|
|
2010-02-09 17:05:31 -08:00
|
|
|
// add a "submittedCrashReport" property to this event
|
|
|
|
variant = do_CreateInstance("@mozilla.org/variant;1");
|
|
|
|
if (!variant) {
|
|
|
|
NS_WARNING("Couldn't create crashSubmit variant for PluginCrashed event!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
variant->SetAsBool(mSubmittedCrashReport);
|
|
|
|
containerEvent->SetData(NS_LITERAL_STRING("submittedCrashReport"), variant);
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
nsEventDispatcher::DispatchDOMEvent(mContent, nullptr, event, nullptr, nullptr);
|
2010-02-09 17:05:31 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
class nsStopPluginRunnable : public nsRunnable, public nsITimerCallback
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
|
2012-05-25 15:34:11 -07:00
|
|
|
nsStopPluginRunnable(nsPluginInstanceOwner* aInstanceOwner,
|
|
|
|
nsObjectLoadingContent* aContent)
|
|
|
|
: mInstanceOwner(aInstanceOwner)
|
|
|
|
, mContent(aContent)
|
2012-01-31 13:55:54 -08:00
|
|
|
{
|
|
|
|
NS_ASSERTION(aInstanceOwner, "need an owner");
|
2012-05-25 15:34:11 -07:00
|
|
|
NS_ASSERTION(aContent, "need a nsObjectLoadingContent");
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// nsRunnable
|
|
|
|
NS_IMETHOD Run();
|
|
|
|
|
|
|
|
// nsITimerCallback
|
|
|
|
NS_IMETHOD Notify(nsITimer *timer);
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsITimer> mTimer;
|
|
|
|
nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
|
2012-05-25 17:43:44 -07:00
|
|
|
nsCOMPtr<nsIObjectLoadingContent> mContent;
|
2012-01-31 13:55:54 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsStopPluginRunnable, nsRunnable, nsITimerCallback)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsStopPluginRunnable::Notify(nsITimer *aTimer)
|
|
|
|
{
|
|
|
|
return Run();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsStopPluginRunnable::Run()
|
|
|
|
{
|
|
|
|
// InitWithCallback calls Release before AddRef so we need to hold a
|
|
|
|
// strong ref on 'this' since we fall through to this scope if it fails.
|
|
|
|
nsCOMPtr<nsITimerCallback> kungFuDeathGrip = this;
|
|
|
|
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
|
|
|
if (appShell) {
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t currentLevel = 0;
|
2012-01-31 13:55:54 -08:00
|
|
|
appShell->GetEventloopNestingLevel(¤tLevel);
|
|
|
|
if (currentLevel > mInstanceOwner->GetLastEventloopNestingLevel()) {
|
|
|
|
if (!mTimer)
|
|
|
|
mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
|
|
|
if (mTimer) {
|
|
|
|
// Fire 100ms timer to try to tear down this plugin as quickly as
|
|
|
|
// possible once the nesting level comes back down.
|
2012-07-05 14:07:46 -07:00
|
|
|
nsresult rv = mTimer->InitWithCallback(this, 100,
|
|
|
|
nsITimer::TYPE_ONE_SHOT);
|
2012-01-31 13:55:54 -08:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_ERROR("Failed to setup a timer to stop the plugin later (at a safe "
|
|
|
|
"time). Stopping the plugin now, this might crash.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mTimer = nullptr;
|
2012-01-31 13:55:54 -08:00
|
|
|
|
2012-05-25 17:43:44 -07:00
|
|
|
static_cast<nsObjectLoadingContent*>(mContent.get())->
|
|
|
|
DoStopPlugin(mInstanceOwner, false, true);
|
2012-01-31 13:55:54 -08:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// You can't take the address of bitfield members, so we have two separate
|
|
|
|
// classes for these :-/
|
|
|
|
|
|
|
|
// Sets a object's mInstantiating bit to false when destroyed
|
2012-07-25 13:39:01 -07:00
|
|
|
class AutoSetInstantiatingToFalse {
|
2012-07-05 14:07:46 -07:00
|
|
|
public:
|
|
|
|
AutoSetInstantiatingToFalse(nsObjectLoadingContent *aContent)
|
|
|
|
: mContent(aContent) {}
|
|
|
|
~AutoSetInstantiatingToFalse() { mContent->mInstantiating = false; }
|
|
|
|
private:
|
|
|
|
nsObjectLoadingContent* mContent;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Sets a object's mInstantiating bit to false when destroyed
|
|
|
|
class AutoSetLoadingToFalse {
|
|
|
|
public:
|
|
|
|
AutoSetLoadingToFalse(nsObjectLoadingContent *aContent)
|
|
|
|
: mContent(aContent) {}
|
|
|
|
~AutoSetLoadingToFalse() { mContent->mIsLoading = false; }
|
|
|
|
private:
|
|
|
|
nsObjectLoadingContent* mContent;
|
2012-07-25 13:39:01 -07:00
|
|
|
};
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// Helper functions
|
|
|
|
///
|
|
|
|
|
|
|
|
static bool
|
|
|
|
IsSuccessfulRequest(nsIRequest* aRequest)
|
|
|
|
{
|
|
|
|
nsresult status;
|
|
|
|
nsresult rv = aRequest->GetStatus(&status);
|
|
|
|
if (NS_FAILED(rv) || NS_FAILED(status)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This may still be an error page or somesuch
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(aRequest));
|
|
|
|
if (httpChan) {
|
|
|
|
bool success;
|
|
|
|
rv = httpChan->GetRequestSucceeded(&success);
|
|
|
|
if (NS_FAILED(rv) || !success) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, the request is successful
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
CanHandleURI(nsIURI* aURI)
|
|
|
|
{
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString scheme;
|
2012-07-05 14:07:46 -07:00
|
|
|
if (NS_FAILED(aURI->GetScheme(scheme))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIIOService* ios = nsContentUtils::GetIOService();
|
|
|
|
if (!ios)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIProtocolHandler> handler;
|
|
|
|
ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
|
|
|
|
if (!handler) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIExternalProtocolHandler> extHandler =
|
|
|
|
do_QueryInterface(handler);
|
|
|
|
// We can handle this URI if its protocol handler is not the external one
|
|
|
|
return extHandler == nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper for tedious URI equality syntax when one or both arguments may be
|
|
|
|
// null and URIEquals(null, null) should be true
|
|
|
|
static bool inline
|
|
|
|
URIEquals(nsIURI *a, nsIURI *b)
|
|
|
|
{
|
|
|
|
bool equal;
|
|
|
|
return (!a && !b) || (a && b && NS_SUCCEEDED(a->Equals(b, &equal)) && equal);
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
static bool
|
2012-07-25 13:39:01 -07:00
|
|
|
IsSupportedImage(const nsCString& aMimeType)
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
2012-10-03 13:17:47 -07:00
|
|
|
return imgLoader::SupportImageWithMimeType(aMimeType.get());
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
static void
|
|
|
|
GetExtensionFromURI(nsIURI* uri, nsCString& ext)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
|
|
|
|
if (url) {
|
|
|
|
url->GetFileExtension(ext);
|
|
|
|
} else {
|
|
|
|
nsCString spec;
|
|
|
|
uri->GetSpec(spec);
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t offset = spec.RFindChar('.');
|
2012-07-05 14:07:46 -07:00
|
|
|
if (offset != kNotFound) {
|
|
|
|
ext = Substring(spec, offset + 1, spec.Length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether a plugin exists and is enabled for the extension
|
|
|
|
* in the given URI. The MIME type is returned in the mimeType out parameter.
|
|
|
|
*/
|
2012-07-05 13:47:39 -07:00
|
|
|
bool
|
|
|
|
IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType)
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString ext;
|
2012-07-05 14:07:46 -07:00
|
|
|
GetExtensionFromURI(uri, ext);
|
|
|
|
|
|
|
|
if (ext.IsEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<nsPluginHost> pluginHost =
|
|
|
|
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
|
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
if (!pluginHost) {
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_NOTREACHED("No pluginhost");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* typeFromExt;
|
2012-07-05 13:47:39 -07:00
|
|
|
nsresult rv = pluginHost->IsPluginEnabledForExtension(ext.get(), typeFromExt);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2012-07-05 14:07:46 -07:00
|
|
|
mimeType = typeFromExt;
|
2012-07-05 13:47:39 -07:00
|
|
|
return true;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
return false;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-07-05 13:47:39 -07:00
|
|
|
IsPluginEnabledForType(const nsCString& aMIMEType)
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
|
|
|
nsRefPtr<nsPluginHost> pluginHost =
|
|
|
|
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
|
|
|
|
|
|
|
|
if (!pluginHost) {
|
|
|
|
NS_NOTREACHED("No pluginhost");
|
2012-08-13 04:41:53 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
nsresult rv = pluginHost->IsPluginEnabledForType(aMIMEType.get());
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
// Check to see if the plugin is disabled before deciding if it
|
|
|
|
// should be in the "click to play" state, since we only want to
|
|
|
|
// display "click to play" UI for enabled plugins.
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
///
|
|
|
|
/// Member Functions
|
|
|
|
///
|
|
|
|
|
2012-12-06 15:10:54 -08:00
|
|
|
// Tedious syntax to create a plugin stream listener with checks and put it in
|
|
|
|
// mFinalListener
|
|
|
|
bool
|
|
|
|
nsObjectLoadingContent::MakePluginListener()
|
|
|
|
{
|
|
|
|
if (!mInstanceOwner) {
|
|
|
|
NS_NOTREACHED("expecting a spawned plugin");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsRefPtr<nsPluginHost> pluginHost =
|
|
|
|
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
|
|
|
|
if (!pluginHost) {
|
|
|
|
NS_NOTREACHED("No pluginHost");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
NS_ASSERTION(!mFinalListener, "overwriting a final listener");
|
|
|
|
nsresult rv;
|
|
|
|
nsRefPtr<nsNPAPIPluginInstance> inst;
|
|
|
|
nsCOMPtr<nsIStreamListener> finalListener;
|
|
|
|
rv = mInstanceOwner->GetInstance(getter_AddRefs(inst));
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
2012-12-12 16:12:41 -08:00
|
|
|
rv = pluginHost->NewPluginStreamListener(mURI, inst,
|
|
|
|
getter_AddRefs(finalListener));
|
2012-12-06 15:10:54 -08:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
mFinalListener = finalListener;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
bool
|
|
|
|
nsObjectLoadingContent::IsSupportedDocument(const nsCString& aMimeType)
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
NS_ASSERTION(thisContent, "must be a content");
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIWebNavigationInfo> info(
|
2012-08-07 17:39:38 -07:00
|
|
|
do_GetService(NS_WEBNAVIGATION_INFO_CONTRACTID));
|
|
|
|
if (!info) {
|
|
|
|
return false;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-08-07 17:39:38 -07:00
|
|
|
nsCOMPtr<nsIWebNavigation> webNav;
|
|
|
|
nsIDocument* currentDoc = thisContent->GetCurrentDoc();
|
|
|
|
if (currentDoc) {
|
|
|
|
webNav = do_GetInterface(currentDoc->GetScriptGlobalObject());
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t supported;
|
2012-08-07 17:39:38 -07:00
|
|
|
nsresult rv = info->IsTypeSupported(aMimeType, webNav, &supported);
|
2012-07-11 08:56:34 -07:00
|
|
|
|
2012-08-07 17:39:38 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (supported != nsIWebNavigationInfo::UNSUPPORTED) {
|
2012-07-05 14:07:46 -07:00
|
|
|
// Don't want to support plugins as documents
|
|
|
|
return supported != nsIWebNavigationInfo::PLUGIN;
|
2007-07-18 14:48:18 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-08-07 17:39:38 -07:00
|
|
|
// Try a stream converter
|
|
|
|
// NOTE: We treat any type we can convert from as a supported type. If a
|
|
|
|
// type is not actually supported, the URI loader will detect that and
|
|
|
|
// return an error, and we'll fallback.
|
|
|
|
nsCOMPtr<nsIStreamConverterService> convServ =
|
|
|
|
do_GetService("@mozilla.org/streamConverters;1");
|
|
|
|
bool canConvert = false;
|
|
|
|
if (convServ) {
|
|
|
|
rv = convServ->CanConvert(aMimeType.get(), "*/*", &canConvert);
|
|
|
|
}
|
|
|
|
return NS_SUCCEEDED(rv) && canConvert;
|
2007-07-18 14:48:18 -07:00
|
|
|
}
|
|
|
|
|
2012-03-28 08:53:56 -07:00
|
|
|
nsresult
|
2012-07-05 14:07:46 -07:00
|
|
|
nsObjectLoadingContent::BindToTree(nsIDocument* aDocument,
|
2012-08-13 15:11:50 -07:00
|
|
|
nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
|
|
|
bool aCompileEventHandlers)
|
2012-03-28 08:53:56 -07:00
|
|
|
{
|
2012-08-13 15:11:50 -07:00
|
|
|
nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
|
|
|
|
2012-03-28 08:53:56 -07:00
|
|
|
if (aDocument) {
|
|
|
|
return aDocument->AddPlugin(this);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-13 15:11:50 -07:00
|
|
|
nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
|
2012-03-28 08:53:56 -07:00
|
|
|
{
|
2012-08-13 15:11:50 -07:00
|
|
|
nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
|
2012-03-28 08:53:56 -07:00
|
|
|
MOZ_ASSERT(thisContent);
|
|
|
|
nsIDocument* ownerDoc = thisContent->OwnerDoc();
|
|
|
|
ownerDoc->RemovePlugin(this);
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 17:56:25 -07:00
|
|
|
if (mType == eType_Plugin && mInstanceOwner) {
|
2012-07-05 14:07:46 -07:00
|
|
|
// we'll let the plugin continue to run at least until we get back to
|
|
|
|
// the event loop. If we get back to the event loop and the node
|
|
|
|
// has still not been added back to the document then we tear down the
|
|
|
|
// plugin
|
|
|
|
nsCOMPtr<nsIRunnable> event = new InDocCheckEvent(this);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
|
|
|
if (appShell) {
|
|
|
|
appShell->RunInStableState(event);
|
|
|
|
}
|
2012-08-14 10:15:45 -07:00
|
|
|
} else if (mType != eType_Image) {
|
|
|
|
// nsImageLoadingContent handles the image case.
|
2012-07-05 17:56:25 -07:00
|
|
|
// Reset state and clear pending events
|
2012-07-05 14:07:46 -07:00
|
|
|
/// XXX(johns): The implementation for GenericFrame notes that ideally we
|
|
|
|
/// would keep the docshell around, but trash the frameloader
|
2012-07-05 13:47:39 -07:00
|
|
|
UnloadObject();
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-03-28 08:53:56 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsObjectLoadingContent::nsObjectLoadingContent()
|
2012-07-30 07:20:58 -07:00
|
|
|
: mPendingInstantiateEvent(nullptr)
|
|
|
|
, mChannel(nullptr)
|
2007-03-22 10:30:00 -07:00
|
|
|
, mType(eType_Loading)
|
2012-07-05 13:47:39 -07:00
|
|
|
, mFallbackType(eFallbackAlternate)
|
2012-07-05 14:07:46 -07:00
|
|
|
, mChannelLoaded(false)
|
2011-10-17 07:59:28 -07:00
|
|
|
, mInstantiating(false)
|
|
|
|
, mNetworkCreated(true)
|
2012-07-05 14:07:46 -07:00
|
|
|
, mActivated(false)
|
2012-08-25 14:18:44 -07:00
|
|
|
, mPlayPreviewCanceled(false)
|
2012-05-25 15:34:11 -07:00
|
|
|
, mIsStopping(false)
|
2012-07-05 14:07:46 -07:00
|
|
|
, mIsLoading(false)
|
2012-12-07 14:50:10 -08:00
|
|
|
, mScriptRequested(false)
|
2012-07-05 13:47:39 -07:00
|
|
|
, mSrcStreamLoading(false) {}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsObjectLoadingContent::~nsObjectLoadingContent()
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
// Should have been unbound from the tree at this point, and InDocCheckEvent
|
|
|
|
// keeps us alive
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mFrameLoader) {
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_NOTREACHED("Should not be tearing down frame loaders at this point");
|
2007-03-22 10:30:00 -07:00
|
|
|
mFrameLoader->Destroy();
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
if (mInstanceOwner) {
|
|
|
|
// This is especially bad as delayed stop will try to hold on to this
|
|
|
|
// object...
|
|
|
|
NS_NOTREACHED("Should not be tearing down a plugin at this point!");
|
|
|
|
StopPluginInstance();
|
|
|
|
}
|
|
|
|
DestroyImageLoadingContent();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsresult
|
2012-12-06 15:10:54 -08:00
|
|
|
nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
|
2012-01-31 13:55:54 -08:00
|
|
|
{
|
2012-12-06 15:10:54 -08:00
|
|
|
if (mInstanceOwner || mType != eType_Plugin || (mIsLoading != aIsLoading) ||
|
|
|
|
mInstantiating) {
|
|
|
|
// If we hit this assertion it's probably because LoadObject re-entered :(
|
|
|
|
//
|
|
|
|
// XXX(johns): This hackiness will go away in bug 767635
|
|
|
|
NS_ASSERTION(mIsLoading || !aIsLoading,
|
|
|
|
"aIsLoading should only be true inside LoadObject");
|
2012-09-06 19:03:22 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-12-06 15:10:54 -08:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
mInstantiating = true;
|
|
|
|
AutoSetInstantiatingToFalse autoInstantiating(this);
|
|
|
|
|
2012-09-06 19:03:22 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent *>(this));
|
2012-08-31 10:52:50 -07:00
|
|
|
|
2012-09-06 19:03:22 -07:00
|
|
|
nsIDocument* doc = thisContent->GetCurrentDoc();
|
2012-08-31 10:52:50 -07:00
|
|
|
if (!doc || !InActiveDocument(thisContent)) {
|
2012-09-06 19:03:22 -07:00
|
|
|
NS_ERROR("Shouldn't be calling "
|
2012-08-31 10:52:50 -07:00
|
|
|
"InstantiatePluginInstance without an active document");
|
2012-09-06 19:03:22 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-08-31 10:52:50 -07:00
|
|
|
// Instantiating an instance can result in script execution, which
|
|
|
|
// can destroy this DOM object. Don't allow that for the scope
|
|
|
|
// of this method.
|
|
|
|
nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
|
|
|
|
|
|
|
|
// Flush layout so that the frame is created if possible and the plugin is
|
|
|
|
// initialized with the latest information.
|
|
|
|
doc->FlushPendingNotifications(Flush_Layout);
|
2012-12-06 15:09:10 -08:00
|
|
|
|
2012-08-31 10:52:50 -07:00
|
|
|
if (!thisContent->GetPrimaryFrame()) {
|
|
|
|
LOG(("OBJLC [%p]: Not instantiating plugin with no frame", this));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-12-06 15:09:10 -08:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
2012-07-05 14:07:46 -07:00
|
|
|
nsRefPtr<nsPluginHost> pluginHost =
|
|
|
|
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
|
|
|
|
|
|
|
|
if (!pluginHost) {
|
|
|
|
NS_NOTREACHED("No pluginhost");
|
2012-08-13 04:41:53 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
// If you add early return(s), be sure to balance this call to
|
|
|
|
// appShell->SuspendNative() with additional call(s) to
|
|
|
|
// appShell->ReturnNative().
|
|
|
|
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
|
|
|
if (appShell) {
|
|
|
|
appShell->SuspendNative();
|
|
|
|
}
|
|
|
|
|
2012-12-12 16:12:41 -08:00
|
|
|
rv = pluginHost->InstantiatePluginInstance(mContentType.get(),
|
|
|
|
mURI.get(), this,
|
|
|
|
getter_AddRefs(mInstanceOwner));
|
2012-01-31 13:55:54 -08:00
|
|
|
|
|
|
|
if (appShell) {
|
|
|
|
appShell->ResumeNative();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up scripting interfaces.
|
|
|
|
NotifyContentObjectWrapper();
|
|
|
|
|
|
|
|
nsRefPtr<nsNPAPIPluginInstance> pluginInstance;
|
|
|
|
GetPluginInstance(getter_AddRefs(pluginInstance));
|
|
|
|
if (pluginInstance) {
|
|
|
|
nsCOMPtr<nsIPluginTag> pluginTag;
|
2012-07-05 14:07:46 -07:00
|
|
|
pluginHost->GetPluginTagForInstance(pluginInstance,
|
|
|
|
getter_AddRefs(pluginTag));
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsCOMPtr<nsIBlocklistService> blocklist =
|
2012-07-05 14:07:46 -07:00
|
|
|
do_GetService("@mozilla.org/extensions/blocklist;1");
|
2012-01-31 13:55:54 -08:00
|
|
|
if (blocklist) {
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t blockState = nsIBlocklistService::STATE_NOT_BLOCKED;
|
2012-01-31 13:55:54 -08:00
|
|
|
blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
|
|
|
|
EmptyString(), &blockState);
|
2012-11-07 13:59:15 -08:00
|
|
|
if (blockState == nsIBlocklistService::STATE_OUTDATED) {
|
|
|
|
// Fire plugin outdated event if necessary
|
2012-12-07 14:50:10 -08:00
|
|
|
LOG(("OBJLC [%p]: Dispatching plugin outdated event for content %p\n",
|
2012-11-07 13:59:15 -08:00
|
|
|
this));
|
2012-12-07 14:50:10 -08:00
|
|
|
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(thisContent,
|
|
|
|
NS_LITERAL_STRING("PluginOutdated"));
|
2012-11-07 13:59:15 -08:00
|
|
|
nsresult rv = NS_DispatchToCurrentThread(ev);
|
|
|
|
if (NS_FAILED(rv)) {
|
2012-12-07 14:50:10 -08:00
|
|
|
NS_WARNING("failed to dispatch nsSimplePluginEvent");
|
2012-11-07 13:59:15 -08:00
|
|
|
}
|
|
|
|
}
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
2012-12-06 15:10:54 -08:00
|
|
|
|
|
|
|
// If we have a URI but didn't open a channel yet (eAllowPluginSkipChannel)
|
|
|
|
// or we did load with a channel but are re-instantiating, re-open the
|
|
|
|
// channel. OpenChannel() performs security checks, and this plugin has
|
|
|
|
// already passed content policy in LoadObject.
|
|
|
|
if ((mURI && !mChannelLoaded) || (mChannelLoaded && !aIsLoading)) {
|
|
|
|
NS_ASSERTION(!mChannel, "should not have an existing channel here");
|
2013-01-17 14:50:25 -08:00
|
|
|
// We intentionally ignore errors here, leaving it up to the plugin to
|
|
|
|
// deal with not having an initial stream.
|
|
|
|
OpenChannel();
|
2012-12-06 15:10:54 -08:00
|
|
|
}
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
|
|
|
|
{
|
|
|
|
if (!mInstanceOwner) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2012-01-31 13:55:54 -08:00
|
|
|
nsIDocument* ownerDoc = thisContent->OwnerDoc();
|
|
|
|
if (!ownerDoc->IsActive()) {
|
|
|
|
StopPluginInstance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// nsIRequestObserver
|
|
|
|
NS_IMETHODIMP
|
2008-03-27 16:12:18 -07:00
|
|
|
nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
|
|
|
|
nsISupports *aContext)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-01-18 16:53:35 -08:00
|
|
|
SAMPLE_LABEL("nsObjectLoadingContent", "OnStartRequest");
|
2012-01-31 13:55:54 -08:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: Channel OnStartRequest", this));
|
|
|
|
|
2011-11-03 22:23:26 -07:00
|
|
|
if (aRequest != mChannel || !aRequest) {
|
2012-07-05 14:07:46 -07:00
|
|
|
// happens when a new load starts before the previous one got here
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
|
2012-12-06 15:10:54 -08:00
|
|
|
// If we already switched to type plugin, this channel can just be passed to
|
|
|
|
// the final listener.
|
|
|
|
if (mType == eType_Plugin) {
|
2013-01-17 14:50:25 -08:00
|
|
|
if (!mInstanceOwner) {
|
2012-12-06 15:10:54 -08:00
|
|
|
// We drop mChannel when stopping plugins, so something is wrong
|
|
|
|
NS_NOTREACHED("Opened a channel in plugin mode, but don't have a plugin");
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
2013-01-17 14:50:25 -08:00
|
|
|
if (MakePluginListener()) {
|
|
|
|
return mFinalListener->OnStartRequest(aRequest, nullptr);
|
|
|
|
} else {
|
|
|
|
NS_NOTREACHED("Failed to create PluginStreamListener, aborting channel");
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
2012-12-06 15:10:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise we should be state loading, and call LoadObject with the channel
|
|
|
|
if (mType != eType_Loading) {
|
|
|
|
NS_NOTREACHED("Should be type loading at this point");
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
mChannelLoaded = true;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
|
|
|
|
NS_ASSERTION(chan, "Why is our request not a channel?");
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
2012-07-25 13:39:01 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
if (IsSuccessfulRequest(aRequest)) {
|
|
|
|
chan->GetURI(getter_AddRefs(uri));
|
2007-08-20 20:26:12 -07:00
|
|
|
}
|
|
|
|
|
2012-04-24 13:25:21 -07:00
|
|
|
if (!uri) {
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
|
|
|
|
// If the request fails, we still call LoadObject() to handle fallback
|
|
|
|
// content and notifying of failure. (mChannelLoaded && !mChannel) indicates
|
|
|
|
// the bad state.
|
|
|
|
mChannel = nullptr;
|
|
|
|
LoadObject(true, false);
|
2012-04-24 13:25:21 -07:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2008-03-27 16:12:18 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
return LoadObject(true, false, aRequest);
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::OnStopRequest(nsIRequest *aRequest,
|
|
|
|
nsISupports *aContext,
|
|
|
|
nsresult aStatusCode)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
|
|
|
|
|
|
|
if (aRequest != mChannel) {
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mChannel = nullptr;
|
2012-07-25 13:39:01 -07:00
|
|
|
|
|
|
|
if (mFinalListener) {
|
2012-10-04 13:50:49 -07:00
|
|
|
// This may re-enter in the case of plugin listeners
|
|
|
|
nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
|
2012-07-30 07:20:58 -07:00
|
|
|
mFinalListener = nullptr;
|
2012-10-04 13:50:49 -07:00
|
|
|
listenerGrip->OnStopRequest(aRequest, aContext, aStatusCode);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return value doesn't matter
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// nsIStreamListener
|
|
|
|
NS_IMETHODIMP
|
2011-11-03 22:23:26 -07:00
|
|
|
nsObjectLoadingContent::OnDataAvailable(nsIRequest *aRequest,
|
|
|
|
nsISupports *aContext,
|
|
|
|
nsIInputStream *aInputStream,
|
2012-09-05 19:41:02 -07:00
|
|
|
uint64_t aOffset, uint32_t aCount)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-11-03 22:23:26 -07:00
|
|
|
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aRequest != mChannel) {
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mFinalListener) {
|
2012-10-04 13:50:49 -07:00
|
|
|
// This may re-enter in the case of plugin listeners
|
|
|
|
nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
|
|
|
|
return listenerGrip->OnDataAvailable(aRequest, aContext, aInputStream,
|
|
|
|
aOffset, aCount);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// We shouldn't have a connected channel with no final listener
|
|
|
|
NS_NOTREACHED("Got data for channel with no connected final listener");
|
|
|
|
mChannel = nullptr;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsIFrameLoaderOwner
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::GetFrameLoader(nsIFrameLoader** aFrameLoader)
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-10-20 14:33:59 -07:00
|
|
|
NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
|
|
|
|
nsObjectLoadingContent::GetFrameLoader()
|
|
|
|
{
|
|
|
|
nsFrameLoader* loader = mFrameLoader;
|
|
|
|
NS_IF_ADDREF(loader);
|
|
|
|
return loader;
|
|
|
|
}
|
|
|
|
|
2008-08-11 01:38:43 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::GetActualType(nsACString& aType)
|
|
|
|
{
|
|
|
|
aType = mContentType;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
nsObjectLoadingContent::GetDisplayedType(uint32_t* aType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
*aType = mType;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-01-31 13:55:54 -08:00
|
|
|
nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
if (mType == eType_Plugin) {
|
|
|
|
if (!mInstanceOwner) {
|
|
|
|
// We have successfully set ourselves up in LoadObject, but not spawned an
|
|
|
|
// instance due to a lack of a frame.
|
|
|
|
AsyncStartPluginInstance();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-08-29 23:09:56 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Disconnect any existing frame
|
|
|
|
DisconnectFrame();
|
2012-07-25 13:39:01 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Set up relationship between instance owner and frame.
|
|
|
|
nsObjectFrame *objFrame = static_cast<nsObjectFrame*>(aFrame);
|
|
|
|
mInstanceOwner->SetFrame(objFrame);
|
2011-08-29 23:09:56 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Set up new frame to draw.
|
|
|
|
objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
|
2012-08-28 22:39:31 -07:00
|
|
|
objFrame->InvalidateFrame();
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-01-31 13:55:54 -08:00
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-01-31 13:55:54 -08:00
|
|
|
nsObjectLoadingContent::DisconnectFrame()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-01-31 13:55:54 -08:00
|
|
|
if (mInstanceOwner) {
|
2012-07-30 07:20:58 -07:00
|
|
|
mInstanceOwner->SetFrame(nullptr);
|
2011-08-29 23:09:56 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-03-14 16:08:57 -07:00
|
|
|
NS_IMETHODIMP
|
2011-05-17 18:48:34 -07:00
|
|
|
nsObjectLoadingContent::GetPluginInstance(nsNPAPIPluginInstance** aInstance)
|
2008-03-14 16:08:57 -07:00
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
*aInstance = nullptr;
|
2008-03-14 16:08:57 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
if (!mInstanceOwner) {
|
2008-03-14 16:08:57 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
return mInstanceOwner->GetInstance(aInstance);
|
2008-03-14 16:08:57 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t* aType)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
*aType = GetTypeOfContent(PromiseFlatCString(aMIMEType));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsIInterfaceRequestor
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::GetInterface(const nsIID & aIID, void **aResult)
|
|
|
|
{
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
|
|
|
|
nsIChannelEventSink* sink = this;
|
|
|
|
*aResult = sink;
|
|
|
|
NS_ADDREF(sink);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsIChannelEventSink
|
|
|
|
NS_IMETHODIMP
|
2010-08-04 19:15:55 -07:00
|
|
|
nsObjectLoadingContent::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
|
|
|
|
nsIChannel *aNewChannel,
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t aFlags,
|
2010-08-04 19:15:55 -07:00
|
|
|
nsIAsyncVerifyRedirectCallback *cb)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-02-28 11:26:05 -08:00
|
|
|
// If we're already busy with a new load, or have no load at all,
|
|
|
|
// cancel the redirect.
|
|
|
|
if (!mChannel || aOldChannel != mChannel) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
mChannel = aNewChannel;
|
2010-08-04 19:15:55 -07:00
|
|
|
cb->OnRedirectVerifyCallback(NS_OK);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// <public>
|
2010-10-20 04:26:32 -07:00
|
|
|
nsEventStates
|
2007-03-22 10:30:00 -07:00
|
|
|
nsObjectLoadingContent::ObjectState() const
|
|
|
|
{
|
|
|
|
switch (mType) {
|
|
|
|
case eType_Loading:
|
|
|
|
return NS_EVENT_STATE_LOADING;
|
|
|
|
case eType_Image:
|
|
|
|
return ImageState();
|
|
|
|
case eType_Plugin:
|
2011-11-19 20:08:27 -08:00
|
|
|
case eType_Document:
|
2007-03-22 10:30:00 -07:00
|
|
|
// These are OK. If documents start to load successfully, they display
|
|
|
|
// something, and are thus not broken in this sense. The same goes for
|
|
|
|
// plugins.
|
2010-10-20 04:26:32 -07:00
|
|
|
return nsEventStates();
|
2007-03-22 10:30:00 -07:00
|
|
|
case eType_Null:
|
2012-07-05 13:47:39 -07:00
|
|
|
switch (mFallbackType) {
|
|
|
|
case eFallbackSuppressed:
|
|
|
|
return NS_EVENT_STATE_SUPPRESSED;
|
|
|
|
case eFallbackUserDisabled:
|
|
|
|
return NS_EVENT_STATE_USERDISABLED;
|
|
|
|
case eFallbackClickToPlay:
|
2011-10-07 10:46:02 -07:00
|
|
|
return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
|
2012-08-25 14:18:44 -07:00
|
|
|
case eFallbackPlayPreview:
|
|
|
|
return NS_EVENT_STATE_TYPE_PLAY_PREVIEW;
|
2012-07-05 13:47:39 -07:00
|
|
|
case eFallbackDisabled:
|
|
|
|
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
|
|
|
|
case eFallbackBlocklisted:
|
|
|
|
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_BLOCKED;
|
|
|
|
case eFallbackCrashed:
|
|
|
|
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_CRASHED;
|
|
|
|
case eFallbackUnsupported: {
|
2012-07-25 21:44:11 -07:00
|
|
|
// Check to see if plugins are blocked on this platform.
|
|
|
|
char* pluginsBlocked = PR_GetEnv("MOZ_PLUGINS_BLOCKED");
|
|
|
|
if (pluginsBlocked && pluginsBlocked[0] == '1') {
|
2012-07-05 13:47:39 -07:00
|
|
|
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM;
|
2012-07-25 21:44:11 -07:00
|
|
|
} else {
|
2012-07-05 13:47:39 -07:00
|
|
|
return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_TYPE_UNSUPPORTED;
|
2012-07-25 21:44:11 -07:00
|
|
|
}
|
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
case eFallbackOutdated:
|
|
|
|
case eFallbackAlternate:
|
|
|
|
return NS_EVENT_STATE_BROKEN;
|
|
|
|
case eFallbackVulnerableUpdatable:
|
|
|
|
return NS_EVENT_STATE_VULNERABLE_UPDATABLE;
|
|
|
|
case eFallbackVulnerableNoUpdate:
|
|
|
|
return NS_EVENT_STATE_VULNERABLE_NO_UPDATE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
NS_NOTREACHED("unknown type?");
|
2012-07-05 14:07:46 -07:00
|
|
|
return NS_EVENT_STATE_LOADING;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-08-16 18:44:14 -07:00
|
|
|
bool
|
2012-08-22 08:56:38 -07:00
|
|
|
nsObjectLoadingContent::CheckLoadPolicy(int16_t *aContentPolicy)
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
2012-08-16 18:44:14 -07:00
|
|
|
if (!aContentPolicy || !mURI) {
|
|
|
|
NS_NOTREACHED("Doing it wrong");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
NS_ASSERTION(thisContent, "Must be an instance of content");
|
|
|
|
|
2012-08-16 18:44:14 -07:00
|
|
|
nsIDocument* doc = thisContent->OwnerDoc();
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-08-16 18:44:14 -07:00
|
|
|
*aContentPolicy = nsIContentPolicy::ACCEPT;
|
|
|
|
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT,
|
|
|
|
mURI,
|
|
|
|
doc->NodePrincipal(),
|
|
|
|
thisContent,
|
|
|
|
mContentType,
|
|
|
|
nullptr, //extra
|
|
|
|
aContentPolicy,
|
|
|
|
nsContentUtils::GetContentPolicy(),
|
|
|
|
nsContentUtils::GetSecurityManager());
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
if (NS_CP_REJECTED(*aContentPolicy)) {
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString uri;
|
|
|
|
nsAutoCString baseUri;
|
2012-08-16 18:44:14 -07:00
|
|
|
mURI->GetSpec(uri);
|
|
|
|
mURI->GetSpec(baseUri);
|
|
|
|
LOG(("OBJLC [%p]: Content policy denied load of %s (base %s)",
|
|
|
|
this, uri.get(), baseUri.get()));
|
2012-07-05 14:07:46 -07:00
|
|
|
return false;
|
2007-07-26 19:49:18 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
return true;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-08-16 18:44:14 -07:00
|
|
|
bool
|
2012-08-22 08:56:38 -07:00
|
|
|
nsObjectLoadingContent::CheckProcessPolicy(int16_t *aContentPolicy)
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
2012-08-16 18:44:14 -07:00
|
|
|
if (!aContentPolicy) {
|
|
|
|
NS_NOTREACHED("Null out variable");
|
|
|
|
return false;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
2012-07-05 14:07:46 -07:00
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_ASSERTION(thisContent, "Must be an instance of content");
|
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
nsIDocument* doc = thisContent->OwnerDoc();
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
int32_t objectType;
|
2012-08-16 18:44:14 -07:00
|
|
|
switch (mType) {
|
|
|
|
case eType_Image:
|
|
|
|
objectType = nsIContentPolicy::TYPE_IMAGE;
|
|
|
|
break;
|
|
|
|
case eType_Document:
|
|
|
|
objectType = nsIContentPolicy::TYPE_DOCUMENT;
|
|
|
|
break;
|
|
|
|
case eType_Plugin:
|
|
|
|
objectType = nsIContentPolicy::TYPE_OBJECT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_NOTREACHED("Calling checkProcessPolicy with a unloadable type");
|
|
|
|
return false;
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-08-16 18:44:14 -07:00
|
|
|
*aContentPolicy = nsIContentPolicy::ACCEPT;
|
|
|
|
nsresult rv =
|
|
|
|
NS_CheckContentProcessPolicy(objectType,
|
|
|
|
mURI,
|
2012-07-05 14:07:46 -07:00
|
|
|
doc->NodePrincipal(),
|
|
|
|
static_cast<nsIImageLoadingContent*>(this),
|
|
|
|
mContentType,
|
|
|
|
nullptr, //extra
|
2012-08-16 18:44:14 -07:00
|
|
|
aContentPolicy,
|
2012-07-05 14:07:46 -07:00
|
|
|
nsContentUtils::GetContentPolicy(),
|
2012-08-16 18:44:14 -07:00
|
|
|
nsContentUtils::GetSecurityManager());
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
2012-08-16 18:44:14 -07:00
|
|
|
|
|
|
|
if (NS_CP_REJECTED(*aContentPolicy)) {
|
|
|
|
LOG(("OBJLC [%p]: CheckContentProcessPolicy rejected load", this));
|
2012-07-05 14:07:46 -07:00
|
|
|
return false;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-08-16 18:44:14 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
return true;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsObjectLoadingContent::ParameterUpdateFlags
|
|
|
|
nsObjectLoadingContent::UpdateObjectParameters()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
NS_ASSERTION(thisContent, "Must be an instance of content");
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t caps = GetCapabilities();
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: Updating object parameters", this));
|
|
|
|
|
|
|
|
nsresult rv;
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString newMime;
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIURI> newURI;
|
|
|
|
nsCOMPtr<nsIURI> newBaseURI;
|
|
|
|
ObjectType newType;
|
2012-08-07 11:42:56 -07:00
|
|
|
bool isJava = false;
|
2012-07-05 14:07:46 -07:00
|
|
|
// Set if this state can't be used to load anything, forces eType_Null
|
|
|
|
bool stateInvalid = false;
|
|
|
|
// Indicates what parameters changed.
|
|
|
|
// eParamChannelChanged - means parameters that affect channel opening
|
|
|
|
// decisions changed
|
|
|
|
// eParamStateChanged - means anything that affects what content we load
|
|
|
|
// changed, even if the channel we'd open remains the
|
|
|
|
// same.
|
|
|
|
//
|
|
|
|
// State changes outside of the channel parameters only matter if we've
|
|
|
|
// already opened a channel or tried to instantiate content, whereas channel
|
|
|
|
// parameter changes require re-opening the channel even if we haven't gotten
|
|
|
|
// that far.
|
|
|
|
nsObjectLoadingContent::ParameterUpdateFlags retval = eParamNoChange;
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Initial MIME Type
|
|
|
|
///
|
|
|
|
if (thisContent->NodeInfo()->Equals(nsGkAtoms::applet)) {
|
|
|
|
newMime.AssignLiteral("application/x-java-vm");
|
2012-08-07 11:42:56 -07:00
|
|
|
isJava = true;
|
2012-07-05 14:07:46 -07:00
|
|
|
} else {
|
|
|
|
nsAutoString typeAttr;
|
|
|
|
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, typeAttr);
|
|
|
|
if (!typeAttr.IsEmpty()) {
|
|
|
|
CopyUTF16toUTF8(typeAttr, newMime);
|
2012-08-07 11:42:56 -07:00
|
|
|
isJava = nsPluginHost::IsJavaMIMEType(newMime.get());
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// classID
|
|
|
|
///
|
|
|
|
|
|
|
|
if (caps & eSupportClassID) {
|
|
|
|
nsAutoString classIDAttr;
|
|
|
|
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::classid, classIDAttr);
|
|
|
|
if (!classIDAttr.IsEmpty()) {
|
2012-08-07 11:42:56 -07:00
|
|
|
// Our classid support is limited to 'java:' ids
|
|
|
|
rv = IsPluginEnabledForType(NS_LITERAL_CSTRING("application/x-java-vm"));
|
|
|
|
if (NS_SUCCEEDED(rv) &&
|
|
|
|
StringBeginsWith(classIDAttr, NS_LITERAL_STRING("java:"))) {
|
|
|
|
newMime.Assign("application/x-java-vm");
|
|
|
|
isJava = true;
|
|
|
|
} else {
|
2012-07-05 14:07:46 -07:00
|
|
|
// XXX(johns): Our de-facto behavior since forever was to refuse to load
|
|
|
|
// Objects who don't have a classid we support, regardless of other type
|
|
|
|
// or uri info leads to a valid plugin.
|
|
|
|
newMime.Assign("");
|
|
|
|
stateInvalid = true;
|
|
|
|
}
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// Codebase
|
|
|
|
///
|
|
|
|
|
|
|
|
nsAutoString codebaseStr;
|
|
|
|
nsCOMPtr<nsIURI> docBaseURI = thisContent->GetBaseURI();
|
|
|
|
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase, codebaseStr);
|
|
|
|
if (codebaseStr.IsEmpty() && thisContent->NodeInfo()->Equals(nsGkAtoms::applet)) {
|
|
|
|
// bug 406541
|
|
|
|
// NOTE we send the full absolute URI resolved here to java in
|
|
|
|
// pluginInstanceOwner to avoid disagreements between parsing of
|
|
|
|
// relative URIs. We need to mimic java's quirks here to make that
|
|
|
|
// not break things.
|
|
|
|
codebaseStr.AssignLiteral("/"); // Java resolves codebase="" as "/"
|
|
|
|
// XXX(johns) This doesn't catch the case of "file:" which java would
|
|
|
|
// interpret as "file:///" but we would interpret as this document's URI
|
|
|
|
// but with a changed scheme.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!codebaseStr.IsEmpty()) {
|
|
|
|
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(newBaseURI),
|
|
|
|
codebaseStr,
|
|
|
|
thisContent->OwnerDoc(),
|
|
|
|
docBaseURI);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
NS_TryToSetImmutable(newBaseURI);
|
|
|
|
} else {
|
|
|
|
// Malformed URI
|
|
|
|
LOG(("OBJLC [%p]: Could not parse plugin's codebase as a URI, "
|
|
|
|
"will use document baseURI instead", this));
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Otherwise, use normal document baseURI
|
|
|
|
if (!newBaseURI) {
|
|
|
|
newBaseURI = docBaseURI;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// URI
|
|
|
|
///
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsAutoString uriStr;
|
|
|
|
// Different elements keep this in various locations
|
2012-08-07 11:42:56 -07:00
|
|
|
if (isJava) {
|
|
|
|
// Applet tags and embed/object with explicit java MIMEs have
|
|
|
|
// src/data attributes that are not parsed as URIs, so we will
|
|
|
|
// act as if URI is null
|
|
|
|
} else if (thisContent->NodeInfo()->Equals(nsGkAtoms::object)) {
|
2012-07-05 14:07:46 -07:00
|
|
|
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, uriStr);
|
|
|
|
} else if (thisContent->NodeInfo()->Equals(nsGkAtoms::embed)) {
|
|
|
|
thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, uriStr);
|
|
|
|
} else {
|
2012-08-07 11:42:56 -07:00
|
|
|
// Applet tags should always have a java MIME type at this point
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_NOTREACHED("Unrecognized plugin-loading tag");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note that the baseURI changing could affect the newURI, even if uriStr did
|
|
|
|
// not change.
|
|
|
|
if (!uriStr.IsEmpty()) {
|
|
|
|
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(newURI),
|
|
|
|
uriStr,
|
|
|
|
thisContent->OwnerDoc(),
|
|
|
|
newBaseURI);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
NS_TryToSetImmutable(newURI);
|
2012-07-25 13:39:01 -07:00
|
|
|
} else {
|
2012-07-05 14:07:46 -07:00
|
|
|
stateInvalid = true;
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-10-19 13:42:37 -07:00
|
|
|
// For eAllowPluginSkipChannel tags, if we have a non-plugin type, but can get
|
|
|
|
// a plugin type from the extension, prefer that to falling back to a channel.
|
|
|
|
if (GetTypeOfContent(newMime) != eType_Plugin && newURI &&
|
|
|
|
(caps & eAllowPluginSkipChannel) &&
|
|
|
|
IsPluginEnabledByExtension(newURI, newMime)) {
|
|
|
|
LOG(("OBJLC [%p]: Using extension as type hint (%s)", this, newMime.get()));
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// Check if the original (pre-channel) content-type or URI changed, and
|
|
|
|
/// record mOriginal{ContentType,URI}
|
|
|
|
///
|
|
|
|
|
|
|
|
if ((mOriginalContentType != newMime) || !URIEquals(mOriginalURI, newURI)) {
|
|
|
|
// These parameters changing requires re-opening the channel, so don't
|
|
|
|
// consider the currently-open channel below
|
|
|
|
// XXX(johns): Changing the mime type might change our decision on whether
|
|
|
|
// or not we load a channel, so we count changes to it as a
|
|
|
|
// channel parameter change for the sake of simplicity.
|
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
|
|
|
|
LOG(("OBJLC [%p]: Channel parameters changed", this));
|
|
|
|
}
|
|
|
|
mOriginalContentType = newMime;
|
|
|
|
mOriginalURI = newURI;
|
|
|
|
|
|
|
|
///
|
|
|
|
/// If we have a channel, see if its MIME type should take precendence and
|
|
|
|
/// check the final (redirected) URL
|
|
|
|
///
|
|
|
|
|
|
|
|
// If we have a loaded channel and channel parameters did not change, use it
|
|
|
|
// to determine what we would load.
|
|
|
|
bool useChannel = mChannelLoaded && !(retval & eParamChannelChanged);
|
2012-12-04 17:10:29 -08:00
|
|
|
// If we have a channel and are type loading, as opposed to having an existing
|
|
|
|
// channel for a previous load.
|
|
|
|
bool newChannel = useChannel && mType == eType_Loading;
|
|
|
|
|
|
|
|
if (newChannel && mChannel) {
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCString channelType;
|
|
|
|
rv = mChannel->GetContentType(channelType);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_NOTREACHED("GetContentType failed");
|
|
|
|
stateInvalid = true;
|
|
|
|
channelType.Assign("");
|
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: Channel has a content type of %s", this, channelType.get()));
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
bool binaryChannelType = false;
|
|
|
|
if (channelType.EqualsASCII(APPLICATION_GUESS_FROM_EXT)) {
|
|
|
|
channelType = APPLICATION_OCTET_STREAM;
|
|
|
|
mChannel->SetContentType(channelType);
|
|
|
|
binaryChannelType = true;
|
|
|
|
} else if (channelType.EqualsASCII(APPLICATION_OCTET_STREAM)
|
|
|
|
|| channelType.EqualsASCII(BINARY_OCTET_STREAM)) {
|
|
|
|
binaryChannelType = true;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Channel can change our URI through redirection
|
|
|
|
rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(newURI));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_NOTREACHED("NS_GetFinalChannelURI failure");
|
|
|
|
stateInvalid = true;
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-12-06 15:09:10 -08:00
|
|
|
ObjectType typeHint = newMime.IsEmpty() ?
|
|
|
|
eType_Null : GetTypeOfContent(newMime);
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
//
|
2012-12-06 15:09:10 -08:00
|
|
|
// In order of preference:
|
|
|
|
//
|
|
|
|
// 1) Use our type hint if it matches a plugin
|
|
|
|
// 2) If we have eAllowPluginSkipChannel, use the uri file extension if
|
|
|
|
// it matches a plugin
|
|
|
|
// 3) If the channel returns a binary stream type:
|
|
|
|
// 3a) If we have a type non-null non-document type hint, use that
|
|
|
|
// 3b) If the uri file extension matches a plugin type, use that
|
|
|
|
// 4) Use the channel type
|
2012-07-05 14:07:46 -07:00
|
|
|
//
|
|
|
|
// XXX(johns): HTML5's "typesmustmatch" attribute would need to be
|
|
|
|
// honored here if implemented
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-12-06 15:09:10 -08:00
|
|
|
bool overrideChannelType = false;
|
|
|
|
if (typeHint == eType_Plugin) {
|
|
|
|
LOG(("OBJLC [%p]: Using plugin type hint in favor of any channel type",
|
|
|
|
this));
|
|
|
|
overrideChannelType = true;
|
|
|
|
} else if ((caps & eAllowPluginSkipChannel) &&
|
|
|
|
IsPluginEnabledByExtension(newURI, newMime)) {
|
|
|
|
LOG(("OBJLC [%p]: Using extension as type hint for "
|
|
|
|
"eAllowPluginSkipChannel tag (%s)", this, newMime.get()));
|
|
|
|
overrideChannelType = true;
|
|
|
|
} else if (binaryChannelType &&
|
|
|
|
typeHint != eType_Null && typeHint != eType_Document) {
|
|
|
|
LOG(("OBJLC [%p]: Using type hint in favor of binary channel type",
|
|
|
|
this));
|
|
|
|
overrideChannelType = true;
|
|
|
|
} else if (binaryChannelType &&
|
|
|
|
IsPluginEnabledByExtension(newURI, newMime)) {
|
|
|
|
LOG(("OBJLC [%p]: Using extension as type hint for binary channel (%s)",
|
|
|
|
this, newMime.get()));
|
|
|
|
overrideChannelType = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (overrideChannelType) {
|
|
|
|
// Set the type we'll use for dispatch on the channel. Otherwise we could
|
|
|
|
// end up trying to dispatch to a nsFrameLoader, which will complain that
|
|
|
|
// it couldn't find a way to handle application/octet-stream
|
|
|
|
nsAutoCString parsedMime, dummy;
|
|
|
|
NS_ParseContentType(newMime, parsedMime, dummy);
|
|
|
|
if (!parsedMime.IsEmpty()) {
|
|
|
|
mChannel->SetContentType(parsedMime);
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
} else {
|
|
|
|
newMime = channelType;
|
2012-08-07 11:42:56 -07:00
|
|
|
if (nsPluginHost::IsJavaMIMEType(newMime.get())) {
|
2012-12-06 15:09:10 -08:00
|
|
|
// Java does not load with a channel, and being java retroactively
|
|
|
|
// changes how we may have interpreted the codebase to construct this
|
|
|
|
// URI above. Because the behavior here is more or less undefined, play
|
|
|
|
// it safe and reject the load.
|
2012-08-07 11:42:56 -07:00
|
|
|
LOG(("OBJLC [%p]: Refusing to load with channel with java MIME",
|
|
|
|
this));
|
|
|
|
stateInvalid = true;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-12-04 17:10:29 -08:00
|
|
|
} else if (newChannel) {
|
|
|
|
LOG(("OBJLC [%p]: We failed to open a channel, marking invalid", this));
|
2012-07-05 14:07:46 -07:00
|
|
|
stateInvalid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Determine final type
|
|
|
|
///
|
2012-12-06 15:09:10 -08:00
|
|
|
// In order of preference:
|
2012-07-05 14:07:46 -07:00
|
|
|
// 1) If we have attempted channel load, or set stateInvalid above, the type
|
|
|
|
// is always null (fallback)
|
2012-12-06 15:09:10 -08:00
|
|
|
// 2) If we have a loaded channel, we grabbed its mimeType above, use that
|
|
|
|
// type.
|
|
|
|
// 3) If we have a plugin type and no URI, use that type.
|
|
|
|
// 4) If we have a plugin type and eAllowPluginSkipChannel, use that type.
|
|
|
|
// 5) if we have a URI, set type to loading to indicate we'd need a channel
|
|
|
|
// to proceed.
|
|
|
|
// 6) Otherwise, type null to indicate unloadable content (fallback)
|
2012-07-05 14:07:46 -07:00
|
|
|
//
|
|
|
|
|
|
|
|
if (stateInvalid) {
|
|
|
|
newType = eType_Null;
|
2012-08-25 14:18:44 -07:00
|
|
|
newMime.Truncate();
|
2012-12-04 17:10:29 -08:00
|
|
|
} else if (newChannel) {
|
|
|
|
// If newChannel is set above, we considered it in setting newMime
|
2012-07-05 14:07:46 -07:00
|
|
|
newType = GetTypeOfContent(newMime);
|
|
|
|
LOG(("OBJLC [%p]: Using channel type", this));
|
2012-08-07 11:42:56 -07:00
|
|
|
} else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
|
2012-12-06 15:09:10 -08:00
|
|
|
GetTypeOfContent(newMime) == eType_Plugin) {
|
2012-07-05 14:07:46 -07:00
|
|
|
newType = eType_Plugin;
|
2012-12-06 15:09:10 -08:00
|
|
|
LOG(("OBJLC [%p]: Plugin type with no URI, skipping channel load", this));
|
2012-07-05 14:07:46 -07:00
|
|
|
} else if (newURI) {
|
|
|
|
// We could potentially load this if we opened a channel on mURI, indicate
|
|
|
|
// This by leaving type as loading
|
|
|
|
newType = eType_Loading;
|
|
|
|
} else {
|
|
|
|
// Unloadable - no URI, and no plugin type. Non-plugin types (images,
|
|
|
|
// documents) always load with a channel.
|
|
|
|
newType = eType_Null;
|
|
|
|
}
|
|
|
|
|
2012-12-04 17:10:29 -08:00
|
|
|
///
|
|
|
|
/// Handle existing channels
|
|
|
|
///
|
|
|
|
|
|
|
|
if (useChannel && newType == eType_Loading) {
|
|
|
|
// We decided to use a channel, and also that the previous channel is still
|
|
|
|
// usable, so re-use the existing values.
|
|
|
|
newType = mType;
|
|
|
|
newMime = mContentType;
|
|
|
|
newURI = mURI;
|
|
|
|
} else if (useChannel && !newChannel) {
|
|
|
|
// We have an existing channel, but did not decide to use one.
|
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
|
|
|
|
useChannel = false;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
///
|
|
|
|
/// Update changed values
|
|
|
|
///
|
|
|
|
|
|
|
|
if (newType != mType) {
|
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
|
|
|
|
LOG(("OBJLC [%p]: Type changed from %u -> %u", this, mType, newType));
|
|
|
|
mType = newType;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!URIEquals(mBaseURI, newBaseURI)) {
|
|
|
|
if (isJava) {
|
|
|
|
// Java bases its class loading on the base URI, so we consider the state
|
|
|
|
// to have changed if this changes. If the object is using a relative URI,
|
|
|
|
// mURI will have changed below regardless
|
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: Object effective baseURI changed", this));
|
|
|
|
mBaseURI = newBaseURI;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!URIEquals(newURI, mURI)) {
|
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
|
|
|
|
LOG(("OBJLC [%p]: Object effective URI changed", this));
|
|
|
|
mURI = newURI;
|
|
|
|
}
|
|
|
|
|
2012-10-04 12:57:24 -07:00
|
|
|
// We don't update content type when loading, as the type is not final and we
|
|
|
|
// don't want to superfluously change between mOriginalContentType ->
|
|
|
|
// mContentType when doing |obj.data = obj.data| with a channel and differing
|
|
|
|
// type.
|
|
|
|
if (mType != eType_Loading && mContentType != newMime) {
|
2012-07-05 14:07:46 -07:00
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamStateChanged);
|
2012-10-04 12:57:24 -07:00
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamContentTypeChanged);
|
|
|
|
LOG(("OBJLC [%p]: Object effective mime type changed (%s -> %s)",
|
|
|
|
this, mContentType.get(), newMime.get()));
|
2012-07-05 14:07:46 -07:00
|
|
|
mContentType = newMime;
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
|
|
|
|
2012-12-04 17:10:29 -08:00
|
|
|
// If we decided to keep using info from an old channel, but also that state
|
|
|
|
// changed, we need to invalidate it.
|
|
|
|
if (useChannel && !newChannel && (retval & eParamStateChanged)) {
|
|
|
|
mType = eType_Loading;
|
|
|
|
retval = (ParameterUpdateFlags)(retval | eParamChannelChanged);
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2012-12-10 16:35:05 -08:00
|
|
|
// Used by PluginDocument to kick off our initial load from the already-opened
|
|
|
|
// channel.
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::InitializeFromChannel(nsIRequest *aChannel)
|
|
|
|
{
|
|
|
|
LOG(("OBJLC [%p] InitializeFromChannel: %p", this, aChannel));
|
|
|
|
if (mType != eType_Loading || mChannel) {
|
|
|
|
// We could technically call UnloadObject() here, if consumers have a valid
|
|
|
|
// reason for wanting to call this on an already-loaded tag.
|
|
|
|
NS_NOTREACHED("Should not have begun loading at this point");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Because we didn't open this channel from an initial LoadObject, we'll
|
|
|
|
// update our parameters now, so the OnStartRequest->LoadObject doesn't
|
|
|
|
// believe our src/type suddenly changed.
|
|
|
|
UpdateObjectParameters();
|
|
|
|
// But we always want to load from a channel, in this case.
|
|
|
|
mType = eType_Loading;
|
|
|
|
mChannel = do_QueryInterface(aChannel);
|
|
|
|
NS_ASSERTION(mChannel, "passed a request that is not a channel");
|
|
|
|
|
|
|
|
// OnStartRequest will now see we have a channel in the loading state, and
|
|
|
|
// call into LoadObject. There's a possibility LoadObject will decide not to
|
|
|
|
// load anything from a channel - it will call CloseChannel() in that case.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Only OnStartRequest should be passing the channel parameter
|
|
|
|
nsresult
|
|
|
|
nsObjectLoadingContent::LoadObject(bool aNotify,
|
|
|
|
bool aForceLoad)
|
|
|
|
{
|
|
|
|
return LoadObject(aNotify, aForceLoad, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsObjectLoadingContent::LoadObject(bool aNotify,
|
|
|
|
bool aForceLoad,
|
|
|
|
nsIRequest *aLoadingChannel)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
NS_ASSERTION(thisContent, "must be a content");
|
|
|
|
nsIDocument* doc = thisContent->OwnerDoc();
|
2012-07-05 13:47:39 -07:00
|
|
|
nsresult rv = NS_OK;
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 17:56:25 -07:00
|
|
|
// Sanity check
|
|
|
|
if (!InActiveDocument(thisContent)) {
|
|
|
|
NS_NOTREACHED("LoadObject called while not bound to an active document");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// XXX(johns): In these cases, we refuse to touch our content and just
|
|
|
|
// remain unloaded, as per legacy behavior. It would make more sense to
|
|
|
|
// load fallback content initially and refuse to ever change state again.
|
|
|
|
if (doc->IsBeingUsedAsImage() || doc->IsLoadedAsData()) {
|
2012-07-25 13:39:01 -07:00
|
|
|
return NS_OK;
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: LoadObject called, notify %u, forceload %u, channel %p",
|
|
|
|
this, aNotify, aForceLoad, aLoadingChannel));
|
|
|
|
|
|
|
|
// We can't re-use an already open channel, but aForceLoad may make us try
|
|
|
|
// to load a plugin without any changes in channel state.
|
|
|
|
if (aForceLoad && mChannelLoaded) {
|
|
|
|
CloseChannel();
|
|
|
|
mChannelLoaded = false;
|
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
// Save these for NotifyStateChanged();
|
|
|
|
nsEventStates oldState = ObjectState();
|
|
|
|
ObjectType oldType = mType;
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
ParameterUpdateFlags stateChange = UpdateObjectParameters();
|
|
|
|
|
2012-08-15 12:16:17 -07:00
|
|
|
if (!stateChange && !aForceLoad) {
|
2012-07-05 14:07:46 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// State has changed, unload existing content and attempt to load new type
|
|
|
|
///
|
|
|
|
LOG(("OBJLC [%p]: LoadObject - plugin state changed (%u)",
|
|
|
|
this, stateChange));
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
// Setup fallback info. We may also change type to fallback below in case of
|
|
|
|
// sanity/OOM/etc. errors. We default to showing alternate content
|
|
|
|
// NOTE LoadFallback can override this in some cases
|
|
|
|
FallbackType fallbackType = eFallbackAlternate;
|
|
|
|
|
2012-11-09 15:02:43 -08:00
|
|
|
// mType can differ with GetTypeOfContent(mContentType) if we support this
|
|
|
|
// type, but the parameters are invalid e.g. a embed tag with type "image/png"
|
|
|
|
// but no URI -- don't show a plugin error or unknown type error in that case.
|
|
|
|
if (mType == eType_Null && GetTypeOfContent(mContentType) == eType_Null) {
|
|
|
|
// See if a disabled or blocked plugin could've handled this
|
2012-07-05 13:47:39 -07:00
|
|
|
nsresult pluginsupport = IsPluginEnabledForType(mContentType);
|
|
|
|
if (pluginsupport == NS_ERROR_PLUGIN_DISABLED) {
|
|
|
|
fallbackType = eFallbackDisabled;
|
|
|
|
} else if (pluginsupport == NS_ERROR_PLUGIN_BLOCKLISTED) {
|
|
|
|
fallbackType = eFallbackBlocklisted;
|
|
|
|
} else {
|
2012-11-09 15:02:43 -08:00
|
|
|
// Completely unknown type
|
2012-07-05 13:47:39 -07:00
|
|
|
fallbackType = eFallbackUnsupported;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-04 12:57:24 -07:00
|
|
|
// Explicit user activation should reset if the object changes content types
|
|
|
|
if (mActivated && (stateChange & eParamContentTypeChanged)) {
|
|
|
|
LOG(("OBJLC [%p]: Content type changed, clearing activation state", this));
|
|
|
|
mActivated = false;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// We synchronously start/stop plugin instances below, which may spin the
|
|
|
|
// event loop. Re-entering into the load is fine, but at that point the
|
|
|
|
// original load call needs to abort when unwinding
|
|
|
|
// NOTE this is located *after* the state change check, a subseqent load
|
|
|
|
// with no subsequently changed state will be a no-op.
|
2012-08-20 12:46:48 -07:00
|
|
|
if (mIsLoading) {
|
|
|
|
LOG(("OBJLC [%p]: Re-entering into LoadObject", this));
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
mIsLoading = true;
|
|
|
|
AutoSetLoadingToFalse reentryCheck(this);
|
|
|
|
|
|
|
|
// Unload existing content, keeping in mind stopping plugins might spin the
|
2012-07-05 13:47:39 -07:00
|
|
|
// event loop. Note that we check for still-open channels below
|
|
|
|
UnloadObject(false); // Don't reset state
|
2012-07-05 14:07:46 -07:00
|
|
|
if (!mIsLoading) {
|
|
|
|
// The event loop must've spun and re-entered into LoadObject, which
|
|
|
|
// finished the load
|
2012-08-20 12:46:48 -07:00
|
|
|
LOG(("OBJLC [%p]: Re-entered into LoadObject, aborting outer load", this));
|
2012-07-05 14:07:46 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-12-06 15:09:10 -08:00
|
|
|
// Determine what's going on with our channel.
|
2012-07-05 14:07:46 -07:00
|
|
|
if (stateChange & eParamChannelChanged) {
|
|
|
|
// If the channel params changed, throw away the channel, but unset
|
|
|
|
// mChannelLoaded so we'll still try to open a new one for this load if
|
|
|
|
// necessary
|
|
|
|
CloseChannel();
|
|
|
|
mChannelLoaded = false;
|
|
|
|
} else if (mType == eType_Null && mChannel) {
|
|
|
|
// If we opened a channel but then failed to find a loadable state, throw it
|
|
|
|
// away. mChannelLoaded will indicate that we tried to load a channel at one
|
|
|
|
// point so we wont recurse
|
|
|
|
CloseChannel();
|
2012-08-15 12:16:17 -07:00
|
|
|
} else if (mType == eType_Loading && mChannel) {
|
|
|
|
// We're still waiting on a channel load, already opened one, and
|
|
|
|
// channel parameters didn't change
|
|
|
|
return NS_OK;
|
2012-07-05 14:07:46 -07:00
|
|
|
} else if (mChannelLoaded && mChannel != aLoadingChannel) {
|
|
|
|
// The only time we should have a loaded channel with a changed state is
|
|
|
|
// when the channel has just opened -- in which case this call should
|
|
|
|
// have originated from OnStartRequest
|
|
|
|
NS_NOTREACHED("Loading with a channel, but state doesn't make sense");
|
|
|
|
return NS_OK;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
//
|
|
|
|
// Security checks
|
|
|
|
//
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
if (mType != eType_Null) {
|
2012-08-22 08:56:38 -07:00
|
|
|
int16_t contentPolicy = nsIContentPolicy::ACCEPT;
|
2012-12-06 15:10:54 -08:00
|
|
|
bool allowLoad = true;
|
|
|
|
// If mChannelLoaded is set we presumably already passed load policy
|
|
|
|
if (mURI && !mChannelLoaded) {
|
|
|
|
allowLoad = CheckLoadPolicy(&contentPolicy);
|
|
|
|
}
|
|
|
|
// If we're loading a type now, check ProcessPolicy. Note that we may check
|
|
|
|
// both now in the case of plugins whose type is determined before opening a
|
|
|
|
// channel.
|
|
|
|
if (allowLoad && mType != eType_Loading) {
|
2012-08-16 18:44:14 -07:00
|
|
|
allowLoad = CheckProcessPolicy(&contentPolicy);
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
2012-08-20 12:46:48 -07:00
|
|
|
|
|
|
|
// Content policy implementations can mutate the DOM, check for re-entry
|
|
|
|
if (!mIsLoading) {
|
|
|
|
LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
|
|
|
|
this));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-12-06 15:09:10 -08:00
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
// Load denied, switch to fallback and set disabled/suppressed if applicable
|
|
|
|
if (!allowLoad) {
|
2012-08-16 18:44:14 -07:00
|
|
|
LOG(("OBJLC [%p]: Load denied by policy", this));
|
2012-07-05 13:47:39 -07:00
|
|
|
mType = eType_Null;
|
|
|
|
if (contentPolicy == nsIContentPolicy::REJECT_TYPE) {
|
2012-08-16 18:44:14 -07:00
|
|
|
// XXX(johns) This is assuming that we were rejected by
|
|
|
|
// nsContentBlocker, which rejects by type if permissions
|
|
|
|
// reject plugins
|
2012-07-05 13:47:39 -07:00
|
|
|
fallbackType = eFallbackUserDisabled;
|
|
|
|
} else {
|
|
|
|
fallbackType = eFallbackSuppressed;
|
|
|
|
}
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
// If we're a plugin but shouldn't start yet, load fallback with
|
2013-02-14 13:38:41 -08:00
|
|
|
// reason click-to-play instead. Items resolved as Image/Document
|
|
|
|
// will not be checked for previews, as well as invalid plugins
|
|
|
|
// (they will not have the mContentType set).
|
2012-07-05 13:47:39 -07:00
|
|
|
FallbackType clickToPlayReason;
|
2013-02-14 13:38:41 -08:00
|
|
|
if ((mType == eType_Null || mType == eType_Plugin) &&
|
|
|
|
!ShouldPlay(clickToPlayReason)) {
|
2012-07-05 13:47:39 -07:00
|
|
|
LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
|
2012-07-05 14:07:46 -07:00
|
|
|
mType = eType_Null;
|
2012-07-05 13:47:39 -07:00
|
|
|
fallbackType = clickToPlayReason;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-10-18 15:38:50 -07:00
|
|
|
if (!mActivated && mType == eType_Plugin) {
|
2013-02-14 13:38:41 -08:00
|
|
|
// Object passed ShouldPlay, so it should be considered
|
2012-10-04 12:57:24 -07:00
|
|
|
// activated until it changes content type
|
|
|
|
LOG(("OBJLC [%p]: Object implicitly activated", this));
|
|
|
|
mActivated = true;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// Sanity check: We shouldn't have any loaded resources, pending events, or
|
|
|
|
// a final listener at this point
|
|
|
|
if (mFrameLoader || mPendingInstantiateEvent || mInstanceOwner ||
|
|
|
|
mFinalListener)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("Trying to load new plugin with existing content");
|
|
|
|
rv = NS_ERROR_UNEXPECTED;
|
2012-07-25 13:39:01 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// More sanity-checking:
|
|
|
|
// If mChannel is set, mChannelLoaded should be set, and vice-versa
|
|
|
|
if (mType != eType_Null && !!mChannel != mChannelLoaded) {
|
|
|
|
NS_NOTREACHED("Trying to load with bad channel state");
|
|
|
|
rv = NS_ERROR_UNEXPECTED;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
/// Attempt to load new type
|
|
|
|
///
|
2012-10-04 13:50:49 -07:00
|
|
|
|
|
|
|
// We don't set mFinalListener until OnStartRequest has been called, to
|
|
|
|
// prevent re-entry ugliness with CloseChannel()
|
|
|
|
nsCOMPtr<nsIStreamListener> finalListener;
|
2012-12-06 15:10:54 -08:00
|
|
|
// If we decide to synchronously spawn a plugin, we do it after firing
|
|
|
|
// notifications to avoid re-entry causing notifications to fire out of order.
|
|
|
|
bool doSpawnPlugin = false;
|
2012-07-05 14:07:46 -07:00
|
|
|
switch (mType) {
|
|
|
|
case eType_Image:
|
|
|
|
if (!mChannel) {
|
|
|
|
// We have a LoadImage() call, but UpdateObjectParameters requires a
|
|
|
|
// channel for images, so this is not a valid state.
|
|
|
|
NS_NOTREACHED("Attempting to load image without a channel?");
|
|
|
|
rv = NS_ERROR_UNEXPECTED;
|
2012-07-05 13:47:39 -07:00
|
|
|
break;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-10-04 13:50:49 -07:00
|
|
|
rv = LoadImageWithChannel(mChannel, getter_AddRefs(finalListener));
|
|
|
|
// finalListener will receive OnStartRequest below
|
2012-07-05 14:07:46 -07:00
|
|
|
break;
|
|
|
|
case eType_Plugin:
|
|
|
|
{
|
|
|
|
if (mChannel) {
|
2012-07-05 13:47:39 -07:00
|
|
|
// Force a sync state change now, we need the frame created
|
|
|
|
NotifyStateChanged(oldType, oldState, true, aNotify);
|
|
|
|
oldType = mType;
|
|
|
|
oldState = ObjectState();
|
|
|
|
|
2012-08-31 10:52:50 -07:00
|
|
|
if (!thisContent->GetPrimaryFrame()) {
|
|
|
|
// We're un-rendered, and can't instantiate a plugin. HasNewFrame will
|
|
|
|
// re-start us when we can proceed.
|
|
|
|
LOG(("OBJLC [%p]: Aborting load - plugin-type, but no frame", this));
|
|
|
|
CloseChannel();
|
|
|
|
break;
|
|
|
|
}
|
2012-12-06 15:09:10 -08:00
|
|
|
|
2012-12-06 15:10:54 -08:00
|
|
|
// We'll handle this below
|
|
|
|
doSpawnPlugin = true;
|
2012-07-05 14:07:46 -07:00
|
|
|
} else {
|
|
|
|
rv = AsyncStartPluginInstance();
|
|
|
|
}
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
break;
|
|
|
|
case eType_Document:
|
|
|
|
{
|
|
|
|
if (!mChannel) {
|
|
|
|
// We could mFrameLoader->LoadURI(mURI), but UpdateObjectParameters
|
|
|
|
// requires documents have a channel, so this is not a valid state.
|
|
|
|
NS_NOTREACHED("Attempting to load a document without a channel");
|
2012-07-05 13:47:39 -07:00
|
|
|
mType = eType_Null;
|
|
|
|
break;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-12-06 15:09:10 -08:00
|
|
|
|
2012-08-14 10:29:29 -07:00
|
|
|
mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
|
|
|
|
mNetworkCreated);
|
2012-07-05 14:07:46 -07:00
|
|
|
if (!mFrameLoader) {
|
2012-08-14 10:29:29 -07:00
|
|
|
NS_NOTREACHED("nsFrameLoader::Create failed");
|
|
|
|
mType = eType_Null;
|
|
|
|
break;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-12-06 15:09:10 -08:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
rv = mFrameLoader->CheckForRecursiveLoad(mURI);
|
|
|
|
if (NS_FAILED(rv)) {
|
2012-10-05 15:30:13 -07:00
|
|
|
LOG(("OBJLC [%p]: Aborting recursive load", this));
|
|
|
|
mFrameLoader->Destroy();
|
|
|
|
mFrameLoader = nullptr;
|
2012-07-05 13:47:39 -07:00
|
|
|
mType = eType_Null;
|
|
|
|
break;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// We're loading a document, so we have to set LOAD_DOCUMENT_URI
|
|
|
|
// (especially important for firing onload)
|
|
|
|
nsLoadFlags flags = 0;
|
|
|
|
mChannel->GetLoadFlags(&flags);
|
|
|
|
flags |= nsIChannel::LOAD_DOCUMENT_URI;
|
|
|
|
mChannel->SetLoadFlags(flags);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
|
|
|
rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
|
2012-07-05 13:47:39 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_NOTREACHED("Could not get DocShell from mFrameLoader?");
|
|
|
|
mType = eType_Null;
|
|
|
|
break;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(docShell));
|
|
|
|
NS_ASSERTION(req, "Docshell must be an ifreq");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURILoader>
|
|
|
|
uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID, &rv));
|
2012-07-05 13:47:39 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_NOTREACHED("Failed to get uriLoader service");
|
|
|
|
mType = eType_Null;
|
|
|
|
break;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
rv = uriLoader->OpenChannel(mChannel, nsIURILoader::DONT_RETARGET, req,
|
2012-10-04 13:50:49 -07:00
|
|
|
getter_AddRefs(finalListener));
|
|
|
|
// finalListener will receive OnStartRequest below
|
2012-07-25 13:39:01 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
break;
|
|
|
|
case eType_Loading:
|
|
|
|
// If our type remains Loading, we need a channel to proceed
|
2012-08-16 18:44:14 -07:00
|
|
|
rv = OpenChannel();
|
2012-07-05 14:07:46 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
LOG(("OBJLC [%p]: OpenChannel returned failure (%u)", this, rv));
|
|
|
|
}
|
|
|
|
break;
|
2012-07-05 13:47:39 -07:00
|
|
|
case eType_Null:
|
|
|
|
// Handled below, silence compiler warnings
|
2012-07-05 14:07:46 -07:00
|
|
|
break;
|
|
|
|
};
|
2012-07-25 13:39:01 -07:00
|
|
|
|
2012-10-04 13:50:49 -07:00
|
|
|
//
|
|
|
|
// Loaded, handle notifications and fallback
|
|
|
|
//
|
2012-07-05 13:47:39 -07:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// If we failed in the loading hunk above, switch to fallback
|
|
|
|
LOG(("OBJLC [%p]: Loading failed, switching to fallback", this));
|
|
|
|
mType = eType_Null;
|
|
|
|
}
|
|
|
|
|
2012-10-04 13:50:49 -07:00
|
|
|
// If we didn't load anything, handle switching to fallback state
|
2012-07-05 13:47:39 -07:00
|
|
|
if (mType == eType_Null) {
|
|
|
|
LOG(("OBJLC [%p]: Loading fallback, type %u", this, fallbackType));
|
|
|
|
NS_ASSERTION(!mFrameLoader && !mInstanceOwner,
|
|
|
|
"switched to type null but also loaded something");
|
|
|
|
|
|
|
|
if (mChannel) {
|
|
|
|
// If we were loading with a channel but then failed over, throw it away
|
|
|
|
CloseChannel();
|
|
|
|
}
|
|
|
|
|
2012-12-06 15:10:54 -08:00
|
|
|
// Don't try to initialize plugins or final listener below
|
|
|
|
doSpawnPlugin = false;
|
2012-11-28 12:34:34 -08:00
|
|
|
finalListener = nullptr;
|
|
|
|
|
2012-11-07 13:59:15 -08:00
|
|
|
// Don't notify, as LoadFallback doesn't know of our previous state
|
2012-07-05 13:47:39 -07:00
|
|
|
// (so really this is just setting mFallbackType)
|
|
|
|
LoadFallback(fallbackType, false);
|
|
|
|
}
|
|
|
|
|
2012-11-07 13:59:15 -08:00
|
|
|
// Notify of our final state
|
2012-07-05 13:47:39 -07:00
|
|
|
NotifyStateChanged(oldType, oldState, false, aNotify);
|
2012-12-06 15:10:54 -08:00
|
|
|
NS_ENSURE_TRUE(mIsLoading, NS_OK);
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-10-04 13:50:49 -07:00
|
|
|
//
|
2012-12-06 15:10:54 -08:00
|
|
|
// Spawning plugins and dispatching to the final listener may re-enter, so are
|
|
|
|
// delayed until after we fire a notification, to prevent missing
|
|
|
|
// notifications or firing them out of order.
|
2012-12-06 15:09:10 -08:00
|
|
|
//
|
2012-12-06 15:10:54 -08:00
|
|
|
// Note that we ensured that we entered into LoadObject() from
|
|
|
|
// ::OnStartRequest above when loading with a channel.
|
2012-10-04 13:50:49 -07:00
|
|
|
//
|
|
|
|
|
2012-12-06 15:10:54 -08:00
|
|
|
rv = NS_OK;
|
|
|
|
if (doSpawnPlugin) {
|
|
|
|
rv = InstantiatePluginInstance(true);
|
|
|
|
NS_ENSURE_TRUE(mIsLoading, NS_OK);
|
|
|
|
// Create the final listener if we're loading with a channel. We can't do
|
|
|
|
// this in the loading block above as it requires an instance.
|
|
|
|
if (aLoadingChannel && NS_SUCCEEDED(rv)) {
|
|
|
|
if (NS_SUCCEEDED(rv) && MakePluginListener()) {
|
2012-12-16 00:25:04 -08:00
|
|
|
rv = mFinalListener->OnStartRequest(mChannel, nullptr);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Plugins can reject their initial stream, but continue to run.
|
|
|
|
CloseChannel();
|
|
|
|
NS_ENSURE_TRUE(mIsLoading, NS_OK);
|
|
|
|
rv = NS_OK;
|
|
|
|
}
|
2012-12-06 15:10:54 -08:00
|
|
|
}
|
|
|
|
}
|
2012-10-04 13:50:49 -07:00
|
|
|
} else if (finalListener) {
|
|
|
|
NS_ASSERTION(mType != eType_Null && mType != eType_Loading,
|
|
|
|
"We should not have a final listener with a non-loaded type");
|
|
|
|
mFinalListener = finalListener;
|
2012-10-18 11:49:45 -07:00
|
|
|
rv = finalListener->OnStartRequest(mChannel, nullptr);
|
2012-12-06 15:10:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv) && mIsLoading) {
|
|
|
|
// Since we've already notified of our transition, we can just Unload and
|
|
|
|
// call LoadFallback (which will notify again)
|
|
|
|
mType = eType_Null;
|
|
|
|
UnloadObject(false);
|
|
|
|
NS_ENSURE_TRUE(mIsLoading, NS_OK);
|
|
|
|
CloseChannel();
|
|
|
|
LoadFallback(fallbackType, true);
|
2012-10-04 13:50:49 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-10-04 13:50:49 -07:00
|
|
|
// This call can re-enter when dealing with plugin listeners
|
2012-07-05 14:07:46 -07:00
|
|
|
nsresult
|
|
|
|
nsObjectLoadingContent::CloseChannel()
|
|
|
|
{
|
|
|
|
if (mChannel) {
|
|
|
|
LOG(("OBJLC [%p]: Closing channel\n", this));
|
2012-10-04 13:50:49 -07:00
|
|
|
// Null the values before potentially-reentering, and ensure they survive
|
|
|
|
// the call
|
|
|
|
nsCOMPtr<nsIChannel> channelGrip(mChannel);
|
|
|
|
nsCOMPtr<nsIStreamListener> listenerGrip(mFinalListener);
|
2012-07-05 14:07:46 -07:00
|
|
|
mChannel = nullptr;
|
2012-10-04 13:50:49 -07:00
|
|
|
mFinalListener = nullptr;
|
|
|
|
channelGrip->Cancel(NS_BINDING_ABORTED);
|
|
|
|
if (listenerGrip) {
|
2013-01-17 14:50:25 -08:00
|
|
|
// mFinalListener is only set by LoadObject after OnStartRequest, or
|
|
|
|
// by OnStartRequest in the case of late-opened plugin streams
|
2012-10-04 13:50:49 -07:00
|
|
|
listenerGrip->OnStopRequest(channelGrip, nullptr, NS_BINDING_ABORTED);
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-16 18:44:14 -07:00
|
|
|
nsObjectLoadingContent::OpenChannel()
|
2012-07-05 14:07:46 -07:00
|
|
|
{
|
2012-12-06 15:10:54 -08:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
2012-07-05 14:07:46 -07:00
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2012-12-06 15:10:54 -08:00
|
|
|
nsCOMPtr<nsIScriptSecurityManager> secMan =
|
|
|
|
nsContentUtils::GetSecurityManager();
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_ASSERTION(thisContent, "must be a content");
|
|
|
|
nsIDocument* doc = thisContent->OwnerDoc();
|
|
|
|
NS_ASSERTION(doc, "No owner document?");
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
mChannel = nullptr;
|
|
|
|
|
|
|
|
// E.g. mms://
|
|
|
|
if (!mURI || !CanHandleURI(mURI)) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-12-06 15:10:54 -08:00
|
|
|
rv = secMan->CheckLoadURIWithPrincipal(thisContent->NodePrincipal(), mURI, 0);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsILoadGroup> group = doc->GetDocumentLoadGroup();
|
|
|
|
nsCOMPtr<nsIChannel> chan;
|
2010-04-23 12:51:25 -07:00
|
|
|
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
|
|
|
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
|
|
|
rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (csp) {
|
|
|
|
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
|
|
|
channelPolicy->SetContentSecurityPolicy(csp);
|
2012-08-16 18:44:14 -07:00
|
|
|
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT);
|
2010-04-23 12:51:25 -07:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
rv = NS_NewChannel(getter_AddRefs(chan), mURI, nullptr, group, this,
|
2010-05-21 14:03:02 -07:00
|
|
|
nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
|
|
|
|
nsIChannel::LOAD_CLASSIFY_URI,
|
2010-04-23 12:51:25 -07:00
|
|
|
channelPolicy);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Referrer
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
|
|
|
|
if (httpChan) {
|
|
|
|
httpChan->SetReferrer(doc->GetDocumentURI());
|
|
|
|
}
|
|
|
|
|
2007-12-03 13:57:17 -08:00
|
|
|
// Set up the channel's principal and such, like nsDocShell::DoURILoad does
|
2011-09-20 14:00:42 -07:00
|
|
|
nsContentUtils::SetUpChannelOwner(thisContent->NodePrincipal(),
|
2012-07-05 14:07:46 -07:00
|
|
|
chan, mURI, true);
|
2007-12-03 13:57:17 -08:00
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
|
|
|
|
if (scriptChannel) {
|
|
|
|
// Allow execution against our context if the principals match
|
2012-07-05 14:07:46 -07:00
|
|
|
scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
|
2007-12-03 13:57:17 -08:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// AsyncOpen can fail if a file does not exist.
|
2012-07-30 07:20:58 -07:00
|
|
|
rv = chan->AsyncOpen(this, nullptr);
|
2012-07-05 14:07:46 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
LOG(("OBJLC [%p]: Channel opened", this));
|
|
|
|
mChannel = chan;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t
|
2007-03-22 10:30:00 -07:00
|
|
|
nsObjectLoadingContent::GetCapabilities() const
|
|
|
|
{
|
|
|
|
return eSupportImages |
|
|
|
|
eSupportPlugins |
|
2011-05-30 00:34:50 -07:00
|
|
|
eSupportDocuments |
|
|
|
|
eSupportSVG;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2012-07-25 13:39:01 -07:00
|
|
|
void
|
2012-07-05 14:07:46 -07:00
|
|
|
nsObjectLoadingContent::DestroyContent()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (mFrameLoader) {
|
|
|
|
mFrameLoader->Destroy();
|
2012-07-30 07:20:58 -07:00
|
|
|
mFrameLoader = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-01-31 13:55:54 -08:00
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
StopPluginInstance();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2011-08-28 07:07:24 -07:00
|
|
|
/* static */
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
2011-08-28 07:07:24 -07:00
|
|
|
nsObjectLoadingContent::Traverse(nsObjectLoadingContent *tmp,
|
|
|
|
nsCycleCollectionTraversalCallback &cb)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2011-08-28 07:07:24 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameLoader");
|
|
|
|
cb.NoteXPCOMChild(static_cast<nsIFrameLoader*>(tmp->mFrameLoader));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-07-05 13:47:39 -07:00
|
|
|
nsObjectLoadingContent::UnloadObject(bool aResetState)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-05 13:47:39 -07:00
|
|
|
// Don't notify in CancelImageRequests until we transition to a new loaded
|
|
|
|
// state
|
2011-10-17 07:59:28 -07:00
|
|
|
CancelImageRequests(false);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mFrameLoader) {
|
|
|
|
mFrameLoader->Destroy();
|
2012-07-30 07:20:58 -07:00
|
|
|
mFrameLoader = nullptr;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
|
|
|
if (aResetState) {
|
2012-10-04 13:50:49 -07:00
|
|
|
if (mType != eType_Plugin) {
|
|
|
|
// This can re-enter when dealing with plugins, and StopPluginInstance
|
|
|
|
// will handle it
|
|
|
|
CloseChannel();
|
|
|
|
}
|
2012-08-14 11:12:30 -07:00
|
|
|
mChannelLoaded = false;
|
2012-07-05 13:47:39 -07:00
|
|
|
mType = eType_Loading;
|
2012-08-14 11:12:30 -07:00
|
|
|
mURI = mOriginalURI = mBaseURI = nullptr;
|
|
|
|
mContentType.Truncate();
|
|
|
|
mOriginalContentType.Truncate();
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
|
|
|
|
2012-12-07 14:50:10 -08:00
|
|
|
mScriptRequested = false;
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
// This call should be last as it may re-enter
|
|
|
|
StopPluginInstance();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
|
2011-05-31 18:46:57 -07:00
|
|
|
nsEventStates aOldState,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool aSync,
|
|
|
|
bool aNotify)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-07-05 13:47:39 -07:00
|
|
|
LOG(("OBJLC [%p]: Notifying about state change: (%u, %llx) -> (%u, %llx)"
|
|
|
|
" (sync %i, notify %i)", this, aOldType, aOldState.GetInternalValue(),
|
|
|
|
mType, ObjectState().GetInternalValue(), aSync, aNotify));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
2007-07-08 00:08:04 -07:00
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(thisContent, "must be a content");
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
NS_ASSERTION(thisContent->IsElement(), "Not an element?");
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// XXX(johns): A good bit of the code below replicates UpdateState(true)
|
|
|
|
|
2011-05-31 18:46:57 -07:00
|
|
|
// Unfortunately, we do some state changes without notifying
|
|
|
|
// (e.g. in Fallback when canceling image requests), so we have to
|
|
|
|
// manually notify object state changes.
|
|
|
|
thisContent->AsElement()->UpdateState(false);
|
|
|
|
|
|
|
|
if (!aNotify) {
|
|
|
|
// We're done here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIDocument* doc = thisContent->GetCurrentDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return; // Nothing to do
|
|
|
|
}
|
|
|
|
|
2010-10-20 04:26:32 -07:00
|
|
|
nsEventStates newState = ObjectState();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (newState != aOldState) {
|
|
|
|
// This will trigger frame construction
|
2012-07-05 17:56:25 -07:00
|
|
|
NS_ASSERTION(InActiveDocument(thisContent), "Something is confused");
|
2010-10-20 04:26:32 -07:00
|
|
|
nsEventStates changedBits = aOldState ^ newState;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
{
|
2011-05-31 14:38:25 -07:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2011-03-28 20:32:11 -07:00
|
|
|
doc->ContentStateChanged(thisContent, changedBits);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
if (aSync) {
|
2011-05-31 18:46:57 -07:00
|
|
|
// Make sure that frames are actually constructed immediately.
|
2007-03-22 10:30:00 -07:00
|
|
|
doc->FlushPendingNotifications(Flush_Frames);
|
|
|
|
}
|
|
|
|
} else if (aOldType != mType) {
|
|
|
|
// If our state changed, then we already recreated frames
|
|
|
|
// Otherwise, need to do that here
|
2010-06-25 06:59:57 -07:00
|
|
|
nsCOMPtr<nsIPresShell> shell = doc->GetShell();
|
2010-01-07 02:36:11 -08:00
|
|
|
if (shell) {
|
2007-03-22 10:30:00 -07:00
|
|
|
shell->RecreateFramesFor(thisContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsObjectLoadingContent::ObjectType
|
|
|
|
nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
if (aMIMEType.IsEmpty()) {
|
|
|
|
return eType_Null;
|
|
|
|
}
|
|
|
|
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t caps = GetCapabilities();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if ((caps & eSupportImages) && IsSupportedImage(aMIMEType)) {
|
|
|
|
return eType_Image;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
// SVGs load as documents, but are their own capability
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isSVG = aMIMEType.LowerCaseEqualsLiteral("image/svg+xml");
|
2012-10-19 13:49:28 -07:00
|
|
|
Capabilities supportType = isSVG ? eSupportSVG : eSupportDocuments;
|
2012-07-05 14:07:46 -07:00
|
|
|
if ((caps & supportType) && IsSupportedDocument(aMIMEType)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return eType_Document;
|
|
|
|
}
|
|
|
|
|
2012-02-10 05:39:40 -08:00
|
|
|
if ((caps & eSupportPlugins) && NS_SUCCEEDED(IsPluginEnabledForType(aMIMEType))) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return eType_Plugin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eType_Null;
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsObjectFrame*
|
|
|
|
nsObjectLoadingContent::GetExistingFrame()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2012-01-31 13:55:54 -08:00
|
|
|
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
nsIFrame* frame = thisContent->GetPrimaryFrame();
|
2009-01-12 11:20:59 -08:00
|
|
|
nsIObjectFrame* objFrame = do_QueryFrame(frame);
|
2012-01-31 13:55:54 -08:00
|
|
|
return static_cast<nsObjectFrame*>(objFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-12-10 20:02:13 -08:00
|
|
|
void
|
|
|
|
nsObjectLoadingContent::CreateStaticClone(nsObjectLoadingContent* aDest) const
|
|
|
|
{
|
|
|
|
nsImageLoadingContent::CreateStaticImageClone(aDest);
|
|
|
|
|
|
|
|
aDest->mType = mType;
|
|
|
|
nsObjectLoadingContent* thisObj = const_cast<nsObjectLoadingContent*>(this);
|
|
|
|
if (thisObj->mPrintFrame.IsAlive()) {
|
|
|
|
aDest->mPrintFrame = thisObj->mPrintFrame;
|
|
|
|
} else {
|
2012-01-31 13:55:54 -08:00
|
|
|
aDest->mPrintFrame = const_cast<nsObjectLoadingContent*>(this)->GetExistingFrame();
|
2009-12-10 20:02:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mFrameLoader) {
|
|
|
|
nsCOMPtr<nsIContent> content =
|
2011-10-01 10:14:35 -07:00
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(aDest));
|
2011-10-17 07:59:28 -07:00
|
|
|
nsFrameLoader* fl = nsFrameLoader::Create(content->AsElement(), false);
|
2009-12-10 20:02:13 -08:00
|
|
|
if (fl) {
|
|
|
|
aDest->mFrameLoader = fl;
|
|
|
|
mFrameLoader->CreateStaticClone(fl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::GetPrintFrame(nsIFrame** aFrame)
|
|
|
|
{
|
|
|
|
*aFrame = mPrintFrame.GetFrame();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-01-13 08:42:41 -08:00
|
|
|
NS_IMETHODIMP
|
2010-03-16 22:10:08 -07:00
|
|
|
nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
|
2010-03-24 14:22:04 -07:00
|
|
|
const nsAString& pluginDumpID,
|
|
|
|
const nsAString& browserDumpID,
|
2011-09-28 23:19:26 -07:00
|
|
|
bool submittedCrashReport)
|
2010-01-13 08:42:41 -08:00
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
LOG(("OBJLC [%p]: Plugin Crashed, queuing crash event", this));
|
|
|
|
NS_ASSERTION(mType == eType_Plugin, "PluginCrashed at non-plugin type");
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
// Instance is dead, clean up
|
|
|
|
mInstanceOwner = nullptr;
|
|
|
|
CloseChannel();
|
|
|
|
|
|
|
|
// Switch to fallback/crashed state, notify
|
|
|
|
LoadFallback(eFallbackCrashed, true);
|
|
|
|
|
|
|
|
// send nsPluginCrashedEvent
|
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2010-03-16 22:10:08 -07:00
|
|
|
|
|
|
|
// Note that aPluginTag in invalidated after we're called, so copy
|
|
|
|
// out any data we need now.
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString pluginName;
|
2010-03-16 22:10:08 -07:00
|
|
|
aPluginTag->GetName(pluginName);
|
2012-09-01 19:35:17 -07:00
|
|
|
nsAutoCString pluginFilename;
|
2010-04-08 00:45:00 -07:00
|
|
|
aPluginTag->GetFilename(pluginFilename);
|
2010-03-16 22:10:08 -07:00
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
nsCOMPtr<nsIRunnable> ev =
|
|
|
|
new nsPluginCrashedEvent(thisContent,
|
|
|
|
pluginDumpID,
|
|
|
|
browserDumpID,
|
|
|
|
NS_ConvertUTF8toUTF16(pluginName),
|
|
|
|
NS_ConvertUTF8toUTF16(pluginFilename),
|
|
|
|
submittedCrashReport);
|
2010-02-09 17:05:31 -08:00
|
|
|
nsresult rv = NS_DispatchToCurrentThread(ev);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("failed to dispatch nsPluginCrashedEvent");
|
|
|
|
}
|
2010-01-13 08:42:41 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-12-10 09:23:05 -08:00
|
|
|
|
2012-12-07 14:50:10 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::ScriptRequestPluginInstance(bool aCallerIsContentJS,
|
|
|
|
nsNPAPIPluginInstance **aResult)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
|
|
|
|
*aResult = nullptr;
|
|
|
|
|
|
|
|
// The first time content script attempts to access placeholder content, fire
|
|
|
|
// an event. Fallback types >= eFallbackClickToPlay are plugin-replacement
|
|
|
|
// types, see header.
|
|
|
|
if (aCallerIsContentJS && !mScriptRequested &&
|
|
|
|
InActiveDocument(thisContent) && mType == eType_Null &&
|
|
|
|
mFallbackType >= eFallbackClickToPlay) {
|
|
|
|
nsCOMPtr<nsIRunnable> ev =
|
|
|
|
new nsSimplePluginEvent(thisContent,
|
|
|
|
NS_LITERAL_STRING("PluginScripted"));
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(ev);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_NOTREACHED("failed to dispatch PluginScripted event");
|
|
|
|
}
|
|
|
|
mScriptRequested = true;
|
|
|
|
} else if (mType == eType_Plugin && !mInstanceOwner &&
|
|
|
|
nsContentUtils::IsSafeToRunScript() &&
|
|
|
|
InActiveDocument(thisContent)) {
|
|
|
|
// If we're configured as a plugin in an active document and it's safe to
|
|
|
|
// run scripts right now, try spawning synchronously
|
|
|
|
SyncStartPluginInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mInstanceOwner) {
|
|
|
|
return mInstanceOwner->GetInstance(aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note that returning a null plugin is expected (and happens often)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::SyncStartPluginInstance()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
|
|
|
|
"Must be able to run script in order to instantiate a plugin instance!");
|
|
|
|
|
2012-02-13 13:26:41 -08:00
|
|
|
// Don't even attempt to start an instance unless the content is in
|
2012-07-05 17:56:25 -07:00
|
|
|
// the document and active
|
2012-02-13 13:26:41 -08:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2012-07-05 17:56:25 -07:00
|
|
|
if (!InActiveDocument(thisContent)) {
|
2012-01-31 13:55:54 -08:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-02-08 15:15:16 -08:00
|
|
|
nsCOMPtr<nsIURI> kungFuURIGrip(mURI);
|
2012-02-13 13:26:41 -08:00
|
|
|
nsCString contentType(mContentType);
|
2012-07-05 14:07:46 -07:00
|
|
|
return InstantiatePluginInstance();
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::AsyncStartPluginInstance()
|
|
|
|
{
|
|
|
|
// OK to have an instance already.
|
|
|
|
if (mInstanceOwner) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
nsIDocument* doc = thisContent->OwnerDoc();
|
|
|
|
if (doc->IsStaticDocument() || doc->IsBeingUsedAsImage()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We always start plugins on a runnable.
|
|
|
|
// We don't want a script blocker on the stack during instantiation.
|
|
|
|
nsCOMPtr<nsIRunnable> event = new nsAsyncInstantiateEvent(this);
|
|
|
|
if (!event) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(event);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Remember this event. This is a weak reference that will be cleared
|
|
|
|
// when the event runs.
|
|
|
|
mPendingInstantiateEvent = event;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-03-12 09:48:27 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::GetSrcURI(nsIURI** aURI)
|
|
|
|
{
|
|
|
|
NS_IF_ADDREF(*aURI = mURI);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
static bool
|
2012-05-25 15:34:11 -07:00
|
|
|
DoDelayedStop(nsPluginInstanceOwner* aInstanceOwner,
|
|
|
|
nsObjectLoadingContent* aContent,
|
|
|
|
bool aDelayedStop)
|
2012-01-31 13:55:54 -08:00
|
|
|
{
|
|
|
|
#if (MOZ_PLATFORM_MAEMO==5)
|
|
|
|
// Don't delay stop on Maemo/Hildon (bug 530739).
|
|
|
|
if (aDelayedStop && aInstanceOwner->MatchPluginName("Shockwave Flash"))
|
|
|
|
return false;
|
|
|
|
#endif
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
// Don't delay stopping QuickTime (bug 425157), Flip4Mac (bug 426524),
|
|
|
|
// XStandard (bug 430219), CMISS Zinc (bug 429604).
|
|
|
|
if (aDelayedStop
|
|
|
|
#if !(defined XP_WIN || defined MOZ_X11)
|
|
|
|
&& !aInstanceOwner->MatchPluginName("QuickTime")
|
|
|
|
&& !aInstanceOwner->MatchPluginName("Flip4Mac")
|
|
|
|
&& !aInstanceOwner->MatchPluginName("XStandard plugin")
|
|
|
|
&& !aInstanceOwner->MatchPluginName("CMISS Zinc Plugin")
|
|
|
|
#endif
|
|
|
|
) {
|
2012-05-25 15:34:11 -07:00
|
|
|
nsCOMPtr<nsIRunnable> evt =
|
|
|
|
new nsStopPluginRunnable(aInstanceOwner, aContent);
|
2012-01-31 13:55:54 -08:00
|
|
|
NS_DispatchToCurrentThread(evt);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
void
|
|
|
|
nsObjectLoadingContent::LoadFallback(FallbackType aType, bool aNotify) {
|
|
|
|
nsEventStates oldState = ObjectState();
|
|
|
|
ObjectType oldType = mType;
|
|
|
|
|
|
|
|
NS_ASSERTION(!mInstanceOwner && !mFrameLoader && !mChannel,
|
|
|
|
"LoadFallback called with loaded content");
|
|
|
|
|
|
|
|
//
|
|
|
|
// Fixup mFallbackType
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
|
|
|
NS_ASSERTION(thisContent, "must be a content");
|
|
|
|
|
2012-08-20 16:28:19 -07:00
|
|
|
if (!thisContent->IsHTML() || mContentType.IsEmpty()) {
|
|
|
|
// Don't let custom fallback handlers run outside HTML, tags without a
|
|
|
|
// determined type should always just be alternate content
|
2012-07-05 13:47:39 -07:00
|
|
|
aType = eFallbackAlternate;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thisContent->Tag() == nsGkAtoms::object &&
|
|
|
|
(aType == eFallbackUnsupported ||
|
|
|
|
aType == eFallbackDisabled ||
|
|
|
|
aType == eFallbackBlocklisted))
|
|
|
|
{
|
2012-08-20 16:16:02 -07:00
|
|
|
// Show alternate content instead, if it exists
|
2012-07-05 13:47:39 -07:00
|
|
|
for (nsIContent* child = thisContent->GetFirstChild();
|
2012-08-20 16:16:02 -07:00
|
|
|
child; child = child->GetNextSibling()) {
|
|
|
|
if (!child->IsHTML(nsGkAtoms::param) &&
|
|
|
|
nsStyleUtil::IsSignificantChild(child, true, false)) {
|
|
|
|
aType = eFallbackAlternate;
|
|
|
|
break;
|
2012-07-05 13:47:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mType = eType_Null;
|
|
|
|
mFallbackType = aType;
|
|
|
|
|
2012-11-07 13:59:15 -08:00
|
|
|
// Notify
|
2012-07-05 13:47:39 -07:00
|
|
|
if (!aNotify) {
|
|
|
|
return; // done
|
|
|
|
}
|
|
|
|
|
|
|
|
NotifyStateChanged(oldType, oldState, false, true);
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
void
|
2012-05-25 15:34:11 -07:00
|
|
|
nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner,
|
|
|
|
bool aDelayedStop,
|
|
|
|
bool aForcedReentry)
|
|
|
|
{
|
|
|
|
// DoStopPlugin can process events and there may be pending InDocCheckEvent
|
|
|
|
// events which can drop in underneath us and destroy the instance we are
|
2012-07-05 13:47:39 -07:00
|
|
|
// about to destroy unless we prevent that with the mPluginStopping flag.
|
2012-05-25 15:34:11 -07:00
|
|
|
// (aForcedReentry is only true from the callback of an earlier delayed stop)
|
|
|
|
if (mIsStopping && !aForcedReentry) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mIsStopping = true;
|
|
|
|
|
2012-05-31 05:44:10 -07:00
|
|
|
nsRefPtr<nsPluginInstanceOwner> kungFuDeathGrip(aInstanceOwner);
|
2012-01-31 13:55:54 -08:00
|
|
|
nsRefPtr<nsNPAPIPluginInstance> inst;
|
|
|
|
aInstanceOwner->GetInstance(getter_AddRefs(inst));
|
|
|
|
if (inst) {
|
2012-05-25 15:34:11 -07:00
|
|
|
if (DoDelayedStop(aInstanceOwner, this, aDelayedStop)) {
|
2012-01-31 13:55:54 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XP_MACOSX)
|
|
|
|
aInstanceOwner->HidePluginWindow();
|
|
|
|
#endif
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
nsRefPtr<nsPluginHost> pluginHost =
|
|
|
|
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
|
|
|
|
NS_ASSERTION(pluginHost, "No plugin host?");
|
|
|
|
pluginHost->StopPluginInstance(inst);
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
aInstanceOwner->Destroy();
|
2012-08-17 14:58:43 -07:00
|
|
|
mIsStopping = false;
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::StopPluginInstance()
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
// Prevents any pending plugin starts from running
|
|
|
|
mPendingInstantiateEvent = nullptr;
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
if (!mInstanceOwner) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:07:46 -07:00
|
|
|
if (mChannel) {
|
|
|
|
// The plugin has already used data from this channel, we'll need to
|
|
|
|
// re-open it to handle instantiating again, even if we don't invalidate
|
|
|
|
// our loaded state.
|
|
|
|
/// XXX(johns): Except currently, we don't, just leaving re-opening channels
|
|
|
|
/// to plugins...
|
|
|
|
LOG(("OBJLC [%p]: StopPluginInstance - Closing used channel", this));
|
|
|
|
CloseChannel();
|
|
|
|
}
|
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
DisconnectFrame();
|
|
|
|
|
|
|
|
bool delayedStop = false;
|
|
|
|
#ifdef XP_WIN
|
|
|
|
// Force delayed stop for Real plugin only; see bug 420886, 426852.
|
|
|
|
nsRefPtr<nsNPAPIPluginInstance> inst;
|
|
|
|
mInstanceOwner->GetInstance(getter_AddRefs(inst));
|
|
|
|
if (inst) {
|
2012-07-30 07:20:58 -07:00
|
|
|
const char* mime = nullptr;
|
2012-01-31 13:55:54 -08:00
|
|
|
if (NS_SUCCEEDED(inst->GetMIMEType(&mime)) && mime) {
|
|
|
|
if (strcmp(mime, "audio/x-pn-realaudio-plugin") == 0) {
|
|
|
|
delayedStop = true;
|
2012-07-05 14:07:46 -07:00
|
|
|
}
|
2012-01-31 13:55:54 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-05-25 15:34:11 -07:00
|
|
|
DoStopPlugin(mInstanceOwner, delayedStop);
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mInstanceOwner = nullptr;
|
2012-05-25 15:34:11 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsObjectLoadingContent::NotifyContentObjectWrapper()
|
|
|
|
{
|
2012-07-05 14:07:46 -07:00
|
|
|
nsCOMPtr<nsIContent> thisContent =
|
|
|
|
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
2012-01-31 13:55:54 -08:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc = thisContent->GetDocument();
|
|
|
|
if (!doc)
|
|
|
|
return;
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsIScriptGlobalObject *sgo = doc->GetScopeObject();
|
|
|
|
if (!sgo)
|
|
|
|
return;
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsIScriptContext *scx = sgo->GetContext();
|
|
|
|
if (!scx)
|
|
|
|
return;
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
JSContext *cx = scx->GetNativeContext();
|
2013-02-26 11:04:10 -08:00
|
|
|
nsCxPusher pusher;
|
2013-02-26 11:04:11 -08:00
|
|
|
pusher.Push(cx);
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
|
|
|
nsContentUtils::XPConnect()->
|
|
|
|
GetWrappedNativeOfNativeObject(cx, sgo->GetGlobalJSObject(), thisContent,
|
|
|
|
NS_GET_IID(nsISupports),
|
|
|
|
getter_AddRefs(wrapper));
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
if (!wrapper) {
|
|
|
|
// Nothing to do here if there's no wrapper for mContent. The proto
|
|
|
|
// chain will be fixed appropriately when the wrapper is created.
|
|
|
|
return;
|
|
|
|
}
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
JSObject *obj = nullptr;
|
2012-01-31 13:55:54 -08:00
|
|
|
nsresult rv = wrapper->GetJSObject(&obj);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
2012-07-05 14:07:46 -07:00
|
|
|
|
2012-01-31 13:55:54 -08:00
|
|
|
nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
|
|
|
|
}
|
|
|
|
|
2011-12-10 09:23:05 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::PlayPlugin()
|
|
|
|
{
|
|
|
|
if (!nsContentUtils::IsCallerChrome())
|
|
|
|
return NS_OK;
|
|
|
|
|
2012-10-04 12:57:24 -07:00
|
|
|
if (!mActivated) {
|
|
|
|
mActivated = true;
|
|
|
|
LOG(("OBJLC [%p]: Activated by user", this));
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're in a click-to-play or play preview state, we need to reload
|
|
|
|
// Fallback types >= eFallbackClickToPlay are plugin-replacement types, see
|
|
|
|
// header
|
|
|
|
if (mType == eType_Null && mFallbackType >= eFallbackClickToPlay) {
|
|
|
|
return LoadObject(true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2011-12-10 09:23:05 -08:00
|
|
|
}
|
2012-03-28 08:53:56 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-07-05 13:47:39 -07:00
|
|
|
nsObjectLoadingContent::GetActivated(bool *aActivated)
|
2012-03-28 08:53:56 -07:00
|
|
|
{
|
2012-10-04 12:57:24 -07:00
|
|
|
*aActivated = mActivated;
|
2012-03-28 08:53:56 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
2012-08-20 15:00:51 -07:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 08:56:38 -07:00
|
|
|
nsObjectLoadingContent::GetPluginFallbackType(uint32_t* aPluginFallbackType)
|
2012-08-20 15:00:51 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
|
|
|
|
*aPluginFallbackType = mFallbackType;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-25 14:18:44 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsObjectLoadingContent::CancelPlayPreview()
|
|
|
|
{
|
|
|
|
if (!nsContentUtils::IsCallerChrome())
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
|
|
|
|
mPlayPreviewCanceled = true;
|
2012-10-04 12:57:24 -07:00
|
|
|
|
|
|
|
// If we're in play preview state already, reload
|
|
|
|
if (mType == eType_Null && mFallbackType == eFallbackPlayPreview) {
|
|
|
|
return LoadObject(true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2012-08-25 14:18:44 -07:00
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
bool
|
|
|
|
nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
|
|
|
|
{
|
|
|
|
// mActivated is true if we've been activated via PlayPlugin() (e.g. user has
|
|
|
|
// clicked through). Otherwise, only play if click-to-play is off or if page
|
|
|
|
// is whitelisted
|
|
|
|
|
|
|
|
nsRefPtr<nsPluginHost> pluginHost =
|
|
|
|
already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
|
|
|
|
|
2013-02-14 13:38:41 -08:00
|
|
|
nsCOMPtr<nsIPluginPlayPreviewInfo> playPreviewInfo;
|
|
|
|
bool isPlayPreviewSpecified = NS_SUCCEEDED(pluginHost->GetPlayPreviewInfo(
|
|
|
|
mContentType, getter_AddRefs(playPreviewInfo)));
|
|
|
|
bool ignoreCTP = false;
|
|
|
|
if (isPlayPreviewSpecified) {
|
|
|
|
playPreviewInfo->GetIgnoreCTP(&ignoreCTP);
|
|
|
|
}
|
|
|
|
if (isPlayPreviewSpecified && !mPlayPreviewCanceled && !mActivated &&
|
|
|
|
ignoreCTP) {
|
|
|
|
// play preview in ignoreCTP mode is shown even if the native plugin
|
|
|
|
// is not present/installed
|
|
|
|
aReason = eFallbackPlayPreview;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// at this point if it's not a plugin, we let it play/fallback
|
|
|
|
if (mType != eType_Plugin) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-19 14:03:24 -08:00
|
|
|
bool isCTP;
|
|
|
|
nsresult rv = pluginHost->IsPluginClickToPlayForType(mContentType, &isCTP);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
|
|
|
if (!isCTP || mActivated) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-01 09:46:05 -07:00
|
|
|
// set the fallback reason
|
2012-07-05 13:47:39 -07:00
|
|
|
aReason = eFallbackClickToPlay;
|
2012-10-01 09:46:05 -07:00
|
|
|
// (if it's click-to-play, it might be because of the blocklist)
|
|
|
|
uint32_t state;
|
2012-11-19 14:03:24 -08:00
|
|
|
rv = pluginHost->GetBlocklistStateForType(mContentType.get(), &state);
|
2012-10-01 09:46:05 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
if (state == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
|
|
|
|
aReason = eFallbackVulnerableUpdatable;
|
|
|
|
}
|
|
|
|
else if (state == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
|
|
|
|
aReason = eFallbackVulnerableNoUpdate;
|
|
|
|
}
|
2012-07-05 13:47:39 -07:00
|
|
|
|
|
|
|
// If plugin type is click-to-play and we have not been explicitly clicked.
|
|
|
|
// check if permissions lets this page bypass - (e.g. user selected 'Always
|
|
|
|
// play plugins on this page')
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
|
|
|
|
MOZ_ASSERT(thisContent);
|
|
|
|
nsIDocument* ownerDoc = thisContent->OwnerDoc();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMWindow> window = ownerDoc->GetWindow();
|
|
|
|
if (!window) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMWindow> topWindow;
|
|
|
|
rv = window->GetTop(getter_AddRefs(topWindow));
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
nsCOMPtr<nsIDOMDocument> topDocument;
|
|
|
|
rv = topWindow->GetDocument(getter_AddRefs(topDocument));
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
nsCOMPtr<nsIDocument> topDoc = do_QueryInterface(topDocument);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
|
|
|
|
bool allowPerm = false;
|
|
|
|
// For now we always say that the system principal uses click-to-play since
|
|
|
|
// that maintains current behavior and we have tests that expect this.
|
|
|
|
// What we really should do is disable plugins entirely in pages that use
|
|
|
|
// the system principal, i.e. in chrome pages. That way the click-to-play
|
|
|
|
// code here wouldn't matter at all. Bug 775301 is tracking this.
|
|
|
|
if (!nsContentUtils::IsSystemPrincipal(topDoc->NodePrincipal())) {
|
2012-11-27 10:09:10 -08:00
|
|
|
nsAutoCString permissionString;
|
|
|
|
rv = pluginHost->GetPermissionStringForType(mContentType, permissionString);
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
2012-08-22 08:56:38 -07:00
|
|
|
uint32_t permission;
|
2012-07-05 13:47:39 -07:00
|
|
|
rv = permissionManager->TestPermissionFromPrincipal(topDoc->NodePrincipal(),
|
2012-11-27 10:09:10 -08:00
|
|
|
permissionString.Data(),
|
2012-07-05 13:47:39 -07:00
|
|
|
&permission);
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
allowPerm = permission == nsIPermissionManager::ALLOW_ACTION;
|
|
|
|
}
|
|
|
|
|
2013-02-14 13:38:41 -08:00
|
|
|
if (aReason == eFallbackClickToPlay && isPlayPreviewSpecified &&
|
|
|
|
!mPlayPreviewCanceled && !ignoreCTP) {
|
|
|
|
// play preview in click-to-play mode is shown instead of standard CTP UI
|
|
|
|
aReason = eFallbackPlayPreview;
|
|
|
|
}
|
|
|
|
|
2012-07-05 13:47:39 -07:00
|
|
|
return allowPerm;
|
|
|
|
}
|
|
|
|
|