public async Task Expect100ContinueForBody()
        {
            using (var server = new TestServer(AppChunked))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "POST / HTTP/1.1",
                        "Expect: 100-continue",
                        "Content-Length: 11",
                        "Connection: close",
                        "\r\n");

                    await connection.Receive("HTTP/1.1 100 Continue", "\r\n");

                    await connection.SendEnd("Hello World");

                    await connection.Receive(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "Connection: close",
                        "",
                        "Hello World");
                }
            }
        }
        public async Task ConnectionClosedIfExeptionThrownAfterZeroLengthWrite()
        {
            using (var server = new TestServer(async frame =>
            {
                var response = frame.Get <IHttpResponseFeature>();
                response.Headers.Clear();
                await response.Body.WriteAsync(new byte[0], 0, 0);
                throw new Exception();
            }))
            {
                using (var connection = new TestConnection())
                {
                    // 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.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Transfer-Encoding: chunked",
                        "",
                        "");
                }
            }
        }
        public async Task ConnectionClosedIfExeptionThrownAfterWrite()
        {
            using (var server = new TestServer(async frame =>
            {
                var response = frame.Get <IHttpResponseFeature>();
                response.Headers.Clear();
                await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World!"), 0, 12);
                throw new Exception();
            }))
            {
                using (var connection = new TestConnection())
                {
                    // 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.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Transfer-Encoding: chunked",
                        "",
                        "c",
                        "Hello World!",
                        "");
                }
            }
        }
        public async Task ThrowingAfterPartialWriteKillsConnection()
        {
            bool onStartingCalled = false;

            using (var server = new TestServer(async frame =>
            {
                frame.OnStarting(_ =>
                {
                    onStartingCalled = true;
                    return(Task.FromResult <object>(null));
                }, null);

                frame.ResponseHeaders.Clear();
                frame.ResponseHeaders["Content-Length"] = new[] { "11" };
                await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Hello"), 0, 5);
                throw new Exception();
            }))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");

                    await connection.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "",
                        "Hello");

                    Assert.True(onStartingCalled);
                }
            }
        }
Beispiel #5
0
        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())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");

                    await connection.ReceiveEnd(
                        "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);
            }
        }
        public async Task Http10TransferEncoding()
        {
            using (var server = new TestServer(App))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "POST / HTTP/1.0",
                        "Transfer-Encoding: chunked",
                        "",
                        "5", "Hello", "6", " World", "0\r\n");

                    await connection.ReceiveEnd(
                        "HTTP/1.0 200 OK",
                        "",
                        "Hello World");
                }
            }
        }
        public async Task Http10ContentLength()
        {
            using (var server = new TestServer(App))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "POST / HTTP/1.0",
                        "Content-Length: 11",
                        "",
                        "Hello World");

                    await connection.ReceiveEnd(
                        "HTTP/1.0 200 OK",
                        "",
                        "Hello World");
                }
            }
        }
Beispiel #8
0
        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())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");

                    await connection.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "",
                        "Hello");

                    Assert.True(onStartingCalled);
                    Assert.Equal(1, testLogger.ApplicationErrorsLogged);
                }
            }
        }
        public async Task ThrowingInOnStartingResultsInFailedWrites()
        {
            using (var server = new TestServer(async frame =>
            {
                var onStartingException = new Exception();

                frame.OnStarting(_ =>
                {
                    throw onStartingException;
                }, null);

                frame.ResponseHeaders.Clear();
                frame.ResponseHeaders["Content-Length"] = new[] { "11" };

                var writeException = await Assert.ThrowsAsync <Exception>(async() =>
                                                                          await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11));

                Assert.Same(onStartingException, writeException);

                // The second write should succeed since the OnStarting callback will not be called again
                await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Exception!!"), 0, 11);
            }))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");

                    await connection.Receive(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "",
                        "Exception!!");;
                }
            }
        }
 public async Task Expect100ContinueForBody()
 {
     using (var server = new TestServer(AppChunked))
     {
         using (var connection = new TestConnection())
         {
             await connection.Send(
                 "POST / HTTP/1.1",
                 "Expect: 100-continue",
                 "Content-Length: 11",
                 "Connection: close",
                 "\r\n");
             await connection.Receive("HTTP/1.1 100 Continue", "\r\n");
             await connection.SendEnd("Hello World");
             await connection.Receive(
                 "HTTP/1.1 200 OK",
                 "Content-Length: 11",
                 "Connection: close",
                 "",
                 "Hello World");
         }
     }
 }
 public async Task Http10TransferEncoding()
 {
     using (var server = new TestServer(App))
     {
         using (var connection = new TestConnection())
         {
             await connection.Send(
                 "POST / HTTP/1.0",
                 "Transfer-Encoding: chunked",
                 "",
                 "5", "Hello", "6", " World", "0\r\n");
             await connection.ReceiveEnd(
                 "HTTP/1.0 200 OK",
                 "",
                 "Hello World");
         }
     }
 }
 public async Task Http10ContentLength()
 {
     using (var server = new TestServer(App))
     {
         using (var connection = new TestConnection())
         {
             await connection.Send(
                 "POST / HTTP/1.0",
                 "Content-Length: 11",
                 "",
                 "Hello World");
             await connection.ReceiveEnd(
                 "HTTP/1.0 200 OK",
                 "",
                 "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 frame =>
            {
                var response = frame.Get<IHttpResponseFeature>();
                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())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");
                    await connection.ReceiveEnd(
                        "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);
            }
        }
        public async Task ThrowingAfterPartialWriteKillsConnection(ServiceContext testContext)
        {
            bool onStartingCalled = false;

            var testLogger = new TestApplicationErrorLogger();
            testContext.Log = new KestrelTrace(testLogger);

            using (var server = new TestServer(async frame =>
            {
                var response = frame.Get<IHttpResponseFeature>();
                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())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");
                    await connection.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "",
                        "Hello");

                    Assert.True(onStartingCalled);
                    Assert.Equal(1, testLogger.ApplicationErrorsLogged);
                }
            }
        }
        public async Task ConnectionClosedIfExeptionThrownAfterZeroLengthWrite()
        {
            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();
            }))
            {
                using (var connection = new TestConnection())
                {
                    // 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.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Transfer-Encoding: chunked",
                        "",
                        "");
                }
            }
        }
Beispiel #16
0
        public async Task FailedWritesResultInAbortedRequest(ServiceContext testContext)
        {
            var writeTcs          = new TaskCompletionSource <object>();
            var registrationWh    = new ManualResetEventSlim();
            var connectionCloseWh = new ManualResetEventSlim();

            using (var server = new TestServer(async httpContext =>
            {
                var response = httpContext.Response;
                var request = httpContext.Request;
                var lifetime = httpContext.Features.Get <IHttpRequestLifetimeFeature>();

                lifetime.RequestAborted.Register(() => registrationWh.Set());

                await request.Body.CopyToAsync(Stream.Null);
                connectionCloseWh.Wait();

                response.Headers.Clear();
                response.Headers["Content-Length"] = new[] { "5" };

                try
                {
                    // Ensure write is long enough to disable write-behind buffering
                    for (int i = 0; i < 10; i++)
                    {
                        await response.WriteAsync(new string('a', 65537));
                    }
                }
                catch (Exception ex)
                {
                    writeTcs.SetException(ex);

                    // Give a chance for RequestAborted to trip before the app completes
                    registrationWh.Wait(1000);

                    throw;
                }

                writeTcs.SetCanceled();
            }, testContext))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "POST / HTTP/1.1",
                        "Content-Length: 5",
                        "",
                        "Hello");

                    // Don't wait to receive the response. Just close the socket.
                }

                connectionCloseWh.Set();

                // Write failed
                await Assert.ThrowsAsync <IOException>(async() => await writeTcs.Task);

                // RequestAborted tripped
                Assert.True(registrationWh.Wait(200));
            }
        }
        public async Task ConnectionClosedIfExeptionThrownAfterZeroLengthWrite()
        {
            using (var server = new TestServer(async frame =>
            {
                frame.ResponseHeaders.Clear();
                await frame.ResponseBody.WriteAsync(new byte[0], 0, 0);
                throw new Exception();
            }))
            {
                using (var connection = new TestConnection())
                {
                    // SendEnd is not called, so it isn't the client closing the connection.
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");

                    // Nothing (not even headers) are written, but the connection is closed.
                    await connection.ReceiveEnd();
                }
            }
        }
        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.SetCanceled();
                }
            }, testContext))
            {
                using (var connection = new TestConnection())
                {
                    // 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.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 5",
                        "",
                        "World");
                }
            }

            await Assert.ThrowsAsync<IOException>(async () => await readTcs.Task);

            // The cancellation token for only the last request should be triggered.
            var abortedRequestId = await registrationTcs.Task;
            Assert.Equal(2, abortedRequestId);
        }
        public async Task FailedWritesResultInAbortedRequest(ServiceContext testContext)
        {
            var writeTcs = new TaskCompletionSource<object>();
            var registrationWh = new ManualResetEventSlim();
            var connectionCloseWh = new ManualResetEventSlim();

            using (var server = new TestServer(async httpContext =>
            {
                var response = httpContext.Response;
                var request = httpContext.Request;
                var lifetime = httpContext.Features.Get<IHttpRequestLifetimeFeature>();

                lifetime.RequestAborted.Register(() => registrationWh.Set());

                await request.Body.CopyToAsync(Stream.Null);
                connectionCloseWh.Wait();

                response.Headers.Clear();
                response.Headers["Content-Length"] = new[] { "5" };

                try
                {
                    // Ensure write is long enough to disable write-behind buffering
                    for (int i = 0; i < 10; i++)
                    {
                        await response.WriteAsync(new string('a', 65537));
                    }
                }
                catch (Exception ex)
                {
                    writeTcs.SetException(ex);

                    // Give a chance for RequestAborted to trip before the app completes
                    registrationWh.Wait(1000);

                    throw;
                }

                writeTcs.SetCanceled();
            }, testContext))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "POST / HTTP/1.1",
                        "Content-Length: 5",
                        "",
                        "Hello");
                    // Don't wait to receive the response. Just close the socket.
                }

                connectionCloseWh.Set();

                // Write failed
                await Assert.ThrowsAsync<IOException>(async () => await writeTcs.Task);
                // RequestAborted tripped
                Assert.True(registrationWh.Wait(200));
            }
        }
        public async Task ThrowingAfterPartialWriteKillsConnection()
        {
            bool onStartingCalled = false;

            using (var server = new TestServer(async frame =>
            {
                frame.OnStarting(_ =>
                {
                    onStartingCalled = true;
                    return Task.FromResult<object>(null);
                }, null);

                frame.ResponseHeaders.Clear();
                frame.ResponseHeaders["Content-Length"] = new[] { "11" };
                await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Hello"), 0, 5);
                throw new Exception();
            }))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");
                    await connection.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "",
                        "Hello");

                    Assert.True(onStartingCalled);
                }
            }
        }
 public async Task ConnectionClosedIfExeptionThrownAfterWrite()
 {
     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();
     }))
     {
         using (var connection = new TestConnection())
         {
             // 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.ReceiveEnd(
                 "HTTP/1.1 200 OK",
                 "Transfer-Encoding: chunked",
                 "",
                 "c",
                 "Hello World!",
                 "");
         }
     }
 }
        public async Task ThrowingInOnStartingResultsInFailedWrites()
        {
            using (var server = new TestServer(async frame =>
            {
                var onStartingException = new Exception();

                frame.OnStarting(_ =>
                {
                    throw onStartingException;
                }, null);

                frame.ResponseHeaders.Clear();
                frame.ResponseHeaders["Content-Length"] = new[] { "11" };

                var writeException = await Assert.ThrowsAsync<Exception>(async () =>
                    await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11));

                Assert.Same(onStartingException, writeException);

                // The second write should succeed since the OnStarting callback will not be called again
                await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Exception!!"), 0, 11);
            }))
            {
                using (var connection = new TestConnection())
                {
                    await connection.Send(
                        "GET / HTTP/1.1",
                        "",
                        "");
                    await connection.Receive(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 11",
                        "",
                        "Exception!!"); ;
                }
            }
        }
Beispiel #23
0
        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.SetCanceled();
                }
            }, testContext))
            {
                using (var connection = new TestConnection())
                {
                    // 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.ReceiveEnd(
                        "HTTP/1.1 200 OK",
                        "Content-Length: 5",
                        "",
                        "World");
                }
            }

            await Assert.ThrowsAsync <IOException>(async() => await readTcs.Task);

            // The cancellation token for only the last request should be triggered.
            var abortedRequestId = await registrationTcs.Task;

            Assert.Equal(2, abortedRequestId);
        }