Skip to content

Commit

Permalink
Match prefixes for routes properly in owin handlers.
Browse files Browse the repository at this point in the history
- Added functional and unit tests.

#1445
  • Loading branch information
davidfowl committed Jan 30, 2013
1 parent 663f54a commit eb8a2ff
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR.Owin.Infrastructure;

namespace Microsoft.AspNet.SignalR.Owin.Handlers
{
Expand All @@ -25,7 +26,7 @@ public HubDispatcherHandler(AppFunc next, string path, HubConfiguration configur
public Task Invoke(IDictionary<string, object> environment)
{
var path = environment.Get<string>(OwinConstants.RequestPath);
if (path == null || !path.StartsWith(_path, StringComparison.OrdinalIgnoreCase))
if (path == null || !PrefixMatcher.IsMatch(_path, path))
{
return _next(environment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hosting;
using Microsoft.AspNet.SignalR.Owin.Infrastructure;

namespace Microsoft.AspNet.SignalR.Owin.Handlers
{
Expand All @@ -27,7 +28,7 @@ public PersistentConnectionHandler(AppFunc next, string path, Type connectionTyp
public Task Invoke(IDictionary<string, object> environment)
{
var path = environment.Get<string>(OwinConstants.RequestPath);
if (path == null || !path.StartsWith(_path, StringComparison.OrdinalIgnoreCase))
if (path == null || !PrefixMatcher.IsMatch(_path, path))
{
return _next(environment);
}
Expand Down
48 changes: 48 additions & 0 deletions src/Microsoft.AspNet.SignalR.Owin/Infrastructure/PrefixMatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;

namespace Microsoft.AspNet.SignalR.Owin.Infrastructure
{
internal static class PrefixMatcher
{
public static bool IsMatch(string pathBase, string path)
{
pathBase = EnsureStartsWithSlash(pathBase);
path = EnsureStartsWithSlash(path);

var pathLength = path.Length;
var pathBaseLength = pathBase.Length;

if (pathLength < pathBaseLength)
{
return false;
}

if (pathLength > pathBaseLength && path[pathBaseLength] != '/')
{
return false;
}

if (!path.StartsWith(pathBase, StringComparison.OrdinalIgnoreCase))
{
return false;
}

return true;
}

private static string EnsureStartsWithSlash(string path)
{
if (path.Length == 0)
{
return path;
}

if (path[0] == '/')
{
return path;
}

return '/' + path;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<Compile Include="Handlers\CallHandler.cs" />
<Compile Include="Handlers\PersistentConnectionHandler.cs" />
<Compile Include="Handlers\HubDispatcherHandler.cs" />
<Compile Include="Infrastructure\PrefixMatcher.cs" />
<Compile Include="Infrastructure\UrlDecoder.cs" />
<Compile Include="RequestExtensions.cs" />
<Compile Include="Resources.Designer.cs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
<Compile Include="..\Microsoft.AspNet.SignalR.Owin\Infrastructure\ParamDictionary.cs">
<Link>Infrastructure\ParamDictionary.cs</Link>
</Compile>
<Compile Include="..\Microsoft.AspNet.SignalR.Owin\Infrastructure\PrefixMatcher.cs">
<Link>Infrastructure\PrefixMatcher.cs</Link>
</Compile>
<Compile Include="..\Microsoft.AspNet.SignalR.Owin\Infrastructure\UrlDecoder.cs">
<Link>Infrastructure\UrlDecoder.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.FunctionalTests.Infrastructure;
using Microsoft.AspNet.SignalR.Hosting.Memory;
using Owin;
using Xunit;
using Xunit.Extensions;

Expand Down Expand Up @@ -56,7 +58,7 @@ public void FallbackToLongPollingWorks(HostType hostType, TransportType transpor
host.Initialize();

var connection = new Client.Connection(host.Url + "/fall-back");

connection.Start(host.Transport).Wait();

Assert.Equal(connection.Transport.Name, "longPolling");
Expand All @@ -65,6 +67,84 @@ public void FallbackToLongPollingWorks(HostType hostType, TransportType transpor
}
}

[Fact]
public void PrefixMatchingIsNotGreedy()
{
using (var host = new MemoryHost())
{
host.Configure(app =>
{
app.MapConnection<MyConnection>("/echo");
app.MapConnection<MyConnection2>("/echo2");
});

var tcs = new TaskCompletionSource<string>();
var connection = new Connection("http://foo/echo2");

connection.Received += data =>
{
tcs.TrySetResult(data);
};

connection.Start(host).Wait();
connection.Send("");

Assert.Equal("MyConnection2", tcs.Task.Result);
}
}

[Fact]
public void PrefixMatchingIsNotGreedyNotStartingWithSlashes()
{
using (var host = new MemoryHost())
{
host.Configure(app =>
{
app.MapConnection<MyConnection>("echo");
app.MapConnection<MyConnection2>("echo2");
});

var tcs = new TaskCompletionSource<string>();
var connection = new Connection("http://foo/echo2");

connection.Received += data =>
{
tcs.TrySetResult(data);
};

connection.Start(host).Wait();
connection.Send("");

Assert.Equal("MyConnection2", tcs.Task.Result);
}
}

[Fact]
public void PrefixMatchingIsNotGreedyExactMatch()
{
using (var host = new MemoryHost())
{
host.Configure(app =>
{
app.MapConnection<MyConnection>("echo");
app.MapConnection<MyConnection2>("echo2");
});

var tcs = new TaskCompletionSource<string>();
var connection = new Connection("http://foo/echo");

connection.Received += data =>
{
tcs.TrySetResult(data);
};

connection.Start(host).Wait();
connection.Send("");

Assert.Equal("MyConnection", tcs.Task.Result);
}
}

[Theory]
[InlineData(HostType.Memory, TransportType.ServerSentEvents)]
[InlineData(HostType.Memory, TransportType.LongPolling)]
Expand Down Expand Up @@ -178,5 +258,21 @@ public void ClientStaysReconnectedAfterDisconnectTimeout(HostType hostType, Tran
}
}
}

private class MyConnection : PersistentConnection
{
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Send(connectionId, "MyConnection");
}
}

private class MyConnection2 : PersistentConnection
{
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Send(connectionId, "MyConnection2");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
<Compile Include="..\..\src\Common\CommonVersionInfo.cs">
<Link>Properties\CommonVersionInfo.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft.AspNet.SignalR.Owin\Infrastructure\PrefixMatcher.cs">
<Link>Infrastructure\PrefixMatcher.cs</Link>
</Compile>
<Compile Include="..\Microsoft.AspNet.SignalR.Tests.Common\Infrastructure\CountDownRange.cs">
<Link>Infrastructure\CountDownRange.cs</Link>
</Compile>
Expand All @@ -83,6 +86,7 @@
<Compile Include="PersistentConnectionFactoryFacts.cs" />
<Compile Include="PersistentConnectionFacts.cs" />
<Compile Include="PersistentResponseFacts.cs" />
<Compile Include="PrefixMatcherFacts.cs" />
<Compile Include="Server\AckHandlerFacts.cs" />
<Compile Include="Server\DiffSetFacts.cs" />
<Compile Include="Server\Hubs\HubDispatcherFacts.cs" />
Expand Down
78 changes: 78 additions & 0 deletions tests/Microsoft.AspNet.SignalR.Tests/PrefixMatcherFacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
using Xunit;

namespace Microsoft.AspNet.SignalR.Tests
{
public class PrefixMatcherFacts
{
[Fact]
public void ExactMatch()
{
// Act
var result = PrefixMatcher.IsMatch("/echo", "/echo");

// Assert
Assert.True(result);
}

[Fact]
public void PrefixMatches()
{
// Act
var result = PrefixMatcher.IsMatch("/echo", "/echo/foo");

// Assert
Assert.True(result);
}

[Fact]
public void InvalidPrefixDoesNotMatch()
{
// Act
var result = PrefixMatcher.IsMatch("/echo", "/echo2/foo");

// Assert
Assert.False(result);
}

[Fact]
public void LongerPrefixDoesNotMatch()
{
// Act
var result = PrefixMatcher.IsMatch("/echo2/foo/bar", "/echo2/foo");

// Assert
Assert.False(result);
}

[Fact]
public void PrefixWithoutSlashesDoesntMatchIfDifferent()
{
// Act
var result = PrefixMatcher.IsMatch("echo", "echo2");

// Assert
Assert.False(result);
}

[Fact]
public void PrefixWithoutSlashesMatchesIfValidPrefix()
{
// Act
var result = PrefixMatcher.IsMatch("echo", "echo/negotiate");

// Assert
Assert.True(result);
}

[Fact]
public void EmptyPrefixMatchesEverything()
{
// Act
var result = PrefixMatcher.IsMatch("", "echo/negotiate");

// Assert
Assert.True(result);
}
}
}

0 comments on commit eb8a2ff

Please sign in to comment.