protected virtual void Parse() { int unparsed = 0; DataParseStatus parseStatus = DataParseStatus.Invalid; try { // Step 1. Parse header [1/23/2004] parseStatus = _headers.ParseHeaders(_EMailBinaryData.GetBuffer(), (int)_EMailBinaryData.Length, ref unparsed); if (parseStatus == DataParseStatus.Done) { // Step 2. Parse Messagy Body [1/23/2004] parseStatus = _mimeEntries.ParseMimeEntries(_EMailBinaryData.GetBuffer(), (int)_EMailBinaryData.Length, ref unparsed, this.Headers); } } catch (Exception ex) { throw new Pop3ServerIncorectEMailFormatException("Internal Parser Error", ex); } if (parseStatus != DataParseStatus.Done) { throw new Pop3ServerIncorectEMailFormatException(); } }
private void ParseHeaders(string responseHeaders) { if (string.IsNullOrEmpty(responseHeaders)) { return; } byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseHeaders); WebParseError error = new WebParseError(); int totalResponseHeadersLength = 0; int offset = 0; int maxHeaderLength = 64000; try { DataParseStatus result = this.headers.ParseHeaders(buffer, buffer.Length, ref offset, ref totalResponseHeadersLength, maxHeaderLength, ref error); if (result != DataParseStatus.Done) { throw WebException.CreateInternal("HttpWebResponse.ParseHeaders"); } } catch (WebException) { throw; } catch (Exception e) { string message = System.Data.Services.Client.Strings.HttpWeb_Internal("HttpWebResponse.ParseHeaders.2"); throw new WebException(message, e); } }
private DataParseStatus ParsePayloadEnd() { Contract.Assert(currentChunkBytesRead == currentChunkLength); DataParseStatus crlfResult = ParseCRLF(ref bufferCurrentPos); if (crlfResult != DataParseStatus.ContinueParsing) { return(crlfResult); } currentChunkLength = noChunkLength; currentChunkBytesRead = 0; readState = ReadState.ChunkLength; return(DataParseStatus.ContinueParsing); }
private DataParseStatus ParseExtension() { int currentPos = bufferCurrentPos; // After the chunk length we can only have <space> or <tab> chars. A LWS with CRLF would be ambiguous since // CRLF also delimits the chunk length from chunk data. DataParseStatus result = ParseWhitespaces(ref currentPos); if (result != DataParseStatus.ContinueParsing) { return(result); } result = ParseExtensionNameValuePairs(ref currentPos); if (result != DataParseStatus.ContinueParsing) { return(result); } result = ParseCRLF(ref currentPos); if (result != DataParseStatus.ContinueParsing) { return(result); } bufferCurrentPos = currentPos; if (currentChunkLength == 0) { // zero-chunk read. We're done with the response. Consume trailer and complete. readState = ReadState.Trailer; } else { readState = ReadState.Payload; } return(DataParseStatus.ContinueParsing); }
protected virtual void ParseHeaderAndBody() { DataParseStatus parseStatus = DataParseStatus.Invalid; try { // Step 1. Parse header [1/23/2004] parseStatus = _headers.ParseHeaders(_BinaryData.GetBuffer(), (int)_BinaryData.Length, ref _BodyOffset); if (parseStatus == DataParseStatus.Done) { ParseBody(); } } catch (Exception ex) { throw new Pop3ServerIncorectEMailFormatException("Internal Parser Error: " + ex.Message, ex); } if (parseStatus != DataParseStatus.Done) { throw new Pop3ServerIncorectEMailFormatException(); } }
protected virtual void ParseBody() { string strFullConentType = _headers["Content-Type"]; if (strFullConentType == null) { strFullConentType = ""; } //string strContentTypeValue = null; Hashtable parametrs; MimeEntry.ParseHeader(strFullConentType, out _contentType, out parametrs); // Step 2. Parse Messagy Body [1/23/2004] if (!_contentType.StartsWith("multipart/")) { _charSet = (string)parametrs["charset"]; if (_charSet == null) { _charSet = Encoding.Default.HeaderName; } string ContentEncoding = _headers["Content-Transfer-Encoding"]; if (ContentEncoding == null) { ContentEncoding = "8bit"; } string strDisposition = _headers["Content-Disposition"]; if (strDisposition != null) { Hashtable DispositionParameters; string DispositionType; MimeEntry.ParseHeader(strDisposition, out DispositionType, out DispositionParameters); DispositionType = DispositionType.ToLower(); if (DispositionType == "attachment") { this._disposition = Disposition.Attachment; } else if (DispositionType == "inline") { this._disposition = Disposition.Inline; } _fileName = (string)DispositionParameters["filename"]; if (_fileName != null) { _fileName = Rfc822HeaderCollection.DeocodeHeaderValue(_fileName); } } //string BodyString = Encoding.Default.GetString(this._BinaryData.GetBuffer(),this._BodyOffset,(int)(this._BinaryData.Length - this._BodyOffset)); Encoding encoding = null; try { encoding = Encoding.GetEncoding(CharSet); } catch { encoding = Encoding.Default; } string BodyString = encoding.GetString(this._BinaryData.GetBuffer(), this._BodyOffset, (int)(this._BinaryData.Length - this._BodyOffset)); //string BodyString = Encoding.ASCII.GetString(this._BinaryData.GetBuffer(),this._BodyOffset,(int)(this._BinaryData.Length - this._BodyOffset)); //string BodyString2 = Encoding.UTF8.GetString(this._BinaryData.GetBuffer(),this._BodyOffset,(int)(this._BinaryData.Length - this._BodyOffset)); switch (ContentEncoding.ToLower()) { case "quoted-printable": _body = encoding.GetBytes(MimeEntry.QDecode(encoding, BodyString)); break; case "7bit": //_body = Encoding.ASCII.GetBytes(BodyString); _body = encoding.GetBytes(BodyString); break; default: case "8bit": _body = encoding.GetBytes(BodyString); break; case "base64": BodyString = BodyString.Trim(); if (BodyString.Length > 0) { int base64FixCount = 0; // Fix If Base 64 is broken while (true) { try { _body = Convert.FromBase64String(BodyString); break; } catch (System.FormatException) { // Remove not supported chars if (base64FixCount == 0) { BodyString = Regex.Replace(BodyString, "[^a-zA-Z0-9+/=]+", string.Empty); } else if (base64FixCount == 1) { BodyString += "="; } else { BodyString = BodyString.Substring(0, BodyString.Length - 1); } if (BodyString.Length == 0 || base64FixCount == 25) // Max 25 Attempts to fix chars { _body = new byte[] { }; break; } base64FixCount++; } } } else { _body = new byte[] {} }; break; case "binary": _body = encoding.GetBytes(BodyString); break; //default: // throw new Pop3ServerIncorectEMailFormatException("Not supported content-encoding " + ContentEncoding + " !"); } } else { DataParseStatus parseStatus = _mimeEntries.ParseMimeEntries(_BinaryData.GetBuffer(), (int)_BinaryData.Length, ref _BodyOffset, this.Headers); } }
internal DataParseStatus ParseHeaders( byte[] byteBuffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength, ref WebParseError parseError) { if (byteBuffer.Length < size) { return(DataParseStatus.NeedMoreData); } char ch; 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; int localTotalResponseHeadersLength = totalResponseHeadersLength; WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic; DataParseStatus parseStatus = DataParseStatus.Invalid; for (;;) { headerName = string.Empty; headerValue = string.Empty; spaceAfterLf = false; headerMultiLineValue = null; if (this.Count == 0) { 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) { parseStatus = DataParseStatus.NeedMoreData; goto quit; } } headerNameStartOffset = index; while (index < size) { ch = (char)byteBuffer[index]; if (ch != ':' && ch != '\n') { if (ch > ' ') { 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) { parseStatus = DataParseStatus.NeedMoreData; goto quit; } startOfValue: numberOfLf = (this.Count == 0 && headerNameEndOffset < 0) ? 1 : 0; while (index < size && numberOfLf < 2) { ch = (char)byteBuffer[index]; if (ch <= ' ') { if (ch == '\n') { numberOfLf++; if (numberOfLf == 1) { if (index + 1 == size) { 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)) { goto addHeader; } if (index == size) { 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) { parseStatus = DataParseStatus.NeedMoreData; goto quit; } 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) { parseStatus = DataParseStatus.NeedMoreData; goto quit; } addHeader: if (headerValueStartOffset >= 0 && headerValueStartOffset > headerNameEndOffset && headerValueEndOffset >= headerValueStartOffset) { headerValue = System.Text.Encoding.UTF8.GetString(byteBuffer, headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1); } headerMultiLineValue = (headerMultiLineValue == null ? headerValue : headerMultiLineValue + " " + headerValue); if (index < size && numberOfLf == 1) { ch = (char)byteBuffer[index]; if (ch == ' ' || ch == '\t') { ++index; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } goto startOfValue; } } if (headerNameStartOffset >= 0 && headerNameEndOffset >= headerNameStartOffset) { headerName = System.Text.Encoding.UTF8.GetString(byteBuffer, headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1); } if (headerName.Length > 0) { this.Add(headerName, headerMultiLineValue); } totalResponseHeadersLength = localTotalResponseHeadersLength; unparsed = index; if (numberOfLf == 2) { parseStatus = DataParseStatus.Done; goto quit; } } quit: if (parseStatus == DataParseStatus.Invalid) { parseError.Section = WebParseErrorSection.ResponseHeader; parseError.Code = parseErrorCode; } return(parseStatus); }
internal DataParseStatus ParseHeaders(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength) { int headerNameStartOffset = -1; int headerNameEndOffset = -1; int headerValueStartOffset = -1; int headerValueEndOffset = -1; int numberOfLf = -1; int index = unparsed; bool spaceAfterLf; string headerMultiLineValue; string headerName; string headerValue; // we need this because this method is entered multiple times. int localTotalResponseHeadersLength = totalResponseHeadersLength; DataParseStatus parseStatus = DataParseStatus.Invalid; GlobalLog.Enter("WebHeaderCollection::ParseHeaders(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size - unparsed)) + "]"); //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): advancing. index=" + index.ToString() + " current character='" + ((char)buffer[index]).ToString() + "':" + ((int)buffer[index]).ToString() + " next character='" + ((char)buffer[index+1]).ToString() + "':" + ((int)buffer[index+1]).ToString()); //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): headerName:[" + headerName + "], headerValue:[" + headerValue + "], headerMultiLineValue:[" + headerMultiLineValue + "] numberOfLf=" + numberOfLf.ToString() + " index=" + index.ToString()); //GlobalLog.Print("WebHeaderCollection::ParseHeaders(): headerNameStartOffset=" + headerNameStartOffset + " headerNameEndOffset=" + headerNameEndOffset + " headerValueStartOffset=" + headerValueStartOffset + " headerValueEndOffset=" + headerValueEndOffset); // // according to RFC216 a header can have the following syntax: // // message-header = field-name ":" [ field-value ] // field-name = token // field-value = *( field-content | LWS ) // field-content = <the OCTETs making up the field-value and consisting of either *TEXT or combinations of token, separators, and quoted-string> // TEXT = <any OCTET except CTLs, but including LWS> // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)> // SP = <US-ASCII SP, space (32)> // HT = <US-ASCII HT, horizontal-tab (9)> // CR = <US-ASCII CR, carriage return (13)> // LF = <US-ASCII LF, linefeed (10)> // LWS = [CR LF] 1*( SP | HT ) // CHAR = <any US-ASCII character (octets 0 - 127)> // token = 1*<any CHAR except CTLs or separators> // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) // qdtext = <any TEXT except <">> // quoted-pair = "\" CHAR // // // At each iteration of the following loop we expect to parse a single HTTP header entirely. // for (;;) { // // trim leading whitespaces (LWS) just for extra robustness, in fact if there are leading white spaces then: // 1) it could be that after the status line we might have spaces. handle this. // 2) this should have been detected to be a multiline header so there'll be no spaces and we'll spend some time here. // headerName = string.Empty; headerValue = string.Empty; spaceAfterLf = false; headerMultiLineValue = null; if (Count == 0) { // // so, restrict this extra trimming only on the first header line // while (index < size && (buffer[index] == ' ' || buffer[index] == '\t')) { index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } } // // what we have here is the beginning of a new header // headerNameStartOffset = index; while (index < size && (buffer[index] != ':' && buffer[index] != '\n')) { if (buffer[index] > ' ') { // // if thre's an illegal character we should return DataParseStatus.Invalid // instead we choose to be flexible, try to trim it, but include it in the string // headerNameEndOffset = index; } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } startOfValue: // // skip all [' ','\t',':','\r','\n'] characters until HeaderValue starts // if we didn't find any headers yet, we set numberOfLf to 1 // so that we take the '\n' from the status line into account // numberOfLf = (Count == 0 && headerNameEndOffset < 0) ? 1 : 0; while (index < size && numberOfLf < 2 && (buffer[index] <= ' ' || buffer[index] == ':')) { if (buffer[index] == '\n') { numberOfLf++; spaceAfterLf = index + 1 < size && (buffer[index + 1] == ' ' || buffer[index + 1] == '\t'); } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (numberOfLf == 2 || (numberOfLf == 1 && !spaceAfterLf)) { // // if we've counted two '\n' we got at the end of the headers even if we're past the end of the buffer // if we've counted one '\n' and the first character after that was a ' ' or a '\t' // no matter if we found a ':' or not, treat this as an empty header name. // goto addHeader; } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } headerValueStartOffset = index; while (index < size && buffer[index] != '\n') { if (buffer[index] > ' ') { headerValueEndOffset = index; } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size) { // // we reached the end of the buffer. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } // // at this point we found either a '\n' or the end of the headers // hence we are at the end of the Header Line. 4 options: // 1) need more data // 2) if we find two '\n' => end of headers // 3) if we find one '\n' and a ' ' or a '\t' => multiline header // 4) if we find one '\n' and a valid char => next header // numberOfLf = 0; while (index < size && numberOfLf < 2 && (buffer[index] == '\r' || buffer[index] == '\n')) { if (buffer[index] == '\n') { numberOfLf++; } index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } } if (index == size && numberOfLf < 2) { // // we reached the end of the buffer but not of the headers. ask for more data. // parseStatus = DataParseStatus.NeedMoreData; goto quit; } addHeader: if (headerValueStartOffset >= 0 && headerValueStartOffset > headerNameEndOffset && headerValueEndOffset >= headerValueStartOffset) { // // Encoding fastest way to build the UNICODE string off the byte[] // headerValue = HeaderEncoding.GetString(buffer, headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1); } // // if we got here from the beginning of the for loop, headerMultiLineValue will be null // otherwise it will contain the headerValue constructed for the multiline header // add this line as well to it, separated by a single space // headerMultiLineValue = (headerMultiLineValue == null ? headerValue : headerMultiLineValue + " " + headerValue); if (index < size && numberOfLf == 1 && (buffer[index] == ' ' || buffer[index] == '\t')) { // // since we found only one Lf and the next header line begins with a Lws, // this is the beginning of a multiline header. // parse the next line into headerValue later it will be added to headerMultiLineValue // index++; if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) { parseStatus = DataParseStatus.DataTooBig; goto quit; } goto startOfValue; } if (headerNameStartOffset >= 0 && headerNameEndOffset >= headerNameStartOffset) { // // Encoding is the fastest way to build the UNICODE string off the byte[] // headerName = HeaderEncoding.GetString(buffer, headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1); } // // now it's finally safe to add the header if we have a name for it // if (headerName.Length > 0) { // // the base clasee will check for pre-existing headerValue and append // it using commas as indicated in the RFC // GlobalLog.Print("WebHeaderCollection::ParseHeaders() calling base.Add() key:[" + headerName + "], value:[" + headerMultiLineValue + "]"); base.Add(headerName, headerMultiLineValue); } // // and update unparsed // totalResponseHeadersLength = localTotalResponseHeadersLength; unparsed = index; if (numberOfLf == 2) { parseStatus = DataParseStatus.Done; goto quit; } } // for (;;) quit: GlobalLog.Leave("WebHeaderCollection::ParseHeaders() returning parseStatus:" + parseStatus.ToString()); return(parseStatus); }