public void MultipartParserNesting(string boundary) { for (var nesting = 0; nesting < 16; nesting++) { string nested = CreateNestedBuffer(nesting); byte[] data = CreateBuffer(boundary, nested); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); Assert.NotNull(parser); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(2, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); Assert.Equal(nested.Length, bodyParts[1].Length); } } }
public async Task MimeMultipartParserTestMultipartContent(string boundary) { MultipartContent content = new MultipartContent("mixed", boundary); content.Add(new StringContent("A")); content.Add(new StringContent("B")); content.Add(new StringContent("C")); MemoryStream memStream = new MemoryStream(); await content.CopyToAsync(memStream); memStream.Position = 0; byte[] data = memStream.ToArray(); for (var readSize = 1; readSize <= data.Length; readSize++) { MimeMultipartParser parser = CreateMimeMultipartParser(boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, readSize, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(4, bodyParts.Count); Assert.Empty(bodyParts[0]); Assert.EndsWith("A", bodyParts[1]); Assert.EndsWith("B", bodyParts[2]); Assert.EndsWith("C", bodyParts[3]); } }
public void MimeMultipartParserTestMultipartContent(string boundary) { MultipartContent content = new MultipartContent("mixed", boundary); content.Add(new StringContent("A")); content.Add(new StringContent("B")); content.Add(new StringContent("C")); MemoryStream memStream = new MemoryStream(); content.CopyToAsync(memStream).Wait(); memStream.Position = 0; byte[] data = memStream.ToArray(); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); Assert.NotNull(parser); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(4, bodyParts.Count); Assert.Empty(bodyParts[0]); Assert.True(bodyParts[1].EndsWith("A")); Assert.True(bodyParts[2].EndsWith("B")); Assert.True(bodyParts[3].EndsWith("C")); } }
public void MaxMessageSizeIsExact() { string boundary = "--A"; byte[] data = CreateBuffer(boundary, "cool"); for (var readSize = 1; readSize <= data.Length; readSize++) { MimeMultipartParser parser = CreateMimeMultipartParser(boundary, data.Length); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps( parser, data, 2, out bodyParts, out totalBytesConsumed ); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(2, bodyParts.Count); Assert.Empty(bodyParts[0]); } }
public void MultipartParserNearMatches( string boundary, bool withExtraWhitespace, bool withExtraCRLF, string nearBoundaryBody ) { byte[] data = CreateBuffer( boundary, withExtraWhitespace, withExtraCRLF, nearBoundaryBody ); for (var readSize = 1; readSize <= data.Length; readSize++) { MimeMultipartParser parser = CreateMimeMultipartParser(boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps( parser, data, readSize, out bodyParts, out totalBytesConsumed ); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(2, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); Assert.Equal(nearBoundaryBody, bodyParts[1]); } }
public void MultipartParserMultipleShortBodyPartsWithLws(string boundary) { string[] text = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" }; byte[] data = CreateBuffer(boundary, true, text); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); Assert.NotNull(parser); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(text.Length + 1, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); for (var check = 0; check < text.Length; check++) { Assert.Equal(1, bodyParts[check + 1].Length); Assert.Equal(text[check], bodyParts[check + 1]); } } }
public void MultipartParserEmptyBuffer(string boundary) { byte[] data = CreateBuffer(boundary); for (var readSize = 1; readSize <= data.Length; readSize++) { MimeMultipartParser parser = CreateMimeMultipartParser(boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps( parser, data, readSize, out bodyParts, out totalBytesConsumed ); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(2, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); Assert.Equal(0, bodyParts[1].Length); } }
public void MultipartParserMultipleLongBodyParts(string boundary) { const string middleText = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; string[] text = new string[] { "A" + middleText + "A", "B" + middleText + "B", "C" + middleText + "C", "D" + middleText + "D", "E" + middleText + "E", "F" + middleText + "F", "G" + middleText + "G", "H" + middleText + "H", "I" + middleText + "I", "J" + middleText + "J", "K" + middleText + "K", "L" + middleText + "L", "M" + middleText + "M", "N" + middleText + "N", "O" + middleText + "O", "P" + middleText + "P", "Q" + middleText + "Q", "R" + middleText + "R", "S" + middleText + "S", "T" + middleText + "T", "U" + middleText + "U", "V" + middleText + "V", "W" + middleText + "W", "X" + middleText + "X", "Y" + middleText + "Y", "Z" + middleText + "Z" }; byte[] data = CreateBuffer(boundary, text); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); Assert.NotNull(parser); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(text.Length + 1, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); for (var check = 0; check < text.Length; check++) { Assert.Equal(text[check].Length, bodyParts[check + 1].Length); Assert.Equal(text[check], bodyParts[check + 1]); } } }
public void MultipartParserNearMatches(string boundary) { string[] text = new string[] { "AAA" + LF, "AAA" + CR, "AAA" + CRLF, "AAA" + CRLF + CRLF, "AAA" + CRLF + Dash, "AAA" + CRLF + Dash + CR, "AAA" + CRLF + Dash + CRLF, CR + Dash + "AAA", CRLF + Dash + "AAA", CRLF + DashDash + "AAA" + CR + "AAA", CRLF, "AAA", "AAA" + CRLF, CRLF + CRLF, CRLF + CRLF + CRLF, "AAA" + DashDash + "AAA", CRLF + "AAA" + DashDash + "AAA" + DashDash, CRLF + DashDash + "AAA" + CRLF, CRLF + DashDash + "AAA" + CRLF + CRLF, CRLF + DashDash + "AAA" + DashDash + CRLF, CRLF + DashDash + "AAA" + DashDash + CRLF + CRLF }; byte[] data = CreateBuffer(boundary, text); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); Assert.NotNull(parser); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(text.Length + 1, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); for (var check = 0; check < text.Length; check++) { Assert.Equal(text[check].Length, bodyParts[check + 1].Length); Assert.Equal(text[check], bodyParts[check + 1]); } } }
public void MimeMultipartParserTestDataTooBig(string boundary) { byte[] data = CreateBuffer(boundary); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(ParserData.MinMessageSize, boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.DataTooBig, state); Assert.Equal(ParserData.MinMessageSize, totalBytesConsumed); } }
private static MimeMultipartParser.State ParseBufferInSteps(MimeMultipartParser parser, byte[] buffer, int readsize, out List <string> bodyParts, out int totalBytesConsumed) { MimeMultipartParser.State state = MimeMultipartParser.State.Invalid; totalBytesConsumed = 0; bodyParts = new List <string>(); bool isFinal = false; byte[] currentBodyPart = new byte[32 * 1024]; int currentBodyLength = 0; while (totalBytesConsumed <= buffer.Length) { int size = Math.Min(buffer.Length - totalBytesConsumed, readsize); byte[] parseBuffer = new byte[size]; Buffer.BlockCopy(buffer, totalBytesConsumed, parseBuffer, 0, size); int bytesConsumed = 0; ArraySegment <byte> out1; ArraySegment <byte> out2; state = parser.ParseBuffer(parseBuffer, parseBuffer.Length, ref bytesConsumed, out out1, out out2, out isFinal); totalBytesConsumed += bytesConsumed; Buffer.BlockCopy(out1.Array, out1.Offset, currentBodyPart, currentBodyLength, out1.Count); currentBodyLength += out1.Count; Buffer.BlockCopy(out2.Array, out2.Offset, currentBodyPart, currentBodyLength, out2.Count); currentBodyLength += out2.Count; if (state == MimeMultipartParser.State.BodyPartCompleted) { var bPart = new byte[currentBodyLength]; Buffer.BlockCopy(currentBodyPart, 0, bPart, 0, currentBodyLength); bodyParts.Add(Encoding.UTF8.GetString(bPart)); currentBodyLength = 0; if (isFinal) { break; } } else if (state != MimeMultipartParser.State.NeedMoreData) { return(state); } } Assert.True(isFinal); return(state); }
public void MultipartParserNearMatches(string boundary, string nearBoundaryBody) { byte[] data = CreateBuffer(boundary, nearBoundaryBody); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(2, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); Assert.Equal(nearBoundaryBody, bodyParts[1]); } }
public void MultipartParserSingleShortBodyPart(string boundary) { byte[] data = CreateBuffer(boundary, "A"); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); Assert.NotNull(parser); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(2, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); Assert.Equal(1, bodyParts[1].Length); Assert.Equal("A", bodyParts[1]); } }
public void MultipartParserMultipleLongBodyParts( string boundary, bool withExtraWhitespace, bool withExtraCRLF, string[] multipleLongBodies ) { byte[] data = CreateBuffer( boundary, withExtraWhitespace, withExtraCRLF, multipleLongBodies ); for (var readSize = 1; readSize <= data.Length; readSize++) { MimeMultipartParser parser = CreateMimeMultipartParser(boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps( parser, data, readSize, out bodyParts, out totalBytesConsumed ); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(multipleLongBodies.Length + 1, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); for (var check = 0; check < multipleLongBodies.Length; check++) { Assert.Equal(multipleLongBodies[check], bodyParts[check + 1]); } } }
public void MultipartParserMultipleShortBodyPartsWithLws(string boundary, string[] multipleShortBodies) { byte[] data = CreateBuffer(boundary, true, multipleShortBodies); for (var cnt = 1; cnt <= data.Length; cnt++) { MimeMultipartParser parser = CreateMimeMultipartParser(data.Length, boundary); int totalBytesConsumed; List <string> bodyParts; MimeMultipartParser.State state = ParseBufferInSteps(parser, data, cnt, out bodyParts, out totalBytesConsumed); Assert.Equal(MimeMultipartParser.State.BodyPartCompleted, state); Assert.Equal(data.Length, totalBytesConsumed); Assert.Equal(multipleShortBodies.Length + 1, bodyParts.Count); Assert.Equal(0, bodyParts[0].Length); for (var check = 0; check < multipleShortBodies.Length; check++) { Assert.Equal(multipleShortBodies[check], bodyParts[check + 1]); } } }
/// <summary> /// Parses the data provided and generates parsed MIME body part bodies in the form of <see cref="ArraySegment{T}"/> which are ready to /// write to the output stream. /// </summary> /// <param name="data">The data to parse</param> /// <param name="bytesRead">The number of bytes available in the input data</param> /// <returns>Parsed <see cref="MimeBodyPart"/> instances.</returns> public IEnumerable<MimeBodyPart> ParseBuffer(byte[] data, int bytesRead) { int bytesConsumed = 0; bool isFinal = false; if (bytesRead == 0) { CleanupCurrentBodyPart(); throw new IOException(Properties.Resources.ReadAsMimeMultipartUnexpectedTermination); } // Make sure we remove an old array segments. _currentBodyPart.Segments.Clear(); while (bytesConsumed < bytesRead) { _mimeStatus = _mimeParser.ParseBuffer(data, bytesRead, ref bytesConsumed, out _parsedBodyPart[0], out _parsedBodyPart[1], out isFinal); if (_mimeStatus != MimeMultipartParser.State.BodyPartCompleted && _mimeStatus != MimeMultipartParser.State.NeedMoreData) { CleanupCurrentBodyPart(); throw new IOException(RS.Format(Properties.Resources.ReadAsMimeMultipartParseError, bytesConsumed, data)); } // First body is empty preamble which we just ignore if (_isFirst) { if (_mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { _isFirst = false; } continue; } // Parse the two array segments containing parsed body parts that the MIME parser gave us foreach (ArraySegment<byte> part in _parsedBodyPart) { if (part.Count == 0) { continue; } if (_bodyPartHeaderStatus != ParserState.Done) { int headerConsumed = part.Offset; _bodyPartHeaderStatus = _currentBodyPart.HeaderParser.ParseBuffer(part.Array, part.Count + part.Offset, ref headerConsumed); if (_bodyPartHeaderStatus == ParserState.Done) { // Add the remainder as body part content _currentBodyPart.Segments.Add(new ArraySegment<byte>(part.Array, headerConsumed, part.Count + part.Offset - headerConsumed)); } else if (_bodyPartHeaderStatus != ParserState.NeedMoreData) { CleanupCurrentBodyPart(); throw new IOException(RS.Format(Properties.Resources.ReadAsMimeMultipartHeaderParseError, headerConsumed, part.Array)); } } else { // Add the data as body part content _currentBodyPart.Segments.Add(part); } } if (_mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { // If body is completed then swap current body part MimeBodyPart completed = _currentBodyPart; completed.IsComplete = true; completed.IsFinal = isFinal; _currentBodyPart = new MimeBodyPart(_streamProvider, _maxBodyPartHeaderSize); _mimeStatus = MimeMultipartParser.State.NeedMoreData; _bodyPartHeaderStatus = ParserState.NeedMoreData; yield return completed; } else { // Otherwise return what we have yield return _currentBodyPart; } } }
/// <summary> /// Parses the data provided and generates parsed MIME body part bodies in the form of <see cref="ArraySegment{T}"/> which are ready to /// write to the output stream. /// </summary> /// <param name="data">The data to parse</param> /// <param name="bytesRead">The number of bytes available in the input data</param> /// <returns>Parsed <see cref="MimeBodyPart"/> instances.</returns> public IEnumerable <MimeBodyPart> ParseBuffer(byte[] data, int bytesRead) { int bytesConsumed = 0; bool isFinal = false; // There's a special case here - if we've reached the end of the message and there's no optional // CRLF, then we're out of bytes to read, but we have finished the message. // // If IsWaitingForEndOfMessage is true and we're at the end of the stream, then we're going to // call into the parser again with an empty array as the buffer to signal the end of the parse. // Then the final boundary segment will be marked as complete. if (bytesRead == 0 && !_mimeParser.IsWaitingForEndOfMessage) { CleanupCurrentBodyPart(); throw new IOException(Properties.Resources.ReadAsMimeMultipartUnexpectedTermination); } // Make sure we remove an old array segments. _currentBodyPart.Segments.Clear(); while (_mimeParser.CanParseMore(bytesRead, bytesConsumed)) { _mimeStatus = _mimeParser.ParseBuffer(data, bytesRead, ref bytesConsumed, out _parsedBodyPart[0], out _parsedBodyPart[1], out isFinal); if (_mimeStatus != MimeMultipartParser.State.BodyPartCompleted && _mimeStatus != MimeMultipartParser.State.NeedMoreData) { CleanupCurrentBodyPart(); throw Error.InvalidOperation(Properties.Resources.ReadAsMimeMultipartParseError, bytesConsumed, data); } // First body is empty preamble which we just ignore if (_isFirst) { if (_mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { _isFirst = false; } continue; } // Parse the two array segments containing parsed body parts that the MIME parser gave us foreach (ArraySegment <byte> part in _parsedBodyPart) { if (part.Count == 0) { continue; } if (_bodyPartHeaderStatus != ParserState.Done) { int headerConsumed = part.Offset; _bodyPartHeaderStatus = _currentBodyPart.HeaderParser.ParseBuffer(part.Array, part.Count + part.Offset, ref headerConsumed); if (_bodyPartHeaderStatus == ParserState.Done) { // Add the remainder as body part content _currentBodyPart.Segments.Add(new ArraySegment <byte>(part.Array, headerConsumed, part.Count + part.Offset - headerConsumed)); } else if (_bodyPartHeaderStatus != ParserState.NeedMoreData) { CleanupCurrentBodyPart(); throw Error.InvalidOperation(Properties.Resources.ReadAsMimeMultipartHeaderParseError, headerConsumed, part.Array); } } else { // Add the data as body part content _currentBodyPart.Segments.Add(part); } } if (_mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { // If body is completed then swap current body part MimeBodyPart completed = _currentBodyPart; completed.IsComplete = true; completed.IsFinal = isFinal; _currentBodyPart = new MimeBodyPart(_streamProvider, _maxBodyPartHeaderSize, _content); _mimeStatus = MimeMultipartParser.State.NeedMoreData; _bodyPartHeaderStatus = ParserState.NeedMoreData; yield return(completed); } else { // Otherwise return what we have yield return(_currentBodyPart); } } }
/// <summary> /// Parses the data provided and generates parsed MIME body part bodies in the form of <see cref="ArraySegment{T}"/> which are ready to /// write to the output stream. /// </summary> /// <param name="data">The data to parse</param> /// <param name="bytesRead">The number of bytes available in the input data</param> /// <returns>Parsed <see cref="MimeBodyPart"/> instances.</returns> public IEnumerable<MimeBodyPart> ParseBuffer(byte[] data, int bytesRead) { int bytesConsumed = 0; bool isFinal = false; // There's a special case here - if we've reached the end of the message and there's no optional // CRLF, then we're out of bytes to read, but we have finished the message. // // If IsWaitingForEndOfMessage is true and we're at the end of the stream, then we're going to // call into the parser again with an empty array as the buffer to signal the end of the parse. // Then the final boundary segment will be marked as complete. if (bytesRead == 0 && !this._mimeParser.IsWaitingForEndOfMessage) { this.CleanupCurrentBodyPart(); throw new IOException(Resources.ReadAsMimeMultipartUnexpectedTermination); } // Make sure we remove an old array segments. this._currentBodyPart.Segments.Clear(); while (this._mimeParser.CanParseMore(bytesRead, bytesConsumed)) { this._mimeStatus = this._mimeParser.ParseBuffer(data, bytesRead, ref bytesConsumed, out this._parsedBodyPart[0], out this._parsedBodyPart[1], out isFinal); if (this._mimeStatus != MimeMultipartParser.State.BodyPartCompleted && this._mimeStatus != MimeMultipartParser.State.NeedMoreData) { this.CleanupCurrentBodyPart(); throw Error.InvalidOperation(Resources.ReadAsMimeMultipartParseError, bytesConsumed, data); } // First body is empty preamble which we just ignore if (this._isFirst) { if (this._mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { this._isFirst = false; } continue; } // Parse the two array segments containing parsed body parts that the MIME parser gave us foreach (ArraySegment<byte> part in this._parsedBodyPart) { if (part.Count == 0) { continue; } if (this._bodyPartHeaderStatus != ParserState.Done) { int headerConsumed = part.Offset; this._bodyPartHeaderStatus = this._currentBodyPart.HeaderParser.ParseBuffer(part.Array, part.Count + part.Offset, ref headerConsumed); if (this._bodyPartHeaderStatus == ParserState.Done) { // Add the remainder as body part content this._currentBodyPart.Segments.Add(new ArraySegment<byte>(part.Array, headerConsumed, part.Count + part.Offset - headerConsumed)); } else if (this._bodyPartHeaderStatus != ParserState.NeedMoreData) { this.CleanupCurrentBodyPart(); throw Error.InvalidOperation(Resources.ReadAsMimeMultipartHeaderParseError, headerConsumed, part.Array); } } else { // Add the data as body part content this._currentBodyPart.Segments.Add(part); } } if (this._mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { // If body is completed then swap current body part MimeBodyPart completed = this._currentBodyPart; completed.IsComplete = true; completed.IsFinal = isFinal; this._currentBodyPart = new MimeBodyPart(this._streamProvider, this._maxBodyPartHeaderSize, this._content); this._mimeStatus = MimeMultipartParser.State.NeedMoreData; this._bodyPartHeaderStatus = ParserState.NeedMoreData; yield return completed; } else { // Otherwise return what we have yield return this._currentBodyPart; } } }
/// <summary> /// Parses the data provided and generates parsed MIME body part bodies in the form of <see cref="ArraySegment{T}"/> which are ready to /// write to the output stream. /// </summary> /// <param name="data">The data to parse</param> /// <param name="bytesRead">The number of bytes available in the input data</param> /// <returns>Parsed <see cref="MimeBodyPart"/> instances.</returns> public IEnumerable <MimeBodyPart> ParseBuffer(byte[] data, int bytesRead) { int bytesConsumed = 0; bool isFinal = false; if (bytesRead == 0) { CleanupCurrentBodyPart(); throw new IOException(Properties.Resources.ReadAsMimeMultipartUnexpectedTermination); } // Make sure we remove an old array segments. _currentBodyPart.Segments.Clear(); while (bytesConsumed < bytesRead) { _mimeStatus = _mimeParser.ParseBuffer(data, bytesRead, ref bytesConsumed, out _parsedBodyPart[0], out _parsedBodyPart[1], out isFinal); if (_mimeStatus != MimeMultipartParser.State.BodyPartCompleted && _mimeStatus != MimeMultipartParser.State.NeedMoreData) { CleanupCurrentBodyPart(); throw new IOException(RS.Format(Properties.Resources.ReadAsMimeMultipartParseError, bytesConsumed, data)); } // First body is empty preamble which we just ignore if (_isFirst) { if (_mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { _isFirst = false; } continue; } // Parse the two array segments containing parsed body parts that the MIME parser gave us foreach (ArraySegment <byte> part in _parsedBodyPart) { if (part.Count == 0) { continue; } if (_bodyPartHeaderStatus != ParserState.Done) { int headerConsumed = part.Offset; _bodyPartHeaderStatus = _currentBodyPart.HeaderParser.ParseBuffer(part.Array, part.Count + part.Offset, ref headerConsumed); if (_bodyPartHeaderStatus == ParserState.Done) { // Add the remainder as body part content _currentBodyPart.Segments.Add(new ArraySegment <byte>(part.Array, headerConsumed, part.Count + part.Offset - headerConsumed)); } else if (_bodyPartHeaderStatus != ParserState.NeedMoreData) { CleanupCurrentBodyPart(); throw new IOException(RS.Format(Properties.Resources.ReadAsMimeMultipartHeaderParseError, headerConsumed, part.Array)); } } else { // Add the data as body part content _currentBodyPart.Segments.Add(part); } } if (_mimeStatus == MimeMultipartParser.State.BodyPartCompleted) { // If body is completed then swap current body part MimeBodyPart completed = _currentBodyPart; completed.IsComplete = true; completed.IsFinal = isFinal; _currentBodyPart = new MimeBodyPart(_streamProvider, _maxBodyPartHeaderSize); _mimeStatus = MimeMultipartParser.State.NeedMoreData; _bodyPartHeaderStatus = ParserState.NeedMoreData; yield return(completed); } else { // Otherwise return what we have yield return(_currentBodyPart); } } }