public async Task HttpConnectionSetsRequestedWithOnAllRequests(HttpTransportType transportType) { var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false); var requestsExecuted = false; testHttpHandler.OnNegotiate((_, cancellationToken) => { return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent())); }); testHttpHandler.OnRequest(async(request, next, token) => { var requestedWithHeader = request.Headers.GetValues(HeaderNames.XRequestedWith); var requestedWithValue = Assert.Single(requestedWithHeader); Assert.Equal("XMLHttpRequest", requestedWithValue); requestsExecuted = true; return(await next()); }); testHttpHandler.OnRequest((request, next, token) => { return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent))); }); await WithConnectionAsync( CreateConnection(testHttpHandler, transportType : transportType), async (connection) => { await connection.StartAsync().DefaultTimeout(); await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World")); }); // Fail safe in case the code is modified and some requests don't execute as a result Assert.True(requestsExecuted); }
public async Task NegotiateThatReturnsRedirectUrlForeverThrowsAfter100Tries() { var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false); testHttpHandler.OnNegotiate((request, cancellationToken) => { return(ResponseUtils.CreateResponse(HttpStatusCode.OK, JsonConvert.SerializeObject(new { url = "https://another.domain.url/chat" }))); }); using (var noErrorScope = new VerifyNoErrorsScope()) { await WithConnectionAsync( CreateConnection(testHttpHandler, loggerFactory : noErrorScope.LoggerFactory), async (connection) => { var exception = await Assert.ThrowsAsync <InvalidOperationException>(() => connection.StartAsync().DefaultTimeout()); Assert.Equal("Negotiate redirection limit exceeded.", exception.Message); }); } }
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 LongPollingTransportCanBeCanceled() { using (StartVerifiableLog()) { var cts = new CancellationTokenSource(); var httpHandler = new TestHttpMessageHandler(autoNegotiate: false); httpHandler.OnNegotiate((request, cancellationToken) => { // Cancel token so that the first request poll will throw cts.Cancel(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent())); }); var lp = new LongPollingTransport(new HttpClient(httpHandler)); await WithConnectionAsync( CreateConnection(httpHandler, transport : lp, transportType : HttpTransportType.LongPolling), async (connection) => { var ex = await Assert.ThrowsAsync <AggregateException>(async() => await connection.StartAsync(cts.Token).DefaultTimeout()); }); } }
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 HttpConnectionRetriesAccessTokenProviderWhenAuthFailsServerSentEvents() { var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false); var requestsExecuted = false; var accessTokenCallCount = 0; testHttpHandler.OnNegotiate((_, cancellationToken) => { return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent())); }); var sendRequestExecuted = false; var sendFinishedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); testHttpHandler.OnSocketSend((_, _) => { if (!sendRequestExecuted) { sendRequestExecuted = true; return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized)); } sendFinishedTcs.SetResult(); return(ResponseUtils.CreateResponse(HttpStatusCode.OK)); }); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var stream = new BlockingStream(tcs); 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); return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.OK, new StreamContent(stream)))); }); Task <string> AccessTokenProvider() { accessTokenCallCount++; return(Task.FromResult(accessTokenCallCount.ToString(CultureInfo.InvariantCulture))); } await WithConnectionAsync( CreateConnection(testHttpHandler, transportType : HttpTransportType.ServerSentEvents, accessTokenProvider : AccessTokenProvider), async (connection) => { await connection.StartAsync().DefaultTimeout(); await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello world 1")); await sendFinishedTcs.Task; tcs.TrySetResult(); await connection.Transport.Input.ReadAllAsync(); }); // 1 negotiate + 1 retry stream request + 1 retry send Assert.Equal(3, accessTokenCallCount); }
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); }