/// <summary> /// /// </summary> /// <param name="in_content"></param> /// <param name="out_stream"></param> public void SerializeMimeContent(MimeContent in_content, Stream out_stream) { byte[] _writeHelper; // // Prepare some bytes written more than once // byte[] _boundaryBytes = ParserEncoding.GetBytes("--" + in_content.Boundary); // // Write every part into the stream // foreach (var item in in_content.Parts) { // // First of all write the boundary // out_stream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); out_stream.Write(_boundaryBytes, 0, _boundaryBytes.Length); out_stream.Write(CarriageReturnLineFeed, 0, 2); // // Write the content-type for the current element // var _builder = new StringBuilder(); _builder.Append(String.Format("Content-Type: {0}", item.ContentType)); if (!String.IsNullOrEmpty(item.CharSet)) { _builder.Append(String.Format("; charset={0}", item.CharSet)); } _builder.Append(new char[] { '\r', '\n' }); if (!String.IsNullOrEmpty(item.TransferEncoding)) { _builder.Append(String.Format("Content-Transfer-Encoding: {0}", item.TransferEncoding)); _builder.Append(new char[] { '\r', '\n' }); } _builder.Append(String.Format("Content-ID: {0}", item.ContentId)); _writeHelper = ParserEncoding.GetBytes(_builder.ToString()); out_stream.Write(_writeHelper, 0, _writeHelper.Length); out_stream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); out_stream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); // // Write the actual content // out_stream.Write(item.Content, 0, item.Content.Length); } // // Write one last content boundary // out_stream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); out_stream.Write(_boundaryBytes, 0, _boundaryBytes.Length); out_stream.Write(EndOfPartsDelimeter, 0, EndOfPartsDelimeter.Length); out_stream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); }
/// <summary> /// /// </summary> /// <param name="http_content_type"></param> /// <param name="binary_content"></param> /// <returns></returns> public MimeContent DeserializeMimeContent(string http_content_type, byte[] binary_content) { // // First of all parse the http content type // string _mimeType = null, _mimeBoundary = null, _mimeStart = null; ParseHttpContentTypeHeader(http_content_type, ref _mimeType, ref _mimeBoundary, ref _mimeStart); // // Create the mime-content // MimeContent _content = new MimeContent() { Boundary = _mimeBoundary }; // // Start finding the parts in the mime message // Note: in MIME RFC a "--" represents the end of something // var _endBoundaryHelperNdx = 0; byte[] _mimeBoundaryBytes = ParserEncoding.GetBytes("--" + _mimeBoundary); for (int i = 0; i < binary_content.Length; i++) { if (AreArrayPartsForTextEqual(_mimeBoundaryBytes, 0, binary_content, i, _mimeBoundaryBytes.Length)) { _endBoundaryHelperNdx = i + _mimeBoundaryBytes.Length; if ((_endBoundaryHelperNdx + 1) < binary_content.Length) { // The end of the MIME-message is the boundary followed by "--" if (binary_content[_endBoundaryHelperNdx] == '-' && binary_content[_endBoundaryHelperNdx + 1] == '-') { break; } } else { throw new ProxyException("Invalid MIME content parsed, premature End-Of-File detected!"); } // Start reading the mime part after the boundary MimePart _part = ReadMimePart(binary_content, ref i, _mimeBoundaryBytes); if (_part != null) { _content.Parts.Add(_part); } } } // // Finally return the ready-to-use object model // _content.SetAsStartPart(_mimeStart); return(_content); }
public void SerializeMimeContent(MimeContent content, Stream contentStream) { byte[] WriteHelper; byte[] CarriageReturnLineFeed = new byte[] { (byte)'\r', (byte)'\n' }; // // Prepare some bytes written more than once // byte[] BoundaryBytes = ParserEncoding.GetBytes("--" + content.Boundary); // // Write every part into the stream // foreach (var item in content.Parts) { // // First of all write the boundary // contentStream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); contentStream.Write(BoundaryBytes, 0, BoundaryBytes.Length); contentStream.Write(CarriageReturnLineFeed, 0, 2); // // Write the content-type for the current element // StringBuilder Builder = new StringBuilder(); Builder.Append(string.Format("Content-Type: {0}", item.ContentType)); if (!string.IsNullOrEmpty(item.CharSet)) { Builder.Append(string.Format("; charset={0}", item.CharSet)); } Builder.Append(new char[] { '\r', '\n' }); Builder.Append(string.Format("Content-Transfer-Encoding: {0}", item.TransferEncoding)); Builder.Append(new char[] { '\r', '\n' }); Builder.Append(string.Format("Content-Id: {0}", item.ContentId)); WriteHelper = ParserEncoding.GetBytes(Builder.ToString()); contentStream.Write(WriteHelper, 0, WriteHelper.Length); contentStream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); contentStream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); // // Write the actual content // contentStream.Write(item.Content, 0, item.Content.Length); } // // Write one last content boundary // contentStream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); contentStream.Write(BoundaryBytes, 0, BoundaryBytes.Length); contentStream.Write(new byte[] { 45, 45 }, 0, 2); contentStream.Write(CarriageReturnLineFeed, 0, CarriageReturnLineFeed.Length); }
private MimePart ReadMimePart(byte[] binary_content, ref int current_index, byte[] mime_boundary_bytes) { byte[] _contentTypeKeyBytes = ParserEncoding.GetBytes("Content-Type:"); byte[] _transferEncodingKeyBytes = ParserEncoding.GetBytes("Content-Transfer-Encoding:"); byte[] _contentIdKeyBytes = ParserEncoding.GetBytes("Content-ID:"); // // Find the appropriate content header indexes // int _contentTypeNdx = -1, _transferEncodingNdx = -1, _contentIdNdx = -1; int _contentTypeLen = -1, _transferEncodingLen = -1, _contentIdLen = -1; while (current_index < binary_content.Length) { // Try compare for keys if (_contentTypeNdx < 0) { if (AreArrayPartsForTextEqual(_contentTypeKeyBytes, 0, binary_content, current_index, _contentTypeKeyBytes.Length) == true) { _contentTypeNdx = current_index; _contentTypeLen = this.GetLengthToCRLF(binary_content, _contentTypeNdx + _contentTypeKeyBytes.Length); } } if (_transferEncodingNdx < 0) { if (AreArrayPartsForTextEqual(_transferEncodingKeyBytes, 0, binary_content, current_index, _transferEncodingKeyBytes.Length) == true) { _transferEncodingNdx = current_index; _transferEncodingLen = this.GetLengthToCRLF(binary_content, _transferEncodingNdx + _transferEncodingKeyBytes.Length); } } if (_contentIdNdx < 0) { if (AreArrayPartsForTextEqual(_contentIdKeyBytes, 0, binary_content, current_index, _contentIdKeyBytes.Length) == true) { _contentIdNdx = current_index; _contentIdLen = this.GetLengthToCRLF(binary_content, _contentIdNdx + _contentIdKeyBytes.Length); } } // All content headers found, last content header split by Carriage Return Line Feed // TODO: Check index out of bounds! if (binary_content[current_index] == 13 && binary_content[current_index + 1] == 10) { if (binary_content[current_index + 2] == 13 && binary_content[current_index + 3] == 10) { break; } } // Next array index current_index++; } // After the last content header, we have \r\n\r\n, always current_index += 4; // // If not all indices found, error // //if (!((_contentTypeNdx >= 0) && (_transferEncodingNdx >= 0) && (_contentIdNdx >= 0))) //{ // // A '0' at the end of the message indicates that the previous part was the last one // if (binary_content[current_index - 1] == 0) // return null; // else if (binary_content[current_index - 2] == 13 && binary_content[current_index - 1] == 10) // return null; // else // throw new ProxyException("Invalid mime content passed into mime parser! Content-Type, Content-Transfer-Encoding or ContentId headers for mime part are missing!"); //} // // Convert the content header information into strings // var _contentType = ""; var _charSet = ""; if (_contentTypeNdx > 0) { _contentType = ParserEncoding.GetString(binary_content, _contentTypeNdx + _contentTypeKeyBytes.Length, _contentTypeLen).Trim(); if (_contentType.Contains(';')) { var _contentTypeSplitIdx = _contentType.IndexOf(';'); var _equalsCharSetNdx = _contentType.IndexOf('=', _contentTypeSplitIdx + 1); if (_equalsCharSetNdx < 0) { _charSet = _contentType.Substring(_contentTypeSplitIdx + 1).Trim(); } else { _charSet = _contentType.Substring(_equalsCharSetNdx + 1).Trim(); } _contentType = _contentType.Substring(0, _contentTypeSplitIdx).Trim(); } } var _transferEncoding = ""; if (_transferEncodingNdx > 0) { _transferEncoding = ParserEncoding.GetString(binary_content, _transferEncodingNdx + _transferEncodingKeyBytes.Length, _transferEncodingLen).Trim(); } var _contentId = ""; if (_contentIdNdx > 0) { _contentId = ParserEncoding.GetString(binary_content, _contentIdNdx + _contentIdKeyBytes.Length, _contentIdLen).Trim(); } // // Current mime content starts now, therefore find the end // var _startContentIndex = current_index; var _endContentIndex = -1; while (current_index < binary_content.Length) { if (AreArrayPartsForTextEqual(mime_boundary_bytes, 0, binary_content, current_index, mime_boundary_bytes.Length)) { _endContentIndex = current_index - 1; break; } current_index++; } if (_endContentIndex == -1) { _endContentIndex = current_index - 1; } // // Tweak start- and end-indexes, cut all Carriage Return Line Feeds // while (true) { if ((binary_content[_startContentIndex] == 13) && (binary_content[_startContentIndex + 1] == 10)) { _startContentIndex += 2; } else { break; } if (_startContentIndex > binary_content.Length) { throw new ProxyException("Error in content, start index cannot go beyond overall content array!"); } } while (true) { if ((binary_content[_endContentIndex - 1] == 13) && (binary_content[_endContentIndex] == 10)) { _endContentIndex -= 2; } else { break; } if (_endContentIndex < 0) { throw new ProxyException("Error in content, end content index cannot go beyond smallest index of content array!"); } } // // Now create a byte array for the current mime-part content // MimePart _mimePart = new MimePart() { ContentId = _contentId, TransferEncoding = _transferEncoding, ContentType = _contentType, CharSet = _charSet, Content = new byte[_endContentIndex - _startContentIndex + 1] }; Array.Copy(binary_content, _startContentIndex, _mimePart.Content, 0, _mimePart.Content.Length); // Go to the last sign before the next boundary starts current_index--; return(_mimePart); }
private MimePart ReadMimePart(byte[] binaryContent, ref int currentIndex, byte[] mimeBoundaryBytes) { byte[] ContentTypeKeyBytes = ParserEncoding.GetBytes("Content-Type:"); byte[] TransferEncodingKeyBytes = ParserEncoding.GetBytes("Content-Transfer-Encoding:"); byte[] ContentIdKeyBytes = ParserEncoding.GetBytes("Content-Id:"); // // Find the appropriate content header indexes // int ContentTypeIdx = -1, TransferEncodingIdx = -1, ContentIdIdx = -1; while (currentIndex < binaryContent.Length) { // Try compare for keys if ((ContentTypeIdx < 0) && AreArrayPartsForTextEqual(ContentTypeKeyBytes, 0, binaryContent, currentIndex, ContentTypeKeyBytes.Length)) { ContentTypeIdx = currentIndex; } else if ((TransferEncodingIdx < 0) && AreArrayPartsForTextEqual(TransferEncodingKeyBytes, 0, binaryContent, currentIndex, TransferEncodingKeyBytes.Length)) { TransferEncodingIdx = currentIndex; } else if ((ContentIdIdx < 0) && AreArrayPartsForTextEqual(ContentIdKeyBytes, 0, binaryContent, currentIndex, ContentIdKeyBytes.Length)) { ContentIdIdx = currentIndex; } // All content headers found, last content header split by Carriage Return Line Feed // TODO: Check index out of bounds! if (binaryContent[currentIndex] == 13 && binaryContent[currentIndex + 1] == 10 && binaryContent[currentIndex + 2] == 13 && binaryContent[currentIndex + 3] == 10) { break; } // Next array index currentIndex++; } // After the last content header, we have \r\n\r\n, always currentIndex += 4; // // If not all indices found, error // if (!((ContentIdIdx >= 0) && (ContentTypeIdx >= 0) && (ContentIdIdx >= 0))) { // A '0' at the end of the message indicates that the previous part was the last one if (binaryContent[currentIndex - 1] == 0) { return(null); } else if (binaryContent[currentIndex - 2] == 13 && binaryContent[currentIndex - 1] == 10) { return(null); } else { throw new ApplicationException("Invalid mime content passed into mime parser! Content-Type, Content-Transfer-Encoding or ContentId headers for mime part are missing!"); } } // // Convert the content header information into strings // string ContentType = ParserEncoding.GetString(binaryContent, ContentTypeIdx + ContentTypeKeyBytes.Length, TransferEncodingIdx - (ContentTypeIdx + ContentTypeKeyBytes.Length)).TrimStart().TrimEnd(); string CharSet = string.Empty; if (ContentType.Contains(';')) { int ContentTypeSplitIdx = ContentType.IndexOf(';'); int EqualsCharSetIdx = ContentType.IndexOf('=', ContentTypeSplitIdx + 1); if (EqualsCharSetIdx < 0) { CharSet = ContentType.Substring(ContentTypeSplitIdx + 1).TrimStart().TrimEnd(); } else { CharSet = ContentType.Substring(EqualsCharSetIdx + 1).TrimStart().TrimEnd(); } ContentType = ContentType.Substring(0, ContentTypeSplitIdx).TrimStart().TrimEnd(); } string TransferEncoding = ParserEncoding.GetString(binaryContent, TransferEncodingIdx + TransferEncodingKeyBytes.Length, ContentIdIdx - (TransferEncodingIdx + TransferEncodingKeyBytes.Length)).TrimStart().TrimEnd(); string ContentId = ParserEncoding.GetString(binaryContent, ContentIdIdx + ContentIdKeyBytes.Length, currentIndex - (ContentIdIdx + ContentIdKeyBytes.Length)).TrimStart().TrimEnd(); // // Current mime content starts now, therefore find the end // int StartContentIndex = currentIndex; int EndContentIndex = -1; while (currentIndex < binaryContent.Length) { if (AreArrayPartsForTextEqual(mimeBoundaryBytes, 0, binaryContent, currentIndex, mimeBoundaryBytes.Length)) { EndContentIndex = currentIndex - 1; break; } currentIndex++; } if (EndContentIndex == -1) { EndContentIndex = currentIndex - 1; } // // Tweak start- and end-indexes, cut all Carriage Return Line Feeds // while (true) { if ((binaryContent[StartContentIndex] == 13) && (binaryContent[StartContentIndex + 1] == 10)) { StartContentIndex += 2; } else { break; } if (StartContentIndex > binaryContent.Length) { throw new ApplicationException("Error in content, start index cannot go beyond overall content array!"); } } while (true) { if ((binaryContent[EndContentIndex - 1] == 13) && (binaryContent[EndContentIndex] == 10)) { EndContentIndex -= 2; } else { break; } if (EndContentIndex < 0) { throw new ApplicationException("Error in content, end content index cannot go beyond smallest index of content array!"); } } // // Now create a byte array for the current mime-part content // MimePart Part = new MimePart() { ContentId = ContentId, TransferEncoding = TransferEncoding, ContentType = ContentType, CharSet = CharSet, Content = new byte[EndContentIndex - StartContentIndex + 1] }; Array.Copy(binaryContent, StartContentIndex, Part.Content, 0, Part.Content.Length); // Go to the last sign before the next boundary starts currentIndex--; return(Part); }