public async Task NoErrorsLoggedWhenServerEndsConnectionBeforeClient(ServiceContext testContext) { var testLogger = new TestApplicationErrorLogger(); testContext.Log = new KestrelTrace(testLogger); using (var server = new TestServer(async httpContext => { var response = httpContext.Response; response.Headers.Clear(); response.Headers["Content-Length"] = new[] { "11" }; await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11); }, testContext)) { using (var connection = new TestConnection(server.Port)) { await connection.Send( "GET / HTTP/1.0", "", ""); await connection.ReceiveForcedEnd( "HTTP/1.0 200 OK", "Content-Length: 11", "", "Hello World"); } } Assert.Equal(0, testLogger.TotalErrorsLogged); }
public async Task ConnectionClosedIfExeptionThrownAfterZeroLengthWrite(ServiceContext testContext) { using (var server = new TestServer(async httpContext => { var response = httpContext.Response; response.Headers.Clear(); await response.Body.WriteAsync(new byte[0], 0, 0); throw new Exception(); }, testContext)) { using (var connection = new TestConnection(server.Port)) { // SendEnd is not called, so it isn't the client closing the connection. await connection.Send( "GET / HTTP/1.1", "", ""); // Headers are sent before connection is closed, but chunked body terminator isn't sent await connection.ReceiveForcedEnd( "HTTP/1.1 200 OK", "Transfer-Encoding: chunked", "", ""); } } }
public async Task ConnectionClosedIfExeptionThrownAfterWrite(ServiceContext testContext) { using (var server = new TestServer(async httpContext => { var response = httpContext.Response; response.Headers.Clear(); await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World!"), 0, 12); throw new Exception(); }, testContext)) { using (var connection = new TestConnection(server.Port)) { // SendEnd is not called, so it isn't the client closing the connection. // client closing the connection. await connection.Send( "GET / HTTP/1.1", "", ""); await connection.ReceiveForcedEnd( "HTTP/1.1 200 OK", "Transfer-Encoding: chunked", "", "c", "Hello World!", ""); } } }
public async Task ThrowingInOnCompletedIsLoggedAndClosesConnection(ServiceContext testContext) { var onCompletedCalled1 = false; var onCompletedCalled2 = false; var testLogger = new TestApplicationErrorLogger(); testContext.Log = new KestrelTrace(testLogger); using (var server = new TestServer(async httpContext => { var response = httpContext.Response; response.OnCompleted(_ => { onCompletedCalled1 = true; throw new Exception(); }, null); response.OnCompleted(_ => { onCompletedCalled2 = true; throw new Exception(); }, null); response.Headers.Clear(); response.Headers["Content-Length"] = new[] { "11" }; await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11); }, testContext)) { using (var connection = new TestConnection(server.Port)) { await connection.Send( "GET / HTTP/1.1", "", ""); await connection.ReceiveForcedEnd( "HTTP/1.1 200 OK", "Content-Length: 11", "", "Hello World"); } // All OnCompleted callbacks should be called even if they throw. Assert.Equal(2, testLogger.ApplicationErrorsLogged); Assert.True(onCompletedCalled1); Assert.True(onCompletedCalled2); } }
private async Task ReceiveBadRequestResponse(TestConnection connection) { await connection.Receive( "HTTP/1.1 400 Bad Request", ""); await connection.Receive( "Connection: close", ""); await connection.ReceiveForcedEnd( $"Date: {connection.Server.Context.DateHeaderValue}", "Content-Length: 0", "", ""); }
public async Task InvalidSizedDataResultsIn400(ServiceContext testContext) { using (var server = new TestServer(async httpContext => { var response = httpContext.Response; var request = httpContext.Request; var buffer = new byte[200]; while (await request.Body.ReadAsync(buffer, 0, buffer.Length) != 0) { ;// read to end } response.Headers.Clear(); response.Headers["Content-Length"] = new[] { "11" }; await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11); }, testContext)) { using (var connection = new TestConnection(server.Port)) { await connection.Send( "POST / HTTP/1.1", "Transfer-Encoding: chunked", "", "C", "HelloChunkedIn"); await connection.Receive( "HTTP/1.1 400 Bad Request", ""); await connection.ReceiveStartsWith("Date:"); await connection.ReceiveForcedEnd( "Content-Length: 0", "Server: Kestrel", "", ""); } } }
public async Task ThrowingAfterPartialWriteKillsConnection(ServiceContext testContext) { bool onStartingCalled = false; var testLogger = new TestApplicationErrorLogger(); testContext.Log = new KestrelTrace(testLogger); using (var server = new TestServer(async httpContext => { var response = httpContext.Response; response.OnStarting(_ => { onStartingCalled = true; return(Task.FromResult <object>(null)); }, null); response.Headers.Clear(); response.Headers["Content-Length"] = new[] { "11" }; await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello"), 0, 5); throw new Exception(); }, testContext)) { using (var connection = new TestConnection(server.Port)) { await connection.Send( "GET / HTTP/1.1", "", ""); await connection.ReceiveForcedEnd( "HTTP/1.1 200 OK", "Content-Length: 11", "", "Hello"); Assert.True(onStartingCalled); Assert.Equal(1, testLogger.ApplicationErrorsLogged); } } }
public async Task RequestsCanBeAbortedMidRead(ServiceContext testContext) { var readTcs = new TaskCompletionSource <object>(); var registrationTcs = new TaskCompletionSource <int>(); var requestId = 0; using (var server = new TestServer(async httpContext => { requestId++; var response = httpContext.Response; var request = httpContext.Request; var lifetime = httpContext.Features.Get <IHttpRequestLifetimeFeature>(); lifetime.RequestAborted.Register(() => registrationTcs.TrySetResult(requestId)); if (requestId == 1) { response.Headers.Clear(); response.Headers["Content-Length"] = new[] { "5" }; await response.WriteAsync("World"); } else { var readTask = request.Body.CopyToAsync(Stream.Null); lifetime.Abort(); try { await readTask; } catch (Exception ex) { readTcs.SetException(ex); throw; } readTcs.SetException(new Exception("This shouldn't be reached.")); } }, testContext)) { using (var connection = new TestConnection(server.Port)) { // Never send the body so CopyToAsync always fails. await connection.Send( "POST / HTTP/1.1", "Content-Length: 5", "", "HelloPOST / HTTP/1.1", "Content-Length: 5", "", ""); await connection.ReceiveForcedEnd( "HTTP/1.1 200 OK", "Content-Length: 5", "", "World"); } } await Assert.ThrowsAsync <TaskCanceledException>(async() => await readTcs.Task); // The cancellation token for only the last request should be triggered. var abortedRequestId = await registrationTcs.Task; Assert.Equal(2, abortedRequestId); }