internal void ReadStartNextRequest(WebRequest currentRequest, ref ConnectionReturnResult returnResult)
{
GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest" + " WriteDone:" + m_WriteDone + " ReadDone:" + m_ReadDone + " WaitList:" + m_WaitList.Count + " WriteList:" + m_WriteList.Count);
GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest");
HttpWebRequest nextRequest = null;
TriState startRequestResult = TriState.Unspecified;
bool calledCloseConnection = false;
bool mustExit = false;
try {
lock(this) {
if (m_WriteList.Count > 0 && (object)currentRequest == m_WriteList[0])
{
// advance back to state 0
m_ReadState = ReadState.Start;
m_WriteList.RemoveAt(0);
// Must reset ConnectStream here to prevent a leak through the stream of the last request on each connection.
m_ResponseData.m_ConnectStream = null;
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() Removed request#" + ValidationHelper.HashString(currentRequest) + " from m_WriteList. New m_WriteList.Count:" + m_WriteList.Count.ToString());
}
else
{
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() The request#" + ValidationHelper.HashString(currentRequest) + " was disassociated so do nothing. m_WriteList.Count:" + m_WriteList.Count.ToString());
mustExit = true;;
}
//
// Since this is called after we're done reading the current
// request, if we're not doing keepalive and we're done
// writing we can close the connection now.
//
if(!mustExit)
{
//
// m_ReadDone==true is implied because we just finished a request but really the value must still be false here
//
if (m_ReadDone)
throw new InternalException(); // other requests may already started reading on this connection, need a QFE
if (!m_KeepAlive || m_Error != WebExceptionStatus.Success || !CanBePooled)
{
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() KeepAlive:" + m_KeepAlive + " WriteDone:" + m_WriteDone);
// Finished one request and connection is closing.
// We will not read from this connection so set readDone = true
m_ReadDone = true;
if (m_WriteDone)
{
// We could be closing because of an unexpected keep-alive
// failure, ie we pipelined a few requests and in the middle
// the remote server stopped doing keep alive. In this
// case m_Error could be success, which would be misleading.
// So in that case we'll set it to KeepAliveFailure.
if (m_Error == WebExceptionStatus.Success) {
// Only reason we could have gotten here is because
// we're not keeping the connection alive.
m_Error = WebExceptionStatus.KeepAliveFailure;
}
// PrepareCloseConnectionSocket has to be called with the critical section held.
PrepareCloseConnectionSocket(ref returnResult);
calledCloseConnection = true;
Close();
}
}
else
{
// We try to sort out KeepAliveFailure thing (search by context)
m_AtLeastOneResponseReceived = true;
if (m_WriteList.Count != 0)
{
// If a *pipelined* request that is being submitted has finished with the headers, post a receive
nextRequest = m_WriteList[0] as HttpWebRequest;
// If the active request has not finished its headers we can set m_ReadDone = true
// and that will be changed when said request will call CheckStartReceive
if (!nextRequest.HeadersCompleted)
{
nextRequest = null;
m_ReadDone = true;
}
}
// If there are no requests left to write (means pipeline),
// we can get the next request from wait list going now.
else
{
m_ReadDone = true;
// Sometime we get a response before completing the body in which case
// we defer next request to WriteStartNextRequest
if (m_WriteDone)
{
nextRequest = CheckNextRequest();
if (nextRequest != null )
{
// We cannot have HeadersCompleted on the request that was not placed yet on the write list
if(nextRequest.HeadersCompleted)
throw new InternalException();
startRequestResult = StartRequest(nextRequest);
}
else
{
//There are no other requests to process, so make connection avaliable for all
m_Free = true;
}
}
}
}
}
}
}
finally
{
CheckIdle();
//set result here to prevent nesting of readstartnextrequest.
if(returnResult != null){
ConnectionReturnResult.SetResponses(returnResult);
}
}
if(!mustExit && !calledCloseConnection)
{
if (startRequestResult != TriState.Unspecified)
{
CompleteStartRequest(false, nextRequest, startRequestResult);
}
else if (nextRequest != null)
{
// Handling receive, note that is for pipelinning case only !
if (!nextRequest.Async)
{
nextRequest.ConnectionReaderAsyncResult.InvokeCallback();
}
else
{
if (m_BytesScanned < m_BytesRead)
{
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() Calling ReadComplete, bytes unparsed = " + (m_BytesRead - m_BytesScanned));
ReadComplete(0, WebExceptionStatus.Success);
}
else if (Thread.CurrentThread.IsThreadPoolThread)
{
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() Calling PostReceive().");
PostReceive();
}
else
{
// Offload to the threadpool to protect against the case where one request's thread posts IO that another request
// depends on, but the first thread dies in the mean time.
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() ThreadPool.UnsafeQueueUserWorkItem(m_PostReceiveDelegate, this)");
ThreadPool.UnsafeQueueUserWorkItem(m_PostReceiveDelegate, this);
}
}
}
}
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest");
}