private static void ReadChunkedCallback(object state) {
#if DEBUG
GlobalLog.SetThreadSource(ThreadKinds.Worker);
using (GlobalLog.SetThreadKind(ThreadKinds.System | ThreadKinds.Sync)) {
#endif
// ********** WARNING - updating logic below should also be updated in ReadChunkedSync *****************
NestedSingleAsyncResult castedAsyncResult = state as NestedSingleAsyncResult;
ConnectStream thisConnectStream = castedAsyncResult.AsyncObject as ConnectStream;
GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(thisConnectStream) + "::ReadChunkedCallback", ValidationHelper.HashString(castedAsyncResult));
try {
if (!thisConnectStream.m_Draining && thisConnectStream.IsClosed) {
// throw on shutdown only if we're not draining the socket.
Exception exception =
new WebException(
NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.ConnectionClosed),
WebExceptionStatus.ConnectionClosed);
castedAsyncResult.InvokeCallback(exception);
GlobalLog.LeaveException("ReadChunkedCallback", exception);
return;
}
else if (thisConnectStream.m_ErrorException!=null) {
// throw on IO error even if we're draining the socket.
castedAsyncResult.InvokeCallback(thisConnectStream.m_ErrorException);
GlobalLog.LeaveException("ReadChunkedCallback", thisConnectStream.m_ErrorException);
return;
}
if (thisConnectStream.m_ChunkedNeedCRLFRead) {
thisConnectStream.ReadCRLF(thisConnectStream.m_TempBuffer);
thisConnectStream.m_ChunkedNeedCRLFRead = false;
}
StreamChunkBytes ReadByteBuffer = new StreamChunkBytes(thisConnectStream);
// We need to determine size of next chunk,
// by carefully reading, byte by byte
thisConnectStream.m_ChunkSize = thisConnectStream.ProcessReadChunkedSize(ReadByteBuffer);
// If this isn't a zero length chunk, read it.
if (thisConnectStream.m_ChunkSize != 0) {
thisConnectStream.m_ChunkedNeedCRLFRead = true;
int bytesToRead = Math.Min(castedAsyncResult.Size, thisConnectStream.m_ChunkSize);
//
// Attempt to fill in our entired read from,
// data previously buffered, if this completely
// satisfies us, then we are done, complete sync
//
int bytesAlreadyRead = 0;
if (thisConnectStream.m_ReadBufferSize > 0)
{
bytesAlreadyRead = thisConnectStream.FillFromBufferedData(castedAsyncResult.Buffer, ref castedAsyncResult.Offset, ref bytesToRead);
if (bytesToRead == 0)
{
castedAsyncResult.InvokeCallback(bytesAlreadyRead);
GlobalLog.Leave("ConnectStream::ReadChunkedCallback");
return;
}
}
//
// otherwise, we need to read more data from the connection.
//
if (thisConnectStream.ErrorInStream)
{
GlobalLog.LeaveException("ConnectStream::ReadChunkedCallback", thisConnectStream.m_ErrorException);
throw thisConnectStream.m_ErrorException;
}
GlobalLog.Assert(thisConnectStream.m_DoneCalled == 0 || thisConnectStream.m_ReadBytes != -1, "ConnectStream::ReadChunkedCallback|Calling BeginRead after ReadDone.");
// Keep track of this during the read so it can be added back at the end.
thisConnectStream.m_BytesAlreadyTransferred = bytesAlreadyRead;
IAsyncResult asyncResult = thisConnectStream.m_Connection.BeginRead(castedAsyncResult.Buffer, castedAsyncResult.Offset, bytesToRead, m_ReadCallbackDelegate, castedAsyncResult);
// a null return indicates that the connection was closed underneath us.
if (asyncResult == null)
{
thisConnectStream.m_BytesAlreadyTransferred = 0;
thisConnectStream.m_ErrorException = new WebException(
NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
WebExceptionStatus.RequestCanceled);
GlobalLog.LeaveException("ConnectStream::ReadChunkedCallback", thisConnectStream.m_ErrorException);
throw thisConnectStream.m_ErrorException;
}
}
else {
// We've found the terminating 0 length chunk. We may be very well looking
// at an extension footer or the very final CRLF.
thisConnectStream.ReadCRLF(thisConnectStream.m_TempBuffer);
thisConnectStream.RemoveTrailers(ReadByteBuffer);
// Remember that we've found this, so we don't try and dechunk
// more.
thisConnectStream.m_ReadBytes = 0;
thisConnectStream.m_ChunkEofRecvd = true;
thisConnectStream.CallDone();
// we're done reading, return 0 bytes
castedAsyncResult.InvokeCallback(0);
}
GlobalLog.Leave("ReadChunkedCallback");
}
catch (Exception exception)
{
if (NclUtilities.IsFatal(exception)) throw;
castedAsyncResult.InvokeCallback(exception);
GlobalLog.LeaveException("ConnectStream::ReadChunkedCallback", exception);
}
// ********** WARNING - updating logic above should also be updated in ReadChunkedSync *****************
#if DEBUG
}
#endif
}