From a9dad55218007bd898851d7fbb76828d1cf0f93a Mon Sep 17 00:00:00 2001 From: Brennan Date: Fri, 8 Nov 2024 15:12:00 -0800 Subject: [PATCH 1/8] Fix IIS outofprocess to remove WebSocket compression handshake --- .../src/Common/DeploymentParameters.cs | 5 +- .../forwardinghandler.cpp | 4 + .../Infrastructure/IISTestSiteCollection.cs | 10 +- .../Infrastructure/IISTestSiteFixture.cs | 5 + .../RequestResponseTests.cs | 2 +- .../WebSocketInProcessTests.cs | 33 +++++++ .../WebSocketOutOfProcessTests.cs | 33 +++++++ .../WebSocketTests.cs | 95 ++++++++++++++----- .../IISExpress.FunctionalTests.csproj | 1 - .../InProcessWebSite/InProcessWebSite.csproj | 1 + .../InProcessWebSite/Startup.WebSockets.cs | 70 +++++++++++--- .../testassets/InProcessWebSite/Startup.cs | 9 +- src/Servers/IIS/IISIntegration.slnf | 3 +- 13 files changed, 224 insertions(+), 47 deletions(-) create mode 100644 src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs create mode 100644 src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs rename src/Servers/IIS/IIS/test/{IISExpress.FunctionalTests/InProcess => Common.FunctionalTests}/WebSocketTests.cs (56%) diff --git a/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs b/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs index 0f13855c2c7e..ad6ccc2ab1d9 100644 --- a/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs +++ b/src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs @@ -183,11 +183,12 @@ public override string ToString() { return string.Format( CultureInfo.InvariantCulture, - "[Variation] :: ServerType={0}, Runtime={1}, Arch={2}, BaseUrlHint={3}, Publish={4}", + "[Variation] :: ServerType={0}, Runtime={1}, Arch={2}, BaseUrlHint={3}, Publish={4}, HostingModel={5}", ServerType, RuntimeFlavor, RuntimeArchitecture, ApplicationBaseUriHint, - PublishApplicationBeforeDeployment); + PublishApplicationBeforeDeployment, + HostingModel); } } diff --git a/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp b/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp index d30883ea5332..6ddd7c4c8a73 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp @@ -180,6 +180,10 @@ FORWARDING_HANDLER::ExecuteRequestHandler() if (cchHeader == 9 && _stricmp(pszWebSocketHeader, "websocket") == 0) { m_fWebSocketEnabled = TRUE; + + // WinHttp does not support any extensions being returned by the server, so we remove the request header to avoid the server + // responding with any accepted extensions. + pRequest->DeleteHeader("Sec-WebSocket-Extensions"); } } diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteCollection.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteCollection.cs index b0c81b037f30..7a96d25087da 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteCollection.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteCollection.cs @@ -9,9 +9,15 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; /// This type just maps collection names to available fixtures /// [CollectionDefinition(Name)] -public class IISTestSiteCollection : ICollectionFixture +public class IISTestSiteCollectionInProc : ICollectionFixture { - public const string Name = nameof(IISTestSiteCollection); + public const string Name = nameof(IISTestSiteCollectionInProc); +} + +[CollectionDefinition(Name)] +public class IISTestSiteCollectionOutOfProc : ICollectionFixture +{ + public const string Name = nameof(IISTestSiteCollectionOutOfProc); } [CollectionDefinition(Name)] diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs index 73074454b0c1..024ed61f9087 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs @@ -46,6 +46,11 @@ internal IISTestSiteFixture(Action configure) ApplicationPublisher = new PublishedApplicationPublisher(Helpers.GetInProcessTestSitesName()), ServerType = DeployerSelector.ServerType }; + + // Uncomment to add IIS debug logs to test output. + //DeploymentParameters.EnvironmentVariables.Add("ASPNETCORE_MODULE_DEBUG", "console"); + + DeploymentParameters.EnableModule("WebSocketModule", "%IIS_BIN%/iiswsock.dll"); } public HttpClient Client => DeploymentResult.HttpClient; diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs index c701dd6bea25..4428a6d1a6dd 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests; namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; #endif -[Collection(IISTestSiteCollection.Name)] +[Collection(IISTestSiteCollectionInProc.Name)] [SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] public class RequestResponseTests { diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs new file mode 100644 index 000000000000..0eff6ec45e0b --- /dev/null +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Server.IIS.FunctionalTests; +using Microsoft.AspNetCore.InternalTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Xunit.Abstractions; + +#if !IIS_FUNCTIONALS +using Microsoft.AspNetCore.Server.IIS.FunctionalTests; + +#if IISEXPRESS_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests; +#elif NEWHANDLER_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests; +#elif NEWSHIM_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests; +#endif +#else + +namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; +#endif + +[Collection(IISTestSiteCollectionInProc.Name)] +[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] +public class WebSocketsInProcessTests : WebSocketsTests +{ + public WebSocketsInProcessTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(fixture, testOutput) + { + Fixture.DeploymentParameters.HostingModel = HostingModel.InProcess; + } +} diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs new file mode 100644 index 000000000000..58b1c148ceb5 --- /dev/null +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.AspNetCore.Server.IIS.FunctionalTests; +using Microsoft.AspNetCore.InternalTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Xunit.Abstractions; + +#if !IIS_FUNCTIONALS +using Microsoft.AspNetCore.Server.IIS.FunctionalTests; + +#if IISEXPRESS_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests; +#elif NEWHANDLER_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests; +#elif NEWSHIM_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests; +#endif +#else + +namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; +#endif + +[Collection(IISTestSiteCollectionOutOfProc.Name)] +[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] +public class WebSocketsOutOfProcessTests : WebSocketsTests +{ + public WebSocketsOutOfProcessTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(fixture, testOutput) + { + Fixture.DeploymentParameters.HostingModel = HostingModel.OutOfProcess; + } +} diff --git a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs similarity index 56% rename from src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs rename to src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs index a5586af0c0b9..8a318d187689 100644 --- a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs @@ -1,57 +1,76 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; +using System.Diagnostics; using System.Globalization; -using System.Linq; using System.Net.Http; using System.Net.Sockets; using System.Net.WebSockets; using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Server.IIS.FunctionalTests; using Microsoft.AspNetCore.InternalTesting; -using Xunit; +using Microsoft.AspNetCore.Server.IIS.FunctionalTests; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; +using Xunit.Abstractions; + +#if !IIS_FUNCTIONALS +using Microsoft.AspNetCore.Server.IIS.FunctionalTests; +#if IISEXPRESS_FUNCTIONALS namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests; +#elif NEWHANDLER_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests; +#elif NEWSHIM_FUNCTIONALS +namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests; +#endif +#else + +namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; +#endif -[Collection(IISTestSiteCollection.Name)] [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] [SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] -public class WebSocketsTests +public abstract class WebSocketsTests : FunctionalTestsBase { - private readonly string _requestUri; - private readonly string _webSocketUri; + public IISTestSiteFixture Fixture { get; } - public WebSocketsTests(IISTestSiteFixture fixture) + public WebSocketsTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(testOutput) { - _requestUri = fixture.DeploymentResult.ApplicationBaseUri; - _webSocketUri = _requestUri.Replace("http:", "ws:"); + Fixture = fixture; + Fixture.DeploymentParameters.EnableLogging("C:/github/aspnetcore/artifacts/log"); } [ConditionalFact] public async Task RequestWithBody_NotUpgradable() { using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(200) }; - using var response = await client.PostAsync(_requestUri + "WebSocketNotUpgradable", new StringContent("Hello World")); + using var response = await client.PostAsync(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketNotUpgradable", new StringContent("Hello World")); response.EnsureSuccessStatusCode(); } [ConditionalFact] public async Task RequestWithoutBody_Upgradable() { + if (Fixture.DeploymentParameters.HostingModel == HostingModel.OutOfProcess) + { + // OutOfProcess doesn't support upgrade requests without the "Upgrade": "websocket" header. + return; + } + using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(200) }; // POST with Content-Length: 0 counts as not having a body. - using var response = await client.PostAsync(_requestUri + "WebSocketUpgradable", new StringContent("")); + using var response = await client.PostAsync(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketUpgradable", new StringContent("")); response.EnsureSuccessStatusCode(); } [ConditionalFact] public async Task OnStartedCalledForWebSocket() { - var cws = new ClientWebSocket(); - await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketLifetimeEvents"), default); + var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri; + webSocketUri = webSocketUri.Replace("http:", "ws:"); + + using var cws = new ClientWebSocket(); + await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketLifetimeEvents"), default); await ReceiveMessage(cws, "OnStarting"); await ReceiveMessage(cws, "Upgraded"); @@ -60,8 +79,11 @@ public async Task OnStartedCalledForWebSocket() [ConditionalFact] public async Task WebReadBeforeUpgrade() { - var cws = new ClientWebSocket(); - await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketReadBeforeUpgrade"), default); + var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri; + webSocketUri = webSocketUri.Replace("http:", "ws:"); + + using var cws = new ClientWebSocket(); + await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketReadBeforeUpgrade"), default); await ReceiveMessage(cws, "Yay"); } @@ -69,8 +91,11 @@ public async Task WebReadBeforeUpgrade() [ConditionalFact] public async Task CanSendAndReceieveData() { - var cws = new ClientWebSocket(); - await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketEcho"), default); + var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri; + webSocketUri = webSocketUri.Replace("http:", "ws:"); + + using var cws = new ClientWebSocket(); + await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketEcho"), default); for (int i = 0; i < 1000; i++) { @@ -80,10 +105,31 @@ public async Task CanSendAndReceieveData() } } + [ConditionalFact] + public async Task Compression() + { + var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri; + webSocketUri = webSocketUri.Replace("http:", "ws:"); + + using var cws = new ClientWebSocket(); + cws.Options.DangerousDeflateOptions = new WebSocketDeflateOptions(); + await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketAllowCompression"), default); + + var expected = Fixture.DeploymentParameters.HostingModel == HostingModel.InProcess ? "permessage-deflate; client_max_window_bits=15" : "None"; + await ReceiveMessage(cws, expected); + + for (int i = 0; i < 1000; i++) + { + var message = i.ToString(CultureInfo.InvariantCulture); + await SendMessage(cws, message); + await ReceiveMessage(cws, message); + } + } + [ConditionalFact] public async Task Http1_0_Request_NotUpgradable() { - Uri uri = new Uri(_requestUri + "WebSocketNotUpgradable"); + Uri uri = new Uri(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketNotUpgradable"); using TcpClient client = new TcpClient(); await client.ConnectAsync(uri.Host, uri.Port); @@ -103,7 +149,7 @@ public async Task Http1_0_Request_NotUpgradable() [ConditionalFact] public async Task Http1_0_Request_UpgradeErrors() { - Uri uri = new Uri(_requestUri + "WebSocketUpgradeFails"); + Uri uri = new Uri(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketUpgradeFails"); using TcpClient client = new TcpClient(); await client.ConnectAsync(uri.Host, uri.Port); @@ -148,6 +194,7 @@ private async Task SendMessage(ClientWebSocket webSocket, string message) private async Task ReceiveMessage(ClientWebSocket webSocket, string expectedMessage) { + Debug.Assert(expectedMessage.Length > 0); var received = new byte[expectedMessage.Length]; var offset = 0; @@ -156,7 +203,7 @@ private async Task ReceiveMessage(ClientWebSocket webSocket, string expectedMess { result = await webSocket.ReceiveAsync(new ArraySegment(received, offset, received.Length - offset), default); offset += result.Count; - } while (!result.EndOfMessage); + } while (!result.EndOfMessage && result.CloseStatus is null && received.Length - offset > 0); Assert.Equal(expectedMessage, Encoding.ASCII.GetString(received)); } diff --git a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj b/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj index 15ad8db11a2f..f34f4f9e7cee 100644 --- a/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj +++ b/src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj @@ -11,7 +11,6 @@ true - diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj index 4fdccefc70e8..7a4cef0ef12d 100644 --- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj +++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj @@ -28,6 +28,7 @@ + diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.WebSockets.cs b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.WebSockets.cs index d0750ef81fd4..c7d502039f55 100644 --- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.WebSockets.cs +++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.WebSockets.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Net.WebSockets; using System.Text; @@ -50,6 +51,8 @@ private void WebSocketReadBeforeUpgrade(IApplicationBuilder app) var ws = await Upgrade(context); await SendMessages(ws, "Yay"); + + await CloseWebSocket(ws, false); }); } @@ -85,6 +88,8 @@ private void WebSocketLifetimeEvents(IApplicationBuilder app) messages.Add("Upgraded"); await SendMessages(ws, messages.ToArray()); + + await CloseWebSocket(ws, false); }); } @@ -94,10 +99,38 @@ private void WebSocketUpgradeFails(IApplicationBuilder app) { var upgradeFeature = context.Features.Get(); var ex = await Assert.ThrowsAsync(() => upgradeFeature.UpgradeAsync()); - Assert.Equal("Upgrade requires HTTP/1.1.", ex.Message); + if (ex.Message != "Upgrade requires HTTP/1.1." + && ex.Message != "Cannot upgrade a non-upgradable request. Check IHttpUpgradeFeature.IsUpgradableRequest to determine if a request can be upgraded.") + { + throw new InvalidOperationException("Unexpected error from UpgradeAsync."); + } }); } +#if !FORWARDCOMPAT + private void WebSocketAllowCompression(IApplicationBuilder app) + { + app.Run(async context => + { + var ws = await context.WebSockets.AcceptWebSocketAsync(new WebSocketAcceptContext() + { + DangerousEnableCompression = true + }); + + var appLifetime = app.ApplicationServices.GetRequiredService(); + + var extensionsHeader = context.Response.Headers.SecWebSocketExtensions.ToString(); + if (extensionsHeader.Length == 0) + { + extensionsHeader = "None"; + } + await ws.SendAsync(Encoding.ASCII.GetBytes(extensionsHeader), WebSocketMessageType.Text, endOfMessage: true, default); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(appLifetime.ApplicationStopping, context.RequestAborted); + await Echo(ws, cts.Token); + }); + } +#endif + private static async Task SendMessages(WebSocket webSocket, params string[] messages) { foreach (var message in messages) @@ -157,17 +190,30 @@ private async Task Echo(WebSocket webSocket, CancellationToken token) } else { - // 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); - } + await CloseWebSocket(webSocket, false); + } + } + + private async Task CloseWebSocket(WebSocket webSocket, bool receivedClose) + { + // 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, "CloseFromServer", CancellationToken.None); + + if (receivedClose) + { + return; + } + + // The server has sent the Close frame. + // Stop sending but keep receiving until we get the Close frame from the client. + WebSocketReceiveResult result; + var buffer = new byte[100]; + do + { + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); } + while (!result.CloseStatus.HasValue); } } diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs index fba1940f881e..7588f67559ea 100644 --- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs +++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs @@ -2,14 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.Marshalling; using System.Security.Principal; using System.Text; using System.Threading; @@ -44,6 +40,11 @@ public void Configure(IApplicationBuilder app, IHttpContextAccessor httpContextA { app.UseHttpsRedirection(); } + +#if !FORWARDCOMPAT + app.UseWebSockets(); +#endif + TestStartup.Register(app, this); _httpContextAccessor = httpContextAccessor; } diff --git a/src/Servers/IIS/IISIntegration.slnf b/src/Servers/IIS/IISIntegration.slnf index db899fc491a9..9b6e5ea81e86 100644 --- a/src/Servers/IIS/IISIntegration.slnf +++ b/src/Servers/IIS/IISIntegration.slnf @@ -20,6 +20,7 @@ "src\\Middleware\\HttpOverrides\\src\\Microsoft.AspNetCore.HttpOverrides.csproj", "src\\Middleware\\HttpsPolicy\\src\\Microsoft.AspNetCore.HttpsPolicy.csproj", "src\\Middleware\\ResponseCompression\\src\\Microsoft.AspNetCore.ResponseCompression.csproj", + "src\\Middleware\\WebSockets\\src\\Microsoft.AspNetCore.WebSockets.csproj", "src\\ObjectPool\\src\\Microsoft.Extensions.ObjectPool.csproj", "src\\Servers\\Connections.Abstractions\\src\\Microsoft.AspNetCore.Connections.Abstractions.csproj", "src\\Servers\\HttpSys\\src\\Microsoft.AspNetCore.Server.HttpSys.csproj", @@ -39,10 +40,10 @@ "src\\Servers\\IIS\\IIS\\samples\\NativeIISSample\\NativeIISSample.csproj", "src\\Servers\\IIS\\IIS\\src\\Microsoft.AspNetCore.Server.IIS.csproj", "src\\Servers\\IIS\\IIS\\test\\IIS.FunctionalTests\\IIS.FunctionalTests.csproj", + "src\\Servers\\IIS\\IIS\\test\\IIS.LongTests\\IIS.LongTests.csproj", "src\\Servers\\IIS\\IIS\\test\\IIS.NewHandler.FunctionalTests\\IIS.NewHandler.FunctionalTests.csproj", "src\\Servers\\IIS\\IIS\\test\\IIS.NewShim.FunctionalTests\\IIS.NewShim.FunctionalTests.csproj", "src\\Servers\\IIS\\IIS\\test\\IIS.ShadowCopy.Tests\\IIS.ShadowCopy.Tests.csproj", - "src\\Servers\\IIS\\IIS\\test\\IIS.LongTests\\IIS.LongTests.csproj", "src\\Servers\\IIS\\IIS\\test\\IIS.Tests\\IIS.Tests.csproj", "src\\Servers\\IIS\\IIS\\test\\IISExpress.FunctionalTests\\IISExpress.FunctionalTests.csproj", "src\\Servers\\IIS\\IIS\\test\\testassets\\IIS.Common.TestLib\\IIS.Common.TestLib.csproj", From d0086a8f1c980c62e94b645fbedb13aee6df433c Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 11 Nov 2024 11:01:19 -0800 Subject: [PATCH 2/8] test name --- .../IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs index 8a318d187689..aa2d7d0ebe3e 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs @@ -106,7 +106,7 @@ public async Task CanSendAndReceieveData() } [ConditionalFact] - public async Task Compression() + public async Task AttemptCompressionWorks() { var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri; webSocketUri = webSocketUri.Replace("http:", "ws:"); @@ -115,7 +115,9 @@ public async Task Compression() cws.Options.DangerousDeflateOptions = new WebSocketDeflateOptions(); await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketAllowCompression"), default); - var expected = Fixture.DeploymentParameters.HostingModel == HostingModel.InProcess ? "permessage-deflate; client_max_window_bits=15" : "None"; + // Compression doesn't work with OutOfProcess, let's make sure the websocket extensions aren't forwarded and the connection still works + var expected = Fixture.DeploymentParameters.HostingModel == HostingModel.InProcess + ? "permessage-deflate; client_max_window_bits=15" : "None"; await ReceiveMessage(cws, expected); for (int i = 0; i < 1000; i++) From 4b2645122fb678b1259c1b2113c5139f21fa6d5a Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 18 Nov 2024 13:41:23 -0800 Subject: [PATCH 3/8] Don't run IIS websocket tests on unsupported queue --- .../Infrastructure/IISTestSiteFixture.cs | 6 +++++- .../IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs index 024ed61f9087..218694178edd 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs @@ -50,7 +50,11 @@ internal IISTestSiteFixture(Action configure) // Uncomment to add IIS debug logs to test output. //DeploymentParameters.EnvironmentVariables.Add("ASPNETCORE_MODULE_DEBUG", "console"); - DeploymentParameters.EnableModule("WebSocketModule", "%IIS_BIN%/iiswsock.dll"); + // This queue does not have websockets enabled currently, adding the module will break all tests using this fixture. + if (HelixHelper.GetTargetHelixQueue().ToLowerInvariant().Contains("windows.amd64.server2022")) + { + DeploymentParameters.EnableModule("WebSocketModule", "%IIS_BIN%/iiswsock.dll"); + } } public HttpClient Client => DeploymentResult.HttpClient; diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs index aa2d7d0ebe3e..dd2fc0a9f8ad 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs @@ -29,7 +29,11 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; #endif [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] -[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] +#if IISEXPRESS_FUNCTIONALS +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")] +#else +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")] +#endif public abstract class WebSocketsTests : FunctionalTestsBase { public IISTestSiteFixture Fixture { get; } @@ -37,7 +41,6 @@ public abstract class WebSocketsTests : FunctionalTestsBase public WebSocketsTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(testOutput) { Fixture = fixture; - Fixture.DeploymentParameters.EnableLogging("C:/github/aspnetcore/artifacts/log"); } [ConditionalFact] From acbd4f7792f3974fcec18ef9fc4fbb85c391f479 Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 18 Nov 2024 15:37:26 -0800 Subject: [PATCH 4/8] comment --- .../IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs index dd2fc0a9f8ad..323b7dd43e1d 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs @@ -32,6 +32,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; #if IISEXPRESS_FUNCTIONALS [SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")] #else +// These queues do not have websockets enabled currently for full IIS [SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")] #endif public abstract class WebSocketsTests : FunctionalTestsBase From a8f9596e9dbe6405eade03f9a4c17ab431da437a Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 18 Nov 2024 19:16:08 -0800 Subject: [PATCH 5/8] using --- .../IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs | 1 - .../test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs index 0eff6ec45e0b..6160d015901f 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.AspNetCore.Server.IIS.FunctionalTests; using Microsoft.AspNetCore.InternalTesting; using Microsoft.AspNetCore.Server.IntegrationTesting; using Xunit.Abstractions; diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs index 58b1c148ceb5..a5aa4e5fb23b 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.AspNetCore.Server.IIS.FunctionalTests; using Microsoft.AspNetCore.InternalTesting; using Microsoft.AspNetCore.Server.IntegrationTesting; using Xunit.Abstractions; From 5dec25424b2c7b1cd5cf111f4653883432202d30 Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 18 Nov 2024 19:16:38 -0800 Subject: [PATCH 6/8] using --- .../IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs index 323b7dd43e1d..e0c7b7cd73e0 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs @@ -8,7 +8,6 @@ using System.Net.WebSockets; using System.Text; using Microsoft.AspNetCore.InternalTesting; -using Microsoft.AspNetCore.Server.IIS.FunctionalTests; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Xunit.Abstractions; From c700eda09699296c8370ee6c0d4d05db9be19160 Mon Sep 17 00:00:00 2001 From: Brennan Date: Mon, 18 Nov 2024 23:34:10 -0800 Subject: [PATCH 7/8] not --- .../Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs index 218694178edd..ec04ad06ba84 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs @@ -51,7 +51,7 @@ internal IISTestSiteFixture(Action configure) //DeploymentParameters.EnvironmentVariables.Add("ASPNETCORE_MODULE_DEBUG", "console"); // This queue does not have websockets enabled currently, adding the module will break all tests using this fixture. - if (HelixHelper.GetTargetHelixQueue().ToLowerInvariant().Contains("windows.amd64.server2022")) + if (!HelixHelper.GetTargetHelixQueue().ToLowerInvariant().Contains("windows.amd64.server2022")) { DeploymentParameters.EnableModule("WebSocketModule", "%IIS_BIN%/iiswsock.dll"); } From d086eec9cd593375a1c190d671469d6dc36c9458 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Fri, 22 Nov 2024 19:50:04 -0800 Subject: [PATCH 8/8] Skip WebSocketOutOfProcessTests on Windows.Amd64.Server2022.Open (#59112) * Skip WebSocketOutOfProcessTests on Windows.Amd64.Server2022.Open * Use if-def from base class * Fix in-proc and remove attributes from abstract class --- .../test/Common.FunctionalTests/WebSocketInProcessTests.cs | 7 ++++++- .../Common.FunctionalTests/WebSocketOutOfProcessTests.cs | 7 ++++++- .../IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs | 7 ------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs index 6160d015901f..1491480b7a65 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketInProcessTests.cs @@ -22,7 +22,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; [Collection(IISTestSiteCollectionInProc.Name)] [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] -[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] +#if IISEXPRESS_FUNCTIONALS +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")] +#else +// These queues do not have websockets enabled currently for full IIS +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")] +#endif public class WebSocketsInProcessTests : WebSocketsTests { public WebSocketsInProcessTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(fixture, testOutput) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs index a5aa4e5fb23b..d50328d10170 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketOutOfProcessTests.cs @@ -22,7 +22,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; [Collection(IISTestSiteCollectionOutOfProc.Name)] [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] -[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")] +#if IISEXPRESS_FUNCTIONALS +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")] +#else +// These queues do not have websockets enabled currently for full IIS +[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")] +#endif public class WebSocketsOutOfProcessTests : WebSocketsTests { public WebSocketsOutOfProcessTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(fixture, testOutput) diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs index e0c7b7cd73e0..606ba6c8c654 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs @@ -27,13 +27,6 @@ namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests; namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; #endif -[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")] -#if IISEXPRESS_FUNCTIONALS -[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")] -#else -// These queues do not have websockets enabled currently for full IIS -[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")] -#endif public abstract class WebSocketsTests : FunctionalTestsBase { public IISTestSiteFixture Fixture { get; }