Bug 475991: Extend NPAPI to allow plugins to participate in redirect handling. r=bsmedberg a=blocking2.0betaN+

This commit is contained in:
Josh Aas 2011-01-05 14:44:21 -05:00
Родитель 322f3d6f04
Коммит d9696766fe
20 изменённых файлов: 373 добавлений и 116 удалений

Просмотреть файл

@ -69,6 +69,10 @@ both:
int32_t aInt);
child:
// Forces the child process to update its plugin function table.
rpc NP_GetEntryPoints()
returns (NPError rv);
// Return the plugin's thread ID, if it can be found.
rpc NP_Initialize()
returns (NativeThreadId tid, NPError rv);
@ -82,6 +86,9 @@ child:
rpc NP_Shutdown()
returns (NPError rv);
rpc URLRedirectNotifySupported()
returns (bool aBoolVal);
parent:
/**
* This message is only used on X11 platforms.

Просмотреть файл

@ -9,14 +9,23 @@ using NPReason;
namespace mozilla {
namespace plugins {
/**
* This empty protocol exists only to be constructed and destroyed.
*/
rpc protocol PStreamNotify
{
manager PPluginInstance;
parent:
/**
* Represents NPN_URLRedirectResponse
*/
async RedirectNotifyResponse(bool allow);
child:
/**
* Represents NPP_URLRedirectNotify
*/
async RedirectNotify(nsCString url, int32_t status);
/**
* Represents NPP_URLNotify
*/

Просмотреть файл

@ -2074,6 +2074,24 @@ StreamNotifyChild::Recv__delete__(const NPReason& reason)
return true;
}
bool
StreamNotifyChild::RecvRedirectNotify(const nsCString& url, const int32_t& status)
{
// NPP_URLRedirectNotify requires a non-null closure. Since core logic
// assumes that all out-of-process notify streams have non-null closure
// data it will assume that the plugin was notified at this point and
// expect a response otherwise the redirect will hang indefinitely.
if (!mClosure) {
SendRedirectNotifyResponse(false);
}
PluginInstanceChild* instance = static_cast<PluginInstanceChild*>(Manager());
if (instance->mPluginIface->urlredirectnotify)
instance->mPluginIface->urlredirectnotify(instance->GetNPP(), mURL.get(), status, mClosure);
return true;
}
void
StreamNotifyChild::NPP_URLNotify(NPReason reason)
{
@ -2145,6 +2163,26 @@ PluginInstanceChild::NPN_NewStream(NPMIMEType aMIMEType, const char* aWindow,
return NPERR_NO_ERROR;
}
void
PluginInstanceChild::NPN_URLRedirectResponse(void* notifyData, NPBool allow)
{
if (!notifyData) {
return;
}
InfallibleTArray<PStreamNotifyChild*> notifyStreams;
ManagedPStreamNotifyChild(notifyStreams);
PRUint32 notifyStreamCount = notifyStreams.Length();
for (PRUint32 i = 0; i < notifyStreamCount; i++) {
StreamNotifyChild* sn = static_cast<StreamNotifyChild*>(notifyStreams[i]);
if (sn->mClosure == notifyData) {
sn->SendRedirectNotifyResponse(static_cast<bool>(allow));
return;
}
}
NS_ASSERTION(PR_FALSE, "Couldn't find stream for redirect response!");
}
bool
PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
const NPRemoteWindow& aWindow)

Просмотреть файл

@ -216,6 +216,8 @@ public:
int GetQuirks();
void NPN_URLRedirectResponse(void* notifyData, NPBool allow);
private:
friend class PluginModuleChild;

Просмотреть файл

@ -80,6 +80,14 @@ UINT gOOPPStopNativeLoopEvent =
using namespace mozilla::plugins;
bool
StreamNotifyParent::RecvRedirectNotifyResponse(const bool& allow)
{
PluginInstanceParent* instance = static_cast<PluginInstanceParent*>(Manager());
instance->mNPNIface->urlredirectresponse(instance->mNPP, this, static_cast<NPBool>(allow));
return true;
}
PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
NPP npp,
const nsCString& aMimeType,
@ -728,6 +736,17 @@ PluginInstanceParent::NPP_SetValue(NPNVariable variable, void* value)
}
}
void
PluginInstanceParent::NPP_URLRedirectNotify(const char* url, int32_t status,
void* notifyData)
{
if (!notifyData)
return;
PStreamNotifyParent* streamNotify = static_cast<PStreamNotifyParent*>(notifyData);
unused << streamNotify->SendRedirectNotify(NullableString(url), status);
}
int16_t
PluginInstanceParent::NPP_HandleEvent(void* event)
{

Просмотреть файл

@ -68,6 +68,7 @@ class PluginInstanceParent : public PPluginInstanceParent
friend class PluginModuleParent;
friend class BrowserStreamParent;
friend class PluginStreamParent;
friend class StreamNotifyParent;
public:
PluginInstanceParent(PluginModuleParent* parent,
@ -217,6 +218,9 @@ public:
NPError NPP_GetValue(NPPVariable variable, void* retval);
NPError NPP_SetValue(NPNVariable variable, void* value);
void NPP_URLRedirectNotify(const char* url, int32_t status,
void* notifyData);
NPError NPP_NewStream(NPMIMEType type, NPStream* stream,
NPBool seekable, uint16_t* stype);
NPError NPP_DestroyStream(NPStream* stream, NPReason reason);

Просмотреть файл

@ -579,6 +579,13 @@ PluginModuleChild::AnswerNP_Shutdown(NPError *rv)
return true;
}
bool
PluginModuleChild::AnswerURLRedirectNotifySupported(bool *aBoolVal)
{
*aBoolVal = !!mFunctions.urlredirectnotify;
return true;
}
void
PluginModuleChild::QuickExit()
{
@ -822,6 +829,9 @@ _convertpoint(NPP instance,
double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
double *destX, double *destY, NPCoordinateSpace destSpace);
static void NP_CALLBACK
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
} /* namespace child */
} /* namespace plugins */
} /* namespace mozilla */
@ -883,7 +893,7 @@ const NPNetscapeFuncs PluginModuleChild::sBrowserFuncs = {
mozilla::plugins::child::_convertpoint,
NULL, // handleevent, unimplemented
NULL, // unfocusinstance, unimplemented
NULL // urlredirectresponse, unimplemented
mozilla::plugins::child::_urlredirectresponse
};
PluginInstanceChild*
@ -1638,12 +1648,34 @@ _convertpoint(NPP instance,
return result;
}
void NP_CALLBACK
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
{
InstCast(instance)->NPN_URLRedirectResponse(notifyData, allow);
}
} /* namespace child */
} /* namespace plugins */
} /* namespace mozilla */
//-----------------------------------------------------------------------------
bool
PluginModuleChild::AnswerNP_GetEntryPoints(NPError* _retval)
{
PLUGIN_LOG_DEBUG_METHOD;
AssertPluginThread();
#if defined(OS_LINUX)
return true;
#elif defined(OS_WIN) || defined(OS_MACOSX)
*_retval = mGetEntryPointsFunc(&mFunctions);
return true;
#else
# error Please implement me for your platform
#endif
}
bool
PluginModuleChild::AnswerNP_Initialize(NativeThreadId* tid, NPError* _retval)
{
@ -1670,24 +1702,8 @@ PluginModuleChild::AnswerNP_Initialize(NativeThreadId* tid, NPError* _retval)
#if defined(OS_LINUX)
*_retval = mInitializeFunc(&sBrowserFuncs, &mFunctions);
return true;
#elif defined(OS_WIN)
nsresult rv = mGetEntryPointsFunc(&mFunctions);
if (NS_FAILED(rv)) {
return false;
}
NS_ASSERTION(HIBYTE(mFunctions.version) >= NP_VERSION_MAJOR,
"callback version is less than NP version");
#elif defined(OS_WIN) || defined(OS_MACOSX)
*_retval = mInitializeFunc(&sBrowserFuncs);
return true;
#elif defined(OS_MACOSX)
*_retval = mInitializeFunc(&sBrowserFuncs);
nsresult rv = mGetEntryPointsFunc(&mFunctions);
if (NS_FAILED(rv)) {
return false;
}
return true;
#else
# error Please implement me for your platform

Просмотреть файл

@ -108,6 +108,7 @@ protected:
}
// Implement the PPluginModuleChild interface
virtual bool AnswerNP_GetEntryPoints(NPError* rv);
virtual bool AnswerNP_Initialize(NativeThreadId* tid, NPError* rv);
virtual PPluginIdentifierChild*
@ -137,6 +138,9 @@ protected:
virtual bool
AnswerNP_Shutdown(NPError *rv);
virtual bool
AnswerURLRedirectNotifySupported(bool *aBoolVal);
virtual void
ActorDestroy(ActorDestroyReason why);

Просмотреть файл

@ -396,6 +396,16 @@ PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
aFuncs->urlnotify = NPP_URLNotify;
aFuncs->getvalue = NPP_GetValue;
aFuncs->setvalue = NPP_SetValue;
aFuncs->gotfocus = NULL;
aFuncs->lostfocus = NULL;
aFuncs->urlredirectnotify = NULL;
// Provide 'NPP_URLRedirectNotify' if it is supported by the plugin.
bool urlRedirectSupported = false;
CallURLRedirectNotifySupported(&urlRedirectSupported);
if (urlRedirectSupported) {
aFuncs->urlredirectnotify = NPP_URLRedirectNotify;
}
}
NPError
@ -558,6 +568,17 @@ PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
return true;
}
void
PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
int32_t status, void* notifyData)
{
PluginInstanceParent* i = InstCast(instance);
if (!i)
return;
i->NPP_URLRedirectNotify(url, status, notifyData);
}
bool
PluginModuleParent::AnswerNPN_UserAgent(nsCString* userAgent)
{
@ -673,6 +694,7 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs
}
SetPluginFuncs(pFuncs);
return NS_OK;
}
#else
@ -743,8 +765,18 @@ PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
{
NS_ASSERTION(pFuncs, "Null pointer!");
// We need to have the child process update its function table
// here by actually calling NP_GetEntryPoints since the parent's
// function table can reflect NULL entries in the child's table.
if (!CallNP_GetEntryPoints(error)) {
return NS_ERROR_FAILURE;
}
else if (*error != NPERR_NO_ERROR) {
return NS_OK;
}
SetPluginFuncs(pFuncs);
*error = NPERR_NO_ERROR;
return NS_OK;
}
#endif

Просмотреть файл

@ -225,6 +225,8 @@ private:
NPPVariable variable, void *ret_value);
static NPError NPP_SetValue(NPP instance, NPNVariable variable,
void *value);
static void NPP_URLRedirectNotify(NPP instance, const char* url,
int32_t status, void* notifyData);
virtual bool HasRequiredFunctions();
virtual nsresult AsyncSetWindow(NPP instance, NPWindow* window);

Просмотреть файл

@ -69,6 +69,8 @@ public:
private:
NS_OVERRIDE virtual bool Recv__delete__(const NPReason& reason);
bool RecvRedirectNotify(const nsCString& url, const int32_t& status);
/**
* If a stream is created for this this URLNotify, we associate the objects
* so that the NPP_URLNotify call is not fired before the stream data is

Просмотреть файл

@ -67,6 +67,8 @@ public:
}
private:
bool RecvRedirectNotifyResponse(const bool& allow);
bool* mDestructionFlag;
};

Просмотреть файл

@ -183,7 +183,7 @@ static NPNetscapeFuncs sBrowserFuncs = {
_convertpoint,
NULL, // handleevent, unimplemented
NULL, // unfocusinstance, unimplemented
NULL // urlredirectresponse, unimplemented
_urlredirectresponse
};
static PRLock *sPluginThreadAsyncCallLock = nsnull;
@ -612,12 +612,15 @@ MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
// Set aCallNotify here to false. If pluginHost->GetURL or PostURL fail,
// the listener's destructor will do the notification while we are about to
// return a failure code.
// Call SetCallNotify(true) bellow after we are sure we cannot return a failure
// Call SetCallNotify(true) below after we are sure we cannot return a failure
// code.
if (!target)
((nsNPAPIPluginInstance*)inst)->NewNotifyStream(getter_AddRefs(listener),
notifyData,
PR_FALSE, relativeURL);
if (!target) {
inst->NewStreamListener(relativeURL, notifyData,
getter_AddRefs(listener));
if (listener) {
static_cast<nsNPAPIPluginStreamListener*>(listener.get())->SetCallNotify(PR_FALSE);
}
}
switch (type) {
case eNPPStreamTypeInternal_Get:
@ -628,8 +631,7 @@ MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
}
case eNPPStreamTypeInternal_Post:
{
if (NS_FAILED(pluginHost->PostURL(inst, relativeURL, len, buf, file, target,
listener)))
if (NS_FAILED(pluginHost->PostURL(inst, relativeURL, len, buf, file, target, listener)))
return NPERR_GENERIC_ERROR;
break;
}
@ -639,11 +641,7 @@ MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
if (listener) {
// SetCallNotify(bDoNotify) here, see comment above.
// XXX Not sure of this cast here, we should probably have an interface API
// for this.
nsNPAPIPluginStreamListener* npAPIPluginStreamListener =
static_cast<nsNPAPIPluginStreamListener*>(listener.get());
npAPIPluginStreamListener->SetCallNotify(bDoNotify);
static_cast<nsNPAPIPluginStreamListener*>(listener.get())->SetCallNotify(bDoNotify);
}
return NPERR_NO_ERROR;
@ -2724,6 +2722,17 @@ _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace so
return inst->ConvertPoint(sourceX, sourceY, sourceSpace, destX, destY, destSpace);
}
void NP_CALLBACK
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
{
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst) {
return;
}
inst->URLRedirectResponse(notifyData, allow);
}
} /* namespace parent */
} /* namespace plugins */
} /* namespace mozilla */

Просмотреть файл

@ -364,6 +364,9 @@ _getJavaEnv();
void* NP_CALLBACK /* OJI type: jref */
_getJavaPeer(NPP npp);
void NP_CALLBACK
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow);
} /* namespace parent */
} /* namespace plugins */
} /* namespace mozilla */

Просмотреть файл

@ -54,8 +54,8 @@
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsDirectoryServiceDefs.h"
#include "nsJSNPRuntime.h"
#include "nsPluginStreamListenerPeer.h"
using namespace mozilla::plugins::parent;
using mozilla::TimeStamp;
@ -195,10 +195,10 @@ NS_IMETHODIMP nsNPAPIPluginInstance::Stop()
OnPluginDestroy(&mNPP);
// clean up open streams
while (mPStreamListeners.Length() > 0) {
nsRefPtr<nsNPAPIPluginStreamListener> currentListener(mPStreamListeners[0]);
while (mStreamListeners.Length() > 0) {
nsRefPtr<nsNPAPIPluginStreamListener> currentListener(mStreamListeners[0]);
currentListener->CleanUpStream(NPRES_USER_BREAK);
mPStreamListeners.RemoveElement(currentListener);
mStreamListeners.RemoveElement(currentListener);
}
if (!mPlugin || !mPlugin->GetLibrary())
@ -292,15 +292,15 @@ nsNPAPIPluginInstance::GetMode(PRInt32 *result)
}
nsTArray<nsNPAPIPluginStreamListener*>*
nsNPAPIPluginInstance::PStreamListeners()
nsNPAPIPluginInstance::StreamListeners()
{
return &mPStreamListeners;
return &mStreamListeners;
}
nsTArray<nsPluginStreamListenerPeer*>*
nsNPAPIPluginInstance::BStreamListeners()
nsNPAPIPluginInstance::FileCachedStreamListeners()
{
return &mBStreamListeners;
return &mFileCachedStreamListeners;
}
nsresult
@ -478,12 +478,11 @@ NS_IMETHODIMP nsNPAPIPluginInstance::SetWindow(NPWindow* window)
return NS_OK;
}
/* NOTE: the caller must free the stream listener */
// Create a normal stream, one without a urlnotify callback
NS_IMETHODIMP
nsNPAPIPluginInstance::NewStreamToPlugin(nsIPluginStreamListener** listener)
{
return NewNotifyStream(listener, nsnull, PR_FALSE, nsnull);
// This method can be removed at the next opportunity.
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
@ -497,17 +496,14 @@ nsNPAPIPluginInstance::NewStreamFromPlugin(const char* type, const char* target,
return stream->QueryInterface(kIOutputStreamIID, (void**)result);
}
// Create a stream that will notify when complete
nsresult nsNPAPIPluginInstance::NewNotifyStream(nsIPluginStreamListener** listener,
void* notifyData,
PRBool aCallNotify,
const char* aURL)
nsresult
nsNPAPIPluginInstance::NewStreamListener(const char* aURL, void* notifyData,
nsIPluginStreamListener** listener)
{
nsNPAPIPluginStreamListener* stream = new nsNPAPIPluginStreamListener(this, notifyData, aURL);
NS_ENSURE_TRUE(stream, NS_ERROR_OUT_OF_MEMORY);
mPStreamListeners.AppendElement(stream);
stream->SetCallNotify(aCallNotify); // set flag in stream to call URLNotify
mStreamListeners.AppendElement(stream);
return stream->QueryInterface(kIPluginStreamListenerIID, (void**)listener);
}
@ -1242,3 +1238,19 @@ nsNPAPIPluginInstance::AsyncSetWindow(NPWindow& window)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
nsNPAPIPluginInstance::URLRedirectResponse(void* notifyData, NPBool allow)
{
if (!notifyData) {
return;
}
PRUint32 listenerCount = mStreamListeners.Length();
for (PRUint32 i = 0; i < listenerCount; i++) {
nsNPAPIPluginStreamListener* currentListener = mStreamListeners[i];
if (currentListener->GetNotifyData() == notifyData) {
currentListener->URLRedirectResponse(allow);
}
}
}

Просмотреть файл

@ -47,6 +47,9 @@
#include "nsITimer.h"
#include "nsIPluginTagInfo.h"
#include "nsIURI.h"
#include "nsIChannel.h"
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/PluginLibrary.h"
@ -93,10 +96,8 @@ public:
void SetEventModel(NPEventModel aModel);
#endif
nsresult NewNotifyStream(nsIPluginStreamListener** listener,
void* notifyData,
PRBool aCallNotify,
const char * aURL);
nsresult NewStreamListener(const char* aURL, void* notifyData,
nsIPluginStreamListener** listener);
nsNPAPIPluginInstance(nsNPAPIPlugin* plugin);
virtual ~nsNPAPIPluginInstance();
@ -136,13 +137,15 @@ public:
NPError PopUpContextMenu(NPMenu* menu);
NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace);
// Returns the array of plugin-initiated streams.
nsTArray<nsNPAPIPluginStreamListener*> *PStreamListeners();
// Returns the array of browser-initiated streams.
nsTArray<nsPluginStreamListenerPeer*> *BStreamListeners();
nsTArray<nsNPAPIPluginStreamListener*> *StreamListeners();
nsTArray<nsPluginStreamListenerPeer*> *FileCachedStreamListeners();
nsresult AsyncSetWindow(NPWindow& window);
void URLRedirectResponse(void* notifyData, NPBool allow);
protected:
nsresult InitializePlugin();
@ -185,11 +188,9 @@ public:
private:
nsNPAPIPlugin* mPlugin;
// array of plugin-initiated stream listeners
nsTArray<nsNPAPIPluginStreamListener*> mPStreamListeners;
// array of browser-initiated stream listeners
nsTArray<nsPluginStreamListenerPeer*> mBStreamListeners;
nsTArray<nsNPAPIPluginStreamListener*> mStreamListeners;
nsTArray<nsPluginStreamListenerPeer*> mFileCachedStreamListeners;
nsTArray<PopupControlState> mPopupStates;

Просмотреть файл

@ -46,6 +46,7 @@
#include "nsNPAPIPlugin.h"
#include "nsPluginSafety.h"
#include "nsPluginLogging.h"
#include "nsPluginStreamListenerPeer.h"
NS_IMPL_ISUPPORTS1(nsPluginStreamToFile, nsIOutputStream)
@ -146,16 +147,16 @@ NS_IMPL_ISUPPORTS3(nsNPAPIPluginStreamListener, nsIPluginStreamListener,
nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst,
void* notifyData,
const char* aURL)
: mNotifyData(notifyData),
mStreamBuffer(nsnull),
: mStreamBuffer(nsnull),
mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
mInst(inst),
mStreamListenerPeer(nsnull),
mStreamBufferSize(0),
mStreamBufferByteCount(0),
mStreamType(NP_NORMAL),
mStreamStarted(PR_FALSE),
mStreamCleanedUp(PR_FALSE),
mCallNotify(PR_FALSE),
mCallNotify(notifyData ? PR_TRUE : PR_FALSE),
mIsSuspended(PR_FALSE),
mIsPluginInitJSStream(mInst->mInPluginInitCall &&
aURL && strncmp(aURL, "javascript:",
@ -163,13 +164,14 @@ mIsPluginInitJSStream(mInst->mInPluginInitCall &&
mResponseHeaderBuf(nsnull)
{
memset(&mNPStream, 0, sizeof(mNPStream));
mNPStream.notifyData = notifyData;
}
nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener()
{
// remove this from the plugin instance's stream list
nsTArray<nsNPAPIPluginStreamListener*> *pStreamListeners = mInst->PStreamListeners();
pStreamListeners->RemoveElement(this);
nsTArray<nsNPAPIPluginStreamListener*> *streamListeners = mInst->StreamListeners();
streamListeners->RemoveElement(this);
// For those cases when NewStream is never called, we still may need
// to fire a notification callback. Return network error as fallback
@ -201,7 +203,13 @@ nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
mStreamCleanedUp = PR_TRUE;
StopDataPump();
// Release any outstanding redirect callback.
if (mHTTPRedirectCallback) {
mHTTPRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
mHTTPRedirectCallback = nsnull;
}
// Seekable streams have an extra addref when they are created which must
// be matched here.
if (NP_SEEK == mStreamType)
@ -265,11 +273,11 @@ nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason)
NPP npp;
mInst->GetNPP(&npp);
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlnotify)(npp, mNotifyURL, reason, mNotifyData), mInst);
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlnotify)(npp, mNotifyURL, reason, mNPStream.notifyData), mInst);
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
this, npp, mNotifyData, reason, mNotifyURL));
this, npp, mNPStream.notifyData, reason, mNotifyURL));
}
}
@ -300,7 +308,6 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
mNPStream.ndata = (void*) this;
pluginInfo->GetURL(&mNPStream.url);
mNPStream.notifyData = mNotifyData;
pluginInfo->GetLength((PRUint32*)&(mNPStream.end));
pluginInfo->GetLastModified((PRUint32*)&(mNPStream.lastmodified));
@ -421,9 +428,9 @@ nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress()
if (!mInst)
return PR_FALSE;
nsTArray<nsNPAPIPluginStreamListener*> *pStreamListeners = mInst->PStreamListeners();
for (unsigned int i = 0; i < pStreamListeners->Length(); i++) {
if (pStreamListeners->ElementAt(i)->mIsPluginInitJSStream) {
nsTArray<nsNPAPIPluginStreamListener*> *streamListeners = mInst->StreamListeners();
for (unsigned int i = 0; i < streamListeners->Length(); i++) {
if (streamListeners->ElementAt(i)->mIsPluginInitJSStream) {
return PR_TRUE;
}
}
@ -826,3 +833,65 @@ nsNPAPIPluginStreamListener::NewResponseHeader(const char* headerName,
mResponseHeaders.Append('\n');
return NS_OK;
}
bool
nsNPAPIPluginStreamListener::HandleRedirectNotification(nsIChannel *oldChannel, nsIChannel *newChannel,
nsIAsyncVerifyRedirectCallback* callback)
{
nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(oldChannel);
nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel);
if (!oldHttpChannel || !newHttpChannel) {
return false;
}
if (!mInst) {
return false;
}
nsNPAPIPlugin* plugin = mInst->GetPlugin();
if (!plugin || !plugin->GetLibrary()) {
return false;
}
NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
if (!pluginFunctions->urlredirectnotify) {
return false;
}
// A non-null closure is required for redirect handling support.
if (mNPStream.notifyData) {
PRUint32 status;
if (NS_SUCCEEDED(oldHttpChannel->GetResponseStatus(&status))) {
nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(newHttpChannel->GetURI(getter_AddRefs(uri))) && uri) {
nsCAutoString spec;
if (NS_SUCCEEDED(uri->GetAsciiSpec(spec))) {
// At this point the plugin will be responsible for making the callback
// so save the callback object.
mHTTPRedirectCallback = callback;
NPP npp;
mInst->GetNPP(&npp);
#if defined(XP_WIN) || defined(XP_OS2)
NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStream.notifyData), mInst);
#else
(*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStream.notifyData);
#endif
return true;
}
}
}
}
callback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
return true;
}
void
nsNPAPIPluginStreamListener::URLRedirectResponse(NPBool allow)
{
if (mHTTPRedirectCallback) {
mHTTPRedirectCallback->OnRedirectVerifyCallback(allow ? NS_OK : NS_ERROR_FAILURE);
mHTTPRedirectCallback = nsnull;
}
}

Просмотреть файл

@ -50,12 +50,13 @@
#include "nsIPluginInstanceOwner.h"
#include "nsString.h"
#include "nsNPAPIPluginInstance.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "mozilla/PluginLibrary.h"
#define MAX_PLUGIN_NECKO_BUFFER 16384
class nsINPAPIPluginStreamInfo;
class nsPluginStreamListenerPeer;
// nsINPAPIPluginStreamInfo is an internal helper interface that exposes
// the underlying necko request to consumers of nsIPluginStreamInfo's.
@ -112,29 +113,34 @@ public:
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSIHTTPHEADERLISTENER
// nsNPAPIPluginStreamListener specific methods:
nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst, void* notifyData,
const char* aURL);
virtual ~nsNPAPIPluginStreamListener();
PRBool IsStarted();
nsresult CleanUpStream(NPReason reason);
void CallURLNotify(NPReason reason);
void SetCallNotify(PRBool aCallNotify)
{
mCallNotify = aCallNotify;
}
void SetCallNotify(PRBool aCallNotify) { mCallNotify = aCallNotify; }
nsresult SuspendRequest();
void ResumeRequest();
nsresult StartDataPump();
void StopDataPump();
PRBool PluginInitJSLoadInProgress();
void* GetNotifyData() { return mNPStream.notifyData; }
nsPluginStreamListenerPeer* GetStreamListenerPeer() { return mStreamListenerPeer; }
void SetStreamListenerPeer(nsPluginStreamListenerPeer* aPeer) { mStreamListenerPeer = aPeer; }
// Returns true if the redirect will be handled by NPAPI, false otherwise.
bool HandleRedirectNotification(nsIChannel *oldChannel, nsIChannel *newChannel,
nsIAsyncVerifyRedirectCallback* callback);
void URLRedirectResponse(NPBool allow);
protected:
void* mNotifyData;
char* mStreamBuffer;
char* mNotifyURL;
nsRefPtr<nsNPAPIPluginInstance> mInst;
nsPluginStreamListenerPeer* mStreamListenerPeer;
NPStream mNPStream;
PRUint32 mStreamBufferSize;
PRInt32 mStreamBufferByteCount;
@ -146,8 +152,8 @@ protected:
PRPackedBool mIsPluginInitJSStream;
nsCString mResponseHeaders;
char* mResponseHeaderBuf;
nsCOMPtr<nsITimer> mDataPumpTimer;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mHTTPRedirectCallback;
public:
nsCOMPtr<nsIPluginStreamInfo> mStreamInfo;

Просмотреть файл

@ -278,7 +278,11 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::dtor this=%p, url=%s\n",this, mURLSpec.get()));
#endif
if (mPStreamListener) {
mPStreamListener->SetStreamListenerPeer(this);
}
// close FD of mFileCacheOutputStream if it's still open
// or we won't be able to remove the cache file
if (mFileCacheOutputStream)
@ -287,7 +291,7 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
delete mDataForwardToRequest;
if (mPluginInstance)
mPluginInstance->BStreamListeners()->RemoveElement(this);
mPluginInstance->FileCachedStreamListeners()->RemoveElement(this);
}
// Called as a result of GetURL and PostURL
@ -309,8 +313,10 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
mURL = aURL;
mPluginInstance = aInstance;
mPStreamListener = aListener;
mPStreamListener = static_cast<nsNPAPIPluginStreamListener*>(aListener);
mPStreamListener->SetStreamListenerPeer(this);
mPendingRequests = requestCount;
mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
@ -396,9 +402,9 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
nsTArray< nsRefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
for (PRUint32 i = 0; i < instances->Length(); i++) {
// most recent streams are at the end of list
nsTArray<nsPluginStreamListenerPeer*> *bStreamListeners = instances->ElementAt(i)->BStreamListeners();
for (PRInt32 i = bStreamListeners->Length() - 1; i >= 0; --i) {
nsPluginStreamListenerPeer *lp = bStreamListeners->ElementAt(i);
nsTArray<nsPluginStreamListenerPeer*> *streamListeners = instances->ElementAt(i)->FileCachedStreamListeners();
for (PRInt32 i = streamListeners->Length() - 1; i >= 0; --i) {
nsPluginStreamListenerPeer *lp = streamListeners->ElementAt(i);
if (lp && lp->mLocalCachedFileHolder) {
useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
if (useExistingCacheFile) {
@ -455,7 +461,7 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
}
// add this listenerPeer to list of stream peers for this instance
mPluginInstance->BStreamListeners()->AppendElement(this);
mPluginInstance->FileCachedStreamListeners()->AppendElement(this);
return rv;
}
@ -1082,15 +1088,18 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// NOTE: this should only happen when a stream was NOT created
// with GetURL or PostURL (i.e. it's the initial stream we
// send to the plugin as determined by the SRC or DATA attribute)
if (!mPStreamListener && mPluginInstance)
rv = mPluginInstance->NewStreamToPlugin(getter_AddRefs(mPStreamListener));
if (NS_FAILED(rv))
return rv;
if (!mPStreamListener)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIPluginStreamListener> streamListener;
if (!mPStreamListener && mPluginInstance) {
rv = mPluginInstance->NewStreamListener(nsnull, nsnull,
getter_AddRefs(streamListener));
if (NS_FAILED(rv) || !streamListener)
return NS_ERROR_FAILURE;
mPStreamListener = static_cast<nsNPAPIPluginStreamListener*>(streamListener.get());
}
mPStreamListener->SetStreamListenerPeer(this);
PRBool useLocalCache = PR_FALSE;
// get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
@ -1106,8 +1115,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// Reassemble the HTTP response status line and provide it to our
// listener. Would be nice if we could get the raw status line,
// but nsIHttpChannel doesn't currently provide that.
nsCOMPtr<nsIHTTPHeaderListener> listener =
do_QueryInterface(mPStreamListener);
nsCOMPtr<nsIHTTPHeaderListener> listener = do_QueryInterface(streamListener);
if (listener) {
// Status code: required; the status line isn't useful without it.
PRUint32 statusNum;
@ -1233,12 +1241,8 @@ nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
NS_IMETHODIMP
nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
{
nsCOMPtr<nsIHTTPHeaderListener> listener = do_QueryInterface(mPStreamListener);
if (!listener)
return NS_ERROR_FAILURE;
return listener->NewResponseHeader(PromiseFlatCString(header).get(),
PromiseFlatCString(value).get());
return mPStreamListener->NewResponseHeader(PromiseFlatCString(header).get(),
PromiseFlatCString(value).get());
}
nsresult
@ -1282,8 +1286,18 @@ NS_IMETHODIMP
nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel,
PRUint32 flags, nsIAsyncVerifyRedirectCallback* callback)
{
// Don't allow cross-origin 307 POST redirects. Fall back to channel event sink for window.
// Disallow redirects if we don't have a stream listener.
if (!mPStreamListener) {
return NS_ERROR_FAILURE;
}
// Give NPAPI a chance to control redirects.
bool notificationHandled = mPStreamListener->HandleRedirectNotification(oldChannel, newChannel, callback);
if (notificationHandled) {
return NS_OK;
}
// Don't allow cross-origin 307 POST redirects.
nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel));
if (oldHttpChannel) {
PRUint32 responseStatus;
@ -1308,10 +1322,11 @@ nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsICh
}
}
// Fall back to channel event sink for window.
nsCOMPtr<nsIChannelEventSink> channelEventSink;
nsresult rv = GetInterfaceGlobal(NS_GET_IID(nsIChannelEventSink), getter_AddRefs(channelEventSink));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
return rv;
}
return channelEventSink->AsyncOnChannelRedirect(oldChannel, newChannel, flags, callback);

Просмотреть файл

@ -38,6 +38,9 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsPluginStreamListenerPeer_h_
#define nsPluginStreamListenerPeer_h_
#include "nscore.h"
#include "nsIFile.h"
#include "nsIStreamListener.h"
@ -129,8 +132,8 @@ private:
nsCOMPtr<nsIURI> mURL;
nsCString mURLSpec; // Have to keep this member because GetURL hands out char*
nsCOMPtr<nsIPluginInstanceOwner> mOwner;
nsCOMPtr<nsIPluginStreamListener> mPStreamListener;
nsRefPtr<nsNPAPIPluginStreamListener> mPStreamListener;
// Set to PR_TRUE if we request failed (like with a HTTP response of 404)
PRPackedBool mRequestFailed;
@ -165,3 +168,5 @@ public:
nsWeakPtr mWeakPtrChannelCallbacks;
nsWeakPtr mWeakPtrChannelLoadGroup;
};
#endif // nsPluginStreamListenerPeer_h_