System.Net.Connection.ParseStatusLineStrict C# (CSharp) Method

ParseStatusLineStrict() private static method

private static ParseStatusLineStrict ( byte statusLine, int statusLineLength, int &bytesParsed, int &statusState, StatusLineValues statusLineValues, int maximumHeaderLength, int &totalBytesParsed, WebParseError &parseError ) : DataParseStatus
statusLine byte
statusLineLength int
bytesParsed int
statusState int
statusLineValues StatusLineValues
maximumHeaderLength int
totalBytesParsed int
parseError WebParseError
return DataParseStatus
        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;
        }