Ejemplo n.º 1
0
        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;
                }
            }
        }