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; }
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; }
nsresult nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer, PRUint32 count, PRUint32 *countWritten) { LOG(("nsHttpPipeline::WriteSegments [this=%x count=%u]\n", this, count)); NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); if (mClosed) return NS_SUCCEEDED(mStatus) ? NS_BASE_STREAM_CLOSED : mStatus; nsAHttpTransaction *trans; nsresult rv; trans = Response(0); // This code deals with the establishment of a CONNECT tunnel through // an HTTP proxy. It allows the connection to do the CONNECT/200 // HTTP transaction to establish an SSL tunnel as a precursor to the // actual pipeline of regular HTTP transactions. if (!trans && mRequestQ.Length() && mConnection->IsProxyConnectInProgress()) { LOG(("nsHttpPipeline::WriteSegments [this=%p] Forced Delegation\n", this)); trans = Request(0); } if (!trans) { if (mRequestQ.Length() > 0) rv = NS_BASE_STREAM_WOULD_BLOCK; else rv = NS_BASE_STREAM_CLOSED; } else { // // ask the transaction to consume data from the connection. // PushBack may be called recursively. // rv = trans->WriteSegments(writer, count, countWritten); if (rv == NS_BASE_STREAM_CLOSED || trans->IsDone()) { trans->Close(NS_OK); // Release the transaction if it is not IsProxyConnectInProgress() if (trans == Response(0)) { NS_RELEASE(trans); mResponseQ.RemoveElementAt(0); mResponseIsPartial = false; ++mHttp1xTransactionCount; } // ask the connection manager to add additional transactions // to our pipeline. nsRefPtr<nsHttpConnectionInfo> ci; GetConnectionInfo(getter_AddRefs(ci)); if (ci) gHttpHandler->ConnMgr()->ProcessPendingQForEntry(ci); } else mResponseIsPartial = true; } if (mPushBackLen) { nsHttpPushBackWriter writer(mPushBackBuf, mPushBackLen); PRUint32 len = mPushBackLen, n; mPushBackLen = 0; // This progress notification has previously been sent from // the socket transport code, but it was delivered to the // previous transaction on the pipeline. nsITransport *transport = Transport(); if (transport) OnTransportStatus(transport, nsISocketTransport::STATUS_RECEIVING_FROM, mReceivingFromProgress); // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE, // so we are guaranteed that the next response will eat the entire // push back buffer (even though it might again call PushBack). rv = WriteSegments(&writer, len, &n); } return rv; }
nsresult nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer, PRUint32 count, PRUint32 *countWritten) { LOG(("nsHttpPipeline::WriteSegments [this=%x count=%u]\n", this, count)); NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); if (mClosed) return NS_SUCCEEDED(mStatus) ? NS_BASE_STREAM_CLOSED : mStatus; nsAHttpTransaction *trans; nsresult rv; trans = Response(0); if (!trans) { if (mRequestQ.Length() > 0) rv = NS_BASE_STREAM_WOULD_BLOCK; else rv = NS_BASE_STREAM_CLOSED; } else { // // ask the transaction to consume data from the connection. // PushBack may be called recursively. // rv = trans->WriteSegments(writer, count, countWritten); if (rv == NS_BASE_STREAM_CLOSED || trans->IsDone()) { trans->Close(NS_OK); NS_RELEASE(trans); mResponseQ.RemoveElementAt(0); mResponseIsPartial = false; ++mHttp1xTransactionCount; // ask the connection manager to add additional transactions // to our pipeline. gHttpHandler->ConnMgr()->AddTransactionToPipeline(this); } else mResponseIsPartial = true; } if (mPushBackLen) { nsHttpPushBackWriter writer(mPushBackBuf, mPushBackLen); PRUint32 len = mPushBackLen, n; mPushBackLen = 0; // This progress notification has previously been sent from // the socket transport code, but it was delivered to the // previous transaction on the pipeline. nsITransport *transport = Transport(); if (transport) OnTransportStatus(transport, nsISocketTransport::STATUS_RECEIVING_FROM, mReceivingFromProgress); // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE, // so we are guaranteed that the next response will eat the entire // push back buffer (even though it might again call PushBack). rv = WriteSegments(&writer, len, &n); } return rv; }