public static void Parse(Stream input, IHttpMessagePrologueParseSink sink)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (sink == null)
            {
                throw new ArgumentNullException(nameof(sink));
            }

            if (!input.CanRead)
            {
                throw new ArgumentException(null, nameof(input));
            }

            var lineBuilder = new StringBuilder();

            string startLine;

            do
            {
                startLine = HttpLine.Read(input, lineBuilder)?.Trim();
                if (startLine == null)
                {
                    throw new FormatException("Missing HTTP request line or status response.");
                }
            }while (startLine.Length == 0);

            var match = Regex.Match(startLine, @"^HTTP/(0\.9|[1-9]\.[0-9])\x20+([1-5][0-9]{2})(?:\x20+(.+))?$");

            if (match.Success)
            {
                var groups       = match.Groups;
                var version      = groups[1].Value;
                var statusCode   = int.Parse(groups[2].Value, NumberStyles.None, CultureInfo.InvariantCulture);
                var reasonPhrase = groups[3].Value;
                sink.OnResponseLine(version, statusCode, reasonPhrase);
            }
            else if ((match = Regex.Match(startLine,
                                          @"^([!#$%&""'*.^_`|~0-9A-Za-z+-]+)\x20+([^\x20]+)(?:\x20+HTTP/([1-9]\.[0-9]))?$")).Success)
            {
                var groups  = match.Groups;
                var method  = groups[1].Value;
                var url     = groups[2].Value;
                var version = groups[3].Success ? groups[3].Value : null;
                sink.OnRequestLine(method, url, version);
            }
            else
            {
                throw new FormatException("Invalid HTTP request line or status response: " + startLine);
            }

            foreach (var(name, value) in ReadHeaders(input, lineBuilder))
            {
                sink.OnHeader(name, value);
            }
        }
        static IEnumerable <KeyValuePair <string, string> > ReadHeaders(Stream input, StringBuilder lineBuilder)
        {
            string headerName  = null;
            string headerValue = null;

            while (true)
            {
                var line = HttpLine.Read(input, lineBuilder);

                if (string.IsNullOrEmpty(line))
                {
                    break;
                }

                if (headerName != null && line[0] == ' ' || line[0] == '\t')
                {
                    headerValue = headerValue + line;
                }
                else
                {
                    if (headerName != null)
                    {
                        yield return(new KeyValuePair <string, string>(headerName, headerValue));
                    }

                    var pair = line.Split(Colon, 2);
                    if (pair.Length != 2)
                    {
                        continue;
                    }

                    headerName  = pair[0].Trim(Whitespace);
                    headerValue = pair[1].TrimStart(Whitespace);
                }
            }

            if (headerName != null)
            {
                yield return(new KeyValuePair <string, string>(headerName, headerValue));
            }
        }