public async Task ConnectionIdGetsSetWithNegotiateProtocolGreaterThanZero()
        {
            string connectionId = null;

            var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);

            testHttpHandler.OnNegotiate((request, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                                                                     JsonConvert.SerializeObject(new
            {
                connectionId        = "0rge0d00-0040-0030-0r00-000q00r00e00",
                negotiateVersion    = 1,
                connectionToken     = "different-id",
                availableTransports = new object[]
                {
                    new
                    {
                        transport       = "LongPolling",
                        transferFormats = new[] { "Text" }
                    },
                },
                newField = "ignore this",
            })));
            testHttpHandler.OnLongPoll(cancellationToken => ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
            testHttpHandler.OnLongPollDelete((token) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted));

            using (var noErrorScope = new VerifyNoErrorsScope())
            {
                await WithConnectionAsync(
                    CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory),
                    async (connection) =>
                {
                    await connection.StartAsync().DefaultTimeout();
                    connectionId = connection.ConnectionId;
                });
            }

            Assert.Equal("0rge0d00-0040-0030-0r00-000q00r00e00", connectionId);
            Assert.Equal("http://fakeuri.org/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[0].RequestUri.ToString());
            Assert.Equal("http://fakeuri.org/?id=different-id", testHttpHandler.ReceivedRequests[1].RequestUri.ToString());
        }
Example #2
0
        public async Task TransportPipeIsCompletedWhenErrorOccursInTransport()
        {
            bool ExpectedErrors(WriteContext writeContext)
            {
                return(writeContext.LoggerName == typeof(LongPollingTransport).FullName &&
                       writeContext.EventId.Name == "ErrorSending");
            }

            using (StartVerifiableLog(expectedErrorsFilter: ExpectedErrors))
            {
                var httpHandler = new TestHttpMessageHandler();

                var longPollResult = new TaskCompletionSource <HttpResponseMessage>();
                httpHandler.OnLongPoll(cancellationToken =>
                {
                    cancellationToken.Register(() =>
                    {
                        longPollResult.TrySetResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
                    });
                    return(longPollResult.Task);
                });
                httpHandler.OnLongPollDelete(cancellationToken => ResponseUtils.CreateResponse(HttpStatusCode.NoContent));

                httpHandler.OnSocketSend((data, _) =>
                {
                    Assert.Collection(data, i => Assert.Equal(0x42, i));
                    return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.InternalServerError)));
                });

                await WithConnectionAsync(
                    CreateConnection(httpHandler, LoggerFactory),
                    async (connection) =>
                {
                    await connection.StartAsync().DefaultTimeout();
                    await connection.Transport.Output.WriteAsync(new byte[] { 0x42 }).DefaultTimeout();

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await connection.Transport.Input.ReadAsync());
                });
            }
        }
        public async Task NegotiateCanHaveNewFields()
        {
            string connectionId = null;

            var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);

            testHttpHandler.OnNegotiate((request, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                                                                     JsonConvert.SerializeObject(new
            {
                connectionId        = "0rge0d00-0040-0030-0r00-000q00r00e00",
                availableTransports = new object[]
                {
                    new
                    {
                        transport       = "LongPolling",
                        transferFormats = new[] { "Text" }
                    },
                },
                newField = "ignore this",
            })));
            testHttpHandler.OnLongPoll(cancellationToken => ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
            testHttpHandler.OnLongPollDelete((token) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted));

            using (var noErrorScope = new VerifyNoErrorsScope())
            {
                await WithConnectionAsync(
                    CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory),
                    async (connection) =>
                {
                    await connection.StartAsync().DefaultTimeout();
                    connectionId = connection.ConnectionId;
                });
            }

            Assert.Equal("0rge0d00-0040-0030-0r00-000q00r00e00", connectionId);
        }
        public async Task NegotiateThatReturnsRedirectUrlDoesNotAddAnotherNegotiateVersionQueryString()
        {
            var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
            var negotiateCount  = 0;

            testHttpHandler.OnNegotiate((request, cancellationToken) =>
            {
                negotiateCount++;
                if (negotiateCount == 1)
                {
                    return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                        JsonConvert.SerializeObject(new
                    {
                        url = "https://another.domain.url/chat?negotiateVersion=1"
                    })));
                }
                else
                {
                    return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                        JsonConvert.SerializeObject(new
                    {
                        connectionId = "0rge0d00-0040-0030-0r00-000q00r00e00",
                        availableTransports = new object[]
                        {
                            new
                            {
                                transport = "LongPolling",
                                transferFormats = new[] { "Text" }
                            },
                        }
                    })));
                }
            });

            testHttpHandler.OnLongPoll((token) =>
            {
                var tcs = new TaskCompletionSource <HttpResponseMessage>(TaskCreationOptions.RunContinuationsAsynchronously);

                token.Register(() => tcs.TrySetResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)));

                return(tcs.Task);
            });

            testHttpHandler.OnLongPollDelete((token) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted));

            using (var noErrorScope = new VerifyNoErrorsScope())
            {
                await WithConnectionAsync(
                    CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory),
                    async (connection) =>
                {
                    await connection.StartAsync().DefaultTimeout();
                });
            }

            Assert.Equal("http://fakeuri.org/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[0].RequestUri.ToString());
            Assert.Equal("https://another.domain.url/chat/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[1].RequestUri.ToString());
            Assert.Equal("https://another.domain.url/chat?negotiateVersion=1&id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[2].RequestUri.ToString());
            Assert.Equal("https://another.domain.url/chat?negotiateVersion=1&id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[3].RequestUri.ToString());
            Assert.Equal(5, testHttpHandler.ReceivedRequests.Count);
        }
        public async Task NegotiateThatReturnsUrlGetFollowedWithAccessToken()
        {
            var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false);
            var firstNegotiate  = true;

            testHttpHandler.OnNegotiate((request, cancellationToken) =>
            {
                if (firstNegotiate)
                {
                    firstNegotiate = false;

                    // The first negotiate requires an access token
                    if (request.Headers.Authorization?.Parameter != "firstSecret")
                    {
                        return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized));
                    }

                    return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                        JsonConvert.SerializeObject(new
                    {
                        url = "https://another.domain.url/chat",
                        accessToken = "secondSecret"
                    })));
                }

                // All other requests require an access token
                if (request.Headers.Authorization?.Parameter != "secondSecret")
                {
                    return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized));
                }

                return(ResponseUtils.CreateResponse(HttpStatusCode.OK,
                                                    JsonConvert.SerializeObject(new
                {
                    connectionId = "0rge0d00-0040-0030-0r00-000q00r00e00",
                    availableTransports = new object[]
                    {
                        new
                        {
                            transport = "LongPolling",
                            transferFormats = new[] { "Text" }
                        },
                    }
                })));
            });

            testHttpHandler.OnLongPoll((request, token) =>
            {
                // All other requests require an access token
                if (request.Headers.Authorization?.Parameter != "secondSecret")
                {
                    return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized)));
                }
                var tcs = new TaskCompletionSource <HttpResponseMessage>(TaskCreationOptions.RunContinuationsAsynchronously);

                token.Register(() => tcs.TrySetResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)));

                return(tcs.Task);
            });

            testHttpHandler.OnLongPollDelete((token) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted));

            Task <string> AccessTokenProvider() => Task.FromResult <string>("firstSecret");

            using (var noErrorScope = new VerifyNoErrorsScope())
            {
                await WithConnectionAsync(
                    CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory, accessTokenProvider : AccessTokenProvider),
                    async (connection) =>
                {
                    await connection.StartAsync().DefaultTimeout();
                });
            }

            Assert.Equal("http://fakeuri.org/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[0].RequestUri.ToString());
            Assert.Equal("https://another.domain.url/chat/negotiate?negotiateVersion=1", testHttpHandler.ReceivedRequests[1].RequestUri.ToString());
            Assert.Equal("https://another.domain.url/chat?id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[2].RequestUri.ToString());
            Assert.Equal("https://another.domain.url/chat?id=0rge0d00-0040-0030-0r00-000q00r00e00", testHttpHandler.ReceivedRequests[3].RequestUri.ToString());
            // Delete request
            Assert.Equal(5, testHttpHandler.ReceivedRequests.Count);
        }
        public async Task HttpConnectionRetriesAccessTokenProviderWhenAuthFailsLongPolling()
        {
            var testHttpHandler      = new TestHttpMessageHandler(autoNegotiate: false);
            var requestsExecuted     = false;
            var accessTokenCallCount = 0;
            var pollCount            = 0;

            testHttpHandler.OnNegotiate((_, cancellationToken) =>
            {
                return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent()));
            });

            var startSendTcs     = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
            var longPollTcs      = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
            var messageFragments = new[] { "This ", "is ", "a ", "test" };

            testHttpHandler.OnLongPoll(async _ =>
            {
                // fail every other request
                if (pollCount % 2 == 0)
                {
                    pollCount++;
                    return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized));
                }
                if (pollCount / 2 >= messageFragments.Length)
                {
                    startSendTcs.SetResult();
                    await longPollTcs.Task;
                    return(ResponseUtils.CreateResponse(HttpStatusCode.NoContent));
                }

                var resp = ResponseUtils.CreateResponse(HttpStatusCode.OK, messageFragments[pollCount / 2]);
                pollCount++;
                return(resp);
            });

            var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            testHttpHandler.OnRequest((request, next, token) =>
            {
                if (!requestsExecuted)
                {
                    requestsExecuted = true;
                    return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized)));
                }

                Assert.Equal("Bearer", request.Headers.Authorization.Scheme);

                Assert.Equal(accessTokenCallCount.ToString(CultureInfo.InvariantCulture), request.Headers.Authorization.Parameter);

                tcs.SetResult();

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

            Task <string> AccessTokenProvider()
            {
                accessTokenCallCount++;
                return(Task.FromResult(accessTokenCallCount.ToString(CultureInfo.InvariantCulture)));
            }

            await WithConnectionAsync(
                CreateConnection(testHttpHandler, transportType : HttpTransportType.LongPolling, accessTokenProvider : AccessTokenProvider),
                async (connection) =>
            {
                await connection.StartAsync().DefaultTimeout();
                var message = await connection.Transport.Input.ReadAtLeastAsync(14);
                Assert.Equal("This is a test", Encoding.UTF8.GetString(message.Buffer));
                await startSendTcs.Task;
                await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello world 1"));
                await tcs.Task;
                longPollTcs.SetResult();
            });

            // 1 negotiate + 4 (number of polls) + 1 for last poll + 1 for send
            Assert.Equal(7, accessTokenCallCount);
        }