diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvConnection.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvConnection.cs index d9b17193ee..f68d3ac024 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvConnection.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvConnection.cs @@ -88,6 +88,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal // Now, complete the input so that no more reads can happen Input.Complete(new ConnectionAbortedException()); + // Send a FIN + Log.ConnectionWriteFin(ConnectionId); + // We're done with the socket now _socket.Dispose(); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs index 54950c23f0..d00610fa53 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/LibuvOutputConsumer.cs @@ -67,18 +67,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal if (result.IsCancelled) { - // Send a FIN - _log.ConnectionWriteFin(_connectionId); - - using (var shutdownReq = new UvShutdownReq(_log)) - { - shutdownReq.Init(_thread); - var shutdownResult = await shutdownReq.ShutdownAsync(_socket); - - _log.ConnectionWroteFin(_connectionId, shutdownResult.Status); - } - - // Ensure no data is written after uv_shutdown break; } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/LibuvFunctions.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/LibuvFunctions.cs index 1d3cbccb96..84572dae53 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/LibuvFunctions.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/LibuvFunctions.cs @@ -42,7 +42,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin _uv_write = NativeMethods.uv_write; _uv_write2 = NativeMethods.uv_write2; } - _uv_shutdown = NativeMethods.uv_shutdown; _uv_err_name = NativeMethods.uv_err_name; _uv_strerror = NativeMethods.uv_strerror; _uv_loop_size = NativeMethods.uv_loop_size; @@ -312,16 +311,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin ThrowIfErrored(_uv_write2(req, handle, bufs, nbufs, sendHandle, cb)); } - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void uv_shutdown_cb(IntPtr req, int status); - protected Func _uv_shutdown; - public void shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb) - { - req.Validate(); - handle.Validate(); - ThrowIfErrored(_uv_shutdown(req, handle, cb)); - } - protected Func _uv_err_name; public string err_name(int err) { @@ -572,9 +561,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] unsafe public static extern int uv_write2(UvRequest req, UvStreamHandle handle, uv_buf_t* bufs, int nbufs, UvStreamHandle sendHandle, uv_write_cb cb); - [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] - public static extern int uv_shutdown(UvShutdownReq req, UvStreamHandle handle, uv_shutdown_cb cb); - [DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] public extern static IntPtr uv_err_name(int err); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/UvShutdownReq.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/UvShutdownReq.cs deleted file mode 100644 index 3b2f74e53c..0000000000 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv/Internal/Networking/UvShutdownReq.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking -{ - /// - /// Summary description for UvShutdownRequest - /// - public class UvShutdownReq : UvRequest - { - private readonly static LibuvFunctions.uv_shutdown_cb _uv_shutdown_cb = UvShutdownCb; - - private Action _callback; - private object _state; - private LibuvAwaitable _awaitable = new LibuvAwaitable(); - - public UvShutdownReq(ILibuvTrace logger) : base(logger) - { - } - - public override void Init(LibuvThread thread) - { - var loop = thread.Loop; - - CreateMemory( - loop.Libuv, - loop.ThreadId, - loop.Libuv.req_size(LibuvFunctions.RequestType.SHUTDOWN)); - - base.Init(thread); - } - - public LibuvAwaitable ShutdownAsync(UvStreamHandle handle) - { - Shutdown(handle, LibuvAwaitable.Callback, _awaitable); - return _awaitable; - } - - public void Shutdown(UvStreamHandle handle, Action callback, object state) - { - _callback = callback; - _state = state; - _uv.shutdown(this, handle, _uv_shutdown_cb); - } - - private static void UvShutdownCb(IntPtr ptr, int status) - { - var req = FromIntPtr(ptr); - - var callback = req._callback; - req._callback = null; - - var state = req._state; - req._state = null; - - Exception error = null; - if (status < 0) - { - req.Libuv.Check(status, out error); - } - - try - { - callback(req, status, error, state); - } - catch (Exception ex) - { - req._log.LogError(0, ex, "UvShutdownCb"); - throw; - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs index 6c2713a511..c4eb51dfdf 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/RequestTests.cs @@ -522,6 +522,32 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } } + [Fact] + public void AbortingTheConnectionSendsFIN() + { + var builder = new WebHostBuilder() + .UseKestrel() + .UseUrls("http://127.0.0.1:0") + .Configure(app => app.Run(context => + { + context.Abort(); + return Task.CompletedTask; + })); + + using (var host = builder.Build()) + { + host.Start(); + + using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort())); + socket.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n")); + int result = socket.Receive(new byte[32]); + Assert.Equal(0, result); + } + } + } + [Theory] [InlineData("http://localhost/abs/path", "/abs/path", null)] [InlineData("https://localhost/abs/path", "/abs/path", null)] // handles mismatch scheme