Пример #1
0
        internal unsafe DataParseStatus ParseHeadersStrict(
                byte[] buffer, 
                int size, 
                ref int unparsed, 
                ref int totalResponseHeadersLength, 
                int maximumResponseHeadersLength, 
                ref WebParseError parseError)
        {
            GlobalLog.Enter("WebHeaderCollection::ParseHeadersStrict(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size-unparsed)) + "]");

            WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic;
            DataParseStatus parseStatus = DataParseStatus.Invalid;

            int i = unparsed;
            RfcChar ch;
            int effectiveSize = maximumResponseHeadersLength <= 0 ? Int32.MaxValue : maximumResponseHeadersLength - totalResponseHeadersLength + i;
            DataParseStatus sizeError = DataParseStatus.DataTooBig;
            if (size < effectiveSize)
            {
                effectiveSize = size;
                sizeError = DataParseStatus.NeedMoreData;
            }

            // Verify the size.
            if (i >= effectiveSize)
            {
                parseStatus = sizeError;
                goto quit;
            }

            fixed (byte* byteBuffer = buffer)
            {
                while (true)
                {
                    // If this is CRLF, actually we're done.
                    if (byteBuffer[i] == '\r')
                    {
                        if (++i == effectiveSize)
                        {
                            parseStatus = sizeError;
                            goto quit;
                        }

                        if (byteBuffer[i++] == '\n')
                        {
                            totalResponseHeadersLength += i - unparsed;
                            unparsed = i;
                            parseStatus = DataParseStatus.Done;
                            goto quit;
                        }

                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit;
                    }

                    // Find the header name; only regular characters allowed.
                    int iBeginName = i;
                    for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.Reg; i++);
                    if (i == effectiveSize)
                    {
                        parseStatus = sizeError;
                        goto quit;
                    }
                    if (i == iBeginName)
                    {
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.InvalidHeaderName;
                        goto quit;
                    }

                    // Read to a colon.
                    int iEndName = i - 1;
                    int crlf = 0;  // 1 = cr, 2 = crlf
                    for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) != RfcChar.Colon; i++)
                    {
                        switch (ch)
                        {
                            case RfcChar.WS:
                                if (crlf == 1)
                                {
                                    break;
                                }
                                crlf = 0;
                                continue;

                            case RfcChar.CR:
                                if (crlf == 0)
                                {
                                    crlf = 1;
                                    continue;
                                }
                                break;

                            case RfcChar.LF:
                                if (crlf == 1)
                                {
                                    crlf = 2;
                                    continue;
                                }
                                break;
                        }
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit;
                    }
                    if (i == effectiveSize)
                    {
                        parseStatus = sizeError;
                        goto quit;
                    }
                    if (crlf != 0)                        
                    {
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.IncompleteHeaderLine;
                        goto quit;
                    }

                    // Skip the colon.
                    if (++i == effectiveSize)
                    {
                        parseStatus = sizeError;
                        goto quit;
                    }

                    // Read the value.  crlf = 3 means in the whitespace after a CRLF
                    int iBeginValue = -1;
                    int iEndValue = -1;
                    StringBuilder valueAccumulator = null;
                    for (; i < effectiveSize && ((ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.WS || crlf != 2); i++)
                    {
                        switch (ch)
                        {
                            case RfcChar.WS:
                                if (crlf == 1)
                                {
                                    break;
                                }
                                if (crlf == 2)
                                {
                                    crlf = 3;
                                }
                                continue;

                            case RfcChar.CR:
                                if (crlf == 0)
                                {
                                    crlf = 1;
                                    continue;
                                }
                                break;

                            case RfcChar.LF:
                                if (crlf == 1)
                                {
                                    crlf = 2;
                                    continue;
                                }
                                break;

                            case RfcChar.High:
                            case RfcChar.Colon:
                            case RfcChar.Delim:
                            case RfcChar.Reg:
                                if (crlf == 1)
                                {
                                    break;
                                }
                                if (crlf == 3)
                                {
                                    crlf = 0;
                                    if (iBeginValue != -1)
                                    {
                                        string s = HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1);
                                        if (valueAccumulator == null)
                                        {
                                            valueAccumulator = new StringBuilder(s, s.Length * 5);
                                        }
                                        else
                                        {
                                            valueAccumulator.Append(" ");
                                            valueAccumulator.Append(s);
                                        }
                                    }
                                    iBeginValue = -1;
                                }
                                if (iBeginValue == -1)
                                {
                                    iBeginValue = i;
                                }
                                iEndValue = i;
                                continue;
                        }
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit;
                    }
                    if (i == effectiveSize)
                    {
                        parseStatus = sizeError;
                        goto quit;
                    }

                    // Make the value.
                    string sValue = iBeginValue == -1 ? "" : HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1);
                    if (valueAccumulator != null)
                    {
                        if (sValue.Length != 0)
                        {
                            valueAccumulator.Append(" ");
                            valueAccumulator.Append(sValue);
                        }
                        sValue = valueAccumulator.ToString();
                    }

                    // Make the name.  See if it's a common header first.
                    string sName = null;
                    int headerNameLength = iEndName - iBeginName + 1;
                    if (m_CommonHeaders != null)
                    {
                        int iHeader = s_CommonHeaderHints[byteBuffer[iBeginName] & 0x1f];
                        if (iHeader >= 0)
                        {
                            while (true)
                            {
                                string s = s_CommonHeaderNames[iHeader++];

                                // Not found if we get to a shorter header or one with a different first character.
                                if (s.Length < headerNameLength || CaseInsensitiveAscii.AsciiToLower[byteBuffer[iBeginName]] != CaseInsensitiveAscii.AsciiToLower[s[0]])
                                    break;

                                // Keep looking if the common header is too long.
                                if (s.Length > headerNameLength)
                                    continue;

                                int j;
                                byte* pBuffer = byteBuffer + iBeginName + 1;
                                for (j = 1; j < s.Length; j++)
                                {
                                    // Avoid the case-insensitive compare in the common case where they match.
                                    if (*(pBuffer++) != s[j] && CaseInsensitiveAscii.AsciiToLower[*(pBuffer - 1)] != CaseInsensitiveAscii.AsciiToLower[s[j]])
                                        break;
                                }
                                if (j == s.Length)
                                {
                                    // Set it to the appropriate index.
                                    m_NumCommonHeaders++;
                                    iHeader--;
                                    if (m_CommonHeaders[iHeader] == null)
                                    {
                                        m_CommonHeaders[iHeader] = sValue;
                                    }
                                    else
                                    {
                                        // Don't currently handle combining multiple header instances in the common header case.
                                        // Nothing to do but punt them all to the NameValueCollection.
                                        NormalizeCommonHeaders();
                                        AddInternalNotCommon(s, sValue);
                                    }

                                    sName = s;
                                    break;
                                }
                            }
                        }
                    }

                    // If it wasn't a common header, add it to the hash.
                    if (sName == null)
                    {
                        sName = HeaderEncoding.GetString(byteBuffer + iBeginName, headerNameLength);
                        AddInternalNotCommon(sName, sValue);
                    }

                    totalResponseHeadersLength += i - unparsed;
                    unparsed = i;
                }
            }

quit:
            GlobalLog.Leave("WebHeaderCollection::ParseHeadersStrict() returning parseStatus:" + parseStatus.ToString());

            if (parseStatus == DataParseStatus.Invalid) {
                parseError.Section = WebParseErrorSection.ResponseHeader; 
                parseError.Code    = parseErrorCode;
            }

            return parseStatus;
        }
Пример #2
0
        //
        // Updated version of ParseStatusLine() - secure and fast
        //
        private static unsafe DataParseStatus ParseStatusLineStrict(
                byte[] statusLine,
                int statusLineLength,
                ref int bytesParsed,
                ref int statusState,
                StatusLineValues statusLineValues,
                int maximumHeaderLength,
                ref int totalBytesParsed,
                ref WebParseError parseError)
        {
            GlobalLog.Enter("Connection::ParseStatusLineStrict", statusLineLength.ToString(NumberFormatInfo.InvariantInfo) + ", " + bytesParsed.ToString(NumberFormatInfo.InvariantInfo) + ", " + statusState.ToString(NumberFormatInfo.InvariantInfo));
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection::ParseStatusLineStrict");
            GlobalLog.Assert((statusLineLength - bytesParsed) >= 0, "Connection::ParseStatusLineStrict()|(statusLineLength - bytesParsed) < 0");
            GlobalLog.Assert(maximumHeaderLength <= 0 || totalBytesParsed <= maximumHeaderLength, "Connection::ParseStatusLineStrict()|Headers already read exceeds limit.");

            // Remember where we started.
            int initialBytesParsed = bytesParsed;

            // Set up parsing status with what will happen if we exceed the buffer.
            DataParseStatus parseStatus = DataParseStatus.DataTooBig;
            int effectiveMax = maximumHeaderLength <= 0 ? int.MaxValue : (maximumHeaderLength - totalBytesParsed + bytesParsed);
            if (statusLineLength < effectiveMax)
            {
                parseStatus = DataParseStatus.NeedMoreData;
                effectiveMax = statusLineLength;
            }

            // sanity check
            if (bytesParsed >= effectiveMax)
                goto quit;

            fixed (byte* byteBuffer = statusLine)
            {
                // Use this switch to jump midway into the action.  They all fall through until the end of the buffer is reached or
                // the status line is fully parsed.
                switch (statusState)
                {
                    case BeforeVersionNumbers:
                        // This takes advantage of the fact that this token must be the very first thing in the response.
                        while (totalBytesParsed - initialBytesParsed + bytesParsed < BeforeVersionNumberBytes.Length)
                        {
                            if ((byte)BeforeVersionNumberBytes[totalBytesParsed - initialBytesParsed + bytesParsed] != byteBuffer[bytesParsed])
                            {
                                parseStatus = DataParseStatus.Invalid;
                                goto quit;
                            }

                            if(++bytesParsed == effectiveMax)
                                goto quit;
                        }

                        // When entering the MajorVersionNumber phase, make sure at least one digit is present.
                        if (byteBuffer[bytesParsed] == '.')
                        {
                            parseStatus = DataParseStatus.Invalid;
                            goto quit;
                        }

                        statusState = MajorVersionNumber;
                        goto case MajorVersionNumber;

                    case MajorVersionNumber:
                        while (byteBuffer[bytesParsed] != '.')
                        {
                            if (byteBuffer[bytesParsed] < '0' || byteBuffer[bytesParsed] > '9')
                            {
                                parseStatus = DataParseStatus.Invalid;
                                goto quit;
                            }

                            statusLineValues.MajorVersion = statusLineValues.MajorVersion * 10 + byteBuffer[bytesParsed] - '0';

                            if (++bytesParsed == effectiveMax)
                                goto quit;
                        }

                        // Need visibility past the dot.
                        if (bytesParsed + 1 == effectiveMax)
                            goto quit;
                        bytesParsed++;

                        // When entering the MinorVersionNumber phase, make sure at least one digit is present.
                        if (byteBuffer[bytesParsed] == ' ')
                        {
                            parseStatus = DataParseStatus.Invalid;
                            goto quit;
                        }

                        statusState = MinorVersionNumber;
                        goto case MinorVersionNumber;

                    case MinorVersionNumber:
                        // Only a single SP character is allowed to delimit fields in the status line.
                        while (byteBuffer[bytesParsed] != ' ')
                        {
                            if (byteBuffer[bytesParsed] < '0' || byteBuffer[bytesParsed] > '9')
                            {
                                parseStatus = DataParseStatus.Invalid;
                                goto quit;
                            }

                            statusLineValues.MinorVersion = statusLineValues.MinorVersion * 10 + byteBuffer[bytesParsed] - '0';

                            if (++bytesParsed == effectiveMax)
                                goto quit;
                        }

                        statusState = StatusCodeNumber;

                        // Start the status code out as "1".  This will effectively add 1000 to the code.  It's used to count
                        // the number of digits to make sure it's three.  At the end, subtract 1000.
                        statusLineValues.StatusCode = 1;

                        // Move past the space.
                        if (++bytesParsed == effectiveMax)
                            goto quit;

                        goto case StatusCodeNumber;

                    case StatusCodeNumber:
                        // RFC2616 says codes with an unrecognized first digit
                        // should be rejected.  We're allowing the application to define their own "understanding" of
                        // 0, 6, 7, 8, and 9xx codes.
                        while (byteBuffer[bytesParsed] >= '0' && byteBuffer[bytesParsed] <= '9')
                        {
                            // Make sure it isn't too big.  The leading '1' will be removed after three digits are read.
                            if (statusLineValues.StatusCode >= 1000)
                            {
                                parseStatus = DataParseStatus.Invalid;
                                goto quit;
                            }

                            statusLineValues.StatusCode = statusLineValues.StatusCode * 10 + byteBuffer[bytesParsed] - '0';

                            if (++bytesParsed == effectiveMax)
                                goto quit;
                        }

                        // Make sure there was enough, and exactly one space.
                        if (byteBuffer[bytesParsed] != ' ' || statusLineValues.StatusCode < 1000)
                        {
                            if(byteBuffer[bytesParsed] == '\r' && statusLineValues.StatusCode >= 1000){
                                statusLineValues.StatusCode -= 1000;
                                statusState = AfterCarriageReturn;
                                if (++bytesParsed == effectiveMax)
                                    goto quit;
                                goto case AfterCarriageReturn;
                            }
                            parseStatus = DataParseStatus.Invalid;
                            goto quit;
                        }

                        // Remove the extra leading 1.
                        statusLineValues.StatusCode -= 1000;

                        statusState = AfterStatusCode;

                        // Move past the space.
                        if (++bytesParsed == effectiveMax)
                            goto quit;

                        goto case AfterStatusCode;

                    case AfterStatusCode:
                    {
                        // Check for shortcuts.
                        if (statusLineValues.StatusDescription == null)
                        {
                            foreach (string s in s_ShortcutStatusDescriptions)
                            {
                                if (bytesParsed < effectiveMax - s.Length && byteBuffer[bytesParsed] == (byte) s[0])
                                {
                                    int i;
                                    byte *pBuffer = byteBuffer + bytesParsed + 1;
                                    for(i = 1; i < s.Length; i++)
                                        if (*(pBuffer++) != (byte) s[i])
                                            break;
                                    if (i == s.Length)
                                    {
                                        statusLineValues.StatusDescription = s;
                                        bytesParsed += s.Length;
                                    }
                                    break;
                                }
                            }
                        }

                        int beginning = bytesParsed;

                        while (byteBuffer[bytesParsed] != '\r')
                        {
                            if (byteBuffer[bytesParsed] < ' ' || byteBuffer[bytesParsed] == 127)
                            {
                                parseStatus = DataParseStatus.Invalid;
                                goto quit;
                            }

                            if (++bytesParsed == effectiveMax)
                            {
                                string s = WebHeaderCollection.HeaderEncoding.GetString(byteBuffer + beginning, bytesParsed - beginning);
                                if (statusLineValues.StatusDescription == null)
                                    statusLineValues.StatusDescription = s;
                                else
                                    statusLineValues.StatusDescription += s;

                                goto quit;
                            }
                        }

                        if (bytesParsed > beginning)
                        {
                            string s = WebHeaderCollection.HeaderEncoding.GetString(byteBuffer + beginning, bytesParsed - beginning);
                            if (statusLineValues.StatusDescription == null)
                                statusLineValues.StatusDescription = s;
                            else
                                statusLineValues.StatusDescription += s;
                        }
                        else if (statusLineValues.StatusDescription == null)
                        {
                            statusLineValues.StatusDescription = "";
                        }

                        statusState = AfterCarriageReturn;

                        // Move past the CR.
                        if (++bytesParsed == effectiveMax)
                            goto quit;

                        goto case AfterCarriageReturn;
                    }

                    case AfterCarriageReturn:
                        if (byteBuffer[bytesParsed] != '\n')
                        {
                            parseStatus = DataParseStatus.Invalid;
                            goto quit;
                        }

                        parseStatus = DataParseStatus.Done;
                        bytesParsed++;
                        break;
                }
            }

quit:
            totalBytesParsed += bytesParsed - initialBytesParsed;

            GlobalLog.Print("Connection::ParseStatusLineStrict() StatusCode:" + statusLineValues.StatusCode + " MajorVersionNumber:" + statusLineValues.MajorVersion + " MinorVersionNumber:" + statusLineValues.MinorVersion + " StatusDescription:" + ValidationHelper.ToString(statusLineValues.StatusDescription));
            GlobalLog.Leave("Connection::ParseStatusLineStrict", parseStatus.ToString());

            if (parseStatus == DataParseStatus.Invalid) {
                parseError.Section = WebParseErrorSection.ResponseStatusLine;
                parseError.Code = WebParseErrorCode.Generic;
            }

            return parseStatus;
        }
Пример #3
0
        // ParseHeaders -
        // Routine Description:
        //
        //     This code is optimized for the case in which all the headers fit in the buffer.
        //     we support multiple re-entrance, but we won't save intermediate
        //     state, we will just roll back all the parsing done for the current header if we can't
        //     parse a whole one (including multiline) or decide something else ("invalid data" or "done parsing").
        //
        //     we're going to cycle through the loop until we
        //
        //     1) find an HTTP violation (in this case we return DataParseStatus.Invalid)
        //     2) we need more data (in this case we return DataParseStatus.NeedMoreData)
        //     3) we found the end of the headers and the beginning of the entity body (in this case we return DataParseStatus.Done)
        //
        //
        // Arguments:
        //
        //     buffer      - buffer containing the data to be parsed
        //     size        - size of the buffer
        //     unparsed    - offset of data yet to be parsed
        //
        // Return Value:
        //
        //     DataParseStatus - status of parsing
        //
        // Revision:
        //
        //     02/13/2001 rewrote the method from scratch.
        //
        // BreakPoint:
        //
        //     b system.dll!System.Net.WebHeaderCollection::ParseHeaders
        internal unsafe DataParseStatus ParseHeaders(
                byte[] buffer, 
                int size, 
                ref int unparsed, 
                ref int totalResponseHeadersLength, 
                int maximumResponseHeadersLength, 
                ref WebParseError parseError) {

            fixed (byte * byteBuffer = buffer) {

            char ch;

            // quick check in the boundaries (as we use unsafe pointer)
            if (buffer.Length < size) {
                return DataParseStatus.NeedMoreData;
            }

            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;

            WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic;
            DataParseStatus parseStatus = DataParseStatus.Invalid;
#if TRAVE
            GlobalLog.Enter("WebHeaderCollection::ParseHeaders(): ANSI size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size-unparsed)) + "]");
#endif

            //
            // 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) {
                         ch = (char) byteBuffer[index];
                         if (ch == ' ' || ch == '\t') {
                             ++index;
                            if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                                parseStatus = DataParseStatus.DataTooBig;
                                goto quit;
                            }
                        }
                        else {
                            break;
                        }
                    }

                    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) {
                    ch = (char) byteBuffer[index];
                    if (ch != ':' && ch != '\n') {
                        if (ch > ' ') {
                            //
                            // if there'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;
                        }
                    }
                    else {
                        if (ch == ':') {
                            ++index;
                            if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                                parseStatus = DataParseStatus.DataTooBig;
                                goto quit;
                            }
                        }
                        break;
                    }
                }
                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) {
                    ch = (char) byteBuffer[index];
                    if (ch <= ' ') {
                        if (ch=='\n') {
                            numberOfLf++;
                            // In this case, need to check for a space.
                            if (numberOfLf == 1)
                            {
                                if (index + 1 == size)
                                {
                                    //
                                    // we reached the end of the buffer. ask for more data.
                                    // need to be able to peek after the \n and see if there's some space.
                                    //
                                    parseStatus = DataParseStatus.NeedMoreData;
                                    goto quit;
                                }
                                spaceAfterLf = (char) byteBuffer[index + 1] == ' ' || (char) byteBuffer[index + 1] == '\t';
                            }
                        }
                        ++index;
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit;
                        }
                    }
                    else {
                        break;
                    }
                }
                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) {
                    ch = (char) byteBuffer[index];
                    if (ch != '\n') {
                        if (ch > ' ') {
                            headerValueEndOffset = index;
                        }
                        ++index;
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit;
                        }
                    }
                    else {
                        break;
                    }
                }
                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) {
                    ch = (char) byteBuffer[index];
                    if (ch =='\r' || ch == '\n') {
                        if (ch == '\n') {
                            numberOfLf++;
                        }
                        ++index;
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit;
                        }
                    }
                    else {
                        break;
                    }
                }
                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(byteBuffer + 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) {
                    ch = (char) byteBuffer[index];
                    if (ch == ' ' || ch == '\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(byteBuffer + 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 AddInternal() key:[" + headerName + "], value:[" + headerMultiLineValue + "]");
                    AddInternal(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());
            if (parseStatus == DataParseStatus.Invalid) {
                parseError.Section = WebParseErrorSection.ResponseHeader; 
                parseError.Code    = parseErrorCode;
            }

            return parseStatus;
            }
        }
Пример #4
0
        private DataParseStatus ParseStatusLine(
                byte [] statusLine,
                int statusLineLength,
                ref int bytesParsed,
                ref int [] statusLineInts,
                ref string statusDescription,
                ref int statusState,
                ref WebParseError parseError) {
            GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ParseStatusLine", statusLineLength.ToString(NumberFormatInfo.InvariantInfo) + ", " + bytesParsed.ToString(NumberFormatInfo.InvariantInfo) +", " +statusState.ToString(NumberFormatInfo.InvariantInfo));
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection#" + ValidationHelper.HashString(this) + "::ParseStatusLine");
            GlobalLog.Assert((statusLineLength - bytesParsed) >= 0, "Connection#{0}::ParseStatusLine()|(statusLineLength - bytesParsed) < 0", ValidationHelper.HashString(this));
            //GlobalLog.Dump(statusLine, bytesParsed, statusLineLength);

            DataParseStatus parseStatus = DataParseStatus.Done;
            int statusLineSize = 0;
            int startIndexStatusDescription = -1;
            int lastUnSpaceIndex = 0;

            //
            // While walking the Status Line looking for terminating \r\n,
            //   we extract the Major.Minor Versions and Status Code in that order.
            //   text and spaces will lie between/before/after the three numbers
            //   but the idea is to remember which number we're calculating based on a numeric state
            //   If all goes well the loop will churn out an array with the 3 numbers plugged in as DWORDs
            //

            while ((bytesParsed < statusLineLength) && (statusLine[bytesParsed] != '\r') && (statusLine[bytesParsed] != '\n')) {

                // below should be wrapped in while (response[i] != ' ') to be more robust???
                switch (statusState) {
                    case BeforeVersionNumbers:
                        if (statusLine[bytesParsed] == '/') {
                            //INET_ASSERT(statusState == BeforeVersionNumbers);
                            statusState++; // = MajorVersionNumber
                        }
                        else if (statusLine[bytesParsed] == ' ') {
                            statusState = StatusCodeNumber;
                        }

                        break;

                    case MajorVersionNumber:

                        if (statusLine[bytesParsed] == '.') {
                            //INET_ASSERT(statusState == MajorVersionNumber);
                            statusState++; // = MinorVersionNumber
                            break;
                        }
                        // fall through
                        goto case MinorVersionNumber;

                    case MinorVersionNumber:

                        if (statusLine[bytesParsed] == ' ') {
                            //INET_ASSERT(statusState == MinorVersionNumber);
                            statusState++; // = StatusCodeNumber
                            break;
                        }
                        // fall through
                        goto case StatusCodeNumber;

                    case StatusCodeNumber:

                        if (Char.IsDigit((char)statusLine[bytesParsed])) {
                            int val = statusLine[bytesParsed] - '0';
                            statusLineInts[statusState] = statusLineInts[statusState] * 10 + val;
                        }
                        else if (statusLineInts[StatusCodeNumber] > 0) {
                            //
                            // we eat spaces before status code is found,
                            //  once we have the status code we can go on to the next
                            //  state on the next non-digit. This is done
                            //  to cover cases with several spaces between version
                            //  and the status code number.
                            //

                            statusState++; // = AfterStatusCode
                            break;
                        }
                        else if (!Char.IsWhiteSpace((char) statusLine[bytesParsed])) {
                            statusLineInts[statusState] = (int)-1;
                        }

                        break;

                    case AfterStatusCode:
                        if (statusLine[bytesParsed] != ' ') {
                            lastUnSpaceIndex = bytesParsed;
                            if (startIndexStatusDescription == -1) {
                                startIndexStatusDescription = bytesParsed;
                            }
                        }
                        break;

                }
                ++bytesParsed;
                if (m_MaximumResponseHeadersLength>=0 && ++m_TotalResponseHeadersLength>=m_MaximumResponseHeadersLength) {
                    parseStatus = DataParseStatus.DataTooBig;
                    goto quit;
                }
            }

            statusLineSize = bytesParsed;

            // add to Description if already partialy parsed
            if (startIndexStatusDescription != -1) {
                statusDescription +=
                    WebHeaderCollection.HeaderEncoding.GetString(
                        statusLine,
                        startIndexStatusDescription,
                        lastUnSpaceIndex - startIndexStatusDescription + 1 );
            }

            if (bytesParsed == statusLineLength) {
                //
                // response now points one past the end of the buffer. We may be looking
                // over the edge...
                //
                // if we're at the end of the connection then the server sent us an
                // incorrectly formatted response. Probably an error.
                //
                // Otherwise its a partial response. We need more
                //
                parseStatus = DataParseStatus.NeedMoreData;
                //
                // if we really hit the end of the response then update the amount of
                // headers scanned
                //
                GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStatusLine", parseStatus.ToString());
                return parseStatus;
            }

            while ((bytesParsed < statusLineLength)
                   && ((statusLine[bytesParsed] == '\r') || (statusLine[bytesParsed] == ' '))) {
                ++bytesParsed;
                if (m_MaximumResponseHeadersLength>=0 && ++m_TotalResponseHeadersLength>=m_MaximumResponseHeadersLength) {
                    parseStatus = DataParseStatus.DataTooBig;
                    goto quit;
                }
            }

            if (bytesParsed == statusLineLength) {

                //
                // hit end of buffer without finding LF
                //

                parseStatus = DataParseStatus.NeedMoreData;
                goto quit;

            }
            else if (statusLine[bytesParsed] == '\n') {
                ++bytesParsed;
                if (m_MaximumResponseHeadersLength>=0 && ++m_TotalResponseHeadersLength>=m_MaximumResponseHeadersLength) {
                    parseStatus = DataParseStatus.DataTooBig;
                    goto quit;
                }
                //
                // if we found the empty line then we are done
                //
                parseStatus = DataParseStatus.Done;
            }


            //
            // Now we have our parsed header to add to the array
            //

quit:
            if (parseStatus == DataParseStatus.Done && statusState != AfterStatusCode) {
                // need to handle the case where we parse the StatusCode,
                //  but didn't get a status Line, and there was no space afer it.
                if (statusState != StatusCodeNumber || statusLineInts[StatusCodeNumber] <= 0) {
                    //
                    // we're done with the status line, if we didn't parse all the
                    // numbers needed this is invalid protocol on the server
                    //
                    parseStatus = DataParseStatus.Invalid;
                }
            }

            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseStatusLine() StatusCode:" + statusLineInts[StatusCodeNumber] + " MajorVersionNumber:" + statusLineInts[MajorVersionNumber] + " MinorVersionNumber:" + statusLineInts[MinorVersionNumber] + " StatusDescription:" + ValidationHelper.ToString(statusDescription));
            GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStatusLine", parseStatus.ToString());

            if (parseStatus == DataParseStatus.Invalid) {
                parseError.Section = WebParseErrorSection.ResponseStatusLine;
                parseError.Code = WebParseErrorCode.Generic;
            }

            return parseStatus;
        }
        private static unsafe DataParseStatus ParseStatusLineStrict(byte[] statusLine, int statusLineLength, ref int bytesParsed, ref int statusState, StatusLineValues statusLineValues, int maximumHeaderLength, ref int totalBytesParsed, ref WebParseError parseError)
        {
            int num = bytesParsed;
            DataParseStatus dataTooBig = DataParseStatus.DataTooBig;
            int num2 = (maximumHeaderLength <= 0) ? 0x7fffffff : ((maximumHeaderLength - totalBytesParsed) + bytesParsed);
            if (statusLineLength < num2)
            {
                dataTooBig = DataParseStatus.NeedMoreData;
                num2 = statusLineLength;
            }
            if (bytesParsed < num2)
            {
                try
                {
                    fixed (byte* numRef = statusLine)
                    {
                        switch (statusState)
                        {
                            case 0:
                                goto Label_00A2;

                            case 1:
                                goto Label_0115;

                            case 2:
                                goto Label_0190;

                            case 3:
                                goto Label_01FB;

                            case 4:
                                goto Label_029B;

                            case 5:
                                goto Label_0423;

                            default:
                                goto Label_043F;
                        }
                    Label_006D:
                        if (((byte) "HTTP/"[(totalBytesParsed - num) + bytesParsed]) != numRef[bytesParsed])
                        {
                            dataTooBig = DataParseStatus.Invalid;
                            goto Label_043F;
                        }
                        if (++bytesParsed == num2)
                        {
                            goto Label_043F;
                        }
                    Label_00A2:
                        if (((totalBytesParsed - num) + bytesParsed) < "HTTP/".Length)
                        {
                            goto Label_006D;
                        }
                        if (numRef[bytesParsed] == 0x2e)
                        {
                            dataTooBig = DataParseStatus.Invalid;
                            goto Label_043F;
                        }
                        statusState = 1;
                    Label_0115:
                        while (numRef[bytesParsed] != 0x2e)
                        {
                            if ((numRef[bytesParsed] < 0x30) || (numRef[bytesParsed] > 0x39))
                            {
                                dataTooBig = DataParseStatus.Invalid;
                                goto Label_043F;
                            }
                            statusLineValues.MajorVersion = ((statusLineValues.MajorVersion * 10) + numRef[bytesParsed]) - 0x30;
                            if (++bytesParsed == num2)
                            {
                                goto Label_043F;
                            }
                        }
                        if ((bytesParsed + 1) == num2)
                        {
                            goto Label_043F;
                        }
                        bytesParsed++;
                        if (numRef[bytesParsed] == 0x20)
                        {
                            dataTooBig = DataParseStatus.Invalid;
                            goto Label_043F;
                        }
                        statusState = 2;
                    Label_0190:
                        while (numRef[bytesParsed] != 0x20)
                        {
                            if ((numRef[bytesParsed] < 0x30) || (numRef[bytesParsed] > 0x39))
                            {
                                dataTooBig = DataParseStatus.Invalid;
                                goto Label_043F;
                            }
                            statusLineValues.MinorVersion = ((statusLineValues.MinorVersion * 10) + numRef[bytesParsed]) - 0x30;
                            if (++bytesParsed == num2)
                            {
                                goto Label_043F;
                            }
                        }
                        statusState = 3;
                        statusLineValues.StatusCode = 1;
                        if (++bytesParsed != num2)
                        {
                            goto Label_01FB;
                        }
                        goto Label_043F;
                    Label_01B8:
                        if (statusLineValues.StatusCode >= 0x3e8)
                        {
                            dataTooBig = DataParseStatus.Invalid;
                            goto Label_043F;
                        }
                        statusLineValues.StatusCode = ((statusLineValues.StatusCode * 10) + numRef[bytesParsed]) - 0x30;
                        if (++bytesParsed == num2)
                        {
                            goto Label_043F;
                        }
                    Label_01FB:
                        if ((numRef[bytesParsed] >= 0x30) && (numRef[bytesParsed] <= 0x39))
                        {
                            goto Label_01B8;
                        }
                        if ((numRef[bytesParsed] != 0x20) || (statusLineValues.StatusCode < 0x3e8))
                        {
                            if ((numRef[bytesParsed] == 13) && (statusLineValues.StatusCode >= 0x3e8))
                            {
                                statusLineValues.StatusCode -= 0x3e8;
                                statusState = 5;
                                if (++bytesParsed != num2)
                                {
                                    goto Label_0423;
                                }
                            }
                            else
                            {
                                dataTooBig = DataParseStatus.Invalid;
                            }
                            goto Label_043F;
                        }
                        statusLineValues.StatusCode -= 0x3e8;
                        statusState = 4;
                        if (++bytesParsed == num2)
                        {
                            goto Label_043F;
                        }
                    Label_029B:
                        if (statusLineValues.StatusDescription == null)
                        {
                            foreach (string str in s_ShortcutStatusDescriptions)
                            {
                                if ((bytesParsed >= (num2 - str.Length)) || (numRef[bytesParsed] != ((byte) str[0])))
                                {
                                    continue;
                                }
                                byte* numPtr = (numRef + bytesParsed) + 1;
                                int num3 = 1;
                                while (num3 < str.Length)
                                {
                                    numPtr++;
                                    if (numPtr[0] != ((byte) str[num3]))
                                    {
                                        break;
                                    }
                                    num3++;
                                }
                                if (num3 == str.Length)
                                {
                                    statusLineValues.StatusDescription = str;
                                    bytesParsed += str.Length;
                                }
                                break;
                            }
                        }
                        int num4 = bytesParsed;
                        while (numRef[bytesParsed] != 13)
                        {
                            if ((numRef[bytesParsed] < 0x20) || (numRef[bytesParsed] == 0x7f))
                            {
                                dataTooBig = DataParseStatus.Invalid;
                                goto Label_043F;
                            }
                            if (++bytesParsed == num2)
                            {
                                string str2 = WebHeaderCollection.HeaderEncoding.GetString(numRef + num4, bytesParsed - num4);
                                if (statusLineValues.StatusDescription == null)
                                {
                                    statusLineValues.StatusDescription = str2;
                                }
                                else
                                {
                                    statusLineValues.StatusDescription = statusLineValues.StatusDescription + str2;
                                }
                                goto Label_043F;
                            }
                        }
                        if (bytesParsed > num4)
                        {
                            string str3 = WebHeaderCollection.HeaderEncoding.GetString(numRef + num4, bytesParsed - num4);
                            if (statusLineValues.StatusDescription == null)
                            {
                                statusLineValues.StatusDescription = str3;
                            }
                            else
                            {
                                statusLineValues.StatusDescription = statusLineValues.StatusDescription + str3;
                            }
                        }
                        else if (statusLineValues.StatusDescription == null)
                        {
                            statusLineValues.StatusDescription = "";
                        }
                        statusState = 5;
                        if (++bytesParsed == num2)
                        {
                            goto Label_043F;
                        }
                    Label_0423:
                        if (numRef[bytesParsed] != 10)
                        {
                            dataTooBig = DataParseStatus.Invalid;
                        }
                        else
                        {
                            dataTooBig = DataParseStatus.Done;
                            bytesParsed++;
                        }
                    }
                }
                finally
                {
                    numRef = null;
                }
            }
        Label_043F:
            totalBytesParsed += bytesParsed - num;
            if (dataTooBig == DataParseStatus.Invalid)
            {
                parseError.Section = WebParseErrorSection.ResponseStatusLine;
                parseError.Code = WebParseErrorCode.Generic;
            }
            return dataTooBig;
        }
        private DataParseStatus ParseStatusLine(byte[] statusLine, int statusLineLength, ref int bytesParsed, ref int[] statusLineInts, ref string statusDescription, ref int statusState, ref WebParseError parseError)
        {
            DataParseStatus done = DataParseStatus.Done;
            int byteIndex = -1;
            int num2 = 0;
            while (((bytesParsed < statusLineLength) && (statusLine[bytesParsed] != 13)) && (statusLine[bytesParsed] != 10))
            {
                switch (statusState)
                {
                    case 0:
                        if (statusLine[bytesParsed] != 0x2f)
                        {
                            break;
                        }
                        statusState++;
                        goto Label_00DA;

                    case 1:
                        if (statusLine[bytesParsed] != 0x2e)
                        {
                            goto Label_0069;
                        }
                        statusState++;
                        goto Label_00DA;

                    case 2:
                        goto Label_0069;

                    case 3:
                        goto Label_007A;

                    case 4:
                        if (statusLine[bytesParsed] != 0x20)
                        {
                            num2 = bytesParsed;
                            if (byteIndex == -1)
                            {
                                byteIndex = bytesParsed;
                            }
                        }
                        goto Label_00DA;

                    default:
                        goto Label_00DA;
                }
                if (statusLine[bytesParsed] == 0x20)
                {
                    statusState = 3;
                }
                goto Label_00DA;
            Label_0069:
                if (statusLine[bytesParsed] == 0x20)
                {
                    statusState++;
                    goto Label_00DA;
                }
            Label_007A:
                if (char.IsDigit((char) statusLine[bytesParsed]))
                {
                    int num3 = statusLine[bytesParsed] - 0x30;
                    statusLineInts[statusState] = (statusLineInts[statusState] * 10) + num3;
                }
                else if (statusLineInts[3] > 0)
                {
                    statusState++;
                }
                else if (!char.IsWhiteSpace((char) statusLine[bytesParsed]))
                {
                    statusLineInts[statusState] = -1;
                }
            Label_00DA:
                bytesParsed++;
                if ((this.m_MaximumResponseHeadersLength >= 0) && (++this.m_TotalResponseHeadersLength >= this.m_MaximumResponseHeadersLength))
                {
                    done = DataParseStatus.DataTooBig;
                    goto Label_01CA;
                }
            }
            if (byteIndex != -1)
            {
                statusDescription = statusDescription + WebHeaderCollection.HeaderEncoding.GetString(statusLine, byteIndex, (num2 - byteIndex) + 1);
            }
            if (bytesParsed != statusLineLength)
            {
                while ((bytesParsed < statusLineLength) && ((statusLine[bytesParsed] == 13) || (statusLine[bytesParsed] == 0x20)))
                {
                    bytesParsed++;
                    if ((this.m_MaximumResponseHeadersLength >= 0) && (++this.m_TotalResponseHeadersLength >= this.m_MaximumResponseHeadersLength))
                    {
                        done = DataParseStatus.DataTooBig;
                        goto Label_01CA;
                    }
                }
                if (bytesParsed == statusLineLength)
                {
                    done = DataParseStatus.NeedMoreData;
                }
                else if (statusLine[bytesParsed] == 10)
                {
                    bytesParsed++;
                    if ((this.m_MaximumResponseHeadersLength >= 0) && (++this.m_TotalResponseHeadersLength >= this.m_MaximumResponseHeadersLength))
                    {
                        done = DataParseStatus.DataTooBig;
                    }
                    else
                    {
                        done = DataParseStatus.Done;
                    }
                }
            }
            else
            {
                return DataParseStatus.NeedMoreData;
            }
        Label_01CA:
            if (((done == DataParseStatus.Done) && (statusState != 4)) && ((statusState != 3) || (statusLineInts[3] <= 0)))
            {
                done = DataParseStatus.Invalid;
            }
            if (done == DataParseStatus.Invalid)
            {
                parseError.Section = WebParseErrorSection.ResponseStatusLine;
                parseError.Code = WebParseErrorCode.Generic;
            }
            return done;
        }
        internal unsafe DataParseStatus ParseHeadersStrict(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength, ref WebParseError parseError)
        {
            WebParseErrorCode generic = WebParseErrorCode.Generic;
            DataParseStatus invalid = DataParseStatus.Invalid;
            int index = unparsed;
            int num2 = (maximumResponseHeadersLength <= 0) ? 0x7fffffff : ((maximumResponseHeadersLength - totalResponseHeadersLength) + index);
            DataParseStatus dataTooBig = DataParseStatus.DataTooBig;
            if (size < num2)
            {
                num2 = size;
                dataTooBig = DataParseStatus.NeedMoreData;
            }
            if (index >= num2)
            {
                invalid = dataTooBig;
            }
            else
            {
                try
                {
                    byte[] buffer2;
                    if (((buffer2 = buffer) == null) || (buffer2.Length == 0))
                    {
                        numRef = null;
                        goto Label_0054;
                    }
                    fixed (byte* numRef = buffer2)
                    {
                        RfcChar ch;
                        string str4;
                    Label_0054:
                        if (numRef[index] == 13)
                        {
                            if (++index == num2)
                            {
                                invalid = dataTooBig;
                            }
                            else if (numRef[index++] == 10)
                            {
                                totalResponseHeadersLength += index - unparsed;
                                unparsed = index;
                                invalid = DataParseStatus.Done;
                            }
                            else
                            {
                                invalid = DataParseStatus.Invalid;
                                generic = WebParseErrorCode.CrLfError;
                            }
                            goto Label_042C;
                        }
                        int num3 = index;
                        while ((index < num2) && ((ch = (numRef[index] > 0x7f) ? RfcChar.High : RfcCharMap[numRef[index]]) == RfcChar.Reg))
                        {
                            index++;
                        }
                        if (index == num2)
                        {
                            invalid = dataTooBig;
                            goto Label_042C;
                        }
                        if (index == num3)
                        {
                            invalid = DataParseStatus.Invalid;
                            generic = WebParseErrorCode.InvalidHeaderName;
                            goto Label_042C;
                        }
                        int num4 = index - 1;
                        int num5 = 0;
                        while ((index < num2) && ((ch = (numRef[index] > 0x7f) ? RfcChar.High : RfcCharMap[numRef[index]]) != RfcChar.Colon))
                        {
                            switch (ch)
                            {
                                case RfcChar.CR:
                                    if (num5 != 0)
                                    {
                                        break;
                                    }
                                    num5 = 1;
                                    goto Label_012B;

                                case RfcChar.LF:
                                    if (num5 != 1)
                                    {
                                        break;
                                    }
                                    num5 = 2;
                                    goto Label_012B;

                                case RfcChar.WS:
                                    if (num5 == 1)
                                    {
                                        break;
                                    }
                                    num5 = 0;
                                    goto Label_012B;
                            }
                            invalid = DataParseStatus.Invalid;
                            generic = WebParseErrorCode.CrLfError;
                            goto Label_042C;
                        Label_012B:
                            index++;
                        }
                        if (index == num2)
                        {
                            invalid = dataTooBig;
                            goto Label_042C;
                        }
                        if (num5 != 0)
                        {
                            invalid = DataParseStatus.Invalid;
                            generic = WebParseErrorCode.IncompleteHeaderLine;
                            goto Label_042C;
                        }
                        if (++index == num2)
                        {
                            invalid = dataTooBig;
                            goto Label_042C;
                        }
                        int num6 = -1;
                        int num7 = -1;
                        StringBuilder builder = null;
                        while ((index < num2) && (((ch = (numRef[index] > 0x7f) ? RfcChar.High : RfcCharMap[numRef[index]]) == RfcChar.WS) || (num5 != 2)))
                        {
                            string str;
                            switch (ch)
                            {
                                case RfcChar.High:
                                case RfcChar.Reg:
                                case RfcChar.Colon:
                                case RfcChar.Delim:
                                    if (num5 == 1)
                                    {
                                        break;
                                    }
                                    if (num5 != 3)
                                    {
                                        goto Label_023D;
                                    }
                                    num5 = 0;
                                    if (num6 != -1)
                                    {
                                        str = HeaderEncoding.GetString(numRef + num6, (num7 - num6) + 1);
                                        if (builder != null)
                                        {
                                            goto Label_0223;
                                        }
                                        builder = new StringBuilder(str, str.Length * 5);
                                    }
                                    goto Label_023A;

                                case RfcChar.CR:
                                    if (num5 != 0)
                                    {
                                        break;
                                    }
                                    num5 = 1;
                                    goto Label_0253;

                                case RfcChar.LF:
                                    if (num5 != 1)
                                    {
                                        break;
                                    }
                                    num5 = 2;
                                    goto Label_0253;

                                case RfcChar.WS:
                                    switch (num5)
                                    {
                                        case 1:
                                            goto Label_024A;

                                        case 2:
                                            num5 = 3;
                                            break;
                                    }
                                    goto Label_0253;
                            }
                            goto Label_024A;
                        Label_0223:
                            builder.Append(" ");
                            builder.Append(str);
                        Label_023A:
                            num6 = -1;
                        Label_023D:
                            if (num6 == -1)
                            {
                                num6 = index;
                            }
                            num7 = index;
                            goto Label_0253;
                        Label_024A:
                            invalid = DataParseStatus.Invalid;
                            generic = WebParseErrorCode.CrLfError;
                            goto Label_042C;
                        Label_0253:
                            index++;
                        }
                        if (index == num2)
                        {
                            invalid = dataTooBig;
                            goto Label_042C;
                        }
                        string str2 = (num6 == -1) ? "" : HeaderEncoding.GetString(numRef + num6, (num7 - num6) + 1);
                        if (builder != null)
                        {
                            if (str2.Length != 0)
                            {
                                builder.Append(" ");
                                builder.Append(str2);
                            }
                            str2 = builder.ToString();
                        }
                        string name = null;
                        int byteCount = (num4 - num3) + 1;
                        if (this.m_CommonHeaders == null)
                        {
                            goto Label_03F8;
                        }
                        int num9 = s_CommonHeaderHints[numRef[num3] & 0x1f];
                        if (num9 < 0)
                        {
                            goto Label_03F8;
                        }
                    Label_0310:
                        str4 = s_CommonHeaderNames[num9++];
                        if ((str4.Length >= byteCount) && (CaseInsensitiveAscii.AsciiToLower[numRef[num3]] == CaseInsensitiveAscii.AsciiToLower[str4[0]]))
                        {
                            if (str4.Length > byteCount)
                            {
                                goto Label_0310;
                            }
                            byte* numPtr = (numRef + num3) + 1;
                            int num10 = 1;
                            while (num10 < str4.Length)
                            {
                                numPtr++;
                                if ((numPtr[0] != str4[num10]) && (CaseInsensitiveAscii.AsciiToLower[*(numPtr - 1)] != CaseInsensitiveAscii.AsciiToLower[str4[num10]]))
                                {
                                    break;
                                }
                                num10++;
                            }
                            if (num10 != str4.Length)
                            {
                                goto Label_0310;
                            }
                            this.m_NumCommonHeaders++;
                            num9--;
                            if (this.m_CommonHeaders[num9] == null)
                            {
                                this.m_CommonHeaders[num9] = str2;
                            }
                            else
                            {
                                this.NormalizeCommonHeaders();
                                this.AddInternalNotCommon(str4, str2);
                            }
                            name = str4;
                        }
                    Label_03F8:
                        if (name == null)
                        {
                            name = HeaderEncoding.GetString(numRef + num3, byteCount);
                            this.AddInternalNotCommon(name, str2);
                        }
                        totalResponseHeadersLength += index - unparsed;
                        unparsed = index;
                        goto Label_0054;
                    }
                }
                finally
                {
                    numRef = null;
                }
            }
        Label_042C:
            if (invalid == DataParseStatus.Invalid)
            {
                parseError.Section = WebParseErrorSection.ResponseHeader;
                parseError.Code = generic;
            }
            return invalid;
        }
 internal unsafe DataParseStatus ParseHeaders(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength, ref WebParseError parseError)
 {
     DataParseStatus status2;
     try
     {
         byte[] buffer2;
         if (((buffer2 = buffer) == null) || (buffer2.Length == 0))
         {
             numRef = null;
             goto Label_001A;
         }
         fixed (byte* numRef = buffer2)
         {
             char ch;
             string str2;
         Label_001A:
             if (buffer.Length < size)
             {
                 return DataParseStatus.NeedMoreData;
             }
             int num = -1;
             int num2 = -1;
             int num3 = -1;
             int num4 = -1;
             int num5 = -1;
             int num6 = unparsed;
             int num7 = totalResponseHeadersLength;
             WebParseErrorCode generic = WebParseErrorCode.Generic;
             DataParseStatus invalid = DataParseStatus.Invalid;
         Label_0044:
             str2 = string.Empty;
             string str3 = string.Empty;
             bool flag = false;
             string str = null;
             if (this.Count == 0)
             {
                 while (num6 < size)
                 {
                     ch = *((char*) (numRef + num6));
                     if ((ch != ' ') && (ch != '\t'))
                     {
                         break;
                     }
                     num6++;
                     if ((maximumResponseHeadersLength >= 0) && (++num7 >= maximumResponseHeadersLength))
                     {
                         invalid = DataParseStatus.DataTooBig;
                         goto Label_0316;
                     }
                 }
                 if (num6 == size)
                 {
                     invalid = DataParseStatus.NeedMoreData;
                     goto Label_0316;
                 }
             }
             num = num6;
             while (num6 < size)
             {
                 ch = *((char*) (numRef + num6));
                 if ((ch != ':') && (ch != '\n'))
                 {
                     if (ch > ' ')
                     {
                         num2 = num6;
                     }
                     num6++;
                     if ((maximumResponseHeadersLength < 0) || (++num7 < maximumResponseHeadersLength))
                     {
                         continue;
                     }
                     invalid = DataParseStatus.DataTooBig;
                 }
                 else
                 {
                     if (ch != ':')
                     {
                         break;
                     }
                     num6++;
                     if ((maximumResponseHeadersLength < 0) || (++num7 < maximumResponseHeadersLength))
                     {
                         break;
                     }
                     invalid = DataParseStatus.DataTooBig;
                 }
                 goto Label_0316;
             }
             if (num6 == size)
             {
                 invalid = DataParseStatus.NeedMoreData;
                 goto Label_0316;
             }
         Label_0114:;
             num5 = ((this.Count == 0) && (num2 < 0)) ? 1 : 0;
             while ((num6 < size) && (num5 < 2))
             {
                 ch = *((char*) (numRef + num6));
                 if (ch > ' ')
                 {
                     break;
                 }
                 if (ch == '\n')
                 {
                     num5++;
                     if (num5 == 1)
                     {
                         if ((num6 + 1) == size)
                         {
                             invalid = DataParseStatus.NeedMoreData;
                             goto Label_0316;
                         }
                         flag = (numRef[num6 + 1] == 0x20) || (numRef[num6 + 1] == 9);
                     }
                 }
                 num6++;
                 if ((maximumResponseHeadersLength >= 0) && (++num7 >= maximumResponseHeadersLength))
                 {
                     invalid = DataParseStatus.DataTooBig;
                     goto Label_0316;
                 }
             }
             if ((num5 != 2) && ((num5 != 1) || flag))
             {
                 if (num6 == size)
                 {
                     invalid = DataParseStatus.NeedMoreData;
                     goto Label_0316;
                 }
                 num3 = num6;
                 while (num6 < size)
                 {
                     ch = *((char*) (numRef + num6));
                     if (ch == '\n')
                     {
                         break;
                     }
                     if (ch > ' ')
                     {
                         num4 = num6;
                     }
                     num6++;
                     if ((maximumResponseHeadersLength >= 0) && (++num7 >= maximumResponseHeadersLength))
                     {
                         invalid = DataParseStatus.DataTooBig;
                         goto Label_0316;
                     }
                 }
                 if (num6 == size)
                 {
                     invalid = DataParseStatus.NeedMoreData;
                     goto Label_0316;
                 }
                 num5 = 0;
                 while ((num6 < size) && (num5 < 2))
                 {
                     ch = *((char*) (numRef + num6));
                     if ((ch != '\r') && (ch != '\n'))
                     {
                         break;
                     }
                     if (ch == '\n')
                     {
                         num5++;
                     }
                     num6++;
                     if ((maximumResponseHeadersLength >= 0) && (++num7 >= maximumResponseHeadersLength))
                     {
                         invalid = DataParseStatus.DataTooBig;
                         goto Label_0316;
                     }
                 }
                 if ((num6 == size) && (num5 < 2))
                 {
                     invalid = DataParseStatus.NeedMoreData;
                     goto Label_0316;
                 }
             }
             if (((num3 >= 0) && (num3 > num2)) && (num4 >= num3))
             {
                 str3 = HeaderEncoding.GetString(numRef + num3, (num4 - num3) + 1);
             }
             str = (str == null) ? str3 : (str + " " + str3);
             if ((num6 < size) && (num5 == 1))
             {
                 switch (*(((char*) (numRef + num6))))
                 {
                     case ' ':
                     case '\t':
                         num6++;
                         if ((maximumResponseHeadersLength < 0) || (++num7 < maximumResponseHeadersLength))
                         {
                             goto Label_0114;
                         }
                         invalid = DataParseStatus.DataTooBig;
                         goto Label_0316;
                 }
             }
             if ((num >= 0) && (num2 >= num))
             {
                 str2 = HeaderEncoding.GetString(numRef + num, (num2 - num) + 1);
             }
             if (str2.Length > 0)
             {
                 this.AddInternal(str2, str);
             }
             totalResponseHeadersLength = num7;
             unparsed = num6;
             if (num5 != 2)
             {
                 goto Label_0044;
             }
             invalid = DataParseStatus.Done;
         Label_0316:
             if (invalid == DataParseStatus.Invalid)
             {
                 parseError.Section = WebParseErrorSection.ResponseHeader;
                 parseError.Code = generic;
             }
             status2 = invalid;
         }
     }
     finally
     {
         numRef = null;
     }
     return status2;
 }