예제 #1
0
NS_IMETHODIMP
nsBaseChannel::OnTransportStatus(nsITransport *transport, nsresult status,
                                 uint64_t progress, uint64_t progressMax)
{
  // In some cases, we may wish to suppress transport-layer status events.

  if (!mPump || NS_FAILED(mStatus) || HasLoadFlag(LOAD_BACKGROUND))
    return NS_OK;

  SUSPEND_PUMP_FOR_SCOPE();

  // Lazily fetch mProgressSink
  if (!mProgressSink) {
    if (mQueriedProgressSink)
      return NS_OK;
    GetCallback(mProgressSink);
    mQueriedProgressSink = true;
    if (!mProgressSink)
      return NS_OK;
  }

  nsAutoString statusArg;
  if (GetStatusArg(status, statusArg))
    mProgressSink->OnStatus(this, mListenerContext, status, statusArg.get());

  if (progress)
    mProgressSink->OnProgress(this, mListenerContext, progress, progressMax);

  return NS_OK;
}
예제 #2
0
NS_IMETHODIMP
nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
  // If our content type is unknown or if the content type is
  // application/octet-stream and the caller requested it, use the content type
  // sniffer. If the sniffer is not available for some reason, then we just keep
  // going as-is.
  bool shouldSniff = mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
            ((mLoadFlags & LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN) &&
            mContentType.EqualsLiteral(APPLICATION_OCTET_STREAM));

  if (NS_SUCCEEDED(mStatus) && shouldSniff) {
    mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
  }

  // Now, the general type sniffers. Skip this if we have none.
  if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
    mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));

  SUSPEND_PUMP_FOR_SCOPE();

  if (mListener) // null in case of redirect
      return mListener->OnStartRequest(this, mListenerContext);
  return NS_OK;
}
예제 #3
0
NS_IMETHODIMP
nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
  MOZ_ASSERT(!mLoadInfo ||
             mLoadInfo->GetSecurityMode() == 0 ||
             mLoadInfo->GetInitialSecurityCheckDone() ||
             (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
              nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
             "security flags in loadInfo but asyncOpen2() not called");

  NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
  NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  NS_ENSURE_ARG(listener);

  // Skip checking for chrome:// sub-resources.
  nsAutoCString scheme;
  mURI->GetScheme(scheme);
  if (!scheme.EqualsLiteral("file")) {
    NS_CompareLoadInfoAndLoadContext(this);
  }

  // Ensure that this is an allowed port before proceeding.
  nsresult rv = NS_CheckPortSafety(mURI);
  if (NS_FAILED(rv)) {
    mCallbacks = nullptr;
    return rv;
  }

  // Store the listener and context early so that OpenContentStream and the
  // stream's AsyncWait method (called by AsyncRead) can have access to them
  // via PushStreamConverter and the StreamListener methods.  However, since
  // this typically introduces a reference cycle between this and the listener,
  // we need to be sure to break the reference if this method does not succeed.
  mListener = listener;
  mListenerContext = ctxt;

  // This method assigns mPump as a side-effect.  We need to clear mPump if
  // this method fails.
  rv = BeginPumpingData();
  if (NS_FAILED(rv)) {
    mPump = nullptr;
    ChannelDone();
    mCallbacks = nullptr;
    return rv;
  }

  // At this point, we are going to return success no matter what.

  mWasOpened = true;

  SUSPEND_PUMP_FOR_SCOPE();

  if (mLoadGroup)
    mLoadGroup->AddRequest(this, nullptr);

  ClassifyURI();

  return NS_OK;
}
예제 #4
0
nsresult
nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
                        bool openNewChannel)
{
  SUSPEND_PUMP_FOR_SCOPE();

  // Transfer properties

  newChannel->SetLoadGroup(mLoadGroup);
  newChannel->SetNotificationCallbacks(mCallbacks);
  newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
  newChannel->SetLoadInfo(mLoadInfo);

  // Try to preserve the privacy bit if it has been overridden
  if (mPrivateBrowsingOverriden) {
    nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
      do_QueryInterface(newChannel);
    if (newPBChannel) {
      newPBChannel->SetPrivate(mPrivateBrowsing);
    }
  }

  nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
  if (bag)
    mPropertyHash.EnumerateRead(CopyProperties, bag.get());

  // Notify consumer, giving chance to cancel redirect.  For backwards compat,
  // we support nsIHttpEventSink if we are an HTTP channel and if this is not
  // an internal redirect.

  nsRefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
      new nsAsyncRedirectVerifyHelper();

  bool checkRedirectSynchronously = !openNewChannel;

  mRedirectChannel = newChannel;
  mRedirectFlags = redirectFlags;
  mOpenRedirectChannel = openNewChannel;
  nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
                                             checkRedirectSynchronously);
  if (NS_FAILED(rv))
    return rv;

  if (checkRedirectSynchronously && NS_FAILED(mStatus))
    return mStatus;

  return NS_OK;
}
예제 #5
0
NS_IMETHODIMP
nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
                               nsIInputStream *stream, uint64_t offset,
                               uint32_t count)
{
  SUSPEND_PUMP_FOR_SCOPE();

  nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
                                           offset, count);
  if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
    uint64_t prog = offset + count;
    OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
  }

  return rv;
}
예제 #6
0
NS_IMETHODIMP
nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
{
  NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
  NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  NS_ENSURE_ARG(listener);

  // Ensure that this is an allowed port before proceeding.
  nsresult rv = NS_CheckPortSafety(mURI);
  if (NS_FAILED(rv)) {
    mCallbacks = nullptr;
    return rv;
  }

  // Store the listener and context early so that OpenContentStream and the
  // stream's AsyncWait method (called by AsyncRead) can have access to them
  // via PushStreamConverter and the StreamListener methods.  However, since
  // this typically introduces a reference cycle between this and the listener,
  // we need to be sure to break the reference if this method does not succeed.
  mListener = listener;
  mListenerContext = ctxt;

  // This method assigns mPump as a side-effect.  We need to clear mPump if
  // this method fails.
  rv = BeginPumpingData();
  if (NS_FAILED(rv)) {
    mPump = nullptr;
    mListener = nullptr;
    mListenerContext = nullptr;
    mCallbacks = nullptr;
    return rv;
  }

  // At this point, we are going to return success no matter what.

  mWasOpened = true;

  SUSPEND_PUMP_FOR_SCOPE();

  if (mLoadGroup)
    mLoadGroup->AddRequest(this, nullptr);

  ClassifyURI();

  return NS_OK;
}
예제 #7
0
NS_IMETHODIMP
nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
                               nsIInputStream *stream, PRUint32 offset,
                               PRUint32 count)
{
    SUSPEND_PUMP_FOR_SCOPE();

    nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
                  offset, count);
    if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
        PRUint64 prog = PRUint64(offset) + count;
        PRUint64 progMax = ContentLength64();
        OnTransportStatus(nsnull, nsITransport::STATUS_READING, prog, progMax);
    }

    return rv;
}
예제 #8
0
NS_IMETHODIMP
nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
    // If our content type is unknown, then use the content type sniffer.  If the
    // sniffer is not available for some reason, then we just keep going as-is.
    if (NS_SUCCEEDED(mStatus) && mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
        mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
    }

    // Now, the general type sniffers. Skip this if we have none.
    if ((mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) &&
            gIOService->GetContentSniffers().Count() != 0)
        mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));

    SUSPEND_PUMP_FOR_SCOPE();

    return mListener->OnStartRequest(this, mListenerContext);
}
예제 #9
0
NS_IMETHODIMP
nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
                               nsIInputStream *stream, uint64_t offset,
                               uint32_t count)
{
  SUSPEND_PUMP_FOR_SCOPE();

  nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
                                           offset, count);
  if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
    int64_t prog = offset + count;
    if (NS_IsMainThread()) {
      OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
    } else {
      class OnTransportStatusAsyncEvent : public nsRunnable
      {
        RefPtr<nsBaseChannel> mChannel;
        int64_t mProgress;
        int64_t mContentLength;
      public:
        OnTransportStatusAsyncEvent(nsBaseChannel* aChannel,
                                    int64_t aProgress,
                                    int64_t aContentLength)
          : mChannel(aChannel),
            mProgress(aProgress),
            mContentLength(aContentLength)
        { }

        NS_IMETHOD Run() override
        {
          return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING,
                                             mProgress, mContentLength);
        }
      };

      nsCOMPtr<nsIRunnable> runnable =
        new OnTransportStatusAsyncEvent(this, prog, mContentLength);
      NS_DispatchToMainThread(runnable);
    }
  }

  return rv;
}
예제 #10
0
NS_IMETHODIMP
nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
  MOZ_ASSERT(request == mPump);

  // If our content type is unknown, use the content type
  // sniffer. If the sniffer is not available for some reason, then we just keep
  // going as-is.
  if (NS_SUCCEEDED(mStatus) &&
      mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
    mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
  }

  // Now, the general type sniffers. Skip this if we have none.
  if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
    mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));

  SUSPEND_PUMP_FOR_SCOPE();

  if (mListener) // null in case of redirect
      return mListener->OnStartRequest(this, mListenerContext);
  return NS_OK;
}
예제 #11
0
nsresult
nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
                        bool openNewChannel)
{
  SUSPEND_PUMP_FOR_SCOPE();

  // Transfer properties

  newChannel->SetLoadGroup(mLoadGroup);
  newChannel->SetNotificationCallbacks(mCallbacks);
  newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);

  // make a copy of the loadinfo, append to the redirectchain
  // and set it on the new channel
  if (mLoadInfo) {
    nsCOMPtr<nsILoadInfo> newLoadInfo =
      static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->Clone();

    nsCOMPtr<nsIPrincipal> uriPrincipal;
    nsIScriptSecurityManager *sm = nsContentUtils::GetSecurityManager();
    sm->GetChannelURIPrincipal(this, getter_AddRefs(uriPrincipal));
    bool isInternalRedirect =
      (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
                        nsIChannelEventSink::REDIRECT_STS_UPGRADE));
    newLoadInfo->AppendRedirectedPrincipal(uriPrincipal, isInternalRedirect);
    newChannel->SetLoadInfo(newLoadInfo);
  }
  else {
    // the newChannel was created with a dummy loadInfo, we should clear
    // it in case the original channel does not have a loadInfo
    newChannel->SetLoadInfo(nullptr);
  }

  // Preserve the privacy bit if it has been overridden
  if (mPrivateBrowsingOverriden) {
    nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
      do_QueryInterface(newChannel);
    if (newPBChannel) {
      newPBChannel->SetPrivate(mPrivateBrowsing);
    }
  }

  nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
  if (bag) {
    for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
      bag->SetProperty(iter.Key(), iter.UserData());
    }
  }

  // Notify consumer, giving chance to cancel redirect.  For backwards compat,
  // we support nsIHttpEventSink if we are an HTTP channel and if this is not
  // an internal redirect.

  RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
      new nsAsyncRedirectVerifyHelper();

  bool checkRedirectSynchronously = !openNewChannel;

  mRedirectChannel = newChannel;
  mRedirectFlags = redirectFlags;
  mOpenRedirectChannel = openNewChannel;
  nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
                                             checkRedirectSynchronously);
  if (NS_FAILED(rv))
    return rv;

  if (checkRedirectSynchronously && NS_FAILED(mStatus))
    return mStatus;

  return NS_OK;
}
예제 #12
0
nsresult
nsBaseChannel::Redirect(nsIChannel *newChannel, PRUint32 redirectFlags)
{
    SUSPEND_PUMP_FOR_SCOPE();

    // Transfer properties

    newChannel->SetOriginalURI(OriginalURI());
    newChannel->SetLoadGroup(mLoadGroup);
    newChannel->SetNotificationCallbacks(mCallbacks);
    newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);

    nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
    if (bag)
        mPropertyHash.EnumerateRead(CopyProperties, bag.get());

    // Notify consumer, giving chance to cancel redirect.  For backwards compat,
    // we support nsIHttpEventSink if we are an HTTP channel and if this is not
    // an internal redirect.

    // Global observers. These come first so that other observers don't see
    // redirects that get aborted for security reasons anyway.
    NS_ASSERTION(gIOService, "Must have an IO service");
    nsresult rv = gIOService->OnChannelRedirect(this, newChannel, redirectFlags);
    if (NS_FAILED(rv))
        return rv;

    // Backwards compat for non-internal redirects from a HTTP channel.
    if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
        nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
        if (httpChannel) {
            nsCOMPtr<nsIHttpEventSink> httpEventSink;
            GetCallback(httpEventSink);
            if (httpEventSink) {
                rv = httpEventSink->OnRedirect(httpChannel, newChannel);
                if (NS_FAILED(rv))
                    return rv;
            }
        }
    }

    nsCOMPtr<nsIChannelEventSink> channelEventSink;
    // Give our consumer a chance to observe/block this redirect.
    GetCallback(channelEventSink);
    if (channelEventSink) {
        rv = channelEventSink->OnChannelRedirect(this, newChannel, redirectFlags);
        if (NS_FAILED(rv))
            return rv;
    }

    // If we fail to open the new channel, then we want to leave this channel
    // unaffected, so we defer tearing down our channel until we have succeeded
    // with the redirect.

    rv = newChannel->AsyncOpen(mListener, mListenerContext);
    if (NS_FAILED(rv))
        return rv;

    // close down this channel
    Cancel(NS_BINDING_REDIRECTED);
    mListener = nsnull;
    mListenerContext = nsnull;

    return NS_OK;
}