private RequestStage FinishRequestStage(RequestStage stage)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"state:{stage}");
if (_exception != null)
stage = RequestStage.ReleaseConnection;
RequestStage prev;
LazyAsyncResult writeResult;
LazyAsyncResult readResult;
FtpControlStream connection;
lock (_syncObject)
{
prev = _requestStage;
if (stage == RequestStage.CheckForError)
return prev;
if (prev == RequestStage.ReleaseConnection &&
stage == RequestStage.ReleaseConnection)
{
return RequestStage.ReleaseConnection;
}
if (stage > prev)
_requestStage = stage;
if (stage <= RequestStage.RequestStarted)
return prev;
writeResult = _writeAsyncResult;
readResult = _readAsyncResult;
connection = _connection;
if (stage == RequestStage.ReleaseConnection)
{
if (_exception == null &&
!_aborted &&
prev != RequestStage.ReadReady &&
_methodInfo.IsDownload &&
!_ftpWebResponse.IsFromCache)
{
return prev;
}
_connection = null;
}
}
try
{
// First check to see on releasing the connection
if ((stage == RequestStage.ReleaseConnection ||
prev == RequestStage.ReleaseConnection)
&& connection != null)
{
try
{
if (_exception != null)
{
connection.Abort(_exception);
}
}
finally
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Releasing connection: {connection}");
connection.CloseSocket();
if (_async)
if (_requestCompleteAsyncResult != null)
_requestCompleteAsyncResult.InvokeCallback();
}
}
return prev;
}
finally
{
try
{
// In any case we want to signal the writer if came here
if (stage >= RequestStage.WriteReady)
{
// If writeResult == null and this is an upload request, it means
// that the user has called GetResponse() without calling
// GetRequestStream() first. So they are not interested in a
// stream. Therefore we close the stream so that the
// request/pipeline can continue
if (_methodInfo.IsUpload && !_getRequestStreamStarted)
{
if (_stream != null)
_stream.Close();
}
else if (writeResult != null && !writeResult.InternalPeekCompleted)
writeResult.InvokeCallback();
}
}
finally
{
// The response is ready either with or without a stream
if (stage >= RequestStage.ReadReady && readResult != null && !readResult.InternalPeekCompleted)
readResult.InvokeCallback();
}
}
}