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

ParseStatusLine() private method

private ParseStatusLine ( byte statusLine, int statusLineLength, int &bytesParsed, int &statusLineInts, string &statusDescription, int &statusState, WebParseError &parseError ) : DataParseStatus
statusLine byte
statusLineLength int
bytesParsed int
statusLineInts int
statusDescription string
statusState int
parseError WebParseError
return DataParseStatus
        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;
        }