From 7c15646303e3e925eb72be6539e2192487d76596 Mon Sep 17 00:00:00 2001 From: John Luo Date: Sat, 5 Nov 2016 23:43:39 -0700 Subject: [PATCH 01/11] Updates for 1.0.2 --- samples/SampleApp/project.json | 2 +- src/Microsoft.AspNetCore.Server.Kestrel/project.json | 2 +- .../project.json | 6 +++--- test/Microsoft.AspNetCore.Server.KestrelTests/project.json | 2 +- .../project.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/samples/SampleApp/project.json b/samples/SampleApp/project.json index 6822d6300b..e632502b5a 100644 --- a/samples/SampleApp/project.json +++ b/samples/SampleApp/project.json @@ -3,7 +3,7 @@ "dependencies": { "Microsoft.AspNetCore.Server.Kestrel": "1.0.2", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.2", - "Microsoft.Extensions.Logging.Console": "1.0.0" + "Microsoft.Extensions.Logging.Console": "1.0.1" }, "buildOptions": { "emitEntryPoint": true diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/project.json b/src/Microsoft.AspNetCore.Server.Kestrel/project.json index 0c2bc1ebc9..42b2681d9f 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/project.json +++ b/src/Microsoft.AspNetCore.Server.Kestrel/project.json @@ -18,7 +18,7 @@ "System.Threading.Tasks.Extensions": "4.0.0", "Libuv": "1.9.0", "Microsoft.AspNetCore.Hosting": "1.0.1", - "Microsoft.Extensions.Logging.Abstractions": "1.0.0" + "Microsoft.Extensions.Logging.Abstractions": "1.0.1" }, "frameworks": { "net451": { diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json index 16bdbf98ea..00c06a068b 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json @@ -2,11 +2,11 @@ "version": "1.0.0-*", "dependencies": { "dotnet-test-xunit": "1.0.0-rc3-000000-01", - "Microsoft.AspNetCore.Http.Abstractions": "1.0.0", + "Microsoft.AspNetCore.Http.Abstractions": "1.0.1", "Microsoft.AspNetCore.Server.Kestrel": "1.0.2", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.2", - "Microsoft.AspNetCore.Testing": "1.0.0-rtm-21431", - "Microsoft.Extensions.Logging.Console": "1.0.0", + "Microsoft.AspNetCore.Testing": "1.0.1", + "Microsoft.Extensions.Logging.Console": "1.0.1", "Newtonsoft.Json": "9.0.1", "xunit": "2.1.0" }, diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json index 0509e08481..a7fa0c7321 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json @@ -4,7 +4,7 @@ "dotnet-test-xunit": "1.0.0-rc3-000000-01", "Microsoft.AspNetCore.Server.Kestrel": "1.0.2", "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.2", - "Microsoft.AspNetCore.Testing": "1.0.0-rtm-21431", + "Microsoft.AspNetCore.Testing": "1.0.1", "xunit": "2.1.0" }, "frameworks": { diff --git a/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json b/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json index 0ef1ca51fe..766acfdddd 100644 --- a/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json +++ b/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json @@ -4,7 +4,7 @@ "emitEntryPoint": true }, "dependencies": { - "Microsoft.AspNetCore.Http.Features": "1.0.0", + "Microsoft.AspNetCore.Http.Features": "1.0.1", "Microsoft.AspNetCore.Hosting": "1.0.1" }, "frameworks": { From 8b97327950a9e4bb93d050aa636601d8e94aca14 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 8 Nov 2016 09:18:35 -0800 Subject: [PATCH 02/11] Updating partner package versions --- NuGet.config | 3 ++- build.ps1 | 2 +- build.sh | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index adbb3c1710..06aa92dbda 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,7 +2,8 @@ - + + \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 6d49c4dccd..6e48462f03 100644 --- a/build.ps1 +++ b/build.ps1 @@ -33,7 +33,7 @@ cd $PSScriptRoot $repoFolder = $PSScriptRoot $env:REPO_FOLDER = $repoFolder -$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/1.0.0.zip" +$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.0.1.zip" if ($env:KOREBUILD_ZIP) { $koreBuildZip=$env:KOREBUILD_ZIP diff --git a/build.sh b/build.sh index a55d3ebc12..023d73a87e 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $repoFolder -koreBuildZip="https://github.com/aspnet/KoreBuild/archive/1.0.0.zip" +koreBuildZip="https://github.com/aspnet/KoreBuild/archive/rel/1.0.1.zip" if [ ! -z $KOREBUILD_ZIP ]; then koreBuildZip=$KOREBUILD_ZIP fi From 610c6ddd837aa98120825467f198a2567bfbeba3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 8 Nov 2016 09:29:49 -0800 Subject: [PATCH 03/11] Updating partner package versions --- samples/LargeResponseApp/project.json | 2 +- samples/SampleApp/project.json | 2 +- .../project.json | 2 +- test/Microsoft.AspNetCore.Server.KestrelTests/project.json | 2 +- .../project.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/LargeResponseApp/project.json b/samples/LargeResponseApp/project.json index c0999b69c9..47f43cb1fb 100644 --- a/samples/LargeResponseApp/project.json +++ b/samples/LargeResponseApp/project.json @@ -11,7 +11,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0", + "version": "1.0.3-*", "type": "platform" } } diff --git a/samples/SampleApp/project.json b/samples/SampleApp/project.json index e632502b5a..467673e7dc 100644 --- a/samples/SampleApp/project.json +++ b/samples/SampleApp/project.json @@ -13,7 +13,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0", + "version": "1.0.3-*", "type": "platform" }, "System.Console": "4.0.0" diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json index 00c06a068b..2176ca5d32 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0", + "version": "1.0.3-*", "type": "platform" }, "System.Net.Http": "4.1.0", diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json index a7fa0c7321..bcbf9561e3 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json @@ -11,7 +11,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0", + "version": "1.0.3-*", "type": "platform" }, "System.Diagnostics.TraceSource": "4.0.0", diff --git a/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json b/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json index 766acfdddd..22390e4adc 100644 --- a/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json +++ b/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json @@ -11,7 +11,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.0", + "version": "1.0.3-*", "type": "platform" } } From 84cf6789051ab75a6bc7bf1f6d4b6156f18668c8 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 8 Nov 2016 18:04:07 -0800 Subject: [PATCH 04/11] Update System.Net.Http --- .../project.json | 2 +- test/Microsoft.AspNetCore.Server.KestrelTests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json index 2176ca5d32..684f86df2f 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json @@ -17,7 +17,7 @@ "version": "1.0.3-*", "type": "platform" }, - "System.Net.Http": "4.1.0", + "System.Net.Http": "4.1.1-servicing-24703-01", "System.Net.Http.WinHttpHandler": "4.0.0", "System.Runtime.Serialization.Primitives": "4.1.1" }, diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json index bcbf9561e3..d69bc34891 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json @@ -17,7 +17,7 @@ "System.Diagnostics.TraceSource": "4.0.0", "System.Globalization.Extensions": "4.0.1", "System.IO": "4.1.0", - "System.Net.Http": "4.1.0", + "System.Net.Http": "4.1.1-servicing-24703-01", "System.Net.Http.WinHttpHandler": "4.0.0", "System.Net.Sockets": "4.1.0", "System.Runtime.Handles": "4.0.1", From eee9520ffdfb01f4c8a9d061e1ff41184910fb0c Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 8 Nov 2016 17:07:23 -0800 Subject: [PATCH 05/11] Ensure clients connecting to Kestrel's dispatch pipe are listeners --- .../Internal/Http/ListenerPrimary.cs | 61 ++++++++++++++++++- .../Internal/Http/ListenerSecondary.cs | 25 +++++++- .../Internal/Infrastructure/Constants.cs | 3 + .../Internal/Networking/UvWriteReq.cs | 38 +++++++++--- 4 files changed, 114 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs index a9b938d158..1bfc4c0ad0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; @@ -75,15 +76,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http try { pipe.Accept(dispatchPipe); + + // Ensure client sends "Kestrel" before adding pipe to _dispatchPipes. + var readContext = new PipeReadContext(this); + dispatchPipe.ReadStart( + (handle, status2, state) => ((PipeReadContext)state).AllocCallback(handle, status2), + (handle, status2, state) => ((PipeReadContext)state).ReadCallback(handle, status2), + readContext); } catch (UvException ex) { dispatchPipe.Dispose(); Log.LogError(0, ex, "ListenerPrimary.OnListenPipe"); - return; } - - _dispatchPipes.Add(dispatchPipe); } protected override void DispatchConnection(UvStreamHandle socket) @@ -179,5 +184,55 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http }, this).ConfigureAwait(false); } } + + private class PipeReadContext + { + private readonly ListenerPrimary _listener; + private readonly IntPtr _bufPtr; + private GCHandle _bufHandle; + private int _bytesRead; + + public PipeReadContext(ListenerPrimary listener) + { + _listener = listener; + _bufHandle = GCHandle.Alloc(new byte[8], GCHandleType.Pinned); + _bufPtr = _bufHandle.AddrOfPinnedObject(); + } + + public Libuv.uv_buf_t AllocCallback(UvStreamHandle dispatchPipe, int suggestedSize) + { + return dispatchPipe.Libuv.buf_init(_bufPtr + _bytesRead, 8 - _bytesRead); + } + + public unsafe void ReadCallback(UvStreamHandle dispatchPipe, int status) + { + try + { + dispatchPipe.Libuv.Check(status); + + _bytesRead += status; + + if (_bytesRead == 8) + { + if (*(ulong*)_bufPtr == Constants.PipeMessage) + { + _listener._dispatchPipes.Add((UvPipeHandle) dispatchPipe); + dispatchPipe.ReadStop(); + _bufHandle.Free(); + } + else + { + throw new IOException("Bad data sent over Kestrel pipe."); + } + } + } + catch (Exception ex) + { + dispatchPipe.Dispose(); + _bufHandle.Free(); + _listener.Log.LogError(0, ex, "ListenerPrimary.ReadCallback"); + } + } + } } } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs index e11729200f..bd4d384fb2 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs @@ -17,6 +17,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http /// public abstract class ListenerSecondary : ListenerContext, IAsyncDisposable { + private static ArraySegment> _pipeMessage = + new ArraySegment>(new[] { new ArraySegment(BitConverter.GetBytes(Constants.PipeMessage)) }); + private string _pipeName; private IntPtr _ptr; private Libuv.uv_buf_t _buf; @@ -89,6 +92,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http return; } + var writeReq = new UvWriteReq(Log); + try { DispatchPipe.ReadStart( @@ -96,10 +101,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http (handle, status2, state) => ((ListenerSecondary)state).ReadStartCallback(handle, status2), this); - tcs.SetResult(0); + writeReq.Init(Thread.Loop); + writeReq.Write( + DispatchPipe, + _pipeMessage, + (req, status2, ex, state) => + { + req.Dispose(); + + if (ex != null) + { + tcs.SetException(ex); + } + else + { + tcs.SetResult(0); + } + }, + tcs); } catch (Exception ex) { + writeReq.Dispose(); DispatchPipe.Dispose(); tcs.SetException(ex); } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs index 2d270d9955..47b04be220 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs @@ -26,6 +26,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure public const string ServerName = "Kestrel"; + // "Kestrel\0" + public const ulong PipeMessage = 0x006C65727473654B; + private static int? GetECONNRESET() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Networking/UvWriteReq.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Networking/UvWriteReq.cs index 4a0aec28bc..93a06519a0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Networking/UvWriteReq.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Networking/UvWriteReq.cs @@ -85,18 +85,30 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Networking _callback = null; _state = null; Unpin(this); - - var block = start.Block; - for (var index = 0; index < nBuffers; index++) - { - block = block.Next; - } - throw; } } - public unsafe void Write2( + public void Write( + UvStreamHandle handle, + ArraySegment> bufs, + Action callback, + object state) + { + WriteArraySegmentInternal(handle, bufs, sendHandle: null, callback: callback, state: state); + } + + public void Write2( + UvStreamHandle handle, + ArraySegment> bufs, + UvStreamHandle sendHandle, + Action callback, + object state) + { + WriteArraySegmentInternal(handle, bufs, sendHandle, callback, state); + } + + private unsafe void WriteArraySegmentInternal( UvStreamHandle handle, ArraySegment> bufs, UvStreamHandle sendHandle, @@ -133,7 +145,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Networking _callback = callback; _state = state; - _uv.write2(this, handle, pBuffers, nBuffers, sendHandle, _uv_write_cb); + + if (sendHandle == null) + { + _uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb); + } + else + { + _uv.write2(this, handle, pBuffers, nBuffers, sendHandle, _uv_write_cb); + } } catch { From ecc8a0088d79e087867b463e5897d8e11868b814 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 8 Nov 2016 22:29:03 -0800 Subject: [PATCH 06/11] Add ListenerPrimaryTests --- .../ListenerPrimaryTests.cs | 229 ++++++++++++++++++ .../TestHelpers/HttpClientSlim.cs | 129 ++++++++++ .../TestHelpers/TestApplicationErrorLogger.cs | 26 +- .../TestHelpers/TestKestrelTrace.cs | 9 +- 4 files changed, 380 insertions(+), 13 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs create mode 100644 test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/HttpClientSlim.cs diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs new file mode 100644 index 0000000000..471aa42b43 --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs @@ -0,0 +1,229 @@ +// 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 System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.Kestrel; +using Microsoft.AspNetCore.Server.Kestrel.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; +using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking; +using Microsoft.AspNetCore.Testing; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Microsoft.AspNetCore.Server.KestrelTests +{ + public class ListenerPrimaryTests + { + [Fact] + public async Task ConnectionsGetRoundRobinedToSecondaryListeners() + { + var libuv = new Libuv(); + + var serviceContextPrimary = new TestServiceContext + { + FrameFactory = context => + { + return new Frame(new TestApplication(c => + { + return c.Response.WriteAsync("Primary"); + }), context); + } + }; + + var serviceContextSecondary = new ServiceContext + { + Log = serviceContextPrimary.Log, + AppLifetime = serviceContextPrimary.AppLifetime, + DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager, + ServerOptions = serviceContextPrimary.ServerOptions, + ThreadPool = serviceContextPrimary.ThreadPool, + FrameFactory = context => + { + return new Frame(new TestApplication(c => + { + return c.Response.WriteAsync("Secondary"); ; + }), context); + } + }; + + using (var kestrelEngine = new KestrelEngine(libuv, serviceContextPrimary)) + { + var address = ServerAddress.FromUrl("http://127.0.0.1:0/"); + var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + + // Start primary listener + var kestrelThreadPrimary = new KestrelThread(kestrelEngine); + await kestrelThreadPrimary.StartAsync(); + var listenerPrimary = new TcpListenerPrimary(serviceContextPrimary); + await listenerPrimary.StartAsync(pipeName, address, kestrelThreadPrimary); + + // Until a secondary listener is added, TCP connections get dispatched directly + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + + // Add secondary listener + var kestrelThreadSecondary = new KestrelThread(kestrelEngine); + await kestrelThreadSecondary.StartAsync(); + var listenerSecondary = new TcpListenerSecondary(serviceContextSecondary); + await listenerSecondary.StartAsync(pipeName, address, kestrelThreadSecondary); + + // Once a secondary listener is added, TCP connections start getting dispatched to it + Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); + + // TCP connections will still get round-robined to the primary listener + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + + await listenerSecondary.DisposeAsync(); + kestrelThreadSecondary.Stop(TimeSpan.FromSeconds(1)); + + await listenerPrimary.DisposeAsync(); + kestrelThreadPrimary.Stop(TimeSpan.FromSeconds(1)); + } + } + + // https://github.com/aspnet/KestrelHttpServer/issues/1182 + [Fact] + public async Task NonListenerPipeConnectionsAreLoggedAndIgnored() + { + var libuv = new Libuv(); + + var primaryTrace = new TestKestrelTrace(); + + var serviceContextPrimary = new TestServiceContext + { + Log = primaryTrace, + FrameFactory = context => + { + return new Frame(new TestApplication(c => + { + return c.Response.WriteAsync("Primary"); + }), context); + } + }; + + var serviceContextSecondary = new ServiceContext + { + Log = new TestKestrelTrace(), + AppLifetime = serviceContextPrimary.AppLifetime, + DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager, + ServerOptions = serviceContextPrimary.ServerOptions, + ThreadPool = serviceContextPrimary.ThreadPool, + FrameFactory = context => + { + return new Frame(new TestApplication(c => + { + return c.Response.WriteAsync("Secondary"); ; + }), context); + } + }; + + using (var kestrelEngine = new KestrelEngine(libuv, serviceContextPrimary)) + { + var address = ServerAddress.FromUrl("http://127.0.0.1:0/"); + var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + + // Start primary listener + var kestrelThreadPrimary = new KestrelThread(kestrelEngine); + await kestrelThreadPrimary.StartAsync(); + var listenerPrimary = new TcpListenerPrimary(serviceContextPrimary); + await listenerPrimary.StartAsync(pipeName, address, kestrelThreadPrimary); + + // Add secondary listener + var kestrelThreadSecondary = new KestrelThread(kestrelEngine); + await kestrelThreadSecondary.StartAsync(); + var listenerSecondary = new TcpListenerSecondary(serviceContextSecondary); + await listenerSecondary.StartAsync(pipeName, address, kestrelThreadSecondary); + + // TCP Connections get round-robined + Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + + // Create a pipe connection and keep it open without sending any data + var connectTcs = new TaskCompletionSource(); + var connectionTrace = new TestKestrelTrace(); + var pipe = new UvPipeHandle(connectionTrace); + + kestrelThreadPrimary.Post(_ => + { + var connectReq = new UvConnectRequest(connectionTrace); + + pipe.Init(kestrelThreadPrimary.Loop, kestrelThreadPrimary.QueueCloseHandle); + connectReq.Init(kestrelThreadPrimary.Loop); + + connectReq.Connect( + pipe, + pipeName, + (req, status, ex, __) => + { + req.Dispose(); + + if (ex != null) + { + connectTcs.SetException(ex); + } + else + { + connectTcs.SetResult(null); + } + }, + null); + }, null); + + await connectTcs.Task; + + // TCP connections will still get round-robined between only the two listeners + Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); + + await kestrelThreadPrimary.PostAsync(_ => pipe.Dispose(), null); + + // Same for after the non-listener pipe connection is closed + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + + await listenerSecondary.DisposeAsync(); + kestrelThreadSecondary.Stop(TimeSpan.FromSeconds(1)); + + await listenerPrimary.DisposeAsync(); + kestrelThreadPrimary.Stop(TimeSpan.FromSeconds(1)); + } + + Assert.Equal(1, primaryTrace.Logger.TotalErrorsLogged); + var errorMessage = primaryTrace.Logger.Messages.First(m => m.LogLevel == LogLevel.Error); + Assert.Contains("EOF", errorMessage.Exception.ToString()); + } + + private class TestApplication : IHttpApplication + { + private readonly Func _app; + + public TestApplication(Func app) + { + _app = app; + } + + public DefaultHttpContext CreateContext(IFeatureCollection contextFeatures) + { + return new DefaultHttpContext(contextFeatures); + } + + public Task ProcessRequestAsync(DefaultHttpContext context) + { + return _app(context); + } + + public void DisposeContext(DefaultHttpContext context, Exception exception) + { + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/HttpClientSlim.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/HttpClientSlim.cs new file mode 100644 index 0000000000..02cf1880fe --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/HttpClientSlim.cs @@ -0,0 +1,129 @@ +// 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 System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Authentication; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Testing +{ + // Lightweight version of HttpClient implemented using Socket and SslStream + public static class HttpClientSlim + { + public static Task GetStringAsync(string requestUri, bool validateCertificate = true) + => GetStringAsync(new Uri(requestUri), validateCertificate); + + public static async Task GetStringAsync(Uri requestUri, bool validateCertificate = true) + { + using (var stream = await GetStream(requestUri, validateCertificate)) + { + using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) + { + await writer.WriteAsync($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n"); + await writer.WriteAsync($"Host: {requestUri.Authority}\r\n"); + await writer.WriteAsync("\r\n"); + } + + return await ReadResponse(stream); + } + } + + public static Task PostAsync(string requestUri, HttpContent content, bool validateCertificate = true) + => PostAsync(new Uri(requestUri), content, validateCertificate); + + public static async Task PostAsync(Uri requestUri, HttpContent content, bool validateCertificate = true) + { + using (var stream = await GetStream(requestUri, validateCertificate)) + { + using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true)) + { + await writer.WriteAsync($"POST {requestUri.PathAndQuery} HTTP/1.0\r\n"); + await writer.WriteAsync($"Host: {requestUri.Authority}\r\n"); + await writer.WriteAsync($"Content-Type: {content.Headers.ContentType}\r\n"); + await writer.WriteAsync($"Content-Length: {content.Headers.ContentLength}\r\n"); + await writer.WriteAsync("\r\n"); + } + + await content.CopyToAsync(stream); + + return await ReadResponse(stream); + } + } + + private static async Task ReadResponse(Stream stream) + { + using (var reader = new StreamReader(stream, Encoding.ASCII, detectEncodingFromByteOrderMarks: true, + bufferSize: 1024, leaveOpen: true)) + { + var response = await reader.ReadToEndAsync(); + + var status = GetStatus(response); + new HttpResponseMessage(status).EnsureSuccessStatusCode(); + + var body = response.Substring(response.IndexOf("\r\n\r\n") + 4); + return body; + } + + } + + private static HttpStatusCode GetStatus(string response) + { + var statusStart = response.IndexOf(' ') + 1; + var statusEnd = response.IndexOf(' ', statusStart) - 1; + var statusLength = statusEnd - statusStart + 1; + return (HttpStatusCode)int.Parse(response.Substring(statusStart, statusLength)); + } + + private static async Task GetStream(Uri requestUri, bool validateCertificate) + { + var socket = await GetSocket(requestUri); + Stream stream = new NetworkStream(socket, ownsSocket: true); + + if (requestUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase)) + { + var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, userCertificateValidationCallback: + validateCertificate ? null : (RemoteCertificateValidationCallback)((a, b, c, d) => true)); + await sslStream.AuthenticateAsClientAsync(requestUri.Host, clientCertificates: null, + enabledSslProtocols: SslProtocols.Tls11 | SslProtocols.Tls12, + checkCertificateRevocation: validateCertificate); + return sslStream; + } + else + { + return stream; + } + } + + public static async Task GetSocket(Uri requestUri) + { + var tcs = new TaskCompletionSource(); + + var socketArgs = new SocketAsyncEventArgs(); + socketArgs.RemoteEndPoint = new DnsEndPoint(requestUri.DnsSafeHost, requestUri.Port); + socketArgs.Completed += (s, e) => tcs.TrySetResult(e.ConnectSocket); + + // Must use static ConnectAsync(), since instance Connect() does not support DNS names on OSX/Linux. + if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, socketArgs)) + { + await tcs.Task; + } + + var socket = socketArgs.ConnectSocket; + + if (socket == null) + { + throw new SocketException((int)socketArgs.SocketError); + } + else + { + return socket; + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestApplicationErrorLogger.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestApplicationErrorLogger.cs index 2534de82da..4d97615b2c 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestApplicationErrorLogger.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestApplicationErrorLogger.cs @@ -2,7 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Server.Kestrel; +using System.Collections.Generic; +using System.Linq; using Microsoft.AspNetCore.Server.Kestrel.Internal; using Microsoft.Extensions.Logging; @@ -13,9 +14,13 @@ namespace Microsoft.AspNetCore.Server.KestrelTests // Application errors are logged using 13 as the eventId. private const int ApplicationErrorEventId = 13; - public int TotalErrorsLogged { get; set; } + public List Messages { get; } = new List(); - public int ApplicationErrorsLogged { get; set; } + public int TotalErrorsLogged => Messages.Count(message => message.LogLevel == LogLevel.Error); + + public int CriticalErrorsLogged => Messages.Count(message => message.LogLevel == LogLevel.Critical); + + public int ApplicationErrorsLogged => Messages.Count(message => message.EventId.Id == ApplicationErrorEventId); public IDisposable BeginScope(TState state) { @@ -33,15 +38,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Console.WriteLine($"Log {logLevel}[{eventId}]: {formatter(state, exception)} {exception?.Message}"); #endif - if (eventId.Id == ApplicationErrorEventId) - { - ApplicationErrorsLogged++; - } + Messages.Add(new LogMessage { LogLevel = logLevel, EventId = eventId, Exception = exception }); + } - if (logLevel == LogLevel.Error) - { - TotalErrorsLogged++; - } + public class LogMessage + { + public LogLevel LogLevel { get; set; } + public EventId EventId { get; set; } + public Exception Exception { get; set; } } } } diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestKestrelTrace.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestKestrelTrace.cs index 741ec54a0b..c3f0860064 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestKestrelTrace.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/TestKestrelTrace.cs @@ -1,5 +1,7 @@ +// 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 Microsoft.AspNetCore.Server.Kestrel.Internal; -using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.KestrelTests { @@ -9,10 +11,13 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { } - public TestKestrelTrace(ILogger testLogger) : base(testLogger) + public TestKestrelTrace(TestApplicationErrorLogger testLogger) : base(testLogger) { + Logger = testLogger; } + public TestApplicationErrorLogger Logger { get; private set; } + public override void ConnectionRead(string connectionId, int count) { //_logger.LogDebug(1, @"Connection id ""{ConnectionId}"" recv {count} bytes.", connectionId, count); From 847e4e2697319567533a9fe9f31a5c5895bed826 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Fri, 11 Nov 2016 14:51:37 -0800 Subject: [PATCH 07/11] Better filter clients connecting to Kestrel's dispatch pipes --- .../Internal/Http/ListenerPrimary.cs | 26 ++++-- .../Internal/Http/ListenerSecondary.cs | 8 +- .../Internal/Infrastructure/Constants.cs | 3 - .../Internal/KestrelEngine.cs | 5 +- .../ListenerPrimaryTests.cs | 85 +++++++++++++++++-- 5 files changed, 108 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs index 1bfc4c0ad0..6520a4ad08 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerPrimary.cs @@ -21,6 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http private readonly List _dispatchPipes = new List(); private int _dispatchIndex; private string _pipeName; + private byte[] _pipeMessage; private IntPtr _fileCompletionInfoPtr; private bool _tryDetachFromIOCP = PlatformApis.IsWindows; @@ -36,10 +37,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http public async Task StartAsync( string pipeName, + byte[] pipeMessage, ServerAddress address, KestrelThread thread) { _pipeName = pipeName; + _pipeMessage = pipeMessage; if (_fileCompletionInfoPtr == IntPtr.Zero) { @@ -187,7 +190,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http private class PipeReadContext { + private const int _bufferLength = 16; + private readonly ListenerPrimary _listener; + private readonly byte[] _buf = new byte[_bufferLength]; private readonly IntPtr _bufPtr; private GCHandle _bufHandle; private int _bytesRead; @@ -195,16 +201,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http public PipeReadContext(ListenerPrimary listener) { _listener = listener; - _bufHandle = GCHandle.Alloc(new byte[8], GCHandleType.Pinned); + _bufHandle = GCHandle.Alloc(_buf, GCHandleType.Pinned); _bufPtr = _bufHandle.AddrOfPinnedObject(); } public Libuv.uv_buf_t AllocCallback(UvStreamHandle dispatchPipe, int suggestedSize) { - return dispatchPipe.Libuv.buf_init(_bufPtr + _bytesRead, 8 - _bytesRead); + return dispatchPipe.Libuv.buf_init(_bufPtr + _bytesRead, _bufferLength - _bytesRead); } - public unsafe void ReadCallback(UvStreamHandle dispatchPipe, int status) + public void ReadCallback(UvStreamHandle dispatchPipe, int status) { try { @@ -212,9 +218,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http _bytesRead += status; - if (_bytesRead == 8) + if (_bytesRead == _bufferLength) { - if (*(ulong*)_bufPtr == Constants.PipeMessage) + var correctMessage = true; + + for (var i = 0; i < _bufferLength; i++) + { + if (_buf[i] != _listener._pipeMessage[i]) + { + correctMessage = false; + } + } + + if (correctMessage) { _listener._dispatchPipes.Add((UvPipeHandle) dispatchPipe); dispatchPipe.ReadStop(); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs index bd4d384fb2..497e1061bb 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/ListenerSecondary.cs @@ -17,10 +17,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http /// public abstract class ListenerSecondary : ListenerContext, IAsyncDisposable { - private static ArraySegment> _pipeMessage = - new ArraySegment>(new[] { new ArraySegment(BitConverter.GetBytes(Constants.PipeMessage)) }); - private string _pipeName; + private byte[] _pipeMessage; private IntPtr _ptr; private Libuv.uv_buf_t _buf; private bool _closed; @@ -34,10 +32,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http public Task StartAsync( string pipeName, + byte[] pipeMessage, ServerAddress address, KestrelThread thread) { _pipeName = pipeName; + _pipeMessage = pipeMessage; _buf = thread.Loop.Libuv.buf_init(_ptr, 4); ServerAddress = address; @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http writeReq.Init(Thread.Loop); writeReq.Write( DispatchPipe, - _pipeMessage, + new ArraySegment>(new [] { new ArraySegment(_pipeMessage) }), (req, status2, ex, state) => { req.Dispose(); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs index 47b04be220..2d270d9955 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/Constants.cs @@ -26,9 +26,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure public const string ServerName = "Kestrel"; - // "Kestrel\0" - public const ulong PipeMessage = 0x006C65727473654B; - private static int? GetECONNRESET() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/KestrelEngine.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/KestrelEngine.cs index a3faaad6a4..976b8c3718 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/KestrelEngine.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/KestrelEngine.cs @@ -57,6 +57,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal try { var pipeName = (Libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + var pipeMessage = Guid.NewGuid().ToByteArray(); var single = Threads.Count == 1; var first = true; @@ -78,7 +79,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal : new TcpListenerPrimary(this); listeners.Add(listener); - listener.StartAsync(pipeName, address, thread).Wait(); + listener.StartAsync(pipeName, pipeMessage, address, thread).Wait(); } else { @@ -86,7 +87,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal ? (ListenerSecondary) new PipeListenerSecondary(this) : new TcpListenerSecondary(this); listeners.Add(listener); - listener.StartAsync(pipeName, address, thread).Wait(); + listener.StartAsync(pipeName, pipeMessage, address, thread).Wait(); } first = false; diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs index 471aa42b43..51d113e335 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/ListenerPrimaryTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; @@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Internal; using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; +using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Internal.Networking; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; @@ -55,12 +57,13 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { var address = ServerAddress.FromUrl("http://127.0.0.1:0/"); var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + var pipeMessage = Guid.NewGuid().ToByteArray(); // Start primary listener var kestrelThreadPrimary = new KestrelThread(kestrelEngine); await kestrelThreadPrimary.StartAsync(); var listenerPrimary = new TcpListenerPrimary(serviceContextPrimary); - await listenerPrimary.StartAsync(pipeName, address, kestrelThreadPrimary); + await listenerPrimary.StartAsync(pipeName, pipeMessage, address, kestrelThreadPrimary); // Until a secondary listener is added, TCP connections get dispatched directly Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); @@ -70,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests var kestrelThreadSecondary = new KestrelThread(kestrelEngine); await kestrelThreadSecondary.StartAsync(); var listenerSecondary = new TcpListenerSecondary(serviceContextSecondary); - await listenerSecondary.StartAsync(pipeName, address, kestrelThreadSecondary); + await listenerSecondary.StartAsync(pipeName, pipeMessage, address, kestrelThreadSecondary); // Once a secondary listener is added, TCP connections start getting dispatched to it Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); @@ -128,18 +131,19 @@ namespace Microsoft.AspNetCore.Server.KestrelTests { var address = ServerAddress.FromUrl("http://127.0.0.1:0/"); var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + var pipeMessage = Guid.NewGuid().ToByteArray(); // Start primary listener var kestrelThreadPrimary = new KestrelThread(kestrelEngine); await kestrelThreadPrimary.StartAsync(); var listenerPrimary = new TcpListenerPrimary(serviceContextPrimary); - await listenerPrimary.StartAsync(pipeName, address, kestrelThreadPrimary); + await listenerPrimary.StartAsync(pipeName, pipeMessage, address, kestrelThreadPrimary); // Add secondary listener var kestrelThreadSecondary = new KestrelThread(kestrelEngine); await kestrelThreadSecondary.StartAsync(); var listenerSecondary = new TcpListenerSecondary(serviceContextSecondary); - await listenerSecondary.StartAsync(pipeName, address, kestrelThreadSecondary); + await listenerSecondary.StartAsync(pipeName, pipeMessage, address, kestrelThreadSecondary); // TCP Connections get round-robined Assert.Equal("Secondary", await HttpClientSlim.GetStringAsync(address.ToString())); @@ -199,7 +203,78 @@ namespace Microsoft.AspNetCore.Server.KestrelTests Assert.Equal(1, primaryTrace.Logger.TotalErrorsLogged); var errorMessage = primaryTrace.Logger.Messages.First(m => m.LogLevel == LogLevel.Error); - Assert.Contains("EOF", errorMessage.Exception.ToString()); + Assert.Equal(Constants.EOF, Assert.IsType(errorMessage.Exception).StatusCode); + } + + [Fact] + public async Task PipeConnectionsWithWrongMessageAreLoggedAndIgnored() + { + var libuv = new Libuv(); + + var primaryTrace = new TestKestrelTrace(); + + var serviceContextPrimary = new TestServiceContext + { + Log = primaryTrace, + FrameFactory = context => + { + return new Frame(new TestApplication(c => + { + return c.Response.WriteAsync("Primary"); + }), context); + } + }; + + var serviceContextSecondary = new ServiceContext + { + Log = new TestKestrelTrace(), + AppLifetime = serviceContextPrimary.AppLifetime, + DateHeaderValueManager = serviceContextPrimary.DateHeaderValueManager, + ServerOptions = serviceContextPrimary.ServerOptions, + ThreadPool = serviceContextPrimary.ThreadPool, + FrameFactory = context => + { + return new Frame(new TestApplication(c => + { + return c.Response.WriteAsync("Secondary"); ; + }), context); + } + }; + + using (var kestrelEngine = new KestrelEngine(libuv, serviceContextPrimary)) + { + var address = ServerAddress.FromUrl("http://127.0.0.1:0/"); + var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n"); + var pipeMessage = Guid.NewGuid().ToByteArray(); + + // Start primary listener + var kestrelThreadPrimary = new KestrelThread(kestrelEngine); + await kestrelThreadPrimary.StartAsync(); + var listenerPrimary = new TcpListenerPrimary(serviceContextPrimary); + await listenerPrimary.StartAsync(pipeName, pipeMessage, address, kestrelThreadPrimary); + + // Add secondary listener with wrong pipe message + var kestrelThreadSecondary = new KestrelThread(kestrelEngine); + await kestrelThreadSecondary.StartAsync(); + var listenerSecondary = new TcpListenerSecondary(serviceContextSecondary); + await listenerSecondary.StartAsync(pipeName, Guid.NewGuid().ToByteArray(), address, kestrelThreadSecondary); + + // TCP Connections get round-robined + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + Assert.Equal("Primary", await HttpClientSlim.GetStringAsync(address.ToString())); + + await listenerSecondary.DisposeAsync(); + kestrelThreadSecondary.Stop(TimeSpan.FromSeconds(1)); + + await listenerPrimary.DisposeAsync(); + kestrelThreadPrimary.Stop(TimeSpan.FromSeconds(1)); + } + + Assert.Equal(1, primaryTrace.Logger.TotalErrorsLogged); + var errorMessage = primaryTrace.Logger.Messages.First(m => m.LogLevel == LogLevel.Error); + Assert.IsType(errorMessage.Exception); + Assert.Contains("Bad data", errorMessage.Exception.ToString()); } private class TestApplication : IHttpApplication From d8c0f4e2bc6f5b00184dd14e8fbc1d8e10e0c3a3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 15 Nov 2016 13:31:45 -0800 Subject: [PATCH 08/11] Pin System.Net.Http to final build --- .../project.json | 2 +- test/Microsoft.AspNetCore.Server.KestrelTests/project.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json index 684f86df2f..db594f6152 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json @@ -17,7 +17,7 @@ "version": "1.0.3-*", "type": "platform" }, - "System.Net.Http": "4.1.1-servicing-24703-01", + "System.Net.Http": "4.1.1", "System.Net.Http.WinHttpHandler": "4.0.0", "System.Runtime.Serialization.Primitives": "4.1.1" }, diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json index d69bc34891..a916a2da57 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json @@ -17,7 +17,7 @@ "System.Diagnostics.TraceSource": "4.0.0", "System.Globalization.Extensions": "4.0.1", "System.IO": "4.1.0", - "System.Net.Http": "4.1.1-servicing-24703-01", + "System.Net.Http": "4.1.1", "System.Net.Http.WinHttpHandler": "4.0.0", "System.Net.Sockets": "4.1.0", "System.Runtime.Handles": "4.0.1", From 48d957ae854678db25cb381bfc6c6832b0ec3b5f Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 17 Nov 2016 10:57:41 -0800 Subject: [PATCH 09/11] Updating to Microsoft.NETCore.App 1.0.3 --- samples/LargeResponseApp/project.json | 2 +- samples/SampleApp/project.json | 2 +- .../project.json | 2 +- test/Microsoft.AspNetCore.Server.KestrelTests/project.json | 2 +- .../project.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/LargeResponseApp/project.json b/samples/LargeResponseApp/project.json index 47f43cb1fb..7482ebee80 100644 --- a/samples/LargeResponseApp/project.json +++ b/samples/LargeResponseApp/project.json @@ -11,7 +11,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.3-*", + "version": "1.0.3", "type": "platform" } } diff --git a/samples/SampleApp/project.json b/samples/SampleApp/project.json index 467673e7dc..0d323ffb28 100644 --- a/samples/SampleApp/project.json +++ b/samples/SampleApp/project.json @@ -13,7 +13,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.3-*", + "version": "1.0.3", "type": "platform" }, "System.Console": "4.0.0" diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json index db594f6152..522b45177a 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json @@ -14,7 +14,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.3-*", + "version": "1.0.3", "type": "platform" }, "System.Net.Http": "4.1.1", diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json index a916a2da57..be73eba5d2 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json @@ -11,7 +11,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.3-*", + "version": "1.0.3", "type": "platform" }, "System.Diagnostics.TraceSource": "4.0.0", diff --git a/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json b/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json index 22390e4adc..e28200677a 100644 --- a/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json +++ b/tools/Microsoft.AspNetCore.Server.Kestrel.GeneratedCode/project.json @@ -11,7 +11,7 @@ "netcoreapp1.0": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.3-*", + "version": "1.0.3", "type": "platform" } } From 4ac842b050c249ff3e15f7516160d8c248cef455 Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Tue, 24 Jan 2017 14:57:51 -0800 Subject: [PATCH 10/11] Update to version 1.0.3. --- samples/LargeResponseApp/project.json | 2 +- samples/SampleApp/project.json | 4 ++-- src/Microsoft.AspNetCore.Server.Kestrel.Https/project.json | 4 ++-- src/Microsoft.AspNetCore.Server.Kestrel/project.json | 2 +- .../project.json | 4 ++-- test/Microsoft.AspNetCore.Server.KestrelTests/project.json | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/samples/LargeResponseApp/project.json b/samples/LargeResponseApp/project.json index 7482ebee80..901c01d703 100644 --- a/samples/LargeResponseApp/project.json +++ b/samples/LargeResponseApp/project.json @@ -1,7 +1,7 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.Kestrel": "1.0.2" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.3" }, "buildOptions": { "emitEntryPoint": true diff --git a/samples/SampleApp/project.json b/samples/SampleApp/project.json index 0d323ffb28..eb27dc59bd 100644 --- a/samples/SampleApp/project.json +++ b/samples/SampleApp/project.json @@ -1,8 +1,8 @@ { "version": "1.0.0-*", "dependencies": { - "Microsoft.AspNetCore.Server.Kestrel": "1.0.2", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.2", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.3", + "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.3", "Microsoft.Extensions.Logging.Console": "1.0.1" }, "buildOptions": { diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Https/project.json b/src/Microsoft.AspNetCore.Server.Kestrel.Https/project.json index dcb023542c..3ccb6c39af 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Https/project.json +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Https/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.2", + "version": "1.0.3", "description": "HTTPS support for the ASP.NET Core Kestrel cross-platform web server.", "buildOptions": { "keyFile": "../../tools/Key.snk", @@ -19,7 +19,7 @@ ] }, "dependencies": { - "Microsoft.AspNetCore.Server.Kestrel": "1.0.2" + "Microsoft.AspNetCore.Server.Kestrel": "1.0.3" }, "frameworks": { "net451": {}, diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/project.json b/src/Microsoft.AspNetCore.Server.Kestrel/project.json index 42b2681d9f..5a227b47e5 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/project.json +++ b/src/Microsoft.AspNetCore.Server.Kestrel/project.json @@ -1,5 +1,5 @@ { - "version": "1.0.2", + "version": "1.0.3", "description": "ASP.NET Core Kestrel cross-platform web server.", "packOptions": { "repository": { diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json index 522b45177a..47f90621ad 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/project.json @@ -3,8 +3,8 @@ "dependencies": { "dotnet-test-xunit": "1.0.0-rc3-000000-01", "Microsoft.AspNetCore.Http.Abstractions": "1.0.1", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.2", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.2", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.3", + "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.3", "Microsoft.AspNetCore.Testing": "1.0.1", "Microsoft.Extensions.Logging.Console": "1.0.1", "Newtonsoft.Json": "9.0.1", diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json index be73eba5d2..9f23e30f5a 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/project.json +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/project.json @@ -2,8 +2,8 @@ "version": "1.0.0-*", "dependencies": { "dotnet-test-xunit": "1.0.0-rc3-000000-01", - "Microsoft.AspNetCore.Server.Kestrel": "1.0.2", - "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.2", + "Microsoft.AspNetCore.Server.Kestrel": "1.0.3", + "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.3", "Microsoft.AspNetCore.Testing": "1.0.1", "xunit": "2.1.0" }, From b9de869a2d504f8a5fd2b7698bbafbfbbdca391d Mon Sep 17 00:00:00 2001 From: Cesar Blum Silveira Date: Tue, 24 Jan 2017 17:10:53 -0800 Subject: [PATCH 11/11] Add SDK version to global.json. --- global.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/global.json b/global.json index 983ba0401e..fa49c8b23f 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,6 @@ { - "projects": ["src"] + "projects": ["src"], + "sdk": { + "version": "1.0.0-preview2-003131" + } }