From 0f622ec53d3c8b8236fc3a6717b386aebf15eed9 Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Thu, 22 Mar 2018 11:48:43 -0700 Subject: [PATCH 1/8] ANCM stress app --- .../ANCMStressTestSample.csproj | 19 ++ samples/ANCMStressTestSample/Program.cs | 43 ++++ .../Properties/launchSettings.json | 27 +++ samples/ANCMStressTestSample/Startup.cs | 213 ++++++++++++++++++ .../WebSockets/Constants.cs | 21 ++ .../WebSockets/HandshakeHelpers.cs | 42 ++++ 6 files changed, 365 insertions(+) create mode 100644 samples/ANCMStressTestSample/ANCMStressTestSample.csproj create mode 100644 samples/ANCMStressTestSample/Program.cs create mode 100644 samples/ANCMStressTestSample/Properties/launchSettings.json create mode 100644 samples/ANCMStressTestSample/Startup.cs create mode 100644 samples/ANCMStressTestSample/WebSockets/Constants.cs create mode 100644 samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs diff --git a/samples/ANCMStressTestSample/ANCMStressTestSample.csproj b/samples/ANCMStressTestSample/ANCMStressTestSample.csproj new file mode 100644 index 0000000000..b1a0c4ec0a --- /dev/null +++ b/samples/ANCMStressTestSample/ANCMStressTestSample.csproj @@ -0,0 +1,19 @@ + + + + ANCMStressTestApp + netcoreapp2.1 + win-x86;win-x64 + + + + + + + + + + + + + diff --git a/samples/ANCMStressTestSample/Program.cs b/samples/ANCMStressTestSample/Program.cs new file mode 100644 index 0000000000..1591952577 --- /dev/null +++ b/samples/ANCMStressTestSample/Program.cs @@ -0,0 +1,43 @@ +// 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 Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Server.IISIntegration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace ANCMStressTestApp +{ + public class Program + { + public static IApplicationLifetime AppLifetime; + public static bool AppLifetimeStopping = false; + + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .ConfigureLogging((_, factory) => + { + factory.AddConsole(); + }) + .UseKestrel() + .UseStartup() + .Build(); + + AppLifetime = (IApplicationLifetime)host.Services.GetService(typeof(IApplicationLifetime)); + AppLifetime.ApplicationStopping.Register( + () => { + AppLifetimeStopping = true; + } + ); + + host.Run(); + } + } +} diff --git a/samples/ANCMStressTestSample/Properties/launchSettings.json b/samples/ANCMStressTestSample/Properties/launchSettings.json new file mode 100644 index 0000000000..8e9b6cfcf7 --- /dev/null +++ b/samples/ANCMStressTestSample/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:16606/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ANCMStressTestSample": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:16607/" + } + } +} \ No newline at end of file diff --git a/samples/ANCMStressTestSample/Startup.cs b/samples/ANCMStressTestSample/Startup.cs new file mode 100644 index 0000000000..cfabe95866 --- /dev/null +++ b/samples/ANCMStressTestSample/Startup.cs @@ -0,0 +1,213 @@ +// 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.Linq; +using System.Threading.Tasks; +using System.Threading; +using System.Text; +using System.Net.WebSockets; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Net.Http.Headers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Primitives; + +namespace ANCMStressTestApp +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + } + + public void Configure(IApplicationBuilder app) + { + app.Map("/HelloWorld", HelloWorld); + app.Map("/ConnectionClose", ConnectionClose); + app.Map("/EchoPostData", EchoPostData); + app.Map("/LargeResponseBody", LargeResponseBody); + app.Map("/ResponseHeaders", ResponseHeaders); + app.Map("/EnvironmentVariables", EnvironmentVariables); + app.Map("/RequestInformation", RequestInformation); + app.Map("/WebSocket", WebSocket); + + app.Run(async context => + { + await context.Response.WriteAsync("Default Page"); + }); + } + + private void HelloWorld(IApplicationBuilder app) + { + app.Run(async context => + { + await context.Response.WriteAsync("Hello World"); + }); + } + + private void ConnectionClose(IApplicationBuilder app) + { + app.Run(async context => + { + context.Response.Headers[HeaderNames.Connection] = "close"; + await context.Response.WriteAsync("Connnection Close"); + await context.Response.Body.FlushAsync(); + }); + } + + private void EchoPostData(IApplicationBuilder app) + { + app.Run(async context => + { + string responseBody = string.Empty; + + if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase)) + { + using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8)) + { + responseBody = await reader.ReadToEndAsync(); + } + } + else + { + responseBody = "NoAction"; + } + + await context.Response.WriteAsync(responseBody); + }); + } + + private void LargeResponseBody(IApplicationBuilder app) + { + app.Run(async context => + { + if (int.TryParse(context.Request.Query["length"], out var length)) + { + await context.Response.WriteAsync(new string('a', length)); + } + }); + } + + private void ResponseHeaders(IApplicationBuilder app) + { + app.Run(async context => + { + context.Response.Headers["UnknownHeader"] = "test123=foo"; + context.Response.ContentType = "text/plain"; + context.Response.Headers["MultiHeader"] = new StringValues(new string[] { "1", "2" }); + await context.Response.WriteAsync("Request Complete"); + }); + } + + private void EnvironmentVariables(IApplicationBuilder app) + { + app.Run(async context => + { + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Environment Variables:" + Environment.NewLine); + var vars = Environment.GetEnvironmentVariables(); + foreach (var key in vars.Keys.Cast().OrderBy(key => key, StringComparer.OrdinalIgnoreCase)) + { + var value = vars[key]; + await context.Response.WriteAsync(key + ": " + value + Environment.NewLine); + } + await context.Response.WriteAsync(Environment.NewLine); + }); + } + + private void RequestInformation(IApplicationBuilder app) + { + app.Run(async context => + { + context.Response.ContentType = "text/plain"; + + await context.Response.WriteAsync("Address:" + Environment.NewLine); + await context.Response.WriteAsync("Scheme: " + context.Request.Scheme + Environment.NewLine); + await context.Response.WriteAsync("Host: " + context.Request.Headers["Host"] + Environment.NewLine); + await context.Response.WriteAsync("PathBase: " + context.Request.PathBase.Value + Environment.NewLine); + await context.Response.WriteAsync("Path: " + context.Request.Path.Value + Environment.NewLine); + await context.Response.WriteAsync("Query: " + context.Request.QueryString.Value + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Connection:" + Environment.NewLine); + await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + Environment.NewLine); + await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + Environment.NewLine); + await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + Environment.NewLine); + await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + Environment.NewLine); + await context.Response.WriteAsync(Environment.NewLine); + + await context.Response.WriteAsync("Headers:" + Environment.NewLine); + foreach (var header in context.Request.Headers) + { + await context.Response.WriteAsync(header.Key + ": " + header.Value + Environment.NewLine); + } + await context.Response.WriteAsync(Environment.NewLine); + }); + } + + private void WebSocket(IApplicationBuilder app) + { + app.Run(async context => + { + var upgradeFeature = context.Features.Get(); + + // Generate WebSocket response headers + string key = string.Join(", ", context.Request.Headers[Constants.Headers.SecWebSocketKey]); + var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key); + foreach (var headerPair in responseHeaders) + { + context.Response.Headers[headerPair.Key] = headerPair.Value; + } + + // Upgrade the connection + Stream opaqueTransport = await upgradeFeature.UpgradeAsync(); + + // Get the WebSocket object + var ws = WebSocketProtocol.CreateFromStream(opaqueTransport, isServer: true, subProtocol: null, keepAliveInterval: TimeSpan.FromMinutes(2)); + + await Echo(ws); + }); + } + + private async Task Echo(WebSocket webSocket) + { + var buffer = new byte[1024 * 4]; + var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + bool closeFromServer = false; + string closeFromServerCmd = "CloseFromServer"; + int closeFromServerLength = closeFromServerCmd.Length; + + while (!result.CloseStatus.HasValue) + { + if ((result.Count == closeFromServerLength && System.Text.Encoding.ASCII.GetString(buffer).Substring(0, result.Count) == closeFromServerCmd) + || Program.AppLifetimeStopping == true) + { + // start closing handshake from backend process when client send "CloseFromServer" text message + // or when any message is sent from client during the graceful shutdown. + closeFromServer = true; + await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, closeFromServerCmd, CancellationToken.None); + } + else + { + await webSocket.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + } + + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + } + + if (!closeFromServer) + { + await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + + } + + webSocket.Dispose(); + } + } +} diff --git a/samples/ANCMStressTestSample/WebSockets/Constants.cs b/samples/ANCMStressTestSample/WebSockets/Constants.cs new file mode 100644 index 0000000000..43b1822ca9 --- /dev/null +++ b/samples/ANCMStressTestSample/WebSockets/Constants.cs @@ -0,0 +1,21 @@ +// 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. + +namespace ANCMStressTestApp +{ + public static class Constants + { + public static class Headers + { + public const string Upgrade = "Upgrade"; + public const string UpgradeWebSocket = "websocket"; + public const string Connection = "Connection"; + public const string ConnectionUpgrade = "Upgrade"; + public const string SecWebSocketKey = "Sec-WebSocket-Key"; + public const string SecWebSocketVersion = "Sec-WebSocket-Version"; + public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; + public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; + public const string SupportedVersion = "13"; + } + } +} diff --git a/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs b/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs new file mode 100644 index 0000000000..a9d5b61b03 --- /dev/null +++ b/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs @@ -0,0 +1,42 @@ +// 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.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace ANCMStressTestApp +{ + // Removed all the + internal static class HandshakeHelpers + { + public static IEnumerable> GenerateResponseHeaders(string key) + { + yield return new KeyValuePair(Constants.Headers.Connection, Constants.Headers.ConnectionUpgrade); + yield return new KeyValuePair(Constants.Headers.Upgrade, Constants.Headers.UpgradeWebSocket); + yield return new KeyValuePair(Constants.Headers.SecWebSocketAccept, CreateResponseKey(key)); + } + + public static string CreateResponseKey(string requestKey) + { + // "The value of this header field is constructed by concatenating /key/, defined above in step 4 + // in Section 4.2.2, with the string "258EAFA5- E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of + // this concatenated value to obtain a 20-byte value and base64-encoding" + // https://tools.ietf.org/html/rfc6455#section-4.2.2 + + if (requestKey == null) + { + throw new ArgumentNullException(nameof(requestKey)); + } + + using (var algorithm = SHA1.Create()) + { + string merged = requestKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + byte[] mergedBytes = Encoding.UTF8.GetBytes(merged); + byte[] hashedBytes = algorithm.ComputeHash(mergedBytes); + return Convert.ToBase64String(hashedBytes); + } + } + } +} From 631c2cdd3ecd6a6e12c26c1c8dd3bdc2a305982d Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Thu, 22 Mar 2018 11:51:53 -0700 Subject: [PATCH 2/8] add SystemNetWebSocketsWebSocketProtocolPackageVersion --- build/dependencies.props | 1 + 1 file changed, 1 insertion(+) diff --git a/build/dependencies.props b/build/dependencies.props index d2cb0c14a9..c315af87ae 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -37,6 +37,7 @@ 4.5.0-preview2-26313-01 6.1.7601.17515 4.5.0-preview2-26313-01 + 4.5.0-preview2-26313-01 4.5.0-preview2-26313-01 4.5.0-preview2-26313-01 4.5.0-preview2-26313-01 From c181d1db9621aa0e24666dee29d931f8061b7010 Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Fri, 23 Mar 2018 17:07:16 -0700 Subject: [PATCH 3/8] Graceful close handshake --- samples/ANCMStressTestSample/Program.cs | 6 +- samples/ANCMStressTestSample/Startup.cs | 66 ++++++++++++------- .../WebSockets/Constants.cs | 3 - 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/samples/ANCMStressTestSample/Program.cs b/samples/ANCMStressTestSample/Program.cs index 1591952577..d3b60867b0 100644 --- a/samples/ANCMStressTestSample/Program.cs +++ b/samples/ANCMStressTestSample/Program.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Threading; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -17,7 +18,7 @@ namespace ANCMStressTestApp public class Program { public static IApplicationLifetime AppLifetime; - public static bool AppLifetimeStopping = false; + public static CancellationTokenSource Cts = new CancellationTokenSource(); public static void Main(string[] args) { @@ -33,7 +34,8 @@ namespace ANCMStressTestApp AppLifetime = (IApplicationLifetime)host.Services.GetService(typeof(IApplicationLifetime)); AppLifetime.ApplicationStopping.Register( () => { - AppLifetimeStopping = true; + Cts.Cancel(); + Cts.Dispose(); } ); diff --git a/samples/ANCMStressTestSample/Startup.cs b/samples/ANCMStressTestSample/Startup.cs index cfabe95866..0dd43be50a 100644 --- a/samples/ANCMStressTestSample/Startup.cs +++ b/samples/ANCMStressTestSample/Startup.cs @@ -158,7 +158,7 @@ namespace ANCMStressTestApp var upgradeFeature = context.Features.Get(); // Generate WebSocket response headers - string key = string.Join(", ", context.Request.Headers[Constants.Headers.SecWebSocketKey]); + string key = context.Request.Headers[Constants.Headers.SecWebSocketKey].ToString(); var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key); foreach (var headerPair in responseHeaders) { @@ -171,43 +171,59 @@ namespace ANCMStressTestApp // Get the WebSocket object var ws = WebSocketProtocol.CreateFromStream(opaqueTransport, isServer: true, subProtocol: null, keepAliveInterval: TimeSpan.FromMinutes(2)); - await Echo(ws); + await Echo(ws, Program.Cts.Token); }); } - private async Task Echo(WebSocket webSocket) + private async Task Echo(WebSocket webSocket, CancellationToken token) { - var buffer = new byte[1024 * 4]; - var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); - bool closeFromServer = false; - string closeFromServerCmd = "CloseFromServer"; - int closeFromServerLength = closeFromServerCmd.Length; - - while (!result.CloseStatus.HasValue) + try { - if ((result.Count == closeFromServerLength && System.Text.Encoding.ASCII.GetString(buffer).Substring(0, result.Count) == closeFromServerCmd) - || Program.AppLifetimeStopping == true) + var buffer = new byte[1024 * 4]; + var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), token); + bool closeFromServer = false; + string closeFromServerCmd = "CloseFromServer"; + int closeFromServerLength = closeFromServerCmd.Length; + + while (!result.CloseStatus.HasValue && !token.IsCancellationRequested && !closeFromServer) { - // start closing handshake from backend process when client send "CloseFromServer" text message - // or when any message is sent from client during the graceful shutdown. - closeFromServer = true; - await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, closeFromServerCmd, CancellationToken.None); + if (result.Count == closeFromServerLength && + System.Text.Encoding.ASCII.GetString(buffer).Substring(0, result.Count) == closeFromServerCmd) + { + // The client sent "CloseFromServer" text message to request the server to close (a test scenario). + closeFromServer = true; + } + else + { + await webSocket.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, token); + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), token); + } + } + + if (result.CloseStatus.HasValue) + { + // Client-initiated close handshake + await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); } else { - await webSocket.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None); + // Server-initiated close handshake due to either of the two conditions: + // (1) The applicaton host is performing a graceful shutdown. + // (2) The client sent "CloseFromServer" text message to request the server to close (a test scenario). + await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, closeFromServerCmd, CancellationToken.None); + + // The server has sent the Close frame. + // Stop sending but keep receiving until we get the Close frame from the client. + while (!result.CloseStatus.HasValue) + { + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + } } - - result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); } - - if (!closeFromServer) + catch (Exception e) { - await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); - + Console.WriteLine("{0} Exception caught!", e); } - - webSocket.Dispose(); } } } diff --git a/samples/ANCMStressTestSample/WebSockets/Constants.cs b/samples/ANCMStressTestSample/WebSockets/Constants.cs index 43b1822ca9..e002def8f1 100644 --- a/samples/ANCMStressTestSample/WebSockets/Constants.cs +++ b/samples/ANCMStressTestSample/WebSockets/Constants.cs @@ -12,10 +12,7 @@ namespace ANCMStressTestApp public const string Connection = "Connection"; public const string ConnectionUpgrade = "Upgrade"; public const string SecWebSocketKey = "Sec-WebSocket-Key"; - public const string SecWebSocketVersion = "Sec-WebSocket-Version"; - public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol"; public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; - public const string SupportedVersion = "13"; } } } From f1c8dc408f69709cf5817bd6f691f251be1d05e6 Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Fri, 23 Mar 2018 17:21:53 -0700 Subject: [PATCH 4/8] updated the solution --- IISIntegration.sln | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/IISIntegration.sln b/IISIntegration.sln index 636f15279e..4d953f657a 100644 --- a/IISIntegration.sln +++ b/IISIntegration.sln @@ -72,6 +72,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCoreModuleTests", "test\AspNetCoreModuleTests\AspNetCoreModuleTests.vcxproj", "{0692D963-DB10-4387-B3EA-460FBB9BD9A3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ANCMStressTestSample", "samples\ANCMStressTestSample\ANCMStressTestSample.csproj", "{ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -228,6 +230,18 @@ Global {0692D963-DB10-4387-B3EA-460FBB9BD9A3}.Release|x64.Build.0 = Release|x64 {0692D963-DB10-4387-B3EA-460FBB9BD9A3}.Release|x86.ActiveCfg = Release|Win32 {0692D963-DB10-4387-B3EA-460FBB9BD9A3}.Release|x86.Build.0 = Release|Win32 + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x64.ActiveCfg = Debug|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x64.Build.0 = Debug|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x86.ActiveCfg = Debug|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x86.Build.0 = Debug|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|Any CPU.Build.0 = Release|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x64.ActiveCfg = Release|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x64.Build.0 = Release|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x86.ActiveCfg = Release|Any CPU + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -246,6 +260,7 @@ Global {D57EA297-6DC2-4BC0-8C91-334863327863} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} {46A8612B-418B-4D70-B3A7-A21DD0627473} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} {0692D963-DB10-4387-B3EA-460FBB9BD9A3} = {EF30B533-D715-421A-92B7-92FEF460AC9C} + {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5} From 9ee0242717092348597272cefa3a6e0aa11c8951 Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Sat, 24 Mar 2018 00:09:16 -0700 Subject: [PATCH 5/8] remove Constants.Headers.ConnectionUpgrade --- samples/ANCMStressTestSample/WebSockets/Constants.cs | 1 - samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/samples/ANCMStressTestSample/WebSockets/Constants.cs b/samples/ANCMStressTestSample/WebSockets/Constants.cs index e002def8f1..bcf5462558 100644 --- a/samples/ANCMStressTestSample/WebSockets/Constants.cs +++ b/samples/ANCMStressTestSample/WebSockets/Constants.cs @@ -10,7 +10,6 @@ namespace ANCMStressTestApp public const string Upgrade = "Upgrade"; public const string UpgradeWebSocket = "websocket"; public const string Connection = "Connection"; - public const string ConnectionUpgrade = "Upgrade"; public const string SecWebSocketKey = "Sec-WebSocket-Key"; public const string SecWebSocketAccept = "Sec-WebSocket-Accept"; } diff --git a/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs b/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs index a9d5b61b03..331f415013 100644 --- a/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs +++ b/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs @@ -13,7 +13,7 @@ namespace ANCMStressTestApp { public static IEnumerable> GenerateResponseHeaders(string key) { - yield return new KeyValuePair(Constants.Headers.Connection, Constants.Headers.ConnectionUpgrade); + yield return new KeyValuePair(Constants.Headers.Connection, Constants.Headers.Upgrade); yield return new KeyValuePair(Constants.Headers.Upgrade, Constants.Headers.UpgradeWebSocket); yield return new KeyValuePair(Constants.Headers.SecWebSocketAccept, CreateResponseKey(key)); } From f2923830907f8a6d6f66f68e3894fe9e1d79f6e1 Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Sun, 25 Mar 2018 22:34:40 -0700 Subject: [PATCH 6/8] use iisintegration --- samples/ANCMStressTestSample/Program.cs | 1 + samples/ANCMStressTestSample/Startup.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/ANCMStressTestSample/Program.cs b/samples/ANCMStressTestSample/Program.cs index d3b60867b0..7bfe0bae9f 100644 --- a/samples/ANCMStressTestSample/Program.cs +++ b/samples/ANCMStressTestSample/Program.cs @@ -28,6 +28,7 @@ namespace ANCMStressTestApp factory.AddConsole(); }) .UseKestrel() + .UseIISIntegration() .UseStartup() .Build(); diff --git a/samples/ANCMStressTestSample/Startup.cs b/samples/ANCMStressTestSample/Startup.cs index 0dd43be50a..a374c65b40 100644 --- a/samples/ANCMStressTestSample/Startup.cs +++ b/samples/ANCMStressTestSample/Startup.cs @@ -188,7 +188,7 @@ namespace ANCMStressTestApp while (!result.CloseStatus.HasValue && !token.IsCancellationRequested && !closeFromServer) { if (result.Count == closeFromServerLength && - System.Text.Encoding.ASCII.GetString(buffer).Substring(0, result.Count) == closeFromServerCmd) + Encoding.ASCII.GetString(buffer).Substring(0, result.Count) == closeFromServerCmd) { // The client sent "CloseFromServer" text message to request the server to close (a test scenario). closeFromServer = true; From 07167895230da91a5ae67be65b1201ec8f83bb99 Mon Sep 17 00:00:00 2001 From: Yanbing Shi Date: Sun, 25 Mar 2018 22:42:37 -0700 Subject: [PATCH 7/8] move to test folder --- IISIntegration.sln | 28 +++++++++---------- .../ANCMStressTestApp.csproj | 1 - .../ANCMStressTestApp}/Program.cs | 0 .../Properties/launchSettings.json | 0 .../ANCMStressTestApp}/Startup.cs | 0 .../WebSockets/Constants.cs | 0 .../WebSockets/HandshakeHelpers.cs | 0 7 files changed, 14 insertions(+), 15 deletions(-) rename samples/ANCMStressTestSample/ANCMStressTestSample.csproj => test/ANCMStressTestApp/ANCMStressTestApp.csproj (94%) rename {samples/ANCMStressTestSample => test/ANCMStressTestApp}/Program.cs (100%) rename {samples/ANCMStressTestSample => test/ANCMStressTestApp}/Properties/launchSettings.json (100%) rename {samples/ANCMStressTestSample => test/ANCMStressTestApp}/Startup.cs (100%) rename {samples/ANCMStressTestSample => test/ANCMStressTestApp}/WebSockets/Constants.cs (100%) rename {samples/ANCMStressTestSample => test/ANCMStressTestApp}/WebSockets/HandshakeHelpers.cs (100%) diff --git a/IISIntegration.sln b/IISIntegration.sln index 4d953f657a..4086f09be5 100644 --- a/IISIntegration.sln +++ b/IISIntegration.sln @@ -72,7 +72,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AspNetCoreModuleTests", "test\AspNetCoreModuleTests\AspNetCoreModuleTests.vcxproj", "{0692D963-DB10-4387-B3EA-460FBB9BD9A3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ANCMStressTestSample", "samples\ANCMStressTestSample\ANCMStressTestSample.csproj", "{ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ANCMStressTestApp", "test\ANCMStressTestApp\ANCMStressTestApp.csproj", "{13FD8F12-FFBE-4D01-B4AC-444F2994B04F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -230,18 +230,18 @@ Global {0692D963-DB10-4387-B3EA-460FBB9BD9A3}.Release|x64.Build.0 = Release|x64 {0692D963-DB10-4387-B3EA-460FBB9BD9A3}.Release|x86.ActiveCfg = Release|Win32 {0692D963-DB10-4387-B3EA-460FBB9BD9A3}.Release|x86.Build.0 = Release|Win32 - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x64.ActiveCfg = Debug|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x64.Build.0 = Debug|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x86.ActiveCfg = Debug|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Debug|x86.Build.0 = Debug|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|Any CPU.Build.0 = Release|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x64.ActiveCfg = Release|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x64.Build.0 = Release|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x86.ActiveCfg = Release|Any CPU - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C}.Release|x86.Build.0 = Release|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x64.ActiveCfg = Debug|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x64.Build.0 = Debug|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x86.ActiveCfg = Debug|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Debug|x86.Build.0 = Debug|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|Any CPU.Build.0 = Release|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x64.ActiveCfg = Release|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x64.Build.0 = Release|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x86.ActiveCfg = Release|Any CPU + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -260,7 +260,7 @@ Global {D57EA297-6DC2-4BC0-8C91-334863327863} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} {46A8612B-418B-4D70-B3A7-A21DD0627473} = {04B1EDB6-E967-4D25-89B9-E6F8304038CD} {0692D963-DB10-4387-B3EA-460FBB9BD9A3} = {EF30B533-D715-421A-92B7-92FEF460AC9C} - {ADCC2D5F-46E2-457E-A426-C1A4B493EE0C} = {C74B8F36-FD2F-45C9-9B8A-00E7CF0126A9} + {13FD8F12-FFBE-4D01-B4AC-444F2994B04F} = {EF30B533-D715-421A-92B7-92FEF460AC9C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DB4F868D-E1AE-4FD7-9333-69FA15B268C5} diff --git a/samples/ANCMStressTestSample/ANCMStressTestSample.csproj b/test/ANCMStressTestApp/ANCMStressTestApp.csproj similarity index 94% rename from samples/ANCMStressTestSample/ANCMStressTestSample.csproj rename to test/ANCMStressTestApp/ANCMStressTestApp.csproj index b1a0c4ec0a..54755b4824 100644 --- a/samples/ANCMStressTestSample/ANCMStressTestSample.csproj +++ b/test/ANCMStressTestApp/ANCMStressTestApp.csproj @@ -1,7 +1,6 @@ - ANCMStressTestApp netcoreapp2.1 win-x86;win-x64 diff --git a/samples/ANCMStressTestSample/Program.cs b/test/ANCMStressTestApp/Program.cs similarity index 100% rename from samples/ANCMStressTestSample/Program.cs rename to test/ANCMStressTestApp/Program.cs diff --git a/samples/ANCMStressTestSample/Properties/launchSettings.json b/test/ANCMStressTestApp/Properties/launchSettings.json similarity index 100% rename from samples/ANCMStressTestSample/Properties/launchSettings.json rename to test/ANCMStressTestApp/Properties/launchSettings.json diff --git a/samples/ANCMStressTestSample/Startup.cs b/test/ANCMStressTestApp/Startup.cs similarity index 100% rename from samples/ANCMStressTestSample/Startup.cs rename to test/ANCMStressTestApp/Startup.cs diff --git a/samples/ANCMStressTestSample/WebSockets/Constants.cs b/test/ANCMStressTestApp/WebSockets/Constants.cs similarity index 100% rename from samples/ANCMStressTestSample/WebSockets/Constants.cs rename to test/ANCMStressTestApp/WebSockets/Constants.cs diff --git a/samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs b/test/ANCMStressTestApp/WebSockets/HandshakeHelpers.cs similarity index 100% rename from samples/ANCMStressTestSample/WebSockets/HandshakeHelpers.cs rename to test/ANCMStressTestApp/WebSockets/HandshakeHelpers.cs From 3eee8b89580b9b1943b309fde4b6857e249fb783 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Mon, 26 Mar 2018 18:15:36 -0700 Subject: [PATCH 8/8] Cleanup CancellationToken code --- test/ANCMStressTestApp/Program.cs | 11 ----------- test/ANCMStressTestApp/Startup.cs | 4 +++- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/test/ANCMStressTestApp/Program.cs b/test/ANCMStressTestApp/Program.cs index 7bfe0bae9f..b0edb5b7f2 100644 --- a/test/ANCMStressTestApp/Program.cs +++ b/test/ANCMStressTestApp/Program.cs @@ -17,9 +17,6 @@ namespace ANCMStressTestApp { public class Program { - public static IApplicationLifetime AppLifetime; - public static CancellationTokenSource Cts = new CancellationTokenSource(); - public static void Main(string[] args) { var host = new WebHostBuilder() @@ -32,14 +29,6 @@ namespace ANCMStressTestApp .UseStartup() .Build(); - AppLifetime = (IApplicationLifetime)host.Services.GetService(typeof(IApplicationLifetime)); - AppLifetime.ApplicationStopping.Register( - () => { - Cts.Cancel(); - Cts.Dispose(); - } - ); - host.Run(); } } diff --git a/test/ANCMStressTestApp/Startup.cs b/test/ANCMStressTestApp/Startup.cs index a374c65b40..be0969ec77 100644 --- a/test/ANCMStressTestApp/Startup.cs +++ b/test/ANCMStressTestApp/Startup.cs @@ -171,7 +171,9 @@ namespace ANCMStressTestApp // Get the WebSocket object var ws = WebSocketProtocol.CreateFromStream(opaqueTransport, isServer: true, subProtocol: null, keepAliveInterval: TimeSpan.FromMinutes(2)); - await Echo(ws, Program.Cts.Token); + var appLifetime = app.ApplicationServices.GetRequiredService(); + + await Echo(ws, appLifetime.ApplicationStopping); }); }