public void MultipartParserNullBuffer() { MimeMultipartParser parser = CreateMimeMultipartParser(128, "-"); int bytesConsumed = 0; ArraySegment <byte> out1; ArraySegment <byte> out2; bool isFinal; Assert.ThrowsArgumentNull(() => { parser.ParseBuffer(null, 0, ref bytesConsumed, out out1, out out2, out isFinal); }, "buffer"); }
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); }
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 (true) { 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, "The last segment is not a final segment."); return state; }
/// <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; 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); } } }