internal bool SubmitRequest(HttpWebRequest request)
{
GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest", "request#" + ValidationHelper.HashString(request));
GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest");
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest() Free:" + m_Free.ToString() + " m_WaitList.Count:" + m_WaitList.Count.ToString());
TriState startRequestResult = TriState.Unspecified;
ConnectionReturnResult returnResult = null;
bool expiredIdleConnection = false;
// See if the connection is free, and if the underlying socket or
// stream is set up. If it is, we can assign this connection to the
// request right now. Otherwise we'll have to put this request on
// on the wait list until it its turn.
lock(this)
{
request.AbortDelegate = m_AbortDelegate;
if (request.Aborted)
{
// Note that request is not on the connection list yet and Abort() will push the response on the request
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest - (Request was aborted before being submitted)", true);
return true;
}
//
// There is a race condition between FindConnection and PrepareCloseConnectionSocket
// Some request may already try to submit themselves while the connection is dying.
//
// Retry if that's the case
//
if (!CanBePooled)
{
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest", "false - can't be pooled");
return false;
}
// See if our timer still matches the SerivcePoint. If not, get rid of it.
if (m_RecycleTimer.Duration != ServicePoint.ConnectionLeaseTimerQueue.Duration) {
m_RecycleTimer.Cancel();
m_RecycleTimer = ServicePoint.ConnectionLeaseTimerQueue.CreateTimer();
}
if (m_RecycleTimer.HasExpired) {
request.KeepAlive = false;
}
//
// If the connection has already been locked by another request, then
// we fail the submission on this Connection.
//
if (LockedRequest != null && LockedRequest != request) {
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest", "false");
return false;
}
//free means no one in the wait list. We should only add a request
//if the request can pipeline, or pipelining isn't available
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest WriteDone:" + m_WriteDone.ToString() + ", ReadDone:" + m_ReadDone.ToString() + ", m_WriteList.Count:" + m_WriteList.Count.ToString());
if (m_Free && m_WriteDone && (m_WriteList.Count == 0 || (request.Pipelined && !request.RequireBody && m_CanPipeline && m_Pipelining && !m_IsPipelinePaused))) {
// Connection is free. Mark it as busy and see if underlying
// socket is up.
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest - Free ");
m_Free = false;
startRequestResult = StartRequest(request);
if (startRequestResult == TriState.Unspecified)
{
expiredIdleConnection = true;
PrepareCloseConnectionSocket(ref returnResult);
// Hard Close the socket.
Close(0);
}
}
else {
m_WaitList.Add(request);
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest - Request added to WaitList#"+ValidationHelper.HashString(request));
CheckNonIdle();
}
}
if (expiredIdleConnection)
{
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest(), expired idle connection", false);
ConnectionReturnResult.SetResponses(returnResult);
return false;
}
GlobalLog.DebugAddRequest(request, this, 0);
if(Logging.On)Logging.Associate(Logging.Web, this, request);
if (startRequestResult != TriState.Unspecified) {
CompleteStartRequest(true, request, startRequestResult);
}
// On Sync, we wait for the Connection to be come availble here,
if (!request.Async)
{
object responseObject = request.ConnectionAsyncResult.InternalWaitForCompletion();
ConnectStream writeStream = responseObject as ConnectStream;
AsyncTriState triStateAsync = null;
if (writeStream == null)
triStateAsync = responseObject as AsyncTriState;
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest() Pipelining:"+m_Pipelining);
if (startRequestResult == TriState.Unspecified && triStateAsync != null) {
// May need to recreate Connection here (i.e. call Socket.Connect)
CompleteStartRequest(true, request, triStateAsync.Value);
}
else if (writeStream != null)
{
// return the Stream to the Request
request.SetRequestSubmitDone(writeStream);
}
#if DEBUG
else if (responseObject is Exception)
{
Exception exception = responseObject as Exception;
WebException webException = responseObject as WebException;
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest (SYNC) - Error waiting for a connection: " + exception.Message,
"Status:" + (webException == null? exception.GetType().FullName: (webException.Status.ToString() + " Internal Status: " + webException.InternalStatus.ToString())));
return true;
}
#endif
}
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SubmitRequest", true);
return true;
}