예제 #1
0
        public async Task CanStartAndStopConnectionUsingGivenTransport(HttpTransportType transportType)
        {
            using (StartVerifiableLog(out var loggerFactory, minLogLevel: LogLevel.Trace, testName: $"CanStartAndStopConnectionUsingGivenTransport_{transportType}"))
            {
                var url        = ServerFixture.Url + "/echo";
                var connection = new HttpConnection(new Uri(url), transportType, loggerFactory);
                await connection.StartAsync(TransferFormat.Text).OrTimeout();

                await connection.DisposeAsync().OrTimeout();
            }
        }
예제 #2
0
        public async Task CanStartAndStopConnectionUsingGivenTransport(HttpTransportType transportType)
        {
            using (StartServer <Startup>(out var server))
            {
                var url        = server.Url + "/echo";
                var connection = new HttpConnection(new Uri(url), transportType, LoggerFactory);
                await connection.StartAsync(TransferFormat.Text).OrTimeout();

                await connection.DisposeAsync().OrTimeout();
            }
        }
예제 #3
0
파일: RawSample.cs 프로젝트: masums/SignalR
        public static async Task <int> ExecuteAsync(string baseUrl)
        {
            baseUrl = string.IsNullOrEmpty(baseUrl) ? "http://localhost:5000/chat" : baseUrl;

            var loggerFactory = new LoggerFactory();
            var logger        = loggerFactory.CreateLogger <Program>();

            Console.WriteLine($"Connecting to {baseUrl}...");
            var connection = new HttpConnection(new Uri(baseUrl), loggerFactory);

            try
            {
                var cts = new CancellationTokenSource();
                connection.OnReceived(data => Console.Out.WriteLineAsync($"{Encoding.UTF8.GetString(data)}"));
                connection.Closed += e =>
                {
                    cts.Cancel();
                    return(Task.CompletedTask);
                };

                await connection.StartAsync();

                Console.WriteLine($"Connected to {baseUrl}");

                Console.CancelKeyPress += (sender, a) =>
                {
                    a.Cancel = true;
                    cts.Cancel();
                };

                while (!cts.Token.IsCancellationRequested)
                {
                    var line = await Task.Run(() => Console.ReadLine(), cts.Token);

                    if (line == null)
                    {
                        break;
                    }

                    await connection.SendAsync(Encoding.UTF8.GetBytes(line), cts.Token);
                }
            }
            catch (AggregateException aex) when(aex.InnerExceptions.All(e => e is OperationCanceledException))
            {
            }
            catch (OperationCanceledException)
            {
            }
            finally
            {
                await connection.DisposeAsync();
            }
            return(0);
        }
예제 #4
0
        public async Task ConnectionCanSendAndReceiveDifferentMessageSizesWebSocketsTransport(string message)
        {
            using (StartLog(out var loggerFactory, testName: $"ConnectionCanSendAndReceiveDifferentMessageSizesWebSocketsTransport_{message.Length}"))
            {
                var logger = loggerFactory.CreateLogger <EndToEndTests>();

                var url        = _serverFixture.BaseUrl + "/echo";
                var connection = new HttpConnection(new Uri(url), TransportType.WebSockets, loggerFactory);
                connection.Features.Set <ITransferModeFeature>(
                    new TransferModeFeature {
                    TransferMode = TransferMode.Binary
                });

                try
                {
                    var receiveTcs = new TaskCompletionSource <byte[]>();
                    connection.Received += data =>
                    {
                        logger.LogInformation("Received {length} byte message", data.Length);
                        receiveTcs.TrySetResult(data);
                        return(Task.CompletedTask);
                    };

                    logger.LogInformation("Starting connection to {url}", url);
                    await connection.StartAsync().OrTimeout();

                    logger.LogInformation("Started connection to {url}", url);

                    var bytes = Encoding.UTF8.GetBytes(message);
                    logger.LogInformation("Sending {length} byte message", bytes.Length);
                    await connection.SendAsync(bytes).OrTimeout();

                    logger.LogInformation("Sent message", bytes.Length);

                    logger.LogInformation("Receiving message");
                    var receivedData = await receiveTcs.Task.OrTimeout();

                    Assert.Equal(message, Encoding.UTF8.GetString(receivedData));
                    logger.LogInformation("Completed receive");
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
예제 #5
0
        public async Task ReceivedCallbackNotRaisedAfterConnectionIsDisposed()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                return(IsNegotiateRequest(request)
                        ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                        : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var mockTransport = new Mock <ITransport>();
            Channel <byte[], SendMessage> channel = null;

            mockTransport.Setup(t => t.StartAsync(It.IsAny <Uri>(), It.IsAny <Channel <byte[], SendMessage> >(), It.IsAny <TransferMode>(), It.IsAny <string>()))
            .Returns <Uri, Channel <byte[], SendMessage>, TransferMode, string>((url, c, transferMode, connectionId) =>
            {
                channel = c;
                return(Task.CompletedTask);
            });
            mockTransport.Setup(t => t.StopAsync())
            .Returns(() =>
            {
                // The connection is now in the Disconnected state so the Received event for
                // this message should not be raised
                channel.Writer.TryWrite(Array.Empty <byte>());
                channel.Writer.TryComplete();
                return(Task.CompletedTask);
            });
            mockTransport.SetupGet(t => t.Mode).Returns(TransferMode.Text);

            var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null,
                                                httpOptions: new HttpOptions {
                HttpMessageHandler = mockHttpHandler.Object
            });

            var onReceivedInvoked = false;

            connection.OnReceived(_ =>
            {
                onReceivedInvoked = true;
                return(Task.CompletedTask);
            });

            await connection.StartAsync();

            await connection.DisposeAsync();

            Assert.False(onReceivedInvoked);
        }
예제 #6
0
        public async Task TransportThatFallsbackCreatesNewConnection()
        {
            var url = _serverFixture.Url + "/echo";
            // The test should connect to the server using WebSockets transport on Windows 8 and newer.
            // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server.

            // The test logic lives in the TestTransportFactory and FakeTransport.
            var connection = new HttpConnection(new Uri(url), new TestTransportFactory(), null, null);
            await connection.StartAsync(TransferFormat.Text).OrTimeout();

            await connection.DisposeAsync().OrTimeout();
        }
 private static async Task WithConnectionAsync(HttpConnection connection, Func <HttpConnection, Task> body)
 {
     try
     {
         // Using OrTimeout here will hide any timeout issues in the test :(.
         await body(connection);
     }
     finally
     {
         await connection.DisposeAsync().OrTimeout();
     }
 }
예제 #8
0
        public async Task ConnectionCanSendAndReceiveMessages(HttpTransportType transportType, TransferFormat requestedTransferFormat)
        {
            using (StartServer <Startup>(out var server))
            {
                var logger = LoggerFactory.CreateLogger <EndToEndTests>();

                const string message = "Major Key";

                var url        = server.Url + "/echo";
                var connection = new HttpConnection(new Uri(url), transportType, LoggerFactory);
                try
                {
                    logger.LogInformation("Starting connection to {url}", url);
                    await connection.StartAsync(requestedTransferFormat).OrTimeout();

                    logger.LogInformation("Started connection to {url}", url);

                    var bytes = Encoding.UTF8.GetBytes(message);

                    logger.LogInformation("Sending {length} byte message", bytes.Length);
                    try
                    {
                        await connection.Transport.Output.WriteAsync(bytes).OrTimeout();
                    }
                    catch (OperationCanceledException)
                    {
                        // Because the server and client are run in the same process there is a race where websocket.SendAsync
                        // can send a message but before returning be suspended allowing the server to run the EchoConnectionHandler and
                        // send a close frame which triggers a cancellation token on the client and cancels the websocket.SendAsync.
                        // Our solution to this is to just catch OperationCanceledException from the sent message if the race happens
                        // because we know the send went through, and its safe to check the response.
                    }

                    logger.LogInformation("Sent message");

                    logger.LogInformation("Receiving message");
                    Assert.Equal(message, Encoding.UTF8.GetString(await connection.Transport.Input.ReadAsync(bytes.Length).OrTimeout()));
                    logger.LogInformation("Completed receive");
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
예제 #9
0
        public async Task EventQueueTimeoutWithException()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                return(IsNegotiateRequest(request)
                        ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                        : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var mockTransport = new Mock <ITransport>();
            Channel <byte[], SendMessage> channel = null;

            mockTransport.Setup(t => t.StartAsync(It.IsAny <Uri>(), It.IsAny <Channel <byte[], SendMessage> >(), It.IsAny <TransferMode>(), It.IsAny <string>()))
            .Returns <Uri, Channel <byte[], SendMessage>, TransferMode, string>((url, c, transferMode, connectionId) =>
            {
                channel = c;
                return(Task.CompletedTask);
            });
            mockTransport.Setup(t => t.StopAsync())
            .Returns(() =>
            {
                channel.Writer.TryComplete();
                return(Task.CompletedTask);
            });
            mockTransport.SetupGet(t => t.Mode).Returns(TransferMode.Text);

            var callbackInvokedTcs = new TaskCompletionSource <object>();

            var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object), loggerFactory: null,
                                                httpOptions: new HttpOptions {
                HttpMessageHandler = mockHttpHandler.Object
            });

            connection.OnReceived(_ =>
            {
                throw new OperationCanceledException();
            });

            await connection.StartAsync();

            channel.Writer.TryWrite(Array.Empty <byte>());

            // Ensure that SignalR isn't blocked by the receive callback
            Assert.False(channel.Reader.TryRead(out var message));

            await connection.DisposeAsync();
        }
예제 #10
0
        public async Task ConnectionCanSendAndReceiveDifferentMessageSizesWebSocketsTransport(string message)
        {
            using (StartLog(out var loggerFactory, LogLevel.Trace, testName: $"ConnectionCanSendAndReceiveDifferentMessageSizesWebSocketsTransport_{message.Length}"))
            {
                var logger = loggerFactory.CreateLogger <EndToEndTests>();

                var url        = _serverFixture.Url + "/echo";
                var connection = new HttpConnection(new Uri(url), TransportType.WebSockets, loggerFactory);

                try
                {
                    var receiveTcs = new TaskCompletionSource <byte[]>();
                    connection.OnReceived((data, state) =>
                    {
                        logger.LogInformation("Received {length} byte message", data.Length);
                        var tcs = (TaskCompletionSource <byte[]>)state;
                        tcs.TrySetResult(data);
                        return(Task.CompletedTask);
                    }, receiveTcs);

                    logger.LogInformation("Starting connection to {url}", url);
                    await connection.StartAsync(TransferFormat.Binary).OrTimeout();

                    logger.LogInformation("Started connection to {url}", url);

                    var bytes = Encoding.UTF8.GetBytes(message);
                    logger.LogInformation("Sending {length} byte message", bytes.Length);
                    await connection.SendAsync(bytes).OrTimeout();

                    logger.LogInformation("Sent message", bytes.Length);

                    logger.LogInformation("Receiving message");
                    // Big timeout here because it can take a while to receive all the bytes
                    var receivedData = await receiveTcs.Task.OrTimeout(TimeSpan.FromSeconds(30));

                    Assert.Equal(message, Encoding.UTF8.GetString(receivedData));
                    logger.LogInformation("Completed receive");
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
        public async Task CanStartAndStopConnectionUsingGivenTransport(HttpTransportType transportType)
        {
            using (var server = await StartServer <Startup>())
            {
                var url        = server.Url + "/echo";
                var connection = new HttpConnection(new HttpConnectionOptions {
                    Url = new Uri(url), Transports = transportType, DefaultTransferFormat = TransferFormat.Text
                }, LoggerFactory);
                await connection.StartAsync().OrTimeout();

                await connection.DisposeAsync().OrTimeout();
            }
        }
예제 #12
0
        public async Task CanStartAndStopConnectionUsingDefaultTransport()
        {
            using (StartServer <Startup>(out var server))
            {
                var url = server.Url + "/echo";
                // The test should connect to the server using WebSockets transport on Windows 8 and newer.
                // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server.
                var connection = new HttpConnection(new Uri(url), HttpTransports.All, LoggerFactory);
                await connection.StartAsync(TransferFormat.Binary).OrTimeout();

                await connection.DisposeAsync().OrTimeout();
            }
        }
예제 #13
0
        public async Task HTTPRequestsNotSentWhenWebSocketsTransportRequested()
        {
            using (StartLog(out var loggerFactory))
            {
                var logger = loggerFactory.CreateLogger <EndToEndTests>();
                var url    = _serverFixture.Url + "/echo";

                var mockHttpHandler = new Mock <HttpMessageHandler>();
                mockHttpHandler.Protected()
                .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
                .Returns <HttpRequestMessage, CancellationToken>(
                    (request, cancellationToken) => Task.FromException <HttpResponseMessage>(new InvalidOperationException("HTTP requests should not be sent.")));

                var connection = new HttpConnection(new Uri(url), TransportType.WebSockets, loggerFactory, new HttpOptions {
                    HttpMessageHandler = mockHttpHandler.Object
                });

                try
                {
                    var receiveTcs = new TaskCompletionSource <byte[]>();
                    connection.OnReceived((data, state) =>
                    {
                        var tcs = (TaskCompletionSource <byte[]>)state;
                        tcs.TrySetResult(data);
                        return(Task.CompletedTask);
                    }, receiveTcs);

                    var message = new byte[] { 42 };
                    await connection.StartAsync().OrTimeout();

                    await connection.SendAsync(message).OrTimeout();

                    var receivedData = await receiveTcs.Task.OrTimeout();

                    Assert.Equal(message, receivedData);
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
예제 #14
0
        public async Task CannotStartDisposedConnection()
        {
            using (var httpClient = new HttpClient())
            {
                var connection = new HttpConnection(new Uri("http://fakeuri.org/"));
                await connection.DisposeAsync();

                var exception =
                    await Assert.ThrowsAsync <InvalidOperationException>(
                        async() => await connection.StartAsync());

                Assert.Equal("Cannot start a connection that is not in the Initial state.", exception.Message);
            }
        }
        public async Task AuthorizedConnectionCanConnect()
        {
            bool ExpectedErrors(WriteContext writeContext)
            {
                return(writeContext.LoggerName == typeof(HttpConnection).FullName &&
                       writeContext.EventId.Name == "ErrorWithNegotiation");
            }

            using (var server = await StartServer <Startup>(ExpectedErrors))
            {
                var logger = LoggerFactory.CreateLogger <EndToEndTests>();

                string token;
                using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri(server.Url);

                    var response = await client.GetAsync("generatetoken?user=bob");

                    token = await response.Content.ReadAsStringAsync();
                }

                var url        = server.Url + "/auth";
                var connection = new HttpConnection(
                    new HttpConnectionOptions()
                {
                    Url = new Uri(url),
                    AccessTokenProvider   = () => Task.FromResult(token),
                    Transports            = HttpTransportType.ServerSentEvents,
                    DefaultTransferFormat = TransferFormat.Text,
                },
                    LoggerFactory);

                try
                {
                    logger.LogInformation("Starting connection to {url}", url);
                    await connection.StartAsync().OrTimeout();

                    logger.LogInformation("Connected to {url}", url);
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
예제 #16
0
        public async Task HttpRequestsNotSentWhenWebSocketsTransportRequestedAndSkipNegotiationSet()
        {
            using (StartServer <Startup>(out var server))
            {
                var logger = LoggerFactory.CreateLogger <EndToEndTests>();
                var url    = server.Url + "/echo";

                var mockHttpHandler = new Mock <HttpMessageHandler>();
                mockHttpHandler.Protected()
                .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
                .Returns <HttpRequestMessage, CancellationToken>(
                    (request, cancellationToken) => Task.FromException <HttpResponseMessage>(new InvalidOperationException("HTTP requests should not be sent.")));

                var httpOptions = new HttpConnectionOptions
                {
                    Url                       = new Uri(url),
                    Transports                = HttpTransportType.WebSockets,
                    SkipNegotiation           = true,
                    HttpMessageHandlerFactory = (httpMessageHandler) => mockHttpHandler.Object
                };

                var connection = new HttpConnection(httpOptions, LoggerFactory);

                try
                {
                    var message = new byte[] { 42 };
                    await connection.StartAsync(TransferFormat.Binary).OrTimeout();

                    await connection.Transport.Output.WriteAsync(message).OrTimeout();

                    var receivedData = await connection.Transport.Input.ReadAsync(1);

                    Assert.Equal(message, receivedData);
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
예제 #17
0
        public async Task ClosedEventNotRaisedWhenTheClientIsStoppedButWasNeverStarted()
        {
            var connection = new HttpConnection(new Uri("http://fakeuri.org/"));

            bool closedEventRaised = false;

            connection.Closed += e =>
            {
                closedEventRaised = true;
                return(Task.CompletedTask);
            };

            await connection.DisposeAsync();

            Assert.False(closedEventRaised);
        }
예제 #18
0
        public async Task CanStopStartingConnection()
        {
            // Used to make sure StartAsync is not completed before DisposeAsync is called
            var releaseNegotiateTcs = new TaskCompletionSource <object>();
            // Used to make sure that DisposeAsync runs after we check the state in StartAsync
            var allowDisposeTcs = new TaskCompletionSource <object>();
            // Used to make sure that DisposeAsync continues only after StartAsync finished
            var releaseDisposeTcs = new TaskCompletionSource <object>();

            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                // allow DisposeAsync to continue once we know we are past the connection state check
                allowDisposeTcs.SetResult(null);
                await releaseNegotiateTcs.Task;
                return(IsNegotiateRequest(request)
                        ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                        : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var transport = new Mock <ITransport>();

            transport.Setup(t => t.StopAsync()).Returns(async() => { await releaseDisposeTcs.Task; });
            var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(transport.Object), loggerFactory: null,
                                                httpOptions: new HttpOptions {
                HttpMessageHandler = mockHttpHandler.Object
            });

            var startTask = connection.StartAsync();
            await allowDisposeTcs.Task;
            var disposeTask = connection.DisposeAsync();

            // allow StartAsync to continue once DisposeAsync has started
            releaseNegotiateTcs.SetResult(null);

            // unblock DisposeAsync only after StartAsync completed
            await startTask.OrTimeout();

            releaseDisposeTcs.SetResult(null);
            await disposeTask.OrTimeout();

            transport.Verify(t => t.StartAsync(It.IsAny <Uri>(), It.IsAny <Channel <byte[], SendMessage> >(), It.IsAny <TransferMode>(), It.IsAny <string>()), Times.Never);
        }
예제 #19
0
        public async Task CanStartConnectionWithoutSettingTransferModeFeature()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                return(IsNegotiateRequest(request)
                        ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                        : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var mockTransport = new Mock <ITransport>();
            Channel <byte[], SendMessage> channel = null;

            mockTransport.Setup(t => t.StartAsync(It.IsAny <Uri>(), It.IsAny <Channel <byte[], SendMessage> >(), It.IsAny <TransferMode>(), It.IsAny <string>()))
            .Returns <Uri, Channel <byte[], SendMessage>, TransferMode, string>((url, c, transferMode, connectionId) =>
            {
                channel = c;
                return(Task.CompletedTask);
            });
            mockTransport.Setup(t => t.StopAsync())
            .Returns(() =>
            {
                channel.Writer.TryComplete();
                return(Task.CompletedTask);
            });
            mockTransport.SetupGet(t => t.Mode).Returns(TransferMode.Binary);

            var connection = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(mockTransport.Object),
                                                loggerFactory: null, httpOptions: new HttpOptions {
                HttpMessageHandler = mockHttpHandler.Object
            });

            await connection.StartAsync().OrTimeout();

            var transferModeFeature = connection.Features.Get <ITransferModeFeature>();
            await connection.DisposeAsync().OrTimeout();

            mockTransport.Verify(t => t.StartAsync(
                                     It.IsAny <Uri>(), It.IsAny <Channel <byte[], SendMessage> >(), TransferMode.Text, It.IsAny <string>()), Times.Once);
            Assert.NotNull(transferModeFeature);
            Assert.Equal(TransferMode.Binary, transferModeFeature.TransferMode);
        }
예제 #20
0
        public async Task ConnectionCanSendAndReceiveDifferentMessageSizesWebSocketsTransport(int length)
        {
            var message = new string('A', length);

            using (StartServer <Startup>(out var server))
            {
                var logger = LoggerFactory.CreateLogger <EndToEndTests>();

                var url        = server.Url + "/echo";
                var connection = new HttpConnection(new Uri(url), HttpTransportType.WebSockets, LoggerFactory);

                try
                {
                    logger.LogInformation("Starting connection to {url}", url);
                    await connection.StartAsync(TransferFormat.Binary).OrTimeout();

                    logger.LogInformation("Started connection to {url}", url);

                    var bytes = Encoding.UTF8.GetBytes(message);
                    logger.LogInformation("Sending {length} byte message", bytes.Length);
                    await connection.Transport.Output.WriteAsync(bytes).OrTimeout();

                    logger.LogInformation("Sent message");

                    logger.LogInformation("Receiving message");
                    // Big timeout here because it can take a while to receive all the bytes
                    var receivedData = await connection.Transport.Input.ReadAsync(bytes.Length).OrTimeout(TimeSpan.FromMinutes(2));

                    Assert.Equal(message, Encoding.UTF8.GetString(receivedData));
                    logger.LogInformation("Completed receive");
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    logger.LogInformation("Disposing Connection");
                    await connection.DisposeAsync().OrTimeout();

                    logger.LogInformation("Disposed Connection");
                }
            }
        }
        /// <inheritdoc />
        public async Task <ConnectionContext> ConnectAsync(TransferFormat transferFormat, CancellationToken cancellationToken = default)
        {
            var connection = new HttpConnection(_httpConnectionOptions, _loggerFactory);

            try
            {
                await connection.StartAsync(transferFormat, cancellationToken);

                return(connection);
            }
            catch
            {
                // Make sure the connection is disposed, in case it allocated any resources before failing.
                await connection.DisposeAsync();

                throw;
            }
        }
예제 #22
0
        public static async Task <int> ExecuteAsync(string baseUrl)
        {
            baseUrl = string.IsNullOrEmpty(baseUrl) ? "http://localhost:5000/chat" : baseUrl;

            Console.WriteLine($"Connecting to {baseUrl}...");

            var connectionOptions = new HttpConnectionOptions
            {
                Url = new Uri(baseUrl),
                DefaultTransferFormat = TransferFormat.Text,
            };

            var connection = new HttpConnection(connectionOptions, loggerFactory: null);

            try
            {
                await connection.StartAsync();

                Console.WriteLine($"Connected to {baseUrl}");
                var shutdown = new TaskCompletionSource <object>();
                Console.CancelKeyPress += (sender, a) =>
                {
                    a.Cancel = true;
                    shutdown.TrySetResult(null);
                };

                _ = ReceiveLoop(Console.Out, connection.Transport.Input);
                _ = SendLoop(Console.In, connection.Transport.Output);

                await shutdown.Task;
            }
            catch (AggregateException aex) when(aex.InnerExceptions.All(e => e is OperationCanceledException))
            {
            }
            catch (OperationCanceledException)
            {
            }
            finally
            {
                await connection.DisposeAsync();
            }
            return(0);
        }
예제 #23
0
        public async Task CanSendData()
        {
            var data = new byte[] { 1, 1, 2, 3, 5, 8 };

            var sendTcs         = new TaskCompletionSource <byte[]>();
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                if (IsNegotiateRequest(request))
                {
                    return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse()));
                }

                if (request.Method == HttpMethod.Post)
                {
                    sendTcs.SetResult(await request.Content.ReadAsByteArrayAsync());
                }

                return(ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null,
                                                httpOptions: new HttpOptions {
                HttpMessageHandler = mockHttpHandler.Object
            });

            try
            {
                await connection.StartAsync();

                await connection.SendAsync(data);

                Assert.Equal(data, await sendTcs.Task.OrTimeout());
            }
            finally
            {
                await connection.DisposeAsync();
            }
        }
예제 #24
0
        public async Task query(string requested, string expectedNegotiate)
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                Assert.Equal(expectedNegotiate, request.RequestUri.ToString());
                return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                    ResponseUtils.CreateNegotiationResponse()));
            });

            var connection = new HttpConnection(new Uri(requested), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
            await connection.StartAsync().OrTimeout();

            await connection.DisposeAsync().OrTimeout();
        }
예제 #25
0
        public async Task CannotSendAfterReceiveThrewException()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();

                return(request.Method == HttpMethod.Get
                        ? ResponseUtils.CreateResponse(HttpStatusCode.InternalServerError)
                        : request.Method == HttpMethod.Options
                            ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                            : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var connection = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);

            try
            {
                var closeTcs = new TaskCompletionSource <Exception>();
                connection.Closed += e =>
                {
                    closeTcs.TrySetResult(e);
                    return(Task.CompletedTask);
                };

                await connection.StartAsync();

                // Exception in send should shutdown the connection
                await closeTcs.Task.OrTimeout();

                var exception = await Assert.ThrowsAsync <InvalidOperationException>(
                    async() => await connection.SendAsync(new byte[0]));

                Assert.Equal("Cannot send messages when the connection is not in the Connected state.", exception.Message);
            }
            finally
            {
                await connection.DisposeAsync();
            }
        }
예제 #26
0
        public async Task HttpConnectionThrowsIfSkipNegotiationSetAndTransportIsNotWebSockets(HttpTransportType transportType)
        {
            using (StartServer <Startup>(out var server))
            {
                var logger = LoggerFactory.CreateLogger <EndToEndTests>();
                var url    = server.Url + "/echo";

                var mockHttpHandler = new Mock <HttpMessageHandler>();
                mockHttpHandler.Protected()
                .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
                .Returns <HttpRequestMessage, CancellationToken>(
                    (request, cancellationToken) => Task.FromException <HttpResponseMessage>(new InvalidOperationException("HTTP requests should not be sent.")));

                var httpOptions = new HttpConnectionOptions
                {
                    Url                       = new Uri(url),
                    Transports                = transportType,
                    SkipNegotiation           = true,
                    HttpMessageHandlerFactory = (httpMessageHandler) => mockHttpHandler.Object
                };

                var connection = new HttpConnection(httpOptions, LoggerFactory);

                try
                {
                    var exception = await Assert.ThrowsAsync <InvalidOperationException>(() => connection.StartAsync(TransferFormat.Binary).OrTimeout());

                    Assert.Equal("Negotiation can only be skipped when using the WebSocket transport directly.", exception.Message);
                }
                catch (Exception ex)
                {
                    logger.LogInformation(ex, "Test threw exception");
                    throw;
                }
                finally
                {
                    await connection.DisposeAsync().OrTimeout();
                }
            }
        }
        /// <summary>
        /// Creates a new connection to an <see cref="UriEndPoint"/>.
        /// </summary>
        /// <param name="endPoint">The <see cref="UriEndPoint"/> to connect to.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None" />.</param>
        /// <returns>
        /// A <see cref="ValueTask{TResult}" /> that represents the asynchronous connect, yielding the <see cref="ConnectionContext" /> for the new connection when completed.
        /// </returns>
        public async ValueTask <ConnectionContext> ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken = default)
        {
            if (endPoint == null)
            {
                throw new ArgumentNullException(nameof(endPoint));
            }

            if (!(endPoint is UriEndPoint uriEndPoint))
            {
                throw new NotSupportedException($"The provided {nameof(EndPoint)} must be of type {nameof(UriEndPoint)}.");
            }

            if (_httpConnectionOptions.Url != null && _httpConnectionOptions.Url != uriEndPoint.Uri)
            {
                throw new InvalidOperationException($"If {nameof(HttpConnectionOptions)}.{nameof(HttpConnectionOptions.Url)} was set, it must match the {nameof(UriEndPoint)}.{nameof(UriEndPoint.Uri)} passed to {nameof(ConnectAsync)}.");
            }

            // Shallow copy before setting the Url property so we don't mutate the user-defined options object.
            var shallowCopiedOptions = ShallowCopyHttpConnectionOptions(_httpConnectionOptions);

            shallowCopiedOptions.Url = uriEndPoint.Uri;

            var connection = new HttpConnection(shallowCopiedOptions, _loggerFactory);

            try
            {
                await connection.StartAsync(cancellationToken);

                return(connection);
            }
            catch
            {
                // Make sure the connection is disposed, in case it allocated any resources before failing.
                await connection.DisposeAsync();

                throw;
            }
        }
예제 #28
0
        public async Task TransportThatFallsbackCreatesNewConnection()
        {
            bool ExpectedErrors(WriteContext writeContext)
            {
                return(writeContext.LoggerName == typeof(HttpConnection).FullName &&
                       writeContext.EventId.Name == "ErrorStartingTransport");
            }

            using (StartServer <Startup>(out var server, expectedErrorsFilter: ExpectedErrors))
            {
                var url = server.Url + "/echo";
                // The test should connect to the server using WebSockets transport on Windows 8 and newer.
                // On Windows 7/2008R2 it should use ServerSentEvents transport to connect to the server.

                // The test logic lives in the TestTransportFactory and FakeTransport.
                var connection = new HttpConnection(new HttpConnectionOptions {
                    Url = new Uri(url)
                }, LoggerFactory, new TestTransportFactory());
                await connection.StartAsync(TransferFormat.Text).OrTimeout();

                await connection.DisposeAsync().OrTimeout();
            }
        }
예제 #29
0
        public async Task ClosedEventRaisedWhenConnectionToServerLost()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();

                return(request.Method == HttpMethod.Get
                        ? ResponseUtils.CreateResponse(HttpStatusCode.InternalServerError)
                        : request.Method == HttpMethod.Options
                            ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                            : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            var connection     = new HttpConnection(new Uri("http://fakeuri.org/"), TransportType.LongPolling, loggerFactory: null, httpMessageHandler: mockHttpHandler.Object);
            var closedEventTcs = new TaskCompletionSource <Exception>();

            connection.Closed += e =>
            {
                closedEventTcs.TrySetResult(e);
                return(Task.CompletedTask);
            };

            try
            {
                await connection.StartAsync();

                Assert.IsType <HttpRequestException>(await closedEventTcs.Task.OrTimeout());
            }
            finally
            {
                await connection.DisposeAsync();
            }
        }
예제 #30
0
        public async Task TransportIsStoppedWhenConnectionIsStopped()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();

                return(IsNegotiateRequest(request)
                        ? ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationResponse())
                        : ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var longPollingTransport = new LongPollingTransport(httpClient, null, new LoggerFactory());
                var connection           = new HttpConnection(new Uri("http://fakeuri.org/"), new TestTransportFactory(longPollingTransport), loggerFactory: null,
                                                              httpOptions: new HttpOptions {
                    HttpMessageHandler = mockHttpHandler.Object
                });

                try
                {
                    await connection.StartAsync();

                    Assert.False(longPollingTransport.Running.IsCompleted);
                }
                finally
                {
                    await connection.DisposeAsync();
                }

                await longPollingTransport.Running.OrTimeout();
            }
        }