async Task <(WebHeaderCollection, byte[], int)> ReadHeaders(Stream stream, CancellationToken cancellationToken) { byte[] retBuffer = null; int status = 200; byte[] buffer = new byte[1024]; MemoryStream ms = new MemoryStream(); while (true) { cancellationToken.ThrowIfCancellationRequested(); int n = await stream.ReadAsync(buffer, 0, 1024, cancellationToken).ConfigureAwait(false); if (n == 0) { throw WebConnection.GetException(WebExceptionStatus.ServerProtocolViolation, null); } ms.Write(buffer, 0, n); int start = 0; string str = null; bool gotStatus = false; WebHeaderCollection headers = new WebHeaderCollection(); while (WebConnection.ReadLine(ms.GetBuffer(), ref start, (int)ms.Length, ref str)) { if (str == null) { int contentLen; var clengthHeader = headers["Content-Length"]; if (string.IsNullOrEmpty(clengthHeader) || !int.TryParse(clengthHeader, out contentLen)) { contentLen = 0; } if (ms.Length - start - contentLen > 0) { // we've read more data than the response header and conents, // give back extra data to the caller retBuffer = new byte[ms.Length - start - contentLen]; Buffer.BlockCopy(ms.GetBuffer(), start + contentLen, retBuffer, 0, retBuffer.Length); } else { // haven't read in some or all of the contents for the response, do so now FlushContents(stream, contentLen - (int)(ms.Length - start)); } return(headers, retBuffer, status); } if (gotStatus) { headers.Add(str); continue; } string[] parts = str.Split(' '); if (parts.Length < 2) { throw WebConnection.GetException(WebExceptionStatus.ServerProtocolViolation, null); } if (String.Compare(parts[0], "HTTP/1.1", true) == 0) { ProxyVersion = HttpVersion.Version11; } else if (String.Compare(parts[0], "HTTP/1.0", true) == 0) { ProxyVersion = HttpVersion.Version10; } else { throw WebConnection.GetException(WebExceptionStatus.ServerProtocolViolation, null); } status = (int)UInt32.Parse(parts[1]); if (parts.Length >= 3) { StatusDescription = String.Join(" ", parts, 2, parts.Length - 2); } gotStatus = true; } } }