internal DataParseStatus ParseHeaders(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength)
        {
            int    headerNameStartOffset  = -1;
            int    headerNameEndOffset    = -1;
            int    headerValueStartOffset = -1;
            int    headerValueEndOffset   = -1;
            int    numberOfLf             = -1;
            int    index = unparsed;
            bool   spaceAfterLf;
            string headerMultiLineValue;
            string headerName;
            string headerValue;

            // we need this because this method is entered multiple times.
            int localTotalResponseHeadersLength = totalResponseHeadersLength;

            DataParseStatus parseStatus = DataParseStatus.Invalid;

            GlobalLog.Enter("WebHeaderCollection::ParseHeaders(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size - unparsed)) + "]");
            //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): advancing. index=" + index.ToString() + " current character='" + ((char)buffer[index]).ToString() + "':" + ((int)buffer[index]).ToString() + " next character='" + ((char)buffer[index+1]).ToString() + "':" + ((int)buffer[index+1]).ToString());
            //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): headerName:[" + headerName + "], headerValue:[" + headerValue + "], headerMultiLineValue:[" + headerMultiLineValue + "] numberOfLf=" + numberOfLf.ToString() + " index=" + index.ToString());
            //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): headerNameStartOffset=" + headerNameStartOffset + " headerNameEndOffset=" + headerNameEndOffset + " headerValueStartOffset=" + headerValueStartOffset + " headerValueEndOffset=" + headerValueEndOffset);

            //
            // according to RFC216 a header can have the following syntax:
            //
            // message-header = field-name ":" [ field-value ]
            // field-name     = token
            // field-value    = *( field-content | LWS )
            // field-content  = <the OCTETs making up the field-value and consisting of either *TEXT or combinations of token, separators, and quoted-string>
            // TEXT           = <any OCTET except CTLs, but including LWS>
            // CTL            = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
            // SP             = <US-ASCII SP, space (32)>
            // HT             = <US-ASCII HT, horizontal-tab (9)>
            // CR             = <US-ASCII CR, carriage return (13)>
            // LF             = <US-ASCII LF, linefeed (10)>
            // LWS            = [CR LF] 1*( SP | HT )
            // CHAR           = <any US-ASCII character (octets 0 - 127)>
            // token          = 1*<any CHAR except CTLs or separators>
            // separators     = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
            // quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
            // qdtext         = <any TEXT except <">>
            // quoted-pair    = "\" CHAR
            //

            //
            // At each iteration of the following loop we expect to parse a single HTTP header entirely.
            //
            for (;;)
            {
                //
                // trim leading whitespaces (LWS) just for extra robustness, in fact if there are leading white spaces then:
                // 1) it could be that after the status line we might have spaces. handle this.
                // 2) this should have been detected to be a multiline header so there'll be no spaces and we'll spend some time here.
                //
                headerName           = string.Empty;
                headerValue          = string.Empty;
                spaceAfterLf         = false;
                headerMultiLineValue = null;

                if (Count == 0)
                {
                    //
                    // so, restrict this extra trimming only on the first header line
                    //
                    while (index < size && (buffer[index] == ' ' || buffer[index] == '\t'))
                    {
                        index++;
                        if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength)
                        {
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit;
                        }
                    }
                    if (index == size)
                    {
                        //
                        // we reached the end of the buffer. ask for more data.
                        //
                        parseStatus = DataParseStatus.NeedMoreData;
                        goto quit;
                    }
                }

                //
                // what we have here is the beginning of a new header
                //
                headerNameStartOffset = index;

                while (index < size && (buffer[index] != ':' && buffer[index] != '\n'))
                {
                    if (buffer[index] > ' ')
                    {
                        //
                        // if thre's an illegal character we should return DataParseStatus.Invalid
                        // instead we choose to be flexible, try to trim it, but include it in the string
                        //
                        headerNameEndOffset = index;
                    }
                    index++;
                    if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength)
                    {
                        parseStatus = DataParseStatus.DataTooBig;
                        goto quit;
                    }
                }
                if (index == size)
                {
                    //
                    // we reached the end of the buffer. ask for more data.
                    //
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }

startOfValue:
                //
                // skip all [' ','\t',':','\r','\n'] characters until HeaderValue starts
                // if we didn't find any headers yet, we set numberOfLf to 1
                // so that we take the '\n' from the status line into account
                //

                numberOfLf = (Count == 0 && headerNameEndOffset < 0) ? 1 : 0;
                while (index < size && numberOfLf < 2 && (buffer[index] <= ' ' || buffer[index] == ':'))
                {
                    if (buffer[index] == '\n')
                    {
                        numberOfLf++;
                        spaceAfterLf = index + 1 < size && (buffer[index + 1] == ' ' || buffer[index + 1] == '\t');
                    }
                    index++;
                    if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength)
                    {
                        parseStatus = DataParseStatus.DataTooBig;
                        goto quit;
                    }
                }
                if (numberOfLf == 2 || (numberOfLf == 1 && !spaceAfterLf))
                {
                    //
                    // if we've counted two '\n' we got at the end of the headers even if we're past the end of the buffer
                    // if we've counted one '\n' and the first character after that was a ' ' or a '\t'
                    // no matter if we found a ':' or not, treat this as an empty header name.
                    //
                    goto addHeader;
                }
                if (index == size)
                {
                    //
                    // we reached the end of the buffer. ask for more data.
                    //
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }

                headerValueStartOffset = index;

                while (index < size && buffer[index] != '\n')
                {
                    if (buffer[index] > ' ')
                    {
                        headerValueEndOffset = index;
                    }
                    index++;
                    if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength)
                    {
                        parseStatus = DataParseStatus.DataTooBig;
                        goto quit;
                    }
                }
                if (index == size)
                {
                    //
                    // we reached the end of the buffer. ask for more data.
                    //
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }

                //
                // at this point we found either a '\n' or the end of the headers
                // hence we are at the end of the Header Line. 4 options:
                // 1) need more data
                // 2) if we find two '\n' => end of headers
                // 3) if we find one '\n' and a ' ' or a '\t' => multiline header
                // 4) if we find one '\n' and a valid char => next header
                //
                numberOfLf = 0;
                while (index < size && numberOfLf < 2 && (buffer[index] == '\r' || buffer[index] == '\n'))
                {
                    if (buffer[index] == '\n')
                    {
                        numberOfLf++;
                    }
                    index++;
                    if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength)
                    {
                        parseStatus = DataParseStatus.DataTooBig;
                        goto quit;
                    }
                }
                if (index == size && numberOfLf < 2)
                {
                    //
                    // we reached the end of the buffer but not of the headers. ask for more data.
                    //
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }

addHeader:
                if (headerValueStartOffset >= 0 && headerValueStartOffset > headerNameEndOffset && headerValueEndOffset >= headerValueStartOffset)
                {
                    //
                    // Encoding fastest way to build the UNICODE string off the byte[]
                    //
                    headerValue = HeaderEncoding.GetString(buffer, headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1);
                }

                //
                // if we got here from the beginning of the for loop, headerMultiLineValue will be null
                // otherwise it will contain the headerValue constructed for the multiline header
                // add this line as well to it, separated by a single space
                //
                headerMultiLineValue = (headerMultiLineValue == null ? headerValue : headerMultiLineValue + " " + headerValue);

                if (index < size && numberOfLf == 1 && (buffer[index] == ' ' || buffer[index] == '\t'))
                {
                    //
                    // since we found only one Lf and the next header line begins with a Lws,
                    // this is the beginning of a multiline header.
                    // parse the next line into headerValue later it will be added to headerMultiLineValue
                    //
                    index++;
                    if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength)
                    {
                        parseStatus = DataParseStatus.DataTooBig;
                        goto quit;
                    }
                    goto startOfValue;
                }

                if (headerNameStartOffset >= 0 && headerNameEndOffset >= headerNameStartOffset)
                {
                    //
                    // Encoding is the fastest way to build the UNICODE string off the byte[]
                    //
                    headerName = HeaderEncoding.GetString(buffer, headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1);
                }

                //
                // now it's finally safe to add the header if we have a name for it
                //
                if (headerName.Length > 0)
                {
                    //
                    // the base clasee will check for pre-existing headerValue and append
                    // it using commas as indicated in the RFC
                    //
                    GlobalLog.Print("WebHeaderCollection::ParseHeaders() calling base.Add() key:[" + headerName + "], value:[" + headerMultiLineValue + "]");
                    base.Add(headerName, headerMultiLineValue);
                }

                //
                // and update unparsed
                //
                totalResponseHeadersLength = localTotalResponseHeadersLength;
                unparsed = index;

                if (numberOfLf == 2)
                {
                    parseStatus = DataParseStatus.Done;
                    goto quit;
                }
            } // for (;;)

quit:
            GlobalLog.Leave("WebHeaderCollection::ParseHeaders() returning parseStatus:" + parseStatus.ToString());
            return(parseStatus);
        }