private long ProcessHeaderData(ref bool fHaveChunked, HttpWebRequest request, out bool dummyResponseStream)
{
long contentLength = -1;
fHaveChunked = false;
//
// Check for the "Transfer-Encoding" header to contain the "chunked" string
//
string transferEncodingString = m_ResponseData.m_ResponseHeaders[HttpKnownHeaderNames.TransferEncoding];
if (transferEncodingString!=null) {
transferEncodingString = transferEncodingString.ToLower(CultureInfo.InvariantCulture);
fHaveChunked = transferEncodingString.IndexOf(HttpWebRequest.ChunkedHeader) != -1;
}
if (!fHaveChunked) {
//
// If the response is not chunked, parse the "Content-Length" into a long for data size.
//
string contentLengthString = m_ResponseData.m_ResponseHeaders.ContentLength;
if (contentLengthString!=null) {
int index = contentLengthString.IndexOf(':');
if (index!=-1) {
contentLengthString = contentLengthString.Substring(index + 1);
}
bool success = long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out contentLength);
if (!success) {
contentLength = -1;
// in some very rare cases, a proxy server may
// send us a pair of numbers in comma delimated
// fashion, so we need to handle this case
index = contentLengthString.LastIndexOf(',');
if (index!=-1) {
contentLengthString = contentLengthString.Substring(index + 1);
success = long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out contentLength);
if (!success) {
contentLength = -1;
}
}
}
if (contentLength < 0)
{
GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ProcessHeaderData - ContentLength value in header: " + contentLengthString + ", HttpWebRequest#"+ValidationHelper.HashString(m_CurrentRequest));
contentLength = c_InvalidContentLength; // This will indicate a CL error to the caller
}
}
}
// ** else ** signal no content-length present??? or error out?
GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ProcessHeaderData() Content-Length parsed:" + contentLength.ToString(NumberFormatInfo.InvariantInfo));
dummyResponseStream = !request.CanGetResponseStream || m_ResponseData.m_StatusCode < HttpStatusCode.OK ||
m_ResponseData.m_StatusCode == HttpStatusCode.NoContent || (m_ResponseData.m_StatusCode == HttpStatusCode.NotModified && contentLength < 0) ;
if (m_KeepAlive)
{
//
// Deciding on KEEP ALIVE
//
bool resetKeepAlive = false;
//(1) if no content-length and no chunked, then turn off keep-alive
// In some cases, though, Content-Length should be assumed to be 0 based on HTTP RFC 2616
if (!dummyResponseStream && contentLength < 0 && !fHaveChunked)
{
resetKeepAlive = true;
}
//(2) A workaround for a failed client ssl session on IIS6
// The problem is that we cannot change the connection group name after it gets created.
// IIS6 does not close the connection on 403 so all subsequent requests will fail to be authorized on THAT connection.
else if (m_ResponseData.m_StatusCode == HttpStatusCode.Forbidden )
{
resetKeepAlive = true;
}
// (3) Possibly cease posting a big body on the connection, was invented mainly for the very first 401 response
//
// This optimization is for the discovery legs only. For ntlm this is fine, because the 1st actual authleg
// is always sent w/ content-length = 0.
// For Kerberos preauth, it there could be 1 or 2 auth legs, but we don't know how many there are in advance,
// so we don't have a way of eliminating the 1st auth leg.
else if (m_ResponseData.m_StatusCode > HttpWebRequest.MaxOkStatus &&
((request.CurrentMethod == KnownHttpVerb.Post || request.CurrentMethod == KnownHttpVerb.Put) &&
m_MaximumUnauthorizedUploadLength >= 0 && request.ContentLength > m_MaximumUnauthorizedUploadLength
&& (request.CurrentAuthenticationState == null || request.CurrentAuthenticationState.Module == null)))
{
resetKeepAlive = true;
}
//(4) for Http/1.0 servers, we can't be sure what their behavior
// in this case, so the best thing is to disable KeepAlive unless explicitly set
//
else
{
bool haveClose = false;
bool haveKeepAlive = false;
string connection = m_ResponseData.m_ResponseHeaders[HttpKnownHeaderNames.Connection];
if (connection == null && ServicePoint.InternalProxyServicePoint) {
connection = m_ResponseData.m_ResponseHeaders[HttpKnownHeaderNames.ProxyConnection];
}
if (connection != null) {
connection = connection.ToLower(CultureInfo.InvariantCulture);
if (connection.IndexOf("keep-alive") != -1) {
haveKeepAlive = true;
}
else if (connection.IndexOf("close") != -1) {
haveClose = true;
}
}
if ((haveClose && ServicePoint.HttpBehaviour==HttpBehaviour.HTTP11) ||
(!haveKeepAlive && ServicePoint.HttpBehaviour<=HttpBehaviour.HTTP10))
{
resetKeepAlive = true;
}
}
if (resetKeepAlive)
{
lock (this) {
m_KeepAlive = false;
m_Free = false;
}
}
}
return contentLength;
}