Example #1
0
        public void TestStreamArguments()
        {
            using (var stream = new MeasuringStream())
                AssertStreamArguments(stream);

            using (var stream = new MemoryBlockStream())
                AssertStreamArguments(stream);

            using (var memory = new MemoryStream()) {
                using (var stream = new FilteredStream(memory))
                    AssertStreamArguments(stream);
            }

            using (var memory = new MemoryStream()) {
                using (var stream = new BoundStream(memory, 0, -1, true))
                    AssertStreamArguments(stream);
            }

            using (var memory = new MemoryStream()) {
                using (var stream = new ChainedStream()) {
                    stream.Add(memory);

                    AssertStreamArguments(stream);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Asynchronously deserializes the given <paramref name="input"/> stream to an <see cref="AS4Message"/> model.
        /// </summary>
        /// <param name="input">The source stream from where the message should be read.</param>
        /// <param name="contentType">The content type required to correctly deserialize the message into different MIME parts.</param>
        /// <param name="cancellation">The token to control the cancellation of the deserialization.</param>
        public async Task <AS4Message> DeserializeAsync(
            Stream input,
            string contentType,
            CancellationToken cancellation = default(CancellationToken))
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            if (contentType == null)
            {
                throw new ArgumentNullException(nameof(contentType));
            }

            var memoryStream = new MemoryStream(
                Encoding.UTF8.GetBytes($"Content-Type: {contentType}\r\n\r\n"));

            var chainedStream = new ChainedStream();

            chainedStream.Add(memoryStream, leaveOpen: false);
            chainedStream.Add(input, leaveOpen: true);

            try
            {
                return(await ParseStreamToAS4MessageAsync(chainedStream, contentType, cancellation).ConfigureAwait(false));
            }
            finally
            {
                // Since the stream has been read, make sure that all
                // parts of the chained-stream are re-positioned to the
                // beginning of each stream.
                chainedStream.Position = 0;
            }
        }
Example #3
0
        public void Setup()
        {
            var bytes    = new byte[10 * 1024];
            int position = 0;

            random = new Random();
            random.NextBytes(bytes);

            // this is our master stream, all operations on the chained stream
            // should match the results on this stream
            master = new MemoryStream(bytes);
            cbuf   = new byte[4096];
            mbuf   = new byte[4096];

            // make a handful of smaller streams based on master to chain together
            chained = new ChainedStream();
            while (position < bytes.Length)
            {
                int n = Math.Min(bytes.Length - position, random.Next() % 4096);

                var segment = new byte[n];
                Buffer.BlockCopy(bytes, position, segment, 0, n);
                lengths.Add(n);
                position += n;

                chained.Add(new ReadOneByteStream(new MemoryStream(segment)));
            }
        }
Example #4
0
        public void TestStreamArguments()
        {
            using (var stream = new MeasuringStream())
                AssertStreamArguments(stream);

            using (var stream = new MemoryBlockStream())
                AssertStreamArguments(stream);

            using (var memory = new MemoryStream()) {
                Assert.Throws <ArgumentNullException> (() => new FilteredStream(null));

                using (var stream = new FilteredStream(memory))
                    AssertStreamArguments(stream);
            }

            using (var memory = new MemoryStream()) {
                Assert.Throws <ArgumentNullException> (() => new BoundStream(null, 0, 10, true));
                Assert.Throws <ArgumentOutOfRangeException> (() => new BoundStream(memory, -1, 10, true));
                Assert.Throws <ArgumentOutOfRangeException> (() => new BoundStream(memory, 5, 1, true));

                using (var stream = new BoundStream(memory, 0, -1, true))
                    AssertStreamArguments(stream);
            }

            using (var memory = new MemoryStream()) {
                using (var stream = new ChainedStream()) {
                    stream.Add(memory);

                    Assert.Throws <ArgumentNullException> (() => stream.Add(null));

                    AssertStreamArguments(stream);
                }
            }
        }
Example #5
0
        /// <summary>
        /// Load a <see cref="MimeEntity"/> from the specified content stream.
        /// </summary>
        /// <remarks>
        /// This method is mostly meant for use with APIs such as <see cref="System.Net.HttpWebResponse"/>
        /// where the headers are parsed separately from the content.
        /// </remarks>
        /// <returns>The parsed MIME entity.</returns>
        /// <param name="options">The parser options.</param>
        /// <param name="contentType">The Content-Type of the stream.</param>
        /// <param name="content">The content stream.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="options"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="contentType"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="content"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.FormatException">
        /// There was an error parsing the entity.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        public static MimeEntity Load(ParserOptions options, ContentType contentType, Stream content, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            if (contentType == null)
            {
                throw new ArgumentNullException("contentType");
            }

            if (content == null)
            {
                throw new ArgumentNullException("content");
            }

            var format = FormatOptions.Default.Clone();

            format.NewLineFormat = NewLineFormat.Dos;

            var encoded = contentType.Encode(format, Encoding.UTF8);
            var header  = string.Format("Content-Type:{0}\r\n", encoded);
            var chained = new ChainedStream();

            chained.Add(new MemoryStream(Encoding.UTF8.GetBytes(header), false));
            chained.Add(content);

            return(Load(options, chained, cancellationToken));
        }
Example #6
0
        public ChainedStreamTests()
        {
            var bytes    = new byte[10 * 1024];
            int position = 0;

            random = new Random();
            random.NextBytes(bytes);

            // this is our master stream, all operations on the chained stream
            // should match the results on this stream
            master  = new MemoryStream(bytes);
            backing = new MemoryStream(master.ToArray());
            cbuf    = new byte[4096];
            mbuf    = new byte[4096];

            // make a handful of smaller streams based on master to chain together
            chained = new ChainedStream();
            while (position < bytes.Length)
            {
                int n = Math.Min(bytes.Length - position, random.Next() % 4096);

                var stream = new BoundStream(backing, position, position + n, true);

                lengths.Add(n);
                position += n;

                chained.Add(new ReadOneByteStream(stream));
            }
        }
        private static async Task <Multipart> ReadMultipartAsync(HttpContent content, CancellationToken ct)
        {
            var responseStream = await content
                                 .ReadAsStreamAsync();

            var headerStream = new MemoryStream();

            using (var headerWriter = new StreamWriter(headerStream, new UTF8Encoding(false), 1000, true)
            {
                NewLine = "\r\n",
            })
            {
                foreach (var contentHeader in content.Headers)
                {
                    var line = $"{contentHeader.Key}: {string.Join(", ", contentHeader.Value)}";
                    await headerWriter.WriteLineAsync(line);
                }

                await headerWriter.WriteLineAsync();
            }

            headerStream.Position = 0;

            using (var input = new ChainedStream())
            {
                input.Add(headerStream);
                input.Add(responseStream, true);

                var multipart = MimeEntity.Load(input, ct);
                return(Assert.IsType <Multipart>(multipart));
            }
        }
        private Stream EncryptData(Stream secretStream, SymmetricAlgorithm algorithm)
        {
            Stream encryptedStream = CreateVirtualStreamOf(secretStream);

            var         cryptoStream = new CryptoStream(encryptedStream, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
            CipherMode  origMode     = algorithm.Mode;
            PaddingMode origPadding  = algorithm.Padding;

            try
            {
                algorithm.Mode    = Mode;
                algorithm.Padding = Padding;
                secretStream.CopyTo(cryptoStream);
            }
            finally
            {
                cryptoStream.FlushFinalBlock();
                algorithm.Mode    = origMode;
                algorithm.Padding = origPadding;
            }

            encryptedStream.Position = 0;

            if (Mode != CipherMode.ECB)
            {
                var chainedStream = new ChainedStream();
                chainedStream.Add(new MemoryStream(algorithm.IV));
                chainedStream.Add(encryptedStream);

                encryptedStream = chainedStream;
            }

            return(encryptedStream);
        }
Example #9
0
        public static MimeMessage ParseMessage(Stream inputStream, HTTPHeaders headers, CancellationToken cancellationToken)
        {
            if (inputStream == null || inputStream == Stream.Null)
            {
                return(null);
            }

            var headerArray = headers.ToArray();

            if (IsMimeMessage(headerArray) == false)
            {
                return(null);
            }

            string headerString = String.Join("\r\n", headerArray.Select(h => $"{h.Name}: {h.Value}"));

            try
            {
                using (ChainedStream streamWithHeaders = new ChainedStream())
                {
                    streamWithHeaders.Add(new MemoryStream(Encoding.UTF8.GetBytes(headerString)), false);
                    streamWithHeaders.Add(inputStream, false);

                    var parser = new MimeKit.MimeParser(streamWithHeaders);

                    return(parser.ParseMessage(cancellationToken));
                }
            }
            catch (FormatException)
            {
                return(null);
            }
        }
Example #10
0
        /// <summary>
        /// Join the specified message/partial parts into the complete message.
        /// </summary>
        /// <param name="options">The parser options to use.</param>
        /// <param name="partials">The list of partial message parts.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="options"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="partials"/>is <c>null</c>.</para>
        /// </exception>
        public static MimeMessage Join(ParserOptions options, IEnumerable <MessagePartial> partials)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            if (partials == null)
            {
                throw new ArgumentNullException("partials");
            }

            var parts = partials.ToList();

            if (parts.Count == 0)
            {
                return(null);
            }

            parts.Sort(PartialCompare);

            if (!parts[parts.Count - 1].Total.HasValue)
            {
                throw new ArgumentException("partials");
            }

            int total = parts[parts.Count - 1].Total.Value;

            if (parts.Count != total)
            {
                throw new ArgumentException("partials");
            }

            string id = parts[0].Id;

            using (var chained = new ChainedStream()) {
                // chain all of the partial content streams...
                for (int i = 0; i < parts.Count; i++)
                {
                    int number = parts[i].Number.Value;

                    if (number != i + 1)
                    {
                        throw new ArgumentException("partials");
                    }

                    var content = parts[i].ContentObject;
                    content.Stream.Seek(0, SeekOrigin.Begin);
                    var filtered = new FilteredStream(content.Stream);
                    filtered.Add(DecoderFilter.Create(content.Encoding));
                    chained.Add(filtered);
                }

                var parser = new MimeParser(options, chained);

                return(parser.ParseMessage());
            }
        }
        public void DisposeWithNoStreams()
        {
            // ARRANGE
            var    chain  = new ChainedStream(Enumerable.Empty <Stream>());
            Action action = () => chain.Dispose();

            // ACT, ASSERT
            action.ShouldNotThrow();
        }
Example #12
0
        /// <summary>
        /// Joins the specified message/partial parts into the complete message.
        /// </summary>
        /// <remarks>
        /// Combines all of the message/partial fragments into its original,
        /// complete, message.
        /// </remarks>
        /// <returns>The re-combined message.</returns>
        /// <param name="options">The parser options to use.</param>
        /// <param name="partials">The list of partial message parts.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <para><paramref name="options"/> is <c>null</c>.</para>
        /// <para>-or-</para>
        /// <para><paramref name="partials"/>is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// <para>The last partial does not have a Total.</para>
        /// <para>-or-</para>
        /// <para>The number of partials provided does not match the expected count.</para>
        /// <para>-or-</para>
        /// <para>One or more partials is missing.</para>
        /// </exception>
        public static MimeMessage Join(ParserOptions options, IEnumerable <MessagePartial> partials)
        {
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            if (partials == null)
            {
                throw new ArgumentNullException("partials");
            }

            var parts = partials.ToList();

            if (parts.Count == 0)
            {
                return(null);
            }

            parts.Sort(PartialCompare);

            if (!parts[parts.Count - 1].Total.HasValue)
            {
                throw new ArgumentException("The last partial does not have a Total.", "partials");
            }

            int total = parts[parts.Count - 1].Total.Value;

            if (parts.Count != total)
            {
                throw new ArgumentException("The number of partials provided does not match the expected count.", "partials");
            }

            string id = parts[0].Id;

            using (var chained = new ChainedStream()) {
                // chain all of the partial content streams...
                for (int i = 0; i < parts.Count; i++)
                {
                    int number = parts[i].Number.Value;

                    if (number != i + 1)
                    {
                        throw new ArgumentException("One or more partials is missing.", "partials");
                    }

                    var content = parts[i].ContentObject;

                    chained.Add(content.Open());
                }

                var parser = new MimeParser(options, chained);

                return(parser.ParseMessage());
            }
        }
        private static void Read_WithNoStreams_ReturnsZero(Func <ChainedStream, byte[], int, int, int> readFunc)
        {
            // ARRANGE
            var chain = new ChainedStream(Enumerable.Empty <Stream>());

            // ACT
            var read = readFunc(chain, new byte[12], 0, 12);

            // ASSERT
            read.Should().Be(0);
        }
Example #14
0
        public void TestGetSetTimeouts()
        {
            using (var chained = new ChainedStream()) {
                chained.Add(new TimeoutStream());

                Assert.Throws <InvalidOperationException> (() => { int x = chained.ReadTimeout; });
                Assert.Throws <InvalidOperationException> (() => { int x = chained.WriteTimeout; });

                Assert.Throws <InvalidOperationException> (() => chained.ReadTimeout  = 5);
                Assert.Throws <InvalidOperationException> (() => chained.WriteTimeout = 5);
            }
        }
Example #15
0
 public override void Write(byte[] buffer, int offset, int count)
 {
     ChainedStream.Write(buffer, offset, count);
     if (HasErrored)
     {
         return;
     }
     if ((((_captureStream) != null)))
     {
         _captureStream.Write(buffer, offset, count);
     }
 }
Example #16
0
 public override void Flush()
 {
     ChainedStream.Flush();
     if (HasErrored)
     {
         return;
     }
     if ((((_captureStream) != null)))
     {
         _captureStream.Flush();
     }
 }
        private static void Read_WhenAvailableIsSameAsDesired_ReadsProperly(Func <ChainedStream, byte[], int, int, int> readFunc)
        {
            // ARRANGE
            const int availableBytes = 8;
            var       buffer         = new byte[availableBytes + 4];
            var       chain          = new ChainedStream(new[] { new MemoryStream(BytesA), new MemoryStream(BytesB) });

            // ACT
            var read = readFunc(chain, buffer, 2, availableBytes);

            // ASSERT
            read.Should().Be(availableBytes);
            buffer.ShouldBeEquivalentTo(new byte[2].Concat(BytesA).Concat(BytesB).Concat(new byte[2]));
        }
        private static void Read_WhenDisposeIsDisabled_DoesNotDisposeStreams(Func <ChainedStream, byte[], int, int, int> readFunc)
        {
            // ARRANGE
            var streamA = new DisposedStream(8);
            var streamB = new DisposedStream(8);
            var chain   = new ChainedStream(new[] { streamA, streamB }, false);

            // ACT
            readFunc(chain, new byte[12], 0, 12);

            // ASSERT
            streamA.Disposed.Should().BeFalse();
            streamB.Disposed.Should().BeFalse();
        }
        public void DisposeWhenNotStarted()
        {
            // ARRANGE
            var streamA = new DisposedStream(8);
            var streamB = new DisposedStream(8);
            var chain   = new ChainedStream(new[] { streamA, streamB });

            // ACT
            chain.Dispose();

            // ASSERT
            streamA.Disposed.Should().BeTrue();
            streamB.Disposed.Should().BeTrue();
        }
        private static void Read_WithMultipleReads_ConsumesEverything(Func <ChainedStream, byte[], int, int, int> readFunc)
        {
            // ARRANGE
            var buffer = new byte[12];
            var chain  = new ChainedStream(new[] { new MemoryStream(BytesA), new MemoryStream(BytesB) });

            // ACT
            var readA = readFunc(chain, buffer, 2, 6);
            var readB = readFunc(chain, buffer, 8, 4);

            // ASSERT
            readA.Should().Be(6);
            readB.Should().Be(2);
            buffer.ShouldBeEquivalentTo(new byte[2].Concat(BytesA).Concat(BytesB).Concat(new byte[2]));
        }
        public void DisposeWhenAllFinished()
        {
            // ARRANGE
            var streamA = new DisposedStream(8);
            var streamB = new DisposedStream(8);
            var chain   = new ChainedStream(new[] { streamA, streamB });

            chain.Read(new byte[16], 0, 16);

            // ACT
            chain.Dispose();

            // ASSERT
            streamA.Disposed.Should().BeTrue();
            streamB.Disposed.Should().BeTrue();
        }
Example #22
0
        public void TestCanReadWriteSeek()
        {
            var buffer = new byte[1024];

            using (var chained = new ChainedStream()) {
                chained.Add(new CanReadWriteSeekStream(true, false, false, false));

                Assert.IsTrue(chained.CanRead);
                Assert.IsFalse(chained.CanWrite);
                Assert.IsFalse(chained.CanSeek);
                Assert.IsFalse(chained.CanTimeout);

                Assert.Throws <NotImplementedException> (() => chained.Read(buffer, 0, buffer.Length));
                Assert.Throws <NotSupportedException> (() => chained.Write(buffer, 0, buffer.Length));
                Assert.Throws <NotSupportedException> (() => chained.Seek(0, SeekOrigin.End));
            }

            using (var chained = new ChainedStream()) {
                chained.Add(new CanReadWriteSeekStream(false, true, false, false));

                Assert.IsFalse(chained.CanRead);
                Assert.IsTrue(chained.CanWrite);
                Assert.IsFalse(chained.CanSeek);
                Assert.IsFalse(chained.CanTimeout);

                Assert.Throws <NotSupportedException> (() => chained.Read(buffer, 0, buffer.Length));
                Assert.Throws <NotImplementedException> (() => chained.Write(buffer, 0, buffer.Length));
                Assert.Throws <NotSupportedException> (() => chained.Seek(0, SeekOrigin.End));
            }

            using (var chained = new ChainedStream()) {
                chained.Add(new CanReadWriteSeekStream(false, false, true, false));

                Assert.IsFalse(chained.CanRead);
                Assert.IsFalse(chained.CanWrite);
                Assert.IsTrue(chained.CanSeek);
                Assert.IsFalse(chained.CanTimeout);

                Assert.Throws <NotSupportedException> (() => chained.Read(buffer, 0, buffer.Length));
                Assert.Throws <NotSupportedException> (() => chained.Write(buffer, 0, buffer.Length));
                Assert.Throws <NotImplementedException> (() => chained.Seek(0, SeekOrigin.End));
            }
        }
        private static void Read_WhenStreamsReturnVariableCount_ReadsProperly(Func <ChainedStream, byte[], int, int, int> readFunc)
        {
            // ARRANGE
            const int availableBytes = 16;
            const int desiredBytes   = 20;
            var       buffer         = new byte[desiredBytes];
            var       chain          = new ChainedStream(new[] { GetVariableReadStreamMock(8, 97).Object, GetVariableReadStreamMock(8, 98).Object });

            // ACT
            var read = readFunc(chain, buffer, 2, desiredBytes);

            // ASSERT
            read.Should().Be(availableBytes);
            buffer.ShouldBeEquivalentTo(Enumerable.Empty <byte>()
                                        .Concat(new byte[2])
                                        .Concat(Enumerable.Repeat((byte)97, 8))
                                        .Concat(Enumerable.Repeat((byte)98, 8))
                                        .Concat(new byte[2]));
        }
Example #24
0
        public void TestChainedHeadersAndContent()
        {
            var buf     = Encoding.ASCII.GetBytes("Content-Type: text/plain\r\n\r\n");
            var headers = new MemoryStream();
            var content = new MemoryStream();

            headers.Write(buf, 0, buf.Length);
            headers.Position = 0;

            buf = Encoding.ASCII.GetBytes("Hello, world!\r\n");

            content.Write(buf, 0, buf.Length);
            content.Position = 0;

            using (var chained = new ChainedStream()) {
                chained.Add(headers);
                chained.Add(content);

                var entity = MimeEntity.Load(chained, true) as TextPart;

                Assert.AreEqual("Hello, world!" + Environment.NewLine, entity.Text);
            }
        }