public async Task ServiceConnectionWithNormalClientConnection()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Warning, expectedErrors: c => true, logChecker:
                                      logs =>
            {
                Assert.Single(logs);
                Assert.Equal("ConnectedStartingFailed", logs[0].Write.EventId.Name);
                Assert.Equal("Unable to authorize request", logs[0].Write.Exception.Message);
                return(true);
            }))
            {
                var hubConfig = new HubConfiguration();
                var ccm       = new ClientConnectionManager(hubConfig, loggerFactory);
                hubConfig.Resolver.Register(typeof(IClientConnectionManager), () => ccm);
                using (var proxy = new TestServiceConnectionProxy(ccm, loggerFactory: loggerFactory))
                {
                    // start the server connection
                    await proxy.StartServiceAsync().OrTimeout();

                    var connectionId = Guid.NewGuid().ToString("N");

                    var connectTask = proxy.WaitForOutgoingMessageAsync(connectionId).OrTimeout();

                    // Application layer sends OpenConnectionMessage to an authorized hub from anonymous user
                    var openConnectionMessage = new OpenConnectionMessage(connectionId, new Claim[0], null, "?transport=webSockets&connectionData=%5B%7B%22name%22%3A%22authchat%22%7D%5D");
                    await proxy.WriteMessageAsync(openConnectionMessage);

                    var message = await connectTask;

                    Assert.True(message is CloseConnectionMessage);

                    // Verify client connection is not created due to authorized failure.
                    Assert.False(ccm.ClientConnections.TryGetValue(connectionId, out var connection));
                }
            }
        }
        public void ParseMessageWithExtraData()
        {
            // Legacy protocol
            var expectedMessage = new OpenConnectionMessage("id", null);
            var bytes = new byte[]
            {
                ArrayBytes(3),                          // Array Length
                4,                                      // Message Type: OpenConnectionMessage
                StringBytes(2), (byte)'i', (byte)'d',   // OpenConnectionMessage.ConnectionId
                MapBytes(0),                            // OpenConnectionMessage.Claims
                StringBytes(2), (byte)'e', (byte)'x'    // Extra trailing data
            };

            bytes = Frame(bytes);
            var message = ParseServiceMessage(bytes);
            var openConnectionMessage = Assert.IsType<OpenConnectionMessage>(message);
            Assert.Equal(expectedMessage, openConnectionMessage, ServiceMessageEqualityComparer.Instance);

            // Current protocol
            expectedMessage = new OpenConnectionMessage("id", null, new Dictionary<string, StringValues>(), "?k=v");
            bytes = new byte[]
            {
                ArrayBytes(5),                                              // Array Length
                4,                                                          // Message Type: OpenConnectionMessage
                StringBytes(2), (byte)'i', (byte)'d',                       // OpenConnectionMessage.ConnectionId
                MapBytes(0),                                                // OpenConnectionMessage.Claims
                MapBytes(0),                                                // OpenConnectionMessage.Headers
                StringBytes(4), (byte)'?', (byte)'k', (byte)'=', (byte)'v', // OpenConnectionMessage.QueryString
                StringBytes(2), (byte)'e', (byte)'x'                        // Extra trailing data
            };

            bytes = Frame(bytes);
            message = ParseServiceMessage(bytes);
            openConnectionMessage = Assert.IsType<OpenConnectionMessage>(message);
            Assert.Equal(expectedMessage, openConnectionMessage, ServiceMessageEqualityComparer.Instance);
        }
 public Task OnClientConnectedAsyncForTest(OpenConnectionMessage message)
 {
     return(base.OnClientConnectedAsync(message));
 }
Exemple #4
0
 public async Task TestCreateConnectionWithInvalidQueryStringThrows(string queryString)
 {
     var message = new OpenConnectionMessage(Guid.NewGuid().ToString("N"), new Claim[0], null, queryString);
     await Assert.ThrowsAsync <InvalidOperationException>(() => _clientConnectionManager.CreateConnection(message));
 }
 protected override Task OnConnectedAsync(OpenConnectionMessage openConnectionMessage)
 {
     return(Task.CompletedTask);
 }
Exemple #6
0
 public ClientConnectionContext CreateConnection(OpenConnectionMessage message, Action <HttpContext> configureContext = null)
 {
     return(new ClientConnectionContext(message, configureContext, _clientPipeOptions, _clientPipeOptions));
 }
Exemple #7
0
 public ServiceConnectionContext CreateConnection(OpenConnectionMessage message)
 {
     return(new ServiceConnectionContext(message, _clientPipeOptions, _clientPipeOptions));
 }
Exemple #8
0
            protected override async Task OnClientConnectedAsync(OpenConnectionMessage message)
            {
                await base.OnClientConnectedAsync(message);

                _clientConnectedTcs.TrySetResult();
            }
Exemple #9
0
 protected abstract Task OnConnectedAsync(OpenConnectionMessage openConnectionMessage);
Exemple #10
0
        private async Task OnConnectedAsyncCore(ClientConnectionContext clientContext, OpenConnectionMessage message)
        {
            var connectionId = message.ConnectionId;

            try
            {
                clientContext.Transport = await _clientConnectionManager.CreateConnection(message);

                Log.ConnectedStarting(Logger, connectionId);
            }
            catch (Exception e)
            {
                Log.ConnectedStartingFailed(Logger, connectionId, e);
                // Should not wait for application task inside the application task
                _ = PerformDisconnectCore(connectionId, false);
                _ = SafeWriteAsync(new CloseConnectionMessage(connectionId, e.Message));
            }
        }
        public async Task ServiceConnectionDispatchGroupMessagesTest()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
            {
                var hubConfig = Utility.GetActualHubConfig(loggerFactory);
                var appName   = "app1";
                var hub       = "chat";
                var scm       = new TestServiceConnectionHandler();
                hubConfig.Resolver.Register(typeof(IServiceConnectionManager), () => scm);
                var ccm = new ClientConnectionManager(hubConfig, loggerFactory);
                hubConfig.Resolver.Register(typeof(IClientConnectionManager), () => ccm);
                DispatcherHelper.PrepareAndGetDispatcher(new TestAppBuilder(), hubConfig, new ServiceOptions {
                    ConnectionString = ConnectionString
                }, appName, loggerFactory);
                using (var proxy = new TestServiceConnectionProxy(ccm, loggerFactory: loggerFactory))
                {
                    // start the server connection
                    await proxy.StartServiceAsync().OrTimeout();

                    var clientConnection = Guid.NewGuid().ToString("N");

                    var connectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout();
                    // Application layer sends OpenConnectionMessage
                    var openConnectionMessage = new OpenConnectionMessage(clientConnection, new Claim[0], null, $"?transport=webSockets&connectionToken=conn1&connectionData=%5B%7B%22name%22%3A%22{hub}%22%7D%5D");
                    await proxy.WriteMessageAsync(openConnectionMessage);

                    var connectMessage = (await connectTask)as GroupBroadcastDataMessage;
                    Assert.NotNull(connectMessage);
                    Assert.Equal($"hg-{hub}.note", connectMessage.GroupName);

                    var message = connectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>();

                    Assert.Equal("Connected", message.A[0]);

                    // group message goes into the manager
                    // make sure the tcs is called before writing message
                    var jgTask = scm.WaitForTransportOutputMessageAsync(typeof(JoinGroupWithAckMessage)).OrTimeout();

                    var gbTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout();

                    await proxy.WriteMessageAsync(new ConnectionDataMessage(clientConnection, Encoding.UTF8.GetBytes($"{{\"H\":\"{hub}\",\"M\":\"JoinGroup\",\"A\":[\"user1\",\"group1\"],\"I\":1}}")));

                    var groupMessage = (await jgTask)as JoinGroupWithAckMessage;
                    Assert.NotNull(groupMessage);
                    Assert.Equal($"hg-{hub}.group1", groupMessage.GroupName);
                    var broadcastMessage = (await gbTask)as GroupBroadcastDataMessage;
                    Assert.NotNull(broadcastMessage);
                    Assert.Equal($"hg-{hub}.group1", broadcastMessage.GroupName);

                    var lgTask = scm.WaitForTransportOutputMessageAsync(typeof(LeaveGroupWithAckMessage)).OrTimeout();
                    gbTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout();

                    await proxy.WriteMessageAsync(new ConnectionDataMessage(clientConnection, Encoding.UTF8.GetBytes($"{{\"H\":\"{hub}\",\"M\":\"LeaveGroup\",\"A\":[\"user1\",\"group1\"],\"I\":1}}")));

                    var leaveGroupMessage = (await lgTask)as LeaveGroupWithAckMessage;
                    Assert.NotNull(leaveGroupMessage);
                    Assert.Equal($"hg-{hub}.group1", leaveGroupMessage.GroupName);

                    broadcastMessage = (await gbTask)as GroupBroadcastDataMessage;
                    Assert.NotNull(broadcastMessage);
                    Assert.Equal($"hg-{hub}.group1", broadcastMessage.GroupName);

                    var disconnectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage))
                                         .OrTimeout();

                    await proxy.WriteMessageAsync(new CloseConnectionMessage(clientConnection));

                    var disconnectMessage = (await disconnectTask)as GroupBroadcastDataMessage;

                    Assert.NotNull(disconnectMessage);
                    Assert.Equal($"hg-{hub}.note", disconnectMessage.GroupName);

                    message = disconnectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>();

                    Assert.Equal("Disconnected", message.A[0]);

                    // cleaned up clearly
                    Assert.Empty(ccm.ClientConnections);
                }
            }
        }
        public async Task ServiceConnectionWithOfflinePingWillTriggerDisconnectClients()
        {
            using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
            {
                var hubConfig = Utility.GetActualHubConfig(loggerFactory);
                var appName   = "app1";
                var hub       = "chat";
                var scm       = new TestServiceConnectionHandler();
                hubConfig.Resolver.Register(typeof(IServiceConnectionManager), () => scm);
                var ccm = new ClientConnectionManager(hubConfig, loggerFactory);
                hubConfig.Resolver.Register(typeof(IClientConnectionManager), () => ccm);
                DispatcherHelper.PrepareAndGetDispatcher(new TestAppBuilder(), hubConfig, new ServiceOptions {
                    ConnectionString = ConnectionString
                }, appName, loggerFactory);
                using (var proxy = new TestServiceConnectionProxy(ccm, loggerFactory: loggerFactory))
                {
                    // prepare 2 clients with different instancesId connected
                    var instanceId1   = Guid.NewGuid().ToString();
                    var connectionId1 = Guid.NewGuid().ToString("N");
                    var header1       = new Dictionary <string, StringValues>()
                    {
                        { Constants.AsrsInstanceId, instanceId1 }
                    };
                    var instanceId2   = Guid.NewGuid().ToString();
                    var connectionId2 = Guid.NewGuid().ToString("N");
                    var header2       = new Dictionary <string, StringValues>()
                    {
                        { Constants.AsrsInstanceId, instanceId2 }
                    };

                    // start the server connection
                    await proxy.StartServiceAsync().OrTimeout();

                    // Application layer sends OpenConnectionMessage for client1
                    var connectTask           = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout();
                    var openConnectionMessage = new OpenConnectionMessage(connectionId1, new Claim[0], header1, $"?transport=webSockets&connectionToken=conn1&connectionData=%5B%7B%22name%22%3A%22{hub}%22%7D%5D");
                    await proxy.WriteMessageAsync(openConnectionMessage);

                    // client1 is connected
                    var connectMessage = (await connectTask)as GroupBroadcastDataMessage;
                    Assert.NotNull(connectMessage);
                    Assert.Equal($"hg-{hub}.note", connectMessage.GroupName);
                    var message = connectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>();
                    Assert.Equal("Connected", message.A[0]);

                    ccm.ClientConnections.TryGetValue(connectionId1, out var transport1);
                    Assert.NotNull(transport1);

                    // Application layer sends OpenConnectionMessage for client2
                    connectTask           = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout();
                    openConnectionMessage = new OpenConnectionMessage(connectionId2, new Claim[0], header2, $"?transport=webSockets&connectionToken=conn2&connectionData=%5B%7B%22name%22%3A%22{hub}%22%7D%5D");
                    await proxy.WriteMessageAsync(openConnectionMessage);

                    // client2 is connected
                    connectMessage = (await connectTask)as GroupBroadcastDataMessage;
                    Assert.NotNull(connectMessage);
                    Assert.Equal($"hg-{hub}.note", connectMessage.GroupName);
                    message = connectMessage.Payloads["json"].GetJsonMessageFromSingleFramePayload <HubResponseItem>();
                    Assert.Equal("Connected", message.A[0]);
                    ccm.ClientConnections.TryGetValue(connectionId2, out var transport2);
                    Assert.NotNull(transport2);

                    // Send ServerOfflinePing on instance1 and will trigger cleanup related client1
                    connectTask = scm.WaitForTransportOutputMessageAsync(typeof(GroupBroadcastDataMessage)).OrTimeout();
                    await proxy.WriteMessageAsync(new PingMessage()
                    {
                        Messages = new[] { "offline", instanceId1 }
                    });

                    // Validate client1 disconnect
                    connectMessage = (await connectTask)as GroupBroadcastDataMessage;
                    Assert.NotNull(connectMessage);
                    Assert.Equal($"hg-{hub}.note", connectMessage.GroupName);
                    message = connectMessage.Payloads["json"]
                              .GetJsonMessageFromSingleFramePayload <HubResponseItem>();
                    Assert.Equal("Disconnected", message.A[0]);

                    // Validate client2 is still connected
                    Assert.Single(ccm.ClientConnections);
                    Assert.Equal(connectionId2, ccm.ClientConnections.FirstOrDefault().Key);
                }
            }
        }
 public ServiceConnectionContext CreateConnection(OpenConnectionMessage message, Action <HttpContext> configureContext = null)
 {
     return(new ServiceConnectionContext(message, configureContext));
 }
Exemple #14
0
 public IServiceTransport CreateConnection(OpenConnectionMessage message, IServiceConnection serviceConnection)
 {
     throw new NotImplementedException();
 }
 public ServiceConnectionContext CreateConnection(OpenConnectionMessage message)
 {
     return(new ServiceConnectionContext(message));
 }
Exemple #16
0
 public void TestCreateConnectionWithCustomQueryStringSucceeds(string queryString)
 {
     var message    = new OpenConnectionMessage(Guid.NewGuid().ToString("N"), new Claim[0], null, queryString);
     var connection = _clientConnectionManager.CreateConnection(message, null);
 }