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;

  nsRefPtr<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_NORMAL,
                       nsIContentPolicy::TYPE_OTHER,
                       loadGroup,
                       callbacks);
  }
  else {
    // in this else branch we really don't know where the load is coming
    // from and in fact should use something better than just using
    // a nullPrincipal as the loadingPrincipal.
    nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
    NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
    rv = NS_NewChannel(getter_AddRefs(channel),
                       mURL,
                       principal,
                       nsILoadInfo::SEC_NORMAL,
                       nsIContentPolicy::TYPE_OTHER,
                       loadGroup,
                       callbacks);
  }

  if (NS_FAILED(rv))
    return rv;

  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  if (!httpChannel)
    return NS_ERROR_FAILURE;

  httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);

  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));
    nsPluginByteRangeStreamListener *brrListener =
    new nsPluginByteRangeStreamListener(weakpeer);
    if (brrListener)
      converter = brrListener;
    else
      return NS_ERROR_OUT_OF_MEMORY;
  }

  mPendingRequests += numRequests;

  nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
  if (NS_FAILED(rv))
    return rv;
  rv = container->SetData(MAGIC_REQUEST_CONTEXT);
  if (NS_FAILED(rv))
    return rv;

  rv = channel->AsyncOpen(converter, container);
  if (NS_SUCCEEDED(rv))
    TrackRequest(channel);
  return rv;
}
NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
                                           nsISupports* aContext)
{
  nsresult rv = NS_OK;
  PROFILER_LABEL("nsPluginStreamListenerPeer", "OnStartRequest",
    js::ProfileEntry::Category::OTHER);

  if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) {
    NS_ASSERTION(mRequests.Count() == 0,
                 "Only our initial stream should be unknown!");
    TrackRequest(request);
  }

  if (mHaveFiredOnStartRequest) {
    return NS_OK;
  }

  mHaveFiredOnStartRequest = true;

  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
  NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);

  // deal with 404 (Not Found) HTTP response,
  // just return, this causes the request to be ignored.
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  if (httpChannel) {
    uint32_t responseCode = 0;
    rv = httpChannel->GetResponseStatus(&responseCode);
    if (NS_FAILED(rv)) {
      // NPP_Notify() will be called from OnStopRequest
      // in nsNPAPIPluginStreamListener::CleanUpStream
      // return error will cancel this request
      // ...and we also need to tell the plugin that
      mRequestFailed = true;
      return NS_ERROR_FAILURE;
    }

    if (responseCode > 206) { // not normal
      uint32_t wantsAllNetworkStreams = 0;

      // We don't always have an instance here already, but if we do, check
      // to see if it wants all streams.
      if (mPluginInstance) {
        rv = mPluginInstance->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) {
        mRequestFailed = true;
        return NS_ERROR_FAILURE;
      }
    }
  }

  nsAutoCString contentType;
  rv = channel->GetContentType(contentType);
  if (NS_FAILED(rv))
    return rv;

  // Check ShouldProcess with content policy
  nsRefPtr<nsPluginInstanceOwner> owner;
  if (mPluginInstance) {
    owner = mPluginInstance->GetOwner();
  }
  nsCOMPtr<nsIDOMElement> element;
  nsCOMPtr<nsIDocument> doc;
  if (owner) {
    owner->GetDOMElement(getter_AddRefs(element));
    owner->GetDocument(getter_AddRefs(doc));
  }
  nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;

  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
  rv = NS_CheckContentProcessPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
                                    mURL,
                                    principal,
                                    element,
                                    contentType,
                                    nullptr,
                                    &shouldLoad);
  if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
    mRequestFailed = true;
    return NS_ERROR_CONTENT_BLOCKED;
  }

  // Get the notification callbacks from the channel and save it as
  // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
  // we'll create channel for byte range request.
  nsCOMPtr<nsIInterfaceRequestor> callbacks;
  channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
  if (callbacks)
    mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);

  nsCOMPtr<nsILoadGroup> loadGroup;
  channel->GetLoadGroup(getter_AddRefs(loadGroup));
  if (loadGroup)
    mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);

  int64_t length;
  rv = channel->GetContentLength(&length);

  // it's possible for the server to not send a Content-Length.
  // we should still work in this case.
  if (NS_FAILED(rv) || length < 0 || length > UINT32_MAX) {
    // check out if this is file channel
    nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
    if (fileChannel) {
      // file does not exist
      mRequestFailed = true;
      return NS_ERROR_FAILURE;
    }
    mLength = 0;
  }
  else {
    mLength = uint32_t(length);
  }

  nsCOMPtr<nsIURI> aURL;
  rv = channel->GetURI(getter_AddRefs(aURL));
  if (NS_FAILED(rv))
    return rv;

  aURL->GetSpec(mURLSpec);

  if (!contentType.IsEmpty())
    mContentType = contentType;

#ifdef PLUGIN_LOGGING
  MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
         ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
          this, request, contentType.get(), mURLSpec.get()));

  PR_LogFlush();
#endif

  // Set up the stream listener...
  rv = SetUpStreamListener(request, aURL);
  if (NS_FAILED(rv)) {
    return rv;
  }

  return rv;
}
NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
        nsISupports* aContext)
{
    nsresult rv = NS_OK;
    SAMPLE_LABEL("nsPluginStreamListenerPeer", "OnStartRequest");

    if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) {
        NS_ASSERTION(mRequests.Count() == 0,
                     "Only our initial stream should be unknown!");
        TrackRequest(request);
    }

    if (mHaveFiredOnStartRequest) {
        return NS_OK;
    }

    mHaveFiredOnStartRequest = true;

    nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);

    // deal with 404 (Not Found) HTTP response,
    // just return, this causes the request to be ignored.
    nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    if (httpChannel) {
        uint32_t responseCode = 0;
        rv = httpChannel->GetResponseStatus(&responseCode);
        if (NS_FAILED(rv)) {
            // NPP_Notify() will be called from OnStopRequest
            // in nsNPAPIPluginStreamListener::CleanUpStream
            // return error will cancel this request
            // ...and we also need to tell the plugin that
            mRequestFailed = true;
            return NS_ERROR_FAILURE;
        }

        if (responseCode > 206) { // not normal
            uint32_t wantsAllNetworkStreams = 0;

            // We don't always have an instance here already, but if we do, check
            // to see if it wants all streams.
            if (mPluginInstance) {
                rv = mPluginInstance->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) {
                mRequestFailed = true;
                return NS_ERROR_FAILURE;
            }
        }
    }

    // Get the notification callbacks from the channel and save it as
    // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
    // we'll create channel for byte range request.
    nsCOMPtr<nsIInterfaceRequestor> callbacks;
    channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
    if (callbacks)
        mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);

    nsCOMPtr<nsILoadGroup> loadGroup;
    channel->GetLoadGroup(getter_AddRefs(loadGroup));
    if (loadGroup)
        mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);

    int64_t length;
    rv = channel->GetContentLength(&length);

    // it's possible for the server to not send a Content-Length.
    // we should still work in this case.
    if (NS_FAILED(rv) || length == -1) {
        // check out if this is file channel
        nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
        if (fileChannel) {
            // file does not exist
            mRequestFailed = true;
            return NS_ERROR_FAILURE;
        }
        mLength = 0;
    }
    else {
        mLength = length;
    }

    nsAutoCString aContentType; // XXX but we already got the type above!
    rv = channel->GetContentType(aContentType);
    if (NS_FAILED(rv))
        return rv;

    nsCOMPtr<nsIURI> aURL;
    rv = channel->GetURI(getter_AddRefs(aURL));
    if (NS_FAILED(rv))
        return rv;

    aURL->GetSpec(mURLSpec);

    if (!aContentType.IsEmpty())
        mContentType = aContentType;

#ifdef PLUGIN_LOGGING
    PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
           ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
            this, request, aContentType.get(), mURLSpec.get()));

    PR_LogFlush();
#endif

    // Set up the stream listener...
    rv = SetUpStreamListener(request, aURL);
    if (NS_FAILED(rv)) return rv;

    return rv;
}
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;
  
  nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
  nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
  nsCOMPtr<nsIChannel> channel;
  rv = NS_NewChannel(getter_AddRefs(channel), mURL, nullptr, loadGroup, callbacks);
  if (NS_FAILED(rv))
    return rv;
  
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  if (!httpChannel)
    return NS_ERROR_FAILURE;
  
  httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
  
  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));
    nsPluginByteRangeStreamListener *brrListener =
    new nsPluginByteRangeStreamListener(weakpeer);
    if (brrListener)
      converter = brrListener;
    else
      return NS_ERROR_OUT_OF_MEMORY;
  }
  
  mPendingRequests += numRequests;
  
  nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
  if (NS_FAILED(rv))
    return rv;
  rv = container->SetData(MAGIC_REQUEST_CONTEXT);
  if (NS_FAILED(rv))
    return rv;
  
  rv = channel->AsyncOpen(converter, container);
  if (NS_SUCCEEDED(rv))
    TrackRequest(channel);
  return rv;
}
NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
                                           nsISupports* aContext)
{
  nsresult rv = NS_OK;

  if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) {
    NS_ASSERTION(mRequests.Count() == 0,
                 "Only our initial stream should be unknown!");
    TrackRequest(request);
  }
  
  if (mHaveFiredOnStartRequest) {
    return NS_OK;
  }
  
  mHaveFiredOnStartRequest = true;
  
  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
  NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
  
  // deal with 404 (Not Found) HTTP response,
  // just return, this causes the request to be ignored.
  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  if (httpChannel) {
    PRUint32 responseCode = 0;
    rv = httpChannel->GetResponseStatus(&responseCode);
    if (NS_FAILED(rv)) {
      // NPP_Notify() will be called from OnStopRequest
      // in nsNPAPIPluginStreamListener::CleanUpStream
      // return error will cancel this request
      // ...and we also need to tell the plugin that
      mRequestFailed = true;
      return NS_ERROR_FAILURE;
    }
    
    if (responseCode > 206) { // not normal
      bool bWantsAllNetworkStreams = false;

      // We don't always have an instance here already, but if we do, check
      // to see if it wants all streams.
      if (mPluginInstance) {
        rv = mPluginInstance->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
                                                 &bWantsAllNetworkStreams);
        // If the call returned an error code make sure we still use our default value.
        if (NS_FAILED(rv)) {
          bWantsAllNetworkStreams = false;
        }
      }

      if (!bWantsAllNetworkStreams) {
        mRequestFailed = true;
        return NS_ERROR_FAILURE;
      }
    }
  }
  
  // do a little sanity check to make sure our frame isn't gone
  // by getting the tag type and checking for an error, we can determine if
  // the frame is gone
  if (mOwner) {
    nsCOMPtr<nsIPluginTagInfo> pti = do_QueryInterface(mOwner);
    NS_ENSURE_TRUE(pti, NS_ERROR_FAILURE);
    nsPluginTagType tagType;
    if (NS_FAILED(pti->GetTagType(&tagType)))
      return NS_ERROR_FAILURE;  // something happened to our object frame, so bail!
  }
  
  // Get the notification callbacks from the channel and save it as
  // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
  // we'll create channel for byte range request.
  nsCOMPtr<nsIInterfaceRequestor> callbacks;
  channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
  if (callbacks)
    mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);
  
  nsCOMPtr<nsILoadGroup> loadGroup;
  channel->GetLoadGroup(getter_AddRefs(loadGroup));
  if (loadGroup)
    mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);
  
  PRInt32 length;
  rv = channel->GetContentLength(&length);
  
  // it's possible for the server to not send a Content-Length.
  // we should still work in this case.
  if (NS_FAILED(rv) || length == -1) {
    // check out if this is file channel
    nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
    if (fileChannel) {
      // file does not exist
      mRequestFailed = true;
      return NS_ERROR_FAILURE;
    }
    mLength = 0;
  }
  else {
    mLength = length;
  }
  
  nsCAutoString aContentType; // XXX but we already got the type above!
  rv = channel->GetContentType(aContentType);
  if (NS_FAILED(rv))
    return rv;
  
  nsCOMPtr<nsIURI> aURL;
  rv = channel->GetURI(getter_AddRefs(aURL));
  if (NS_FAILED(rv))
    return rv;
  
  aURL->GetSpec(mURLSpec);
  
  if (!aContentType.IsEmpty())
    mContentType = aContentType;
  
#ifdef PLUGIN_LOGGING
  PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
         ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
          this, request, aContentType.get(), mURLSpec.get()));
  
  PR_LogFlush();
#endif
  
  NPWindow* window = nsnull;
  
  // if we don't have an nsNPAPIPluginInstance (mPluginInstance), it means
  // we weren't able to load a plugin previously because we
  // didn't have the mimetype.  Now that we do (aContentType),
  // we'll try again with SetUpPluginInstance()
  // which is called by InstantiateEmbeddedPlugin()
  // NOTE: we don't want to try again if we didn't get the MIME type this time
  
  if (!mPluginInstance && mOwner && !aContentType.IsEmpty()) {
    nsRefPtr<nsNPAPIPluginInstance> pluginInstRefPtr;
    mOwner->GetInstance(getter_AddRefs(pluginInstRefPtr));
    mPluginInstance = pluginInstRefPtr.get();

    mOwner->GetWindow(window);
    if (!mPluginInstance && window) {
      nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
      rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
      if (NS_SUCCEEDED(rv)) {
        mOwner->GetInstance(getter_AddRefs(pluginInstRefPtr));
        mPluginInstance = pluginInstRefPtr.get();
        if (mPluginInstance) {
          mOwner->CreateWidget();
          // If we've got a native window, the let the plugin know about it.
          mOwner->SetWindow();
        }
      }
    }
  }
  
  // Set up the stream listener...
  rv = SetUpStreamListener(request, aURL);
  if (NS_FAILED(rv)) return rv;
  
  return rv;
}