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; }
// // 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; }
// 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; } }
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; }