private DataParseStatus ParseStreamData(ref ConnectionReturnResult returnResult)
{
GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData");
if (m_CurrentRequest == null)
{
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData - Aborted Request, return DataParseStatus.Invalid");
m_ParseError.Section = WebParseErrorSection.Generic;
m_ParseError.Code = WebParseErrorCode.UnexpectedServerResponse;
return DataParseStatus.Invalid;
}
bool fHaveChunked = false;
bool dummyResponseStream;
// content-length if there is one
long contentLength = ProcessHeaderData(ref fHaveChunked, m_CurrentRequest, out dummyResponseStream);
GlobalLog.Assert(!fHaveChunked || contentLength == -1, "Connection#{0}::ParseStreamData()|fHaveChunked but contentLength != -1", ValidationHelper.HashString(this));
if (contentLength == c_InvalidContentLength)
{
m_ParseError.Section = WebParseErrorSection.ResponseHeader;
m_ParseError.Code = WebParseErrorCode.InvalidContentLength;
return DataParseStatus.Invalid;
}
// bytes left over that have not been parsed
int bufferLeft = (m_BytesRead - m_BytesScanned);
if (m_ResponseData.m_StatusCode > HttpWebRequest.MaxOkStatus)
{
// This will tell the request to be prepared for possible connection drop
// Also that will stop writing on the wire if the connection is not kept alive
m_CurrentRequest.ErrorStatusCodeNotify(this, m_KeepAlive, false);
}
int bytesToCopy;
//
// If pipelining, then look for extra data that could
// be part of of another stream, if its there,
// then we need to copy it, add it to a stream,
// and then continue with the next headers
//
if (dummyResponseStream)
{
bytesToCopy = 0;
fHaveChunked = false;
}
else
{
if (fHaveChunked)
{
bytesToCopy = FindChunkEntitySize(m_ReadBuffer, m_BytesScanned, bufferLeft);
if (bytesToCopy == 0)
{
// If we get a 0 back, we had some sort of error in
// parsing the chunk.
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData - Invalid Chunk in the resposne, HttpWebRequest#"+ValidationHelper.HashString(m_CurrentRequest));
m_ParseError.Section = WebParseErrorSection.ResponseBody;
m_ParseError.Code = WebParseErrorCode.InvalidChunkFormat;
return DataParseStatus.Invalid;
}
}
else
{
if (contentLength > (long)Int32.MaxValue)
bytesToCopy = -1;
else
bytesToCopy = (int)contentLength;
}
}
DataParseStatus result;
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData() bytesToCopy:" + bytesToCopy + " bufferLeft:" + bufferLeft);
if (bytesToCopy != -1 && bytesToCopy <= bufferLeft)
{
m_ResponseData.m_ConnectStream = new ConnectStream(this, m_ReadBuffer, m_BytesScanned, bytesToCopy, dummyResponseStream? 0: contentLength, fHaveChunked, m_CurrentRequest);
// The parsing will be resumed from m_BytesScanned when response stream is closed.
result = DataParseStatus.ContinueParsing;
m_BytesScanned += bytesToCopy;
}
else
{
m_ResponseData.m_ConnectStream = new ConnectStream(this, m_ReadBuffer, m_BytesScanned, bufferLeft, dummyResponseStream? 0: contentLength, fHaveChunked, m_CurrentRequest);
// This is the default case where we have a buffer with no more streams except the last one to create so we create it.
// Note the buffer is fully consumed so we can reset the buffer offests.
result = DataParseStatus.Done;
ClearReaderState();
}
m_ResponseData.m_ContentLength = contentLength;
ConnectionReturnResult.Add(ref returnResult, m_CurrentRequest, m_ResponseData.Clone());
#if DEBUG
GlobalLog.DebugUpdateRequest(m_CurrentRequest, this, GlobalLog.WaitingForReadDoneFlag);
#endif
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData");
return result; // response stream is taking over the reading
}