NS_IMETHODIMP nsNPAPIPluginStreamListener::Notify(nsITimer *aTimer) { NS_ASSERTION(aTimer == mDataPumpTimer, "Uh, wrong timer?"); int32_t oldStreamBufferByteCount = mStreamBufferByteCount; nsresult rv = OnDataAvailable(mStreamListenerPeer, nullptr, mStreamBufferByteCount); if (NS_FAILED(rv)) { // We ran into an error, no need to keep firing this timer then. StopDataPump(); MaybeRunStopBinding(); return NS_OK; } if (mStreamBufferByteCount != oldStreamBufferByteCount && ((mStreamState == eStreamTypeSet && mStreamBufferByteCount < 1024) || mStreamBufferByteCount == 0)) { // The plugin read some data and we've got less than 1024 bytes in // our buffer (or its empty and the stream is already // done). Resume the request so that we get more data off the // network. ResumeRequest(); // Necko will pump data now that we've resumed the request. StopDataPump(); } MaybeRunStopBinding(); return NS_OK; }
nsresult nsNPAPIPluginStreamListener::OnStopBinding(nsPluginStreamListenerPeer* streamPeer, nsresult status) { if (NS_FAILED(status)) { // The stream was destroyed, or died for some reason. Make sure we // cancel the underlying request. if (mStreamListenerPeer) { mStreamListenerPeer->CancelRequests(status); } } if (!mInst || !mInst->CanFireNotifications()) { StopDataPump(); return NS_ERROR_FAILURE; } // We need to detect that the stop is due to async stream init completion. if (mStreamStopMode == eDoDeferredStop) { // We shouldn't be delivering this until async init is done mStreamStopMode = eStopPending; mPendingStopBindingStatus = status; if (!mDataPumpTimer) { StartDataPump(); } return NS_OK; } StopDataPump(); NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE; if (mRedirectDenied || status == NS_BINDING_ABORTED) { reason = NPRES_USER_BREAK; } // The following code can result in the deletion of 'this'. Don't // assume we are alive after this! return CleanUpStream(reason); }
nsresult nsNPAPIPluginStreamListener::OnStopBinding(nsPluginStreamListenerPeer* streamPeer, nsresult status) { StopDataPump(); if (NS_FAILED(status)) { // The stream was destroyed, or died for some reason. Make sure we // cancel the underlying request. if (mStreamListenerPeer) { mStreamListenerPeer->CancelRequests(status); } } if (!mInst || !mInst->CanFireNotifications()) return NS_ERROR_FAILURE; NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE; if (mRedirectDenied || status == NS_BINDING_ABORTED) { reason = NPRES_USER_BREAK; } // 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::CleanUpStream(NPReason reason) { nsresult rv = NS_ERROR_FAILURE; // Various bits of code in the rest of this method may result in the // deletion of this object. Use a KungFuDeathGrip to keep ourselves // alive during cleanup. nsRefPtr<nsNPAPIPluginStreamListener> kungFuDeathGrip(this); if (mStreamCleanedUp) return NS_OK; mStreamCleanedUp = true; StopDataPump(); // Release any outstanding redirect callback. if (mHTTPRedirectCallback) { mHTTPRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_FAILURE); mHTTPRedirectCallback = nullptr; } // Seekable streams have an extra addref when they are created which must // be matched here. if (NP_SEEK == mStreamType && mStreamStarted) NS_RELEASE_THIS(); if (mStreamListenerPeer) { mStreamListenerPeer->CancelRequests(NS_BINDING_ABORTED); mStreamListenerPeer = nullptr; } if (!mInst || !mInst->CanFireNotifications()) return rv; PluginDestructionGuard guard(mInst); nsNPAPIPlugin* plugin = mInst->GetPlugin(); if (!plugin || !plugin->GetLibrary()) return rv; NPPluginFuncs* pluginFunctions = plugin->PluginFuncs(); NPP npp; mInst->GetNPP(&npp); if (mStreamStarted && pluginFunctions->destroystream) { NPPAutoPusher nppPusher(npp); NPError error; NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroystream)(npp, &mNPStreamWrapper->mNPStream, reason), mInst, NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPP DestroyStream called: this=%p, npp=%p, reason=%d, return=%d, url=%s\n", this, npp, reason, error, mNPStreamWrapper->mNPStream.url)); if (error == NPERR_NO_ERROR) rv = NS_OK; } mStreamStarted = false; // fire notification back to plugin, just like before CallURLNotify(reason); return rv; }