Example #1
0
        public async Task EmptyStreamReader()
        {
            byte []               buffer      = new byte[1000];
            var                   testString  = "";
            MemoryStream          inputStream = new MemoryStream(Encoding.ASCII.GetBytes(testString));
            UnencodedStreamReader reader      = new UnencodedStreamReader(inputStream);
            var                   read        = await reader.TryReadLineAsync(buffer, CancellationToken.None);

            Assert.False(read.HasValue);
            Assert.Equal(0, buffer[0]);
            Assert.Equal(testString.Length, reader.BytePositition);
        }
Example #2
0
        public async Task ReallyLongLine()
        {
            byte[]                buffer      = new byte[10000];
            var                   testString  = "A" + new string('_', 5000) + "B";
            MemoryStream          inputStream = new MemoryStream(Encoding.ASCII.GetBytes(testString));
            UnencodedStreamReader reader      = new UnencodedStreamReader(inputStream);
            var                   read        = await reader.TryReadLineAsync(buffer, CancellationToken.None);

            Assert.Equal(testString.Length, read);
            Assert.Equal(testString, Encoding.ASCII.GetString(buffer, 0, read.Value));
            Assert.Equal(testString.Length, reader.BytePositition);
        }
Example #3
0
        public async Task MultipleLines()
        {
            byte[]                buffer      = new byte[1000];
            var                   testString  = "ABC\r\nDEF\r\nGHI\r\n";
            MemoryStream          inputStream = new MemoryStream(Encoding.ASCII.GetBytes(testString));
            UnencodedStreamReader reader      = new UnencodedStreamReader(inputStream);
            var                   read        = await reader.TryReadLineAsync(buffer, CancellationToken.None);

            Assert.Equal(3, read);
            Assert.Equal("ABC", Encoding.ASCII.GetString(buffer, 0, read.Value));
            Assert.Equal(5, reader.BytePositition);
            read = await reader.TryReadLineAsync(buffer, CancellationToken.None);

            Assert.Equal(3, read);
            Assert.Equal("DEF", Encoding.ASCII.GetString(buffer, 0, read.Value));
            read = await reader.TryReadLineAsync(buffer, CancellationToken.None);

            Assert.Equal(3, read);
            Assert.Equal("GHI", Encoding.ASCII.GetString(buffer, 0, read.Value));
            read = await reader.TryReadLineAsync(buffer, CancellationToken.None);

            Assert.False(read.HasValue);
            Assert.Equal(testString.Length, reader.BytePositition);
        }
Example #4
0
        public async Task <MimePartSpan> ReadStructureAsync(Stream mailStream, CancellationToken cancellationToken)
        {
            using (UnencodedStreamReader reader = new UnencodedStreamReader(mailStream, leaveOpen: true))
            {
                MimePartBuilder topLevelBuilder = new MimePartBuilder();
                var             currentBuilder  = topLevelBuilder;

                StringBuilder currentHeader = new StringBuilder();
                while ((await ReadLine(reader, cancellationToken)).TryGet(out Memory <byte> line))
                {
                    long position = reader.BytePositition;
                    if (currentBuilder.Parent != null &&
                        currentBuilder.Parent.EndBoundary.Span.SequenceEqual(line.Span))
                    {
                        currentBuilder = currentBuilder.Parent;
                        continue;
                    }

                    if (currentBuilder.Parent != null &&
                        currentBuilder.Parent.Boundary.Span.SequenceEqual(line.Span))
                    {
                        currentBuilder = new MimePartBuilder(currentBuilder.Parent, position);
                        continue;
                    }

                    if (!currentBuilder.Boundary.IsEmpty &&
                        currentBuilder.Children == null &&
                        currentBuilder.Boundary.Span.SequenceEqual(line.Span))
                    {
                        currentBuilder.Children = new List <MimePartBuilder>();
                        currentBuilder          = new MimePartBuilder(currentBuilder, position);
                        continue;
                    }

                    currentBuilder.End = position;

                    if (!currentBuilder.HeaderComplete)
                    {
                        void ProcessPendingHeader()
                        {
                            if (currentHeader.Length == 0)
                            {
                                return;
                            }

                            string headerString = currentHeader.ToString();

                            currentHeader.Clear();
                            if (TestRegex(ContentTypeRegex, headerString, out var match))
                            {
                                string type = match.Groups["type"].Value;
                                if (type == "multipart")
                                {
                                    CaptureCollection paramCaptures = match.Groups["param"].Captures;
                                    CaptureCollection valueCaptures = match.Groups["value"].Captures;
                                    for (int i = 0; i < paramCaptures.Count; i++)
                                    {
                                        switch (paramCaptures[i].Value.ToLowerInvariant())
                                        {
                                        case "charset":
                                            break;

                                        case "boundary":
                                            ReadOnlySpan <char> value = valueCaptures[i].Value.AsSpan();
                                            if (value.Length > 1 &&
                                                value[0] == '"' &&
                                                value[value.Length - 1] == '"')
                                            {
                                                value = value.Slice(1, value.Length - 2);
                                                if (value.Contains("\\", StringComparison.Ordinal))
                                                {
                                                    value = Regex.Replace(value.ToString(), @"\\.", m => m.Value[1].ToString());
                                                }
                                            }

                                            currentBuilder.EndBoundary =
                                                Encoding.ASCII.GetBytes("--" + value.ToString() + "--");
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        if (line.Length == 0)
                        {
                            // header's over, process pending ones
                            ProcessPendingHeader();
                            currentBuilder.ContentStart = position;
                            continue;
                        }

                        if (IsImportantHeader(line))
                        {
                            currentHeader.Append(Encoding.ASCII.GetString(line.Span));
                            continue;
                        }

                        if (currentHeader.Length > 0)
                        {
                            byte first = line.Span[0];
                            if (first == ' ' || first == '\t')
                            {
                                currentHeader.Append(Encoding.ASCII.GetString(line.Span));
                                continue;
                            }

                            // We found another header, process the current one.
                            ProcessPendingHeader();

                            if (IsImportantHeader(line))
                            {
                                currentHeader.Append(Encoding.ASCII.GetString(line.Span));
                            }
                        }
                    }
                }

                currentBuilder.End = reader.BytePositition;

                return(topLevelBuilder.ToMimePart());
            }
        }