Пример #1
0
        public async Task <ConnectionContext> ConnectAsync(TransferFormat transferFormat, string connectionId, string target, CancellationToken cancellationToken = default)
        {
            var httpConnectionOptions = new HttpConnectionOptions
            {
                Url = GetServiceUrl(connectionId, target),
                AccessTokenProvider = () => Task.FromResult(_provider.GenerateServerAccessToken(_hubName, _userId)),
                Transports          = HttpTransportType.WebSockets,
                SkipNegotiation     = true,
                Headers             = CustomHeader
            };
            var httpConnection = new HttpConnection(httpConnectionOptions, _loggerFactory);

            try
            {
                await httpConnection.StartAsync(transferFormat);

                return(httpConnection);
            }
            catch
            {
                await httpConnection.DisposeAsync();

                throw;
            }
        }
Пример #2
0
        private async Task StartAsyncCore(TransferFormat transferFormat)
        {
            CheckDisposed();

            if (_started)
            {
                Log.SkippingStart(_logger);
                return;
            }

            await _connectionLock.WaitAsync();

            try
            {
                CheckDisposed();

                if (_started)
                {
                    Log.SkippingStart(_logger);
                    return;
                }

                Log.Starting(_logger);

                await SelectAndStartTransport(transferFormat);

                _started = true;
                Log.Started(_logger);
            }
            finally
            {
                _connectionLock.Release();
            }
        }
Пример #3
0
        public async Task LongPollingTransportSetsTransferFormat(TransferFormat transferFormat)
        {
            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(ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var longPollingTransport = new LongPollingTransport(httpClient);

                try
                {
                    var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                    await longPollingTransport.StartAsync(new Uri("http://fakeuri.org"), pair.Application, transferFormat, connection : new TestConnection());
                }
                finally
                {
                    await longPollingTransport.StopAsync();
                }
            }
        }
        public async Task LongPollingTransportSetsTransferFormat(TransferFormat transferFormat)
        {
            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(ResponseUtils.CreateResponse(HttpStatusCode.OK));
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var longPollingTransport = new LongPollingTransport(httpClient);

                try
                {
                    await longPollingTransport.StartAsync(TestUri, transferFormat);
                }
                finally
                {
                    await longPollingTransport.StopAsync();
                }
            }
        }
        [InlineData((TransferFormat)42)]                          // Unexpected value
        public async Task SSETransportThrowsForInvalidTransferFormat(TransferFormat transferFormat)
        {
            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(new HttpResponseMessage {
                    Content = new StringContent(string.Empty)
                });
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
                using (StartVerifiableLog())
                {
                    var sseTransport = new ServerSentEventsTransport(httpClient, LoggerFactory);
                    var exception    = await Assert.ThrowsAsync <ArgumentException>(() =>
                                                                                    sseTransport.StartAsync(new Uri("http://fakeuri.org"), transferFormat));

                    Assert.Contains($"The '{transferFormat}' transfer format is not supported by this transport.", exception.Message);
                    Assert.Equal("transferFormat", exception.ParamName);
                }
        }
        public async Task StartAsync(Uri url, IDuplexPipe application, TransferFormat transferFormat, IConnection connection)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }

            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            if (transferFormat != TransferFormat.Binary && transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException($"The '{transferFormat}' transfer format is not supported by this transport.", nameof(transferFormat));
            }

            _application          = application;
            _webSocketMessageType = transferFormat == TransferFormat.Binary
                ? WebSocketMessageType.Binary
                : WebSocketMessageType.Text;


            Log.StartTransport(_logger, transferFormat);

            await Connect(url);

            // TODO: Handle TCP connection errors
            // https://github.com/SignalR/SignalR/blob/1fba14fa3437e24c204dfaf8a18db3fce8acad3c/src/Microsoft.AspNet.SignalR.Core/Owin/WebSockets/WebSocketHandler.cs#L248-L251
            Running = ProcessSocketAsync(_webSocket);
        }
Пример #7
0
        public Task StartAsync(Uri url, IDuplexPipe application, TransferFormat transferFormat, IConnection connection)
        {
            if (transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException($"The '{transferFormat}' transfer format is not supported by this transport.", nameof(transferFormat));
            }

            _application = application;

            Log.StartTransport(_logger, transferFormat);

            var sendTask    = SendUtils.SendMessages(url, _application, _httpClient, _httpOptions, _transportCts, _logger);
            var receiveTask = OpenConnection(_application, url, _transportCts.Token);

            Running = Task.WhenAll(sendTask, receiveTask).ContinueWith(t =>
            {
                Log.TransportStopped(_logger, t.Exception?.InnerException);
                _application.Output.Complete(t.Exception?.InnerException);
                _application.Input.Complete();

                return(t);
            }).Unwrap();

            return(Task.CompletedTask);
        }
Пример #8
0
        public Task <ConnectionContext> ConnectAsync(HubServiceEndpoint endpoint, TransferFormat transferFormat, string connectionId, string target, CancellationToken cancellationToken = default, IDictionary <string, string> headers = null)
        {
            var connection = new TestConnectionContext();

            _waitForServerConnection.TrySetResult(connection);
            return(Task.FromResult <ConnectionContext>(connection));
        }
Пример #9
0
        private Task StartAsyncCore(TransferFormat transferFormat)
        {
            if (ChangeState(from: ConnectionState.Disconnected, to: ConnectionState.Connecting) != ConnectionState.Disconnected)
            {
                return(Task.FromException(
                           new InvalidOperationException($"Cannot start a connection that is not in the {nameof(ConnectionState.Disconnected)} state.")));
            }

            _startTcs   = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);
            _eventQueue = new TaskQueue();

            StartAsyncInternal(transferFormat)
            .ContinueWith(t =>
            {
                var abortException = _abortException;
                if (t.IsFaulted || abortException != null)
                {
                    _startTcs.SetException(_abortException ?? t.Exception.InnerException);
                }
                else if (t.IsCanceled)
                {
                    _startTcs.SetCanceled();
                }
                else
                {
                    _startTcs.SetResult(null);
                }
            });

            return(_startTcs.Task);
        }
Пример #10
0
        public async Task StartAsync(Uri url, TransferFormat transferFormat)
        {
            if (transferFormat != TransferFormat.Binary && transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException($"The '{transferFormat}' transfer format is not supported by this transport.", nameof(transferFormat));
            }

            Log.StartTransport(_logger, transferFormat);

            // Make initial long polling request
            // Server uses first long polling request to finish initializing connection and it returns without data
            var request = new HttpRequestMessage(HttpMethod.Get, url);

            using (var response = await _httpClient.SendAsync(request))
            {
                response.EnsureSuccessStatusCode();
            }

            // Create the pipe pair (Application's writer is connected to Transport's reader, and vice versa)
            var options = ClientPipeOptions.DefaultOptions;
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            Running = ProcessAsync(url);
        }
        public Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken)
        {
            if (transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException(
                          $"The '{transferFormat}' transfer format is not supported by this transport.",
                          nameof(transferFormat));
            }

            Log.StartTransport(_logger, transferFormat);

            // Create pipe
            PipeOptions options = ClientPipeOptions.DefaultOptions;

            DuplexPipe.DuplexPipePair pair = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            CancellationTokenSource inputCts = new CancellationTokenSource();

            _application.Input.OnWriterCompleted((exception, state) => ((CancellationTokenSource)state).Cancel(),
                                                 inputCts);

            // Start streams
            Running = ProcessAsync(url, inputCts.Token);

            return(Task.CompletedTask);
        }
        private static HttpConnection CreateConnection(
            HttpConnectionOptions httpConnectionOptions,
            ILoggerFactory loggerFactory       = null,
            ITransport transport               = null,
            ITransportFactory transportFactory = null,
            TransferFormat transferFormat      = TransferFormat.Text)
        {
            loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
            httpConnectionOptions.Url ??= new Uri("http://fakeuri.org/");
            httpConnectionOptions.DefaultTransferFormat = transferFormat;

            if (transportFactory == null && transport != null)
            {
                transportFactory = new TestTransportFactory(transport);
            }

            if (transportFactory != null)
            {
                return(new HttpConnection(httpConnectionOptions, loggerFactory, transportFactory));
            }
            else
            {
                // Use the public constructor to get the default transport factory.
                return(new HttpConnection(httpConnectionOptions, loggerFactory));
            }
        }
Пример #13
0
            public Task StartAsync(Uri url, TransferFormat transferFormat)
            {
                var options = ClientPipeOptions.DefaultOptions;
                var pair    = DuplexPipe.CreateConnectionPair(options, options);

                _transport   = pair.Transport;
                _application = pair.Application;
                _tries++;
                Assert.True(QueryHelpers.ParseQuery(url.Query).TryGetValue("id", out var id));
                if (_prevConnectionId == null)
                {
                    _prevConnectionId = id;
                }
                else
                {
                    Assert.True(_prevConnectionId != id);
                    _prevConnectionId = id;
                }

                if (_tries < availableTransports)
                {
                    return(Task.FromException(new Exception()));
                }
                else
                {
                    return(Task.CompletedTask);
                }
            }
Пример #14
0
        public async Task <ConnectionContext> ConnectAsync(HubServiceEndpoint hubServiceEndpoint,
                                                           TransferFormat transferFormat,
                                                           string connectionId,
                                                           string target,
                                                           CancellationToken cancellationToken  = default,
                                                           IDictionary <string, string> headers = null)
        {
            var provider = hubServiceEndpoint.Provider;
            var hubName  = hubServiceEndpoint.Hub;

            Task <string> accessTokenGenerater() => provider.GenerateServerAccessTokenAsync(hubName, _userId);

            var url = GetServiceUrl(provider, hubName, connectionId, target);
            var connectionOptions = new WebSocketConnectionOptions
            {
                Headers = headers,
                Proxy   = provider.Proxy,
            };
            var connection = new WebSocketConnectionContext(connectionOptions, _loggerFactory, accessTokenGenerater);

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

                return(connection);
            }
            catch
            {
                await connection.StopAsync();

                throw;
            }
        }
        public Task <ConnectionContext> ConnectAsync(HubServiceEndpoint endpoint, TransferFormat transferFormat, string connectionId, string target, CancellationToken cancellationToken = default, IDictionary <string, string> headers = null)
        {
            // ConnectAsync merely means establish a physical connection.
            // In our case this means connect the pipes and start the message processing loops
            ConnectionContext c = new MockServiceConnectionContext(_mockService, endpoint, target, connectionId);

            return(Task.FromResult(c));
        }
Пример #16
0
 public WebSocketsTransport(IDuplexPipe pipe, WebSocketOptions options, ILogger logger)
 {
     this.pipe      = pipe;
     this.options   = options;
     this.logger    = logger;
     cancellation   = new CancellationTokenSource();
     transferFormat = TransferFormat.Binary;
 }
            public static void StartTransport(ILogger?logger, TransferFormat transferFormat)
            {
                if (logger is null)
                {
                    return;
                }

                StartTransportMessage(logger, transferFormat, null);
            }
                public Task StartAsync(Uri url, IDuplexPipe application, TransferFormat transferFormat, IConnection connection)
                {
                    _application = application;
                    Action <Exception, object> onCompletedCallback = (ex, tcs) => { ((TaskCompletionSource <object>)tcs).TrySetResult(null); };

                    _application.Input.OnWriterCompleted(onCompletedCallback, _writerTcs);
                    _application.Output.OnReaderCompleted(onCompletedCallback, _readerTcs);
                    throw new Exception();
                }
Пример #19
0
            public Task <ConnectionContext> ConnectAsync(TransferFormat transferFormat, string connectionId, string hubName, CancellationToken cancellationToken = default)
            {
                var connection = new TestConnectionContext();

                _connectCallback?.Invoke(connection);

                _waitForServerConnection.TrySetResult(connection);
                return(Task.FromResult <ConnectionContext>(connection));
            }
Пример #20
0
 public Task StartAsync(Uri url, IDuplexPipe application, TransferFormat transferFormat, IConnection connection)
 {
     if ((Format & transferFormat) == 0)
     {
         throw new InvalidOperationException($"The '{transferFormat}' transfer format is not supported by this transport.");
     }
     Application = application;
     return(_startHandler());
 }
 public static void TransportDoesNotSupportTransferFormat(ILogger logger, HttpTransportType transport,
                                                          TransferFormat transferFormat)
 {
     if (!logger.IsEnabled(LogLevel.Debug))
     {
         return;
     }
     _transportDoesNotSupportTransferFormat(logger, transport.ToString(), transferFormat.ToString(),
                                            (Exception)null);
 }
Пример #22
0
        public async Task StartAsync(Uri url, TransferFormat transferFormat)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }

            if (transferFormat != TransferFormat.Binary && transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException($"The '{transferFormat}' transfer format is not supported by this transport.", nameof(transferFormat));
            }

            _webSocketMessageType = transferFormat == TransferFormat.Binary
                ? WebSocketMessageType.Binary
                : WebSocketMessageType.Text;

            var resolvedUrl = ResolveWebSocketsUrl(url);

            // We don't need to capture to a local because we never change this delegate.
            if (_accessTokenProvider != null)
            {
                var accessToken = await _accessTokenProvider();

                if (!string.IsNullOrEmpty(accessToken))
                {
                    _webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
                }
            }

            Log.StartTransport(_logger, transferFormat, resolvedUrl);

            try
            {
                await _webSocket.ConnectAsync(resolvedUrl, CancellationToken.None);
            }
            catch
            {
                _webSocket.Dispose();
                throw;
            }

            Log.StartedTransport(_logger);

            // Create the pipe pair (Application's writer is connected to Transport's reader, and vice versa)
            var options = ClientPipeOptions.DefaultOptions;
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            // TODO: Handle TCP connection errors
            // https://github.com/SignalR/SignalR/blob/1fba14fa3437e24c204dfaf8a18db3fce8acad3c/src/Microsoft.AspNet.SignalR.Core/Owin/WebSockets/WebSocketHandler.cs#L248-L251
            Running = ProcessSocketAsync(_webSocket);
        }
        public static Task StartAsync(this IDuplexPipe pipe, Uri uri, TransferFormat transferFormat)
        {
#pragma warning disable CA1062
            var method = pipe.GetType().GetMethod(
                nameof(StartAsync), new Type[] { typeof(Uri), typeof(TransferFormat), typeof(CancellationToken) });
#pragma warning restore CA1062
            Debug.Assert(method != null);
            var result = method !.Invoke(pipe, new object[] { uri, transferFormat, default(CancellationToken) }) as Task;
            Debug.Assert(result != null);
            return(result !);
        }
Пример #24
0
        public async Task WebSocketsTransportThrowsForInvalidTransferFormat(TransferFormat transferFormat)
        {
            using (StartVerifiableLog(out var loggerFactory))
            {
                var webSocketsTransport = new WebSocketsTransport(httpConnectionOptions: null, loggerFactory: loggerFactory, accessTokenProvider: null);
                var exception           = await Assert.ThrowsAsync <ArgumentException>(() =>
                                                                                       webSocketsTransport.StartAsync(new Uri("http://fakeuri.org"), transferFormat));

                Assert.Contains($"The '{transferFormat}' transfer format is not supported by this transport.", exception.Message);
                Assert.Equal("transferFormat", exception.ParamName);
            }
        }
Пример #25
0
        public void ValidHash()
        {
            using (var mem = new MemoryStream()) {
                var messages = GenerateMessages(7);
                TransferFormat.WriteMessages(messages, mem);
                mem.Seek(0, SeekOrigin.Begin);

                var actual = TransferFormat.ReadMessages(mem);

                AssertEqual(messages, actual);
            }
        }
Пример #26
0
        public async Task WebSocketsTransportThrowsForInvalidTransferFormat(TransferFormat transferFormat)
        {
            using (StartLog(out var loggerFactory))
            {
                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);
                var exception           = await Assert.ThrowsAsync <ArgumentException>(() =>
                                                                                       webSocketsTransport.StartAsync(new Uri("http://fakeuri.org"), pair.Application, transferFormat, connection: Mock.Of <IConnection>()));

                Assert.Contains($"The '{transferFormat}' transfer format is not supported by this transport.", exception.Message);
                Assert.Equal("transferFormat", exception.ParamName);
            }
        }
Пример #27
0
        public async Task StartAsync(TransferFormat transferFormat)
        {
            _started.TrySetResult(null);

            await _onStart();

            if (_autoHandshake)
            {
                // We can't await this as it will block StartAsync which will block
                // HubConnection.StartAsync which sends the Handshake in the first place!
                _ = ReadHandshakeAndSendResponseAsync();
            }
        }
Пример #28
0
        public async Task WebSocketsTransportSetsTransferFormat(TransferFormat transferFormat)
        {
            using (StartVerifiableLog(out var loggerFactory))
            {
                var webSocketsTransport = new WebSocketsTransport(httpConnectionOptions: null, loggerFactory: loggerFactory, accessTokenProvider: null);

                await webSocketsTransport.StartAsync(new Uri(ServerFixture.WebSocketsUrl + "/echo"),
                                                     transferFormat).OrTimeout();

                await webSocketsTransport.StopAsync().OrTimeout();

                await webSocketsTransport.Running.OrTimeout();
            }
        }
Пример #29
0
        public async Task WebSocketsTransportSetsTransferFormat(TransferFormat transferFormat)
        {
            using (StartLog(out var loggerFactory))
            {
                var webSocketsTransport = new WebSocketsTransport(httpOptions: null, loggerFactory: loggerFactory);

                await webSocketsTransport.StartAsync(new Uri(_serverFixture.WebSocketsUrl + "/echo"),
                                                     transferFormat).OrTimeout();

                await webSocketsTransport.StopAsync().OrTimeout();

                await webSocketsTransport.Running.OrTimeout();
            }
        }
        public async Task WebSocketsTransportSetsTransferFormat(TransferFormat transferFormat)
        {
            await using (var server = await StartServer <Startup>())
            {
                var webSocketsTransport = new WebSocketsTransport(httpConnectionOptions: null, loggerFactory: LoggerFactory, accessTokenProvider: null);

                await webSocketsTransport.StartAsync(new Uri(server.WebSocketsUrl + "/echo"),
                                                     transferFormat).DefaultTimeout();

                await webSocketsTransport.StopAsync().DefaultTimeout();

                await webSocketsTransport.Running.DefaultTimeout();
            }
        }