| File: System\Net\Mime\MimePart.cs | Web Access |
| Project: src\runtime\src\libraries\System.Net.Mail\src\System.Net.Mail.csproj (System.Net.Mail) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.Globalization; using System.IO; using System.Net.Mail; using System.Runtime.ExceptionServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace System.Net.Mime { /// <summary> /// Summary description for MimePart. /// </summary> internal sealed class MimePart : MimeBasePart, IDisposable { private Stream? _stream; private bool _streamSet; private bool _streamUsedOnce; private const int maxBufferSize = 0x4400; //seems optimal for send based on perf analysis internal MimePart() { } public void Dispose() { _stream?.Close(); } internal Stream? Stream => _stream; internal ContentDisposition? ContentDisposition { get { return _contentDisposition; } set { _contentDisposition = value; if (value == null) { ((HeaderCollection)Headers).InternalRemove(MailHeaderInfo.GetString(MailHeaderID.ContentDisposition)!); } else { _contentDisposition!.PersistIfNeeded((HeaderCollection)Headers, true); } } } internal TransferEncoding TransferEncoding { get { string value = Headers[MailHeaderInfo.GetString(MailHeaderID.ContentTransferEncoding)!]!; if (value.Equals("base64", StringComparison.OrdinalIgnoreCase)) { return TransferEncoding.Base64; } else if (value.Equals("quoted-printable", StringComparison.OrdinalIgnoreCase)) { return TransferEncoding.QuotedPrintable; } else if (value.Equals("7bit", StringComparison.OrdinalIgnoreCase)) { return TransferEncoding.SevenBit; } else if (value.Equals("8bit", StringComparison.OrdinalIgnoreCase)) { return TransferEncoding.EightBit; } else { return TransferEncoding.Unknown; } } set { //QFE 4554 if (value == TransferEncoding.Base64) { Headers[MailHeaderInfo.GetString(MailHeaderID.ContentTransferEncoding)] = "base64"; } else if (value == TransferEncoding.QuotedPrintable) { Headers[MailHeaderInfo.GetString(MailHeaderID.ContentTransferEncoding)] = "quoted-printable"; } else if (value == TransferEncoding.SevenBit) { Headers[MailHeaderInfo.GetString(MailHeaderID.ContentTransferEncoding)] = "7bit"; } else if (value == TransferEncoding.EightBit) { Headers[MailHeaderInfo.GetString(MailHeaderID.ContentTransferEncoding)] = "8bit"; } else { throw new NotSupportedException(SR.Format(SR.MimeTransferEncodingNotSupported, value)); } } } internal void SetContent(Stream stream) { ArgumentNullException.ThrowIfNull(stream); if (_streamSet) { _stream!.Close(); } _stream = stream; _streamSet = true; _streamUsedOnce = false; TransferEncoding = TransferEncoding.Base64; } internal void SetContent(Stream stream, string? name, string? mimeType) { ArgumentNullException.ThrowIfNull(stream); if (mimeType != null && mimeType != string.Empty) { _contentType = new ContentType(mimeType); } if (name != null && name != string.Empty) { ContentType.Name = name; } SetContent(stream); } internal void SetContent(Stream stream, ContentType? contentType) { ArgumentNullException.ThrowIfNull(stream); _contentType = contentType; SetContent(stream); } internal Stream GetEncodedStream(Stream stream) { Stream outputStream = stream; if (TransferEncoding == TransferEncoding.Base64) { outputStream = new Base64Stream(outputStream, new Base64WriteStateInfo()); } else if (TransferEncoding == TransferEncoding.QuotedPrintable) { outputStream = new QuotedPrintableStream(outputStream, true); } else if (TransferEncoding == TransferEncoding.SevenBit || TransferEncoding == TransferEncoding.EightBit) { outputStream = new EightBitStream(outputStream); } return outputStream; } internal override async Task SendAsync<TIOAdapter>(BaseWriter writer, bool allowUnicode, CancellationToken cancellationToken = default) { if (Stream != null) { byte[] buffer = new byte[maxBufferSize]; PrepareHeaders(allowUnicode); writer.WriteHeaders(Headers, allowUnicode); Stream outputStream = writer.GetContentStream(); outputStream = GetEncodedStream(outputStream); ResetStream(); _streamUsedOnce = true; int read; while ((read = await TIOAdapter.ReadAsync(Stream, buffer.AsMemory(0, maxBufferSize), cancellationToken).ConfigureAwait(false)) > 0) { await TIOAdapter.WriteAsync(outputStream, buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); } outputStream.Close(); } } //Ensures that if we've used the stream once, we will either reset it to the origin, or throw. internal void ResetStream() { if (_streamUsedOnce) { if (Stream!.CanSeek) { Stream.Seek(0, SeekOrigin.Begin); _streamUsedOnce = false; } else { throw new InvalidOperationException(SR.MimePartCantResetStream); } } } } }