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;
}