public static TestHttpMessageHandler CreateDefault() { var testHttpMessageHandler = new TestHttpMessageHandler(); var deleteCts = new CancellationTokenSource(); testHttpMessageHandler.OnSocketSend((_, __) => ResponseUtils.CreateResponse(HttpStatusCode.Accepted)); testHttpMessageHandler.OnLongPoll(async cancellationToken => { var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, deleteCts.Token); // Just block until canceled var tcs = new TaskCompletionSource(); using (cts.Token.Register(() => tcs.TrySetResult())) { await tcs.Task; } return(ResponseUtils.CreateResponse(HttpStatusCode.NoContent)); }); testHttpMessageHandler.OnRequest((request, next, cancellationToken) => { if (request.Method.Equals(HttpMethod.Delete) && request.RequestUri.PathAndQuery.Contains("id=")) { deleteCts.Cancel(); return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.Accepted))); } return(next()); }); return(testHttpMessageHandler); }
public async Task HttpConnectionSetsAccessTokenOnAllRequests(HttpTransportType transportType) { var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false); var requestsExecuted = false; var callCount = 0; testHttpHandler.OnNegotiate((_, cancellationToken) => { return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent())); }); testHttpHandler.OnRequest(async(request, next, token) => { Assert.Equal("Bearer", request.Headers.Authorization.Scheme); // Call count increments with each call and is used as the access token Assert.Equal(callCount.ToString(CultureInfo.InvariantCulture), request.Headers.Authorization.Parameter); requestsExecuted = true; return(await next()); }); testHttpHandler.OnRequest((request, next, token) => { return(Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent))); }); Task <string> AccessTokenProvider() { callCount++; return(Task.FromResult(callCount.ToString(CultureInfo.InvariantCulture))); } await WithConnectionAsync( CreateConnection(testHttpHandler, transportType : transportType, accessTokenProvider : AccessTokenProvider), async (connection) => { await connection.StartAsync().DefaultTimeout(); await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello world 1")); await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello world 2")); }); // Fail safe in case the code is modified and some requests don't execute as a result Assert.True(requestsExecuted); Assert.Equal(1, callCount); }
public async Task HttpConnectionSetsUserAgentOnAllRequests(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 userAgentHeader = request.Headers.UserAgent.ToString(); Assert.NotNull(userAgentHeader); Assert.StartsWith("Microsoft SignalR/", userAgentHeader); // user agent version should come from version embedded in assembly metadata var assemblyVersion = typeof(Constants) .Assembly .GetCustomAttribute <AssemblyInformationalVersionAttribute>(); Assert.Contains(assemblyVersion.InformationalVersion, userAgentHeader); 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 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 ConnectionIsDisposedIfItFailsToStartAsync() { var testHandler = new TestHttpMessageHandler(autoNegotiate: false, handleFirstPoll: false); testHandler.OnRequest((req, next, ct) => Task.FromException <HttpResponseMessage>(new Exception("BOOM"))); var factory = new HttpConnectionFactory( Options.Create(new HttpConnectionOptions { DefaultTransferFormat = TransferFormat.Text, HttpMessageHandlerFactory = _ => testHandler, }), NullLoggerFactory.Instance); // We don't care about the specific exception await Assert.ThrowsAnyAsync <Exception>(async() => await factory.ConnectAsync(new UriEndPoint(new Uri("http://example.com")))); // We care that the handler (and by extension the client) was disposed Assert.True(testHandler.Disposed); }
public async Task HttpConnectionFailsAfterFirstRetryFailsServerSentEvents() { var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false); var accessTokenCallCount = 0; testHttpHandler.OnNegotiate((_, cancellationToken) => { return(ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent())); }); testHttpHandler.OnSocketSend((_, _) => { return(ResponseUtils.CreateResponse(HttpStatusCode.Unauthorized)); }); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var stream = new BlockingStream(tcs); testHttpHandler.OnRequest((request, next, token) => { 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 Assert.ThrowsAsync <HttpRequestException>(async() => await connection.Transport.Input.ReadAllAsync()); }); // 1 negotiate + 1 retry stream request Assert.Equal(2, accessTokenCallCount); }
public async Task HttpConnectionSetsInherentKeepAliveFeature(HttpTransportType transportType, bool expectedValue) { using (StartVerifiableLog()) { var testHttpHandler = new TestHttpMessageHandler(autoNegotiate: false); testHttpHandler.OnNegotiate((_, cancellationToken) => ResponseUtils.CreateResponse(HttpStatusCode.OK, ResponseUtils.CreateNegotiationContent())); testHttpHandler.OnRequest((request, next, token) => Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.NoContent))); await WithConnectionAsync( CreateConnection(testHttpHandler, transportType : transportType, loggerFactory : LoggerFactory), async (connection) => { await connection.StartAsync().DefaultTimeout(); var feature = connection.Features.Get <IConnectionInherentKeepAliveFeature>(); Assert.NotNull(feature); Assert.Equal(expectedValue, feature.HasInherentKeepAlive); }); } }
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); }