Skip to content

Commit

Permalink
fixed bug with not handling multiple buffers in the token reader prop…
Browse files Browse the repository at this point in the history
…erly
  • Loading branch information
cosullivan committed Jun 15, 2021
1 parent f0b6751 commit 2b455e6
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 90 deletions.
14 changes: 13 additions & 1 deletion Examples/SampleApp/Examples/SessionTracingExample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ public static void Run()
.Build();

var server = new SmtpServer.SmtpServer(options, ServiceProvider.Default);

server.SessionCreated += OnSessionCreated;
server.SessionCompleted += OnSessionCompleted;
server.SessionFaulted += OnSessionFaulted;
server.SessionCancelled += OnSessionCancelled;

var serverTask = server.StartAsync(_cancellationTokenSource.Token);

Expand All @@ -32,6 +34,16 @@ public static void Run()
serverTask.WaitWithoutException();
}

static void OnSessionFaulted(object sender, SessionFaultedEventArgs e)
{
Console.WriteLine("SessionFaulted: {0}", e.Exception);
}

static void OnSessionCancelled(object sender, SessionEventArgs e)
{
Console.WriteLine("SessionCancelled");
}

static void OnSessionCreated(object sender, SessionEventArgs e)
{
Console.WriteLine("SessionCreated: {0}", e.Context.Properties[EndpointListener.RemoteEndPointKey]);
Expand Down
9 changes: 7 additions & 2 deletions Examples/SampleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using MimeKit;
using SampleApp.Examples;
using SmtpServer.IO;
using SmtpServer.Protocol;
using SmtpServer.Tests;
using SmtpServer.Text;

namespace SampleApp
Expand All @@ -22,9 +24,12 @@ static void Main(string[] args)
//SimpleServerExample.Run();
//CustomEndpointListenerExample.Run();
//ServerCancellingExample.Run();
//SessionTracingExample.Run();
SessionTracingExample.Run();
//DependencyInjectionExample.Run();
SecureServerExample.Run();
//SecureServerExample.Run();

//SampleMailClient.Send(user: "user1", password: "password1", useSsl: false, port: 587);
//SampleMailClient.Send(useSsl: false, port: 587);

//var files = Directory.GetFiles(@"C:\Temp\enron_mail_20150507.tar", "*.*", SearchOption.AllDirectories).ToList();
//Console.WriteLine(files.OrderByDescending(file => new FileInfo(file).Length).First());
Expand Down
1 change: 1 addition & 0 deletions Examples/SampleApp/SampleApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Src\SmtpServer.Tests\SmtpServer.Tests.csproj" />
<ProjectReference Include="..\..\Src\SmtpServer\SmtpServer.csproj" />
</ItemGroup>

Expand Down
9 changes: 7 additions & 2 deletions Examples/SampleApp/SampleMailClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@ public static void Send(
string password = null,
MimeEntity body = null,
int count = 1,
bool useSsl = false)
bool useSsl = false,
int port = 9025)
{
//var message = MimeMessage.Load(@"C:\Dev\Cain\Temp\message.eml");
var message = new MimeMessage();

message.From.Add(MailboxAddress.Parse(from ?? "[email protected]"));
message.To.Add(MailboxAddress.Parse(to ?? "[email protected]"));
//for (var i = 0; i < 400; i++)
//{
// message.To.Add(MailboxAddress.Parse(to ?? $"testuser{i+1000}@longemaildomain1000001.com"));
//}
message.Subject = subject ?? "Hello";
message.Body = body ?? new TextPart("plain")
{
Expand All @@ -28,7 +33,7 @@ public static void Send(

using var client = new SmtpClient();

client.Connect("localhost", 9025, useSsl);
client.Connect("localhost", port, useSsl);

if (user != null && password != null)
{
Expand Down
33 changes: 33 additions & 0 deletions Src/SmtpServer.Tests/SmtpParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Net;
using System.Text;
using SmtpServer.IO;
using SmtpServer.Mail;
using SmtpServer.Protocol;
using SmtpServer.Text;
Expand All @@ -19,6 +20,18 @@ static TokenReader CreateReader(string text)
return new TokenReader(new ReadOnlySequence<byte>(buffer, 0, buffer.Length));
}

static TokenReader CreateReader(params byte[][] buffers)
{
var segmentList = new ByteArraySegmentList();

foreach (var buffer in buffers)
{
segmentList.Append(buffer);
}

return new TokenReader(segmentList.Build());
}

static SmtpParser Parser => new SmtpParser(new SmtpCommandFactory());

[Fact]
Expand Down Expand Up @@ -210,6 +223,9 @@ public void CanNotMakeMail(string input)
[InlineData("RCPT TO:<[email protected]>", "cain.osullivan", "gmail.com")]
[InlineData(@"RCPT TO:<""Abc@def""@example.com>", "Abc@def", "example.com")]
[InlineData("RCPT TO:<pelé@example.com>", "pelé", "example.com")]
[InlineData("RCPT TO:<@example1.com:[email protected]>", "someone", "example.com")]
[InlineData("RCPT TO:<@example1.com,@example2.com:[email protected]>", "someone", "example.com")]
[InlineData("RCPT TO:<example/[email protected]>", "example/example", "example.com")]
public void CanMakeRcpt(string input, string user, string host)
{
// arrange
Expand All @@ -225,6 +241,22 @@ public void CanMakeRcpt(string input, string user, string host)
Assert.Equal(host, ((RcptCommand)command).Address.Host);
}

[Theory]
[InlineData("RCPT TO:<someone@@example.com>")]
[InlineData("RCPT TO:<[email protected]>")]
[InlineData("RCPT TO:<someone@-examplecom>")]
public void CanNotMakeRcpt(string input)
{
// arrange
var reader = CreateReader(input);

// act
var result = Parser.TryMakeRcpt(ref reader, out _, out _);

// assert
Assert.False(result);
}

[Fact]
public void CanMakeProxyUnknown()
{
Expand Down Expand Up @@ -389,6 +421,7 @@ public void CanMakeDomain()
[InlineData(@"[email protected]", "$A12345", "example.com")]
[InlineData(@"!def!xyz%[email protected]", "!def!xyz%abc", "example.com")]
[InlineData(@"[email protected]", "_somename", "example.com")]
[InlineData(@"[email protected]", "somename", "127.0.0.1")]
public void CanMakeMailbox(string email, string user, string host)
{
// arrange
Expand Down
42 changes: 42 additions & 0 deletions Src/SmtpServer.Tests/TokenReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,47 @@ public void CanTokenizeMultiSegmentWord()
Assert.Equal("DEF", reader.Take().ToText());
Assert.Equal(TokenKind.None, reader.Take().Kind);
}

[Fact]
public void CanMakeSequences()
{
// arrange
var reader = CreateReader("1", "AB", "CDE", "F234", "5678");

// act
var made1 = reader.TryMake(TryMakeNumber, out var sequence1);
var made2 = reader.TryMake(TryMakeText, out var sequence2);
var made3 = reader.TryMake(TryMakeNumber, out var sequence3);

// assert
Assert.True(made1);
Assert.Equal("1", StringUtil.Create(sequence1));
Assert.True(made2);
Assert.Equal("ABCDEF", StringUtil.Create(sequence2));
Assert.True(made3);
Assert.Equal("2345678", StringUtil.Create(sequence3));

static bool TryMakeText(ref TokenReader r)
{
if (r.Peek().Kind == TokenKind.Text)
{
r.Skip(TokenKind.Text);
return true;
}

return false;
}

static bool TryMakeNumber(ref TokenReader r)
{
if (r.Peek().Kind == TokenKind.Number)
{
r.Skip(TokenKind.Number);
return true;
}

return false;
}
}
}
}
60 changes: 60 additions & 0 deletions Src/SmtpServer/IO/BuffersExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,65 @@ static bool TryMoveNext(ref ReadOnlySequence<byte> source, ref SequencePosition
span = default;
return false;
}

internal static bool CaseInsensitiveStringEquals(this ReadOnlySequence<byte> buffer, ref Span<char> text)
{
if (buffer.IsSingleSegment)
{
var span = buffer.First.Span;

return CaseInsensitiveStringEquals(ref span, ref text, 0);
}

var i = 0;
var position = buffer.GetPosition(0);

while (buffer.TryGet(ref position, out var memory, advance: true))
{
var span = memory.Span;

if (CaseInsensitiveStringEquals(ref span, ref text, i) == false)
{
return false;
}

i += span.Length;
}

return i > 0;
}

static bool CaseInsensitiveStringEquals(ref ReadOnlySpan<byte> span, ref Span<char> text, int offset)
{
if (text.Length - offset != span.Length)
{
return false;
}

for (var i = 0; i < span.Length; i++)
{
var ch = (char)span[i];

if (char.ToUpper(ch) != char.ToUpper(text[i + offset]))
{
return false;
}
}

return true;
}

internal static bool IsHex(this ref ReadOnlySpan<byte> buffer)
{
for (var i = 0; i < buffer.Length; i++)
{
if ((buffer[i] < 'a' || buffer[i] > 'f') && (buffer[i] < 'A' || buffer[i] > 'F'))
{
return false;
}
}

return true;
}
}
}
1 change: 1 addition & 0 deletions Src/SmtpServer/Protocol/SmtpParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using SmtpServer.IO;
using SmtpServer.Mail;
using SmtpServer.Text;

Expand Down
5 changes: 4 additions & 1 deletion Src/SmtpServer/SmtpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ async Task ListenAsync(IEndpointDefinition endpointDefinition, CancellationToken
continue;
}

_sessions.Run(sessionContext, cancellationTokenSource.Token);
if (sessionContext.Pipe != null)
{
_sessions.Run(sessionContext, cancellationTokenSource.Token);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions Src/SmtpServer/SmtpServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<LangVersion>8.0</LangVersion>
<AssemblyName>SmtpServer</AssemblyName>
<RootNamespace>SmtpServer</RootNamespace>
<Version>9.0.0</Version>
<Version>9.0.1</Version>
<Description>.NET SmtpServer</Description>
<Authors>Cain O'Sullivan</Authors>
<Company />
Expand All @@ -15,8 +15,8 @@
<PackageTags>smtp smtpserver smtp server</PackageTags>
<PackageLicenseUrl></PackageLicenseUrl>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<AssemblyVersion>9.0.0.0</AssemblyVersion>
<FileVersion>9.0.0.0</FileVersion>
<AssemblyVersion>9.0.1.0</AssemblyVersion>
<FileVersion>9.0.1.0</FileVersion>
<PackageReleaseNotes>Version 9
Breaking API change by removing the Certificate from the server options and adding it to the endpoint.

Expand Down
2 changes: 2 additions & 0 deletions Src/SmtpServer/SmtpSessionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ async Task RunAsync(SmtpSessionHandle handle, CancellationToken cancellationToke
{
try
{
cancellationToken.ThrowIfCancellationRequested();

_smtpServer.OnSessionCreated(new SessionEventArgs(handle.SessionContext));

await handle.Session.RunAsync(cancellationToken);
Expand Down
48 changes: 0 additions & 48 deletions Src/SmtpServer/Text/BufferExtensions.cs

This file was deleted.

Loading

0 comments on commit 2b455e6

Please sign in to comment.