Bug 1352567 - Remove NPAPI seekable and file streams from the dom/plugins/base code, r=jimm

MozReview-Commit-ID: 4qxEFjTKMVZ
This commit is contained in:
Benjamin Smedberg 2017-10-02 12:51:35 -07:00 коммит произвёл Kyle Machulis
Родитель ce00e2cd37
Коммит 28588c1731
5 изменённых файлов: 15 добавлений и 853 удалений

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

@ -1727,46 +1727,7 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
NPError
_requestread(NPStream *pstream, NPByteRange *rangeList)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n"));
return NPERR_INVALID_PARAM;
}
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n",
(void*)pstream));
#ifdef PLUGIN_LOGGING
for(NPByteRange * range = rangeList; range != nullptr; range = range->next)
MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY,
("%i-%i", range->offset, range->offset + range->length - 1));
MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n"));
PR_LogFlush();
#endif
if (!pstream || !rangeList || !pstream->ndata)
return NPERR_INVALID_PARAM;
nsNPAPIStreamWrapper* streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
nsNPAPIPluginStreamListener* streamlistener = streamWrapper->GetStreamListener();
if (!streamlistener) {
return NPERR_GENERIC_ERROR;
}
int32_t streamtype = NP_NORMAL;
streamlistener->GetStreamType(&streamtype);
if (streamtype != NP_SEEK)
return NPERR_STREAM_NOT_SEEKABLE;
if (!streamlistener->mStreamListenerPeer)
return NPERR_GENERIC_ERROR;
nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList);
if (NS_FAILED(rv))
return NPERR_GENERIC_ERROR;
return NPERR_NO_ERROR;
return NPERR_STREAM_NOT_SEEKABLE;
}
// Deprecated, only stubbed out

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

@ -46,7 +46,6 @@ nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance*
, mInst(inst)
, mStreamBufferSize(0)
, mStreamBufferByteCount(0)
, mStreamType(NP_NORMAL)
, mStreamState(eStreamStopped)
, mStreamCleanedUp(false)
, mCallNotify(notifyData ? true : false)
@ -115,11 +114,6 @@ nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
mHTTPRedirectCallback = nullptr;
}
// Seekable streams have an extra addref when they are created which must
// be matched here.
if (NP_SEEK == mStreamType && mStreamState == eStreamTypeSet)
NS_RELEASE_THIS();
if (mStreamListenerPeer) {
mStreamListenerPeer->CancelRequests(NS_BINDING_ABORTED);
mStreamListenerPeer = nullptr;
@ -212,7 +206,6 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
NPP npp;
mInst->GetNPP(&npp);
bool seekable;
char* contentType;
uint16_t streamType = NP_NORMAL;
NPError error;
@ -220,7 +213,6 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
streamPeer->GetURL(&mNPStreamWrapper->mNPStream.url);
streamPeer->GetLength((uint32_t*)&(mNPStreamWrapper->mNPStream.end));
streamPeer->GetLastModified((uint32_t*)&(mNPStreamWrapper->mNPStream.lastmodified));
streamPeer->IsSeekable(&seekable);
streamPeer->GetContentType(&contentType);
if (!mResponseHeaders.IsEmpty()) {
@ -232,68 +224,25 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
NPPAutoPusher nppPusher(npp);
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, seekable, &streamType), mInst,
NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, false, &streamType), mInst,
NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
this, npp, (char *)contentType, seekable, streamType, error, mNPStreamWrapper->mNPStream.url));
this, npp, (char *)contentType, false, streamType, error, mNPStreamWrapper->mNPStream.url));
if (error != NPERR_NO_ERROR)
return NS_ERROR_FAILURE;
mStreamState = eNewStreamCalled;
if (!SetStreamType(streamType, false)) {
if (streamType != NP_NORMAL) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
bool
nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
{
switch(aType)
{
case NP_NORMAL:
mStreamType = NP_NORMAL;
break;
case NP_ASFILEONLY:
mStreamType = NP_ASFILEONLY;
break;
case NP_ASFILE:
mStreamType = NP_ASFILE;
break;
case NP_SEEK:
mStreamType = NP_SEEK;
// Seekable streams should continue to exist even after OnStopRequest
// is fired, so we AddRef ourself an extra time and Release when the
// plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
// calls NPN_DestroyStream the stream will be destroyed before the plugin
// instance is destroyed.
NS_ADDREF_THIS();
break;
case nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN:
MOZ_ASSERT(!aNeedsResume);
mStreamType = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
SuspendRequest();
mStreamStopMode = eDoDeferredStop;
// In this case we do not want to execute anything else in this function.
return true;
default:
return false;
}
mStreamState = eStreamTypeSet;
if (aNeedsResume) {
if (mStreamListenerPeer) {
mStreamListenerPeer->OnStreamTypeSet(mStreamType);
}
ResumeRequest();
}
return true;
}
void
nsNPAPIPluginStreamListener::SuspendRequest()
{
@ -709,25 +658,7 @@ nsNPAPIPluginStreamListener::OnStopBinding(nsPluginStreamListenerPeer* streamPee
// The following code can result in the deletion of 'this'. Don't
// assume we are alive after this!
//
// Delay cleanup if the stream is of type NP_SEEK and status isn't
// NS_BINDING_ABORTED (meaning the plugin hasn't called NPN_DestroyStream).
// This is because even though we're done delivering data the plugin may
// want to seek. Eventually either the plugin will call NPN_DestroyStream
// or we'll perform cleanup when the instance goes away. See bug 91140.
if (mStreamType != NP_SEEK ||
(NP_SEEK == mStreamType && NS_BINDING_ABORTED == status)) {
return CleanUpStream(reason);
}
return NS_OK;
}
nsresult
nsNPAPIPluginStreamListener::GetStreamType(int32_t *result)
{
*result = mStreamType;
return NS_OK;
return CleanUpStream(reason);
}
bool

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

@ -65,8 +65,6 @@ public:
const char* fileName);
nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
nsresult status);
nsresult GetStreamType(int32_t *result);
bool SetStreamType(uint16_t aType, bool aNeedsResume = true);
bool IsStarted();
nsresult CleanUpStream(NPReason reason);
@ -112,7 +110,6 @@ protected:
nsNPAPIStreamWrapper *mNPStreamWrapper;
uint32_t mStreamBufferSize;
int32_t mStreamBufferByteCount;
int32_t mStreamType;
StreamState mStreamState;
bool mStreamCleanedUp;
bool mCallNotify;

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

@ -20,7 +20,6 @@
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsPluginHost.h"
#include "nsIByteRangeRequest.h"
#include "nsIMultiPartChannel.h"
#include "nsIInputStreamTee.h"
#include "nsPrintfCString.h"
@ -35,224 +34,6 @@
#include "nsDataHashtable.h"
#include "NullPrincipal.h"
#define BYTERANGE_REQUEST_CONTEXT 0x01020304
// nsPluginByteRangeStreamListener
class nsPluginByteRangeStreamListener
: public nsIStreamListener
, public nsIInterfaceRequestor
{
public:
explicit nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
private:
virtual ~nsPluginByteRangeStreamListener();
nsCOMPtr<nsIStreamListener> mStreamConverter;
nsWeakPtr mWeakPtrPluginStreamListenerPeer;
bool mRemoveByteRangeRequest;
};
NS_IMPL_ISUPPORTS(nsPluginByteRangeStreamListener,
nsIRequestObserver,
nsIStreamListener,
nsIInterfaceRequestor)
nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr)
{
mWeakPtrPluginStreamListenerPeer = aWeakPtr;
mRemoveByteRangeRequest = false;
}
nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
{
mStreamConverter = nullptr;
mWeakPtrPluginStreamListenerPeer = nullptr;
}
/**
* Unwrap any byte-range requests so that we can check whether the base channel
* is being tracked properly.
*/
static nsCOMPtr<nsIRequest>
GetBaseRequest(nsIRequest* r)
{
nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(r);
if (!mp)
return r;
nsCOMPtr<nsIChannel> base;
mp->GetBaseChannel(getter_AddRefs(base));
return already_AddRefed<nsIRequest>(base.forget());
}
NS_IMETHODIMP
nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
nsresult rv;
nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
nsPluginStreamListenerPeer *pslp =
static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
#ifdef DEBUG
nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
#endif
NS_ASSERTION(pslp->mRequests.IndexOfObject(baseRequest) != -1,
"Untracked byte-range request?");
nsCOMPtr<nsIStreamConverterService> serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
"*/*",
finalStreamListener,
nullptr,
getter_AddRefs(mStreamConverter));
if (NS_SUCCEEDED(rv)) {
rv = mStreamConverter->OnStartRequest(request, ctxt);
if (NS_SUCCEEDED(rv))
return rv;
}
}
mStreamConverter = nullptr;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
if (!httpChannel) {
return NS_ERROR_FAILURE;
}
uint32_t responseCode = 0;
rv = httpChannel->GetResponseStatus(&responseCode);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
if (responseCode != 200) {
uint32_t wantsAllNetworkStreams = 0;
rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
&wantsAllNetworkStreams);
// If the call returned an error code make sure we still use our default value.
if (NS_FAILED(rv)) {
wantsAllNetworkStreams = 0;
}
if (!wantsAllNetworkStreams){
return NS_ERROR_FAILURE;
}
}
// if server cannot continue with byte range (206 status) and sending us whole object (200 status)
// reset this seekable stream & try serve it to plugin instance as a file
mStreamConverter = finalStreamListener;
mRemoveByteRangeRequest = true;
rv = pslp->ServeStreamAsFile(request, ctxt);
return rv;
}
NS_IMETHODIMP
nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
nsresult status)
{
if (!mStreamConverter)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
nsPluginStreamListenerPeer *pslp =
static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
bool found = pslp->mRequests.RemoveObject(request);
if (!found) {
NS_ERROR("OnStopRequest received for untracked byte-range request!");
}
if (mRemoveByteRangeRequest) {
// remove byte range request from container
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(ctxt);
if (container) {
uint32_t byteRangeRequest = 0;
container->GetData(&byteRangeRequest);
if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
// to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
// set it to something that is not the byte range request.
container->SetData(0);
}
} else {
NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
}
}
return mStreamConverter->OnStopRequest(request, ctxt, status);
}
// CachedFileHolder
CachedFileHolder::CachedFileHolder(nsIFile* cacheFile)
: mFile(cacheFile)
{
NS_ASSERTION(mFile, "Empty CachedFileHolder");
}
CachedFileHolder::~CachedFileHolder()
{
mFile->Remove(false);
}
void
CachedFileHolder::AddRef()
{
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "CachedFileHolder", sizeof(*this));
}
void
CachedFileHolder::Release()
{
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "CachedFileHolder");
if (0 == mRefCnt)
delete this;
}
NS_IMETHODIMP
nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
nsIInputStream *inStr,
uint64_t sourceOffset,
uint32_t count)
{
if (!mStreamConverter)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
}
NS_IMETHODIMP
nsPluginByteRangeStreamListener::GetInterface(const nsIID& aIID, void** result)
{
// Forward interface requests to our parent
nsCOMPtr<nsIInterfaceRequestor> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
if (!finalStreamListener)
return NS_ERROR_FAILURE;
return finalStreamListener->GetInterface(aIID, result);
}
// nsPluginStreamListenerPeer
NS_IMPL_ISUPPORTS(nsPluginStreamListenerPeer,
@ -267,15 +48,12 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
{
mStreamType = NP_NORMAL;
mStartBinding = false;
mAbort = false;
mRequestFailed = false;
mPendingRequests = 0;
mHaveFiredOnStartRequest = false;
mDataForwardToRequest = nullptr;
mUseLocalCache = false;
mSeekable = false;
mModified = 0;
mStreamOffset = 0;
mStreamComplete = 0;
@ -291,16 +69,6 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
if (mPStreamListener) {
mPStreamListener->SetStreamListenerPeer(nullptr);
}
// close FD of mFileCacheOutputStream if it's still open
// or we won't be able to remove the cache file
if (mFileCacheOutputStream)
mFileCacheOutputStream = nullptr;
delete mDataForwardToRequest;
if (mPluginInstance)
mPluginInstance->FileCachedStreamListeners()->RemoveElement(this);
}
// Called as a result of GetURL and PostURL, or by the host in the case of the
@ -338,91 +106,9 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
mPendingRequests = 1;
mDataForwardToRequest = new nsDataHashtable<nsUint32HashKey, uint32_t>();
return NS_OK;
}
// SetupPluginCacheFile is called if we have to save the stream to disk.
//
// These files will be deleted when the host is destroyed.
//
// TODO? What if we fill up the the dest dir?
nsresult
nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
{
nsresult rv = NS_OK;
bool useExistingCacheFile = false;
RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
// Look for an existing cache file for the URI.
nsTArray< RefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
for (uint32_t i = 0; i < instances->Length(); i++) {
// most recent streams are at the end of list
nsTArray<nsPluginStreamListenerPeer*> *streamListeners = instances->ElementAt(i)->FileCachedStreamListeners();
for (int32_t i = streamListeners->Length() - 1; i >= 0; --i) {
nsPluginStreamListenerPeer *lp = streamListeners->ElementAt(i);
if (lp && lp->mLocalCachedFileHolder) {
useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
if (useExistingCacheFile) {
mLocalCachedFileHolder = lp->mLocalCachedFileHolder;
break;
}
}
if (useExistingCacheFile)
break;
}
}
// Create a new cache file if one could not be found.
if (!useExistingCacheFile) {
nsCOMPtr<nsIFile> pluginTmp;
rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
if (NS_FAILED(rv)) {
return rv;
}
// Get the filename from the channel
nsCOMPtr<nsIURI> uri;
rv = channel->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
if (!url)
return NS_ERROR_FAILURE;
nsAutoCString filename;
url->GetFileName(filename);
if (NS_FAILED(rv))
return rv;
// Create a file to save our stream into. Should we scramble the name?
filename.InsertLiteral("plugin-", 0);
rv = pluginTmp->AppendNative(filename);
if (NS_FAILED(rv))
return rv;
// Yes, make it unique.
rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv))
return rv;
// create a file output stream to write to...
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
if (NS_FAILED(rv))
return rv;
// save the file.
mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
}
// add this listenerPeer to list of stream peers for this instance
mPluginInstance->FileCachedStreamListeners()->AppendElement(this);
return rv;
}
NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
nsISupports* aContext)
@ -430,8 +116,7 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
nsresult rv = NS_OK;
AUTO_PROFILER_LABEL("nsPluginStreamListenerPeer::OnStartRequest", OTHER);
nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
if (mRequests.IndexOfObject(baseRequest) == -1) {
if (mRequests.IndexOfObject(request) == -1) {
NS_ASSERTION(mRequests.Count() == 0,
"Only our initial stream should be unknown!");
TrackRequest(request);
@ -597,13 +282,6 @@ nsPluginStreamListenerPeer::GetContentType(char** result)
}
nsresult
nsPluginStreamListenerPeer::IsSeekable(bool* result)
{
*result = mSeekable;
return NS_OK;
}
nsresult
nsPluginStreamListenerPeer::GetLength(uint32_t* result)
{
@ -625,41 +303,6 @@ nsPluginStreamListenerPeer::GetURL(const char** result)
return NS_OK;
}
void
nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
int32_t *numRequests)
{
rangeRequest.Truncate();
*numRequests = 0;
//the string should look like this: bytes=500-700,601-999
if (!aRangeList)
return;
int32_t requestCnt = 0;
nsAutoCString string("bytes=");
for (NPByteRange * range = aRangeList; range != nullptr; range = range->next) {
// XXX zero length?
if (!range->length)
continue;
// XXX needs to be fixed for negative offsets
string.AppendInt(range->offset);
string.Append('-');
string.AppendInt(range->offset + range->length - 1);
if (range->next)
string.Append(',');
requestCnt++;
}
// get rid of possible trailing comma
string.Trim(",", false);
rangeRequest = string;
*numRequests = requestCnt;
}
// XXX: Converting the channel within nsPluginStreamListenerPeer
// to use asyncOpen2() and do not want to touch the fragile logic
// of byte range requests. Hence we just introduce this lightweight
@ -717,99 +360,6 @@ private:
NS_IMPL_ISUPPORTS(PluginContextProxy, nsIStreamListener)
nsresult
nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
{
nsAutoCString rangeString;
int32_t numRequests;
MakeByteRangeString(rangeList, rangeString, &numRequests);
if (numRequests == 0)
return NS_ERROR_FAILURE;
nsresult rv = NS_OK;
RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
nsCOMPtr<nsIDOMElement> element;
nsCOMPtr<nsIDocument> doc;
if (owner) {
rv = owner->GetDOMElement(getter_AddRefs(element));
NS_ENSURE_SUCCESS(rv, rv);
rv = owner->GetDocument(getter_AddRefs(doc));
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
if (requestingNode) {
rv = NS_NewChannel(getter_AddRefs(channel),
mURL,
requestingNode,
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
loadGroup,
callbacks,
nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
}
else {
// In this else branch we really don't know where the load is coming
// from. Let's fall back to using the SystemPrincipal for such Plugins.
rv = NS_NewChannel(getter_AddRefs(channel),
mURL,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
loadGroup,
callbacks,
nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
}
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (!httpChannel)
return NS_ERROR_FAILURE;
rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
mAbort = true; // instruct old stream listener to cancel
// the request on the next ODA.
nsCOMPtr<nsIStreamListener> converter;
if (numRequests == 1) {
converter = this;
// set current stream offset equal to the first offset in the range list
// it will work for single byte range request
// for multy range we'll reset it in ODA
SetStreamOffset(rangeList->offset);
} else {
nsWeakPtr weakpeer =
do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
converter = new nsPluginByteRangeStreamListener(weakpeer);
}
mPendingRequests += numRequests;
nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = container->SetData(BYTERANGE_REQUEST_CONTEXT);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<PluginContextProxy> pluginContextProxy =
new PluginContextProxy(converter, container);
rv = channel->AsyncOpen2(pluginContextProxy);
NS_ENSURE_SUCCESS(rv, rv);
TrackRequest(channel);
return NS_OK;
}
nsresult
nsPluginStreamListenerPeer::GetStreamOffset(int32_t* result)
{
@ -824,72 +374,13 @@ nsPluginStreamListenerPeer::SetStreamOffset(int32_t value)
return NS_OK;
}
nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
nsISupports* aContext)
{
if (!mPluginInstance)
return NS_ERROR_FAILURE;
// mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
mPluginInstance->Stop();
mPluginInstance->Start();
RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
if (owner) {
NPWindow* window = nullptr;
owner->GetWindow(window);
#if (MOZ_WIDGET_GTK == 2)
// Should call GetPluginPort() here.
// This part is copied from nsPluginInstanceOwner::GetPluginPort().
nsCOMPtr<nsIWidget> widget;
((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
if (widget) {
window->window = widget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
}
#endif
owner->CallSetWindow();
}
mSeekable = false;
mPStreamListener->OnStartBinding(this);
mStreamOffset = 0;
// force the plugin to use stream as file
mStreamType = NP_ASFILE;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (channel) {
SetupPluginCacheFile(channel);
}
// unset mPendingRequests
mPendingRequests = 0;
return NS_OK;
}
bool
nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
{
NS_ENSURE_TRUE(psi, false);
if (psi->mLength == mLength &&
psi->mModified == mModified &&
mStreamComplete &&
mURLSpec.Equals(psi->mURLSpec))
{
return true;
}
return false;
}
NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
nsISupports* aContext,
nsIInputStream *aIStream,
uint64_t sourceOffset,
uint32_t aLength)
{
nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
if (mRequests.IndexOfObject(baseRequest) == -1) {
if (mRequests.IndexOfObject(request) == -1) {
MOZ_ASSERT(false, "Received OnDataAvailable for untracked request.");
return NS_ERROR_UNEXPECTED;
}
@ -897,19 +388,6 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
if (mRequestFailed)
return NS_ERROR_FAILURE;
if (mAbort) {
uint32_t byteRangeRequest = 0; // set it to something that is not the byte range request.
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
if (container)
container->GetData(&byteRangeRequest);
if (byteRangeRequest != BYTERANGE_REQUEST_CONTEXT) {
// this is not one of our range requests
mAbort = false;
return NS_BINDING_ABORTED;
}
}
nsresult rv = NS_OK;
if (!mPStreamListener)
@ -922,70 +400,17 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%" PRIu64 ", length=%u, url=%s\n",
this, request, sourceOffset, aLength, url ? url : "no url set"));
// if the plugin has requested an AsFileOnly stream, then don't
// call OnDataAvailable
if (mStreamType != NP_ASFILEONLY) {
// get the absolute offset of the request, if one exists.
nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
if (brr) {
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIInputStream> stream = aIStream;
rv = mPStreamListener->OnDataAvailable(this,
stream,
aLength);
int64_t absoluteOffset64 = 0;
brr->GetStartRange(&absoluteOffset64);
// XXX handle 64-bit for real
int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
// we need to track how much data we have forwarded to the
// plugin.
// FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
//
// Why couldn't this be tracked on the plugin info, and not in a
// *hash table*?
int32_t amtForwardToPlugin = mDataForwardToRequest->Get(absoluteOffset);
mDataForwardToRequest->Put(absoluteOffset, (amtForwardToPlugin + aLength));
SetStreamOffset(absoluteOffset + amtForwardToPlugin);
}
nsCOMPtr<nsIInputStream> stream = aIStream;
// if we are caching the file ourselves to disk, we want to 'tee' off
// the data as the plugin read from the stream. We do this by the magic
// of an input stream tee.
if (mFileCacheOutputStream) {
rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
if (NS_FAILED(rv))
return rv;
}
rv = mPStreamListener->OnDataAvailable(this,
stream,
aLength);
// if a plugin returns an error, the peer must kill the stream
// else the stream and PluginStreamListener leak
if (NS_FAILED(rv))
request->Cancel(rv);
// if a plugin returns an error, the peer must kill the stream
// else the stream and PluginStreamListener leak
if (NS_FAILED(rv)) {
request->Cancel(rv);
}
else
{
// if we don't read from the stream, OnStopRequest will never be called
char* buffer = new char[aLength];
uint32_t amountRead, amountWrote = 0;
rv = aIStream->Read(buffer, aLength, &amountRead);
// if we are caching this to disk ourselves, lets write the bytes out.
if (mFileCacheOutputStream) {
while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
}
}
delete [] buffer;
}
return rv;
}
@ -1007,43 +432,10 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%" PRIu32 " request=%p\n",
this, static_cast<uint32_t>(aStatus), request));
// for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
if (brr) {
int64_t absoluteOffset64 = 0;
brr->GetStartRange(&absoluteOffset64);
// XXX support 64-bit offsets
int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
// remove the request from our data forwarding count hash.
mDataForwardToRequest->Remove(absoluteOffset);
PLUGIN_LOG(PLUGIN_LOG_NOISY,
(" ::OnStopRequest for ByteRangeRequest Started=%d\n",
absoluteOffset));
} else {
// if this is not byte range request and
// if we are writting the stream to disk ourselves,
// close & tear it down here
mFileCacheOutputStream = nullptr;
}
// if we still have pending stuff to do, lets not close the plugin socket.
if (--mPendingRequests > 0)
return NS_OK;
// we keep our connections around...
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
if (container) {
uint32_t byteRangeRequest = 0; // something other than the byte range request.
container->GetData(&byteRangeRequest);
if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
// this is one of our range requests
return NS_OK;
}
}
if (!mPStreamListener)
return NS_ERROR_FAILURE;
@ -1070,24 +462,6 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
return NS_OK;
}
// call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
if (mStreamType >= NP_ASFILE) {
nsCOMPtr<nsIFile> localFile;
if (mLocalCachedFileHolder)
localFile = mLocalCachedFileHolder->file();
else {
// see if it is a file channel.
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
if (fileChannel) {
fileChannel->GetFile(getter_AddRefs(localFile));
}
}
if (localFile) {
OnFileAvailable(localFile);
}
}
if (mStartBinding) {
// On start binding has been called
mPStreamListener->OnStopBinding(this, aStatus);
@ -1176,32 +550,6 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
rv = httpChannel->VisitResponseHeaders(this);
MOZ_ASSERT(NS_SUCCEEDED(rv));
mSeekable = false;
// first we look for a content-encoding header. If we find one, we tell the
// plugin that stream is not seekable, because the plugin always sees
// uncompressed data, so it can't make meaningful range requests on a
// compressed entity. Also, we force the plugin to use
// nsPluginStreamType_AsFile stream type and we have to save decompressed
// file into local plugin cache, because necko cache contains original
// compressed file.
nsAutoCString contentEncoding;
if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding))) {
mUseLocalCache = true;
} else {
// set seekability (seekable if the stream has a known length and if the
// http server accepts byte ranges).
uint32_t length;
GetLength(&length);
if (length) {
nsAutoCString range;
if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
mSeekable = true;
}
}
}
// we require a content len
// get Last-Modified header for plugin info
nsAutoCString lastModified;
@ -1226,56 +574,9 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
if (NS_FAILED(rv))
return rv;
int32_t streamType = NP_NORMAL;
mPStreamListener->GetStreamType(&streamType);
if (streamType != STREAM_TYPE_UNKNOWN) {
OnStreamTypeSet(streamType);
}
return NS_OK;
}
void
nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
{
MOZ_ASSERT(aStreamType != STREAM_TYPE_UNKNOWN);
MOZ_ASSERT(mRequest);
mStreamType = aStreamType;
if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
// check it out if this is not a file channel.
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
if (!fileChannel) {
mUseLocalCache = true;
}
}
if (mUseLocalCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
SetupPluginCacheFile(channel);
}
}
nsresult
nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
{
nsresult rv;
if (!mPStreamListener)
return NS_ERROR_FAILURE;
nsAutoCString path;
rv = aFile->GetNativePath(path);
if (NS_FAILED(rv)) return rv;
if (path.IsEmpty()) {
NS_WARNING("empty path");
return NS_OK;
}
rv = mPStreamListener->OnFileAvailable(this, path.get());
return rv;
}
NS_IMETHODIMP
nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
{

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

@ -63,29 +63,17 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
// Called by RequestRead
void
MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, int32_t *numRequests);
bool UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi);
// Called by GetURL and PostURL (via NewStream) or by the host in the case of
// the initial plugin stream.
nsresult Initialize(nsIURI *aURL,
nsNPAPIPluginInstance *aInstance,
nsNPAPIPluginStreamListener *aListener);
nsresult OnFileAvailable(nsIFile* aFile);
nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; }
nsresult RequestRead(NPByteRange* rangeList);
nsresult GetLength(uint32_t* result);
nsresult GetURL(const char** result);
nsresult GetLastModified(uint32_t* result);
nsresult IsSeekable(bool* result);
nsresult GetContentType(char** result);
nsresult GetStreamOffset(int32_t* result);
nsresult SetStreamOffset(int32_t value);
@ -128,16 +116,8 @@ public:
requestsCopy[i]->Resume();
}
// Called by nsNPAPIPluginStreamListener
void OnStreamTypeSet(const int32_t aStreamType);
enum {
STREAM_TYPE_UNKNOWN = UINT16_MAX
};
private:
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
nsresult SetupPluginCacheFile(nsIChannel* channel);
nsresult GetInterfaceGlobal(const nsIID& aIID, void** result);
nsCOMPtr<nsIURI> mURL;
@ -159,23 +139,15 @@ private:
uint32_t mLength;
int32_t mStreamType;
// local cached file, we save the content into local cache if browser cache is not available,
// or plugin asks stream as file and it expects file extension until bug 90558 got fixed
RefPtr<CachedFileHolder> mLocalCachedFileHolder;
nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
nsDataHashtable<nsUint32HashKey, uint32_t>* mDataForwardToRequest;
nsCString mContentType;
bool mUseLocalCache;
nsCOMPtr<nsIRequest> mRequest;
bool mSeekable;
uint32_t mModified;
RefPtr<nsNPAPIPluginInstance> mPluginInstance;
int32_t mStreamOffset;
bool mStreamComplete;
public:
bool mAbort;
int32_t mPendingRequests;
nsWeakPtr mWeakPtrChannelCallbacks;
nsWeakPtr mWeakPtrChannelLoadGroup;