public async Task RequestToDisposedConnectionIdReturns404(TransportType transportType) { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); connection.Status = DefaultConnectionContext.ConnectionStatus.Disposed; var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); SetTransport(context, transportType); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); await dispatcher.ExecuteAsync(context, options, app); Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode); }
public async Task WebSocketTransportTimesOutWhenCloseFrameNotReceived() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); SetTransport(context, TransportType.WebSockets); var services = new ServiceCollection(); services.AddEndPoint <ImmediatelyCompleteEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <ImmediatelyCompleteEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.WebSockets.CloseTimeout = TimeSpan.FromSeconds(1); var task = dispatcher.ExecuteAsync(context, options, app); await task.OrTimeout(); }
public async Task NegotiateReservesConnectionIdAndReturnsIt() { var manager = CreateConnectionManager(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = new DefaultHttpContext(); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); services.AddOptions(); var ms = new MemoryStream(); context.Request.Path = "/foo"; context.Request.Method = "OPTIONS"; context.Response.Body = ms; var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions(), app); var negotiateResponse = JsonConvert.DeserializeObject <JObject>(Encoding.UTF8.GetString(ms.ToArray())); var connectionId = negotiateResponse.Value <string>("connectionId"); Assert.True(manager.TryGetConnection(connectionId, out var connectionContext)); Assert.Equal(connectionId, connectionContext.ConnectionId); }
public async Task ConnectionStateSetToInactiveAfterPoll() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); var task = dispatcher.ExecuteAsync(context, options, app); var buffer = Encoding.UTF8.GetBytes("Hello World"); // Write to the transport so the poll yields await connection.Transport.Writer.WriteAsync(buffer); await task; Assert.Equal(DefaultConnectionContext.ConnectionStatus.Inactive, connection.Status); Assert.Null(connection.GetHttpContext()); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); }
public async Task PostNotAllowedForWebSocketConnections() { var manager = CreateConnectionManager(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var connection = manager.CreateConnection(); connection.Metadata[ConnectionMetadataNames.Transport] = TransportType.WebSockets; using (var strm = new MemoryStream()) { var context = new DefaultHttpContext(); context.Response.Body = strm; var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); services.AddOptions(); context.Request.Path = "/foo"; context.Request.Method = "POST"; var values = new Dictionary <string, StringValues>(); values["id"] = connection.ConnectionId; var qs = new QueryCollection(values); context.Request.Query = qs; var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions(), app); Assert.Equal(StatusCodes.Status405MethodNotAllowed, context.Response.StatusCode); await strm.FlushAsync(); Assert.Equal("POST requests are not allowed for WebSocket connections.", Encoding.UTF8.GetString(strm.ToArray())); } }
public async Task EndpointsThatRequireConnectionId400WhenNoConnectionIdProvidedForPost() { var manager = CreateConnectionManager(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); using (var strm = new MemoryStream()) { var context = new DefaultHttpContext(); context.Response.Body = strm; var services = new ServiceCollection(); services.AddOptions(); services.AddEndPoint <TestEndPoint>(); context.Request.Path = "/foo"; context.Request.Method = "POST"; var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions(), app); Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode); await strm.FlushAsync(); Assert.Equal("Connection ID required", Encoding.UTF8.GetString(strm.ToArray())); } }
public async Task TransportCapabilitiesSet(TransportType transportType, TransferMode expectedTransportCapabilities) { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); SetTransport(context, transportType); var services = new ServiceCollection(); services.AddEndPoint <ImmediatelyCompleteEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <ImmediatelyCompleteEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.WebSockets.CloseTimeout = TimeSpan.FromSeconds(0); await dispatcher.ExecuteAsync(context, options, app); Assert.Equal(expectedTransportCapabilities, connection.TransportCapabilities); }
public async Task EndpointsThatAcceptConnectionId404WhenUnknownConnectionIdProvidedForPost() { var manager = CreateConnectionManager(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); using (var strm = new MemoryStream()) { var context = new DefaultHttpContext(); context.Response.Body = strm; var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); services.AddOptions(); context.Request.Path = "/foo"; context.Request.Method = "POST"; var values = new Dictionary <string, StringValues>(); values["id"] = "unknown"; var qs = new QueryCollection(values); context.Request.Query = qs; var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions(), app); Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode); await strm.FlushAsync(); Assert.Equal("No Connection with that ID", Encoding.UTF8.GetString(strm.ToArray())); } }
public async Task BlockingConnectionWorksWithLongPollingConnection() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); var services = new ServiceCollection(); services.AddEndPoint <BlockingEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <BlockingEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); var task = dispatcher.ExecuteAsync(context, options, app); var buffer = Encoding.UTF8.GetBytes("Hello World"); // Write to the application await connection.Application.Writer.WriteAsync(buffer); await task; Assert.Equal(StatusCodes.Status204NoContent, context.Response.StatusCode); bool exists = manager.TryGetConnection(connection.ConnectionId, out _); Assert.False(exists); }
public async Task SetsInherentKeepAliveFeatureOnFirstLongPollingRequest() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.LongPolling.PollTimeout = TimeSpan.FromMilliseconds(1); // We don't care about the poll itself Assert.Null(connection.Features.Get <IConnectionInherentKeepAliveFeature>()); await dispatcher.ExecuteAsync(context, options, app).OrTimeout(); Assert.NotNull(connection.Features.Get <IConnectionInherentKeepAliveFeature>()); Assert.Equal(options.LongPolling.PollTimeout, connection.Features.Get <IConnectionInherentKeepAliveFeature>().KeepAliveInterval); }
public async Task NegotiateReturnsAvailableTransports(TransportType transports) { var manager = CreateConnectionManager(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = new DefaultHttpContext(); context.Features.Set <IHttpResponseFeature>(new ResponseFeature()); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); services.AddOptions(); var ms = new MemoryStream(); context.Request.Path = "/foo"; context.Request.Method = "OPTIONS"; context.Response.Body = ms; var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions { Transports = transports }, app); var negotiateResponse = JsonConvert.DeserializeObject <JObject>(Encoding.UTF8.GetString(ms.ToArray())); var availableTransports = (TransportType)0; foreach (var transport in negotiateResponse["availableTransports"]) { availableTransports |= (TransportType)Enum.Parse(typeof(TransportType), transport.Value <string>()); } Assert.Equal(transports, availableTransports); }
public async Task SynchronusExceptionEndsConnection() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); SetTransport(context, TransportType.ServerSentEvents); var services = new ServiceCollection(); services.AddEndPoint <SynchronusExceptionEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <SynchronusExceptionEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions(), app); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); bool exists = manager.TryGetConnection(connection.ConnectionId, out _); Assert.False(exists); }
public async Task AuthorizedConnectionWithAcceptedSchemesCanConnectToEndPoint() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = new DefaultHttpContext(); context.Features.Set <IHttpResponseFeature>(new ResponseFeature()); var services = new ServiceCollection(); services.AddOptions(); services.AddEndPoint <TestEndPoint>(); services.AddAuthorization(o => { o.AddPolicy("test", policy => { policy.RequireClaim(ClaimTypes.NameIdentifier); policy.AddAuthenticationSchemes("Default"); }); }); services.AddAuthorizationPolicyEvaluator(); services.AddLogging(); services.AddAuthenticationCore(o => { o.DefaultScheme = "Default"; o.AddScheme("Default", a => a.HandlerType = typeof(TestAuthenticationHandler)); }); var sp = services.BuildServiceProvider(); context.Request.Path = "/foo"; context.Request.Method = "GET"; context.RequestServices = sp; var values = new Dictionary <string, StringValues>(); values["id"] = connection.ConnectionId; var qs = new QueryCollection(values); context.Request.Query = qs; context.Response.Body = new MemoryStream(); var builder = new SocketBuilder(sp); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.AuthorizationData.Add(new AuthorizeAttribute("test")); // "authorize" user context.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "name") })); var endPointTask = dispatcher.ExecuteAsync(context, options, app); await connection.Transport.Writer.WriteAsync(Encoding.UTF8.GetBytes("Hello, World")).OrTimeout(); await endPointTask.OrTimeout(); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); Assert.Equal("Hello, World", GetContentAsString(context.Response.Body)); }
public async Task AuthorizedConnectionWithRejectedSchemesFailsToConnectToEndPoint() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = new DefaultHttpContext(); var services = new ServiceCollection(); services.AddOptions(); services.AddEndPoint <TestEndPoint>(); services.AddAuthorization(o => { o.AddPolicy("test", policy => { policy.RequireClaim(ClaimTypes.NameIdentifier); policy.AddAuthenticationSchemes("Default"); }); }); services.AddAuthorizationPolicyEvaluator(); services.AddLogging(); services.AddAuthenticationCore(o => { o.DefaultScheme = "Default"; o.AddScheme("Default", a => a.HandlerType = typeof(RejectHandler)); }); var sp = services.BuildServiceProvider(); context.Request.Path = "/foo"; context.Request.Method = "GET"; context.RequestServices = sp; var values = new Dictionary <string, StringValues>(); values["id"] = connection.ConnectionId; var qs = new QueryCollection(values); context.Request.Query = qs; context.Response.Body = new MemoryStream(); var builder = new SocketBuilder(sp); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.AuthorizationData.Add(new AuthorizeAttribute("test")); // "authorize" user context.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "name") })); // would block if EndPoint was executed await dispatcher.ExecuteAsync(context, options, app).OrTimeout(); Assert.Equal(StatusCodes.Status401Unauthorized, context.Response.StatusCode); }
public async Task RequestToActiveConnectionId409ForStreamingTransports(TransportType transportType) { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context1 = MakeRequest("/foo", connection); var context2 = MakeRequest("/foo", connection); SetTransport(context1, transportType); SetTransport(context2, transportType); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); var request1 = dispatcher.ExecuteAsync(context1, options, app); await dispatcher.ExecuteAsync(context2, options, app); Assert.Equal(StatusCodes.Status409Conflict, context2.Response.StatusCode); var webSocketTask = Task.CompletedTask; var ws = (TestWebSocketConnectionFeature)context1.Features.Get <IHttpWebSocketFeature>(); if (ws != null) { await ws.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); } manager.CloseConnections(); await request1.OrTimeout(); }
public async Task SendingWithoutConnectionIdThrows() { var manager = new ConnectionManager(); using (var factory = new ChannelFactory()) { var dispatcher = new HttpConnectionDispatcher(manager, factory); var context = new DefaultHttpContext(); context.Request.Path = "/send"; await Assert.ThrowsAsync <InvalidOperationException>(async() => { await dispatcher.ExecuteAsync <TestEndPoint>("", context); }); } }
public async Task AuthenticatedUserWithoutPermissionCausesForbidden() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = new DefaultHttpContext(); var services = new ServiceCollection(); services.AddOptions(); services.AddEndPoint <TestEndPoint>(); services.AddAuthorizationPolicyEvaluator(); services.AddAuthorization(o => { o.AddPolicy("test", policy => policy.RequireClaim(ClaimTypes.NameIdentifier)); }); services.AddAuthenticationCore(o => { o.DefaultScheme = "Default"; o.AddScheme("Default", a => a.HandlerType = typeof(TestAuthenticationHandler)); }); services.AddLogging(); var sp = services.BuildServiceProvider(); context.Request.Path = "/foo"; context.Request.Method = "GET"; context.RequestServices = sp; var values = new Dictionary <string, StringValues>(); values["id"] = connection.ConnectionId; var qs = new QueryCollection(values); context.Request.Query = qs; var builder = new SocketBuilder(sp); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.AuthorizationData.Add(new AuthorizeAttribute("test")); context.User = new ClaimsPrincipal(new ClaimsIdentity("authenticated")); // would hang if EndPoint was running await dispatcher.ExecuteAsync(context, options, app).OrTimeout(); Assert.Equal(StatusCodes.Status403Forbidden, context.Response.StatusCode); }
public async Task SendingToUnknownConnectionIdThrows() { var manager = new ConnectionManager(); using (var factory = new ChannelFactory()) { var dispatcher = new HttpConnectionDispatcher(manager, factory); var context = new DefaultHttpContext(); context.Request.Path = "/send"; var values = new Dictionary <string, StringValues>(); values["id"] = "unknown"; var qs = new QueryCollection(values); context.Request.Query = qs; await Assert.ThrowsAsync <InvalidOperationException>(async() => { await dispatcher.ExecuteAsync <TestEndPoint>("", context); }); } }
public async Task GetIdReservesConnectionIdAndReturnsIt() { var manager = new ConnectionManager(); using (var factory = new ChannelFactory()) { var dispatcher = new HttpConnectionDispatcher(manager, factory); var context = new DefaultHttpContext(); var ms = new MemoryStream(); context.Request.Path = "/getid"; context.Response.Body = ms; await dispatcher.ExecuteAsync <TestEndPoint>("", context); var id = Encoding.UTF8.GetString(ms.ToArray()); ConnectionState state; Assert.True(manager.TryGetConnection(id, out state)); Assert.Equal(id, state.Connection.ConnectionId); } }
private static async Task CheckTransportSupported(TransportType supportedTransports, TransportType transportType, int status) { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); using (var strm = new MemoryStream()) { var context = new DefaultHttpContext(); context.Features.Set <IHttpResponseFeature>(new ResponseFeature()); context.Response.Body = strm; var services = new ServiceCollection(); services.AddOptions(); services.AddEndPoint <ImmediatelyCompleteEndPoint>(); SetTransport(context, transportType); context.Request.Path = "/foo"; context.Request.Method = "GET"; var values = new Dictionary <string, StringValues>(); values["id"] = connection.ConnectionId; var qs = new QueryCollection(values); context.Request.Query = qs; var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <ImmediatelyCompleteEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.Transports = supportedTransports; await dispatcher.ExecuteAsync(context, options, app); Assert.Equal(status, context.Response.StatusCode); await strm.FlushAsync(); // Check the message for 404 if (status == 404) { Assert.Equal($"{transportType} transport not supported by this end point type", Encoding.UTF8.GetString(strm.ToArray())); } } }
public async Task LongPollingTimeoutSets200StatusCode() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); var services = new ServiceCollection(); services.AddEndPoint <TestEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <TestEndPoint>(); var app = builder.Build(); var options = new HttpSocketOptions(); options.LongPolling.PollTimeout = TimeSpan.FromSeconds(2); await dispatcher.ExecuteAsync(context, options, app).OrTimeout(); Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); }
public async Task CompletedEndPointEndsLongPollingConnection() { var manager = CreateConnectionManager(); var connection = manager.CreateConnection(); var dispatcher = new HttpConnectionDispatcher(manager, new LoggerFactory()); var context = MakeRequest("/foo", connection); var services = new ServiceCollection(); services.AddEndPoint <ImmediatelyCompleteEndPoint>(); var builder = new SocketBuilder(services.BuildServiceProvider()); builder.UseEndPoint <ImmediatelyCompleteEndPoint>(); var app = builder.Build(); await dispatcher.ExecuteAsync(context, new HttpSocketOptions(), app); Assert.Equal(StatusCodes.Status204NoContent, context.Response.StatusCode); bool exists = manager.TryGetConnection(connection.ConnectionId, out _); Assert.False(exists); }
public void MapEndpoint <TEndPoint>(string path) where TEndPoint : EndPoint { _routes.AddPrefixRoute(path, new RouteHandler(c => _dispatcher.ExecuteAsync <TEndPoint>(path, c))); }