Skip to content

Commit 401ae7c

Browse files
github-actions[bot]BrennanConroycaptainsafia
authored
[release/9.0] Fix IIS outofprocess to remove WebSocket compression handshake (#58931)
* Fix IIS outofprocess to remove WebSocket compression handshake * test name * Don't run IIS websocket tests on unsupported queue * comment * using * using * not * 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 --------- Co-authored-by: Brennan <[email protected]> Co-authored-by: Safia Abdalla <[email protected]>
1 parent 0eb3437 commit 401ae7c

File tree

13 files changed

+236
-49
lines changed

13 files changed

+236
-49
lines changed

src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,12 @@ public override string ToString()
183183
{
184184
return string.Format(
185185
CultureInfo.InvariantCulture,
186-
"[Variation] :: ServerType={0}, Runtime={1}, Arch={2}, BaseUrlHint={3}, Publish={4}",
186+
"[Variation] :: ServerType={0}, Runtime={1}, Arch={2}, BaseUrlHint={3}, Publish={4}, HostingModel={5}",
187187
ServerType,
188188
RuntimeFlavor,
189189
RuntimeArchitecture,
190190
ApplicationBaseUriHint,
191-
PublishApplicationBeforeDeployment);
191+
PublishApplicationBeforeDeployment,
192+
HostingModel);
192193
}
193194
}

src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/forwardinghandler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ FORWARDING_HANDLER::ExecuteRequestHandler()
180180
if (cchHeader == 9 && _stricmp(pszWebSocketHeader, "websocket") == 0)
181181
{
182182
m_fWebSocketEnabled = TRUE;
183+
184+
// WinHttp does not support any extensions being returned by the server, so we remove the request header to avoid the server
185+
// responding with any accepted extensions.
186+
pRequest->DeleteHeader("Sec-WebSocket-Extensions");
183187
}
184188
}
185189

src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteCollection.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
99
/// This type just maps collection names to available fixtures
1010
/// </summary>
1111
[CollectionDefinition(Name)]
12-
public class IISTestSiteCollection : ICollectionFixture<IISTestSiteFixture>
12+
public class IISTestSiteCollectionInProc : ICollectionFixture<IISTestSiteFixture>
1313
{
14-
public const string Name = nameof(IISTestSiteCollection);
14+
public const string Name = nameof(IISTestSiteCollectionInProc);
15+
}
16+
17+
[CollectionDefinition(Name)]
18+
public class IISTestSiteCollectionOutOfProc : ICollectionFixture<IISTestSiteFixture>
19+
{
20+
public const string Name = nameof(IISTestSiteCollectionOutOfProc);
1521
}
1622

1723
[CollectionDefinition(Name)]

src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/IISTestSiteFixture.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ internal IISTestSiteFixture(Action<IISDeploymentParameters> configure)
4646
ApplicationPublisher = new PublishedApplicationPublisher(Helpers.GetInProcessTestSitesName()),
4747
ServerType = DeployerSelector.ServerType
4848
};
49+
50+
// Uncomment to add IIS debug logs to test output.
51+
//DeploymentParameters.EnvironmentVariables.Add("ASPNETCORE_MODULE_DEBUG", "console");
52+
53+
// This queue does not have websockets enabled currently, adding the module will break all tests using this fixture.
54+
if (!HelixHelper.GetTargetHelixQueue().ToLowerInvariant().Contains("windows.amd64.server2022"))
55+
{
56+
DeploymentParameters.EnableModule("WebSocketModule", "%IIS_BIN%/iiswsock.dll");
57+
}
4958
}
5059

5160
public HttpClient Client => DeploymentResult.HttpClient;

src/Servers/IIS/IIS/test/Common.FunctionalTests/RequestResponseTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests;
2929
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
3030
#endif
3131

32-
[Collection(IISTestSiteCollection.Name)]
32+
[Collection(IISTestSiteCollectionInProc.Name)]
3333
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")]
3434
public class RequestResponseTests
3535
{
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.InternalTesting;
5+
using Microsoft.AspNetCore.Server.IntegrationTesting;
6+
using Xunit.Abstractions;
7+
8+
#if !IIS_FUNCTIONALS
9+
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
10+
11+
#if IISEXPRESS_FUNCTIONALS
12+
namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests;
13+
#elif NEWHANDLER_FUNCTIONALS
14+
namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests;
15+
#elif NEWSHIM_FUNCTIONALS
16+
namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests;
17+
#endif
18+
#else
19+
20+
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
21+
#endif
22+
23+
[Collection(IISTestSiteCollectionInProc.Name)]
24+
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")]
25+
#if IISEXPRESS_FUNCTIONALS
26+
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")]
27+
#else
28+
// These queues do not have websockets enabled currently for full IIS
29+
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")]
30+
#endif
31+
public class WebSocketsInProcessTests : WebSocketsTests
32+
{
33+
public WebSocketsInProcessTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(fixture, testOutput)
34+
{
35+
Fixture.DeploymentParameters.HostingModel = HostingModel.InProcess;
36+
}
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using Microsoft.AspNetCore.InternalTesting;
5+
using Microsoft.AspNetCore.Server.IntegrationTesting;
6+
using Xunit.Abstractions;
7+
8+
#if !IIS_FUNCTIONALS
9+
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
10+
11+
#if IISEXPRESS_FUNCTIONALS
12+
namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests;
13+
#elif NEWHANDLER_FUNCTIONALS
14+
namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests;
15+
#elif NEWSHIM_FUNCTIONALS
16+
namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests;
17+
#endif
18+
#else
19+
20+
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
21+
#endif
22+
23+
[Collection(IISTestSiteCollectionOutOfProc.Name)]
24+
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")]
25+
#if IISEXPRESS_FUNCTIONALS
26+
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open")]
27+
#else
28+
// These queues do not have websockets enabled currently for full IIS
29+
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;Windows.Amd64.Server2022.Open")]
30+
#endif
31+
public class WebSocketsOutOfProcessTests : WebSocketsTests
32+
{
33+
public WebSocketsOutOfProcessTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(fixture, testOutput)
34+
{
35+
Fixture.DeploymentParameters.HostingModel = HostingModel.OutOfProcess;
36+
}
37+
}

src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs renamed to src/Servers/IIS/IIS/test/Common.FunctionalTests/WebSocketTests.cs

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,72 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
4+
using System.Diagnostics;
55
using System.Globalization;
6-
using System.Linq;
76
using System.Net.Http;
87
using System.Net.Sockets;
98
using System.Net.WebSockets;
109
using System.Text;
11-
using System.Threading;
12-
using System.Threading.Tasks;
13-
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
1410
using Microsoft.AspNetCore.InternalTesting;
15-
using Xunit;
11+
using Microsoft.AspNetCore.Server.IntegrationTesting;
12+
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
13+
using Xunit.Abstractions;
14+
15+
#if !IIS_FUNCTIONALS
16+
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
1617

18+
#if IISEXPRESS_FUNCTIONALS
1719
namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests;
20+
#elif NEWHANDLER_FUNCTIONALS
21+
namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests;
22+
#elif NEWSHIM_FUNCTIONALS
23+
namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests;
24+
#endif
25+
#else
1826

19-
[Collection(IISTestSiteCollection.Name)]
20-
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")]
21-
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")]
22-
public class WebSocketsTests
27+
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
28+
#endif
29+
30+
public abstract class WebSocketsTests : FunctionalTestsBase
2331
{
24-
private readonly string _requestUri;
25-
private readonly string _webSocketUri;
32+
public IISTestSiteFixture Fixture { get; }
2633

27-
public WebSocketsTests(IISTestSiteFixture fixture)
34+
public WebSocketsTests(IISTestSiteFixture fixture, ITestOutputHelper testOutput) : base(testOutput)
2835
{
29-
_requestUri = fixture.DeploymentResult.ApplicationBaseUri;
30-
_webSocketUri = _requestUri.Replace("http:", "ws:");
36+
Fixture = fixture;
3137
}
3238

3339
[ConditionalFact]
3440
public async Task RequestWithBody_NotUpgradable()
3541
{
3642
using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(200) };
37-
using var response = await client.PostAsync(_requestUri + "WebSocketNotUpgradable", new StringContent("Hello World"));
43+
using var response = await client.PostAsync(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketNotUpgradable", new StringContent("Hello World"));
3844
response.EnsureSuccessStatusCode();
3945
}
4046

4147
[ConditionalFact]
4248
public async Task RequestWithoutBody_Upgradable()
4349
{
50+
if (Fixture.DeploymentParameters.HostingModel == HostingModel.OutOfProcess)
51+
{
52+
// OutOfProcess doesn't support upgrade requests without the "Upgrade": "websocket" header.
53+
return;
54+
}
55+
4456
using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(200) };
4557
// POST with Content-Length: 0 counts as not having a body.
46-
using var response = await client.PostAsync(_requestUri + "WebSocketUpgradable", new StringContent(""));
58+
using var response = await client.PostAsync(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketUpgradable", new StringContent(""));
4759
response.EnsureSuccessStatusCode();
4860
}
4961

5062
[ConditionalFact]
5163
public async Task OnStartedCalledForWebSocket()
5264
{
53-
var cws = new ClientWebSocket();
54-
await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketLifetimeEvents"), default);
65+
var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri;
66+
webSocketUri = webSocketUri.Replace("http:", "ws:");
67+
68+
using var cws = new ClientWebSocket();
69+
await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketLifetimeEvents"), default);
5570

5671
await ReceiveMessage(cws, "OnStarting");
5772
await ReceiveMessage(cws, "Upgraded");
@@ -60,17 +75,23 @@ public async Task OnStartedCalledForWebSocket()
6075
[ConditionalFact]
6176
public async Task WebReadBeforeUpgrade()
6277
{
63-
var cws = new ClientWebSocket();
64-
await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketReadBeforeUpgrade"), default);
78+
var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri;
79+
webSocketUri = webSocketUri.Replace("http:", "ws:");
80+
81+
using var cws = new ClientWebSocket();
82+
await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketReadBeforeUpgrade"), default);
6583

6684
await ReceiveMessage(cws, "Yay");
6785
}
6886

6987
[ConditionalFact]
7088
public async Task CanSendAndReceieveData()
7189
{
72-
var cws = new ClientWebSocket();
73-
await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketEcho"), default);
90+
var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri;
91+
webSocketUri = webSocketUri.Replace("http:", "ws:");
92+
93+
using var cws = new ClientWebSocket();
94+
await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketEcho"), default);
7495

7596
for (int i = 0; i < 1000; i++)
7697
{
@@ -80,10 +101,33 @@ public async Task CanSendAndReceieveData()
80101
}
81102
}
82103

104+
[ConditionalFact]
105+
public async Task AttemptCompressionWorks()
106+
{
107+
var webSocketUri = Fixture.DeploymentResult.ApplicationBaseUri;
108+
webSocketUri = webSocketUri.Replace("http:", "ws:");
109+
110+
using var cws = new ClientWebSocket();
111+
cws.Options.DangerousDeflateOptions = new WebSocketDeflateOptions();
112+
await cws.ConnectAsync(new Uri(webSocketUri + "WebSocketAllowCompression"), default);
113+
114+
// Compression doesn't work with OutOfProcess, let's make sure the websocket extensions aren't forwarded and the connection still works
115+
var expected = Fixture.DeploymentParameters.HostingModel == HostingModel.InProcess
116+
? "permessage-deflate; client_max_window_bits=15" : "None";
117+
await ReceiveMessage(cws, expected);
118+
119+
for (int i = 0; i < 1000; i++)
120+
{
121+
var message = i.ToString(CultureInfo.InvariantCulture);
122+
await SendMessage(cws, message);
123+
await ReceiveMessage(cws, message);
124+
}
125+
}
126+
83127
[ConditionalFact]
84128
public async Task Http1_0_Request_NotUpgradable()
85129
{
86-
Uri uri = new Uri(_requestUri + "WebSocketNotUpgradable");
130+
Uri uri = new Uri(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketNotUpgradable");
87131
using TcpClient client = new TcpClient();
88132

89133
await client.ConnectAsync(uri.Host, uri.Port);
@@ -103,7 +147,7 @@ public async Task Http1_0_Request_NotUpgradable()
103147
[ConditionalFact]
104148
public async Task Http1_0_Request_UpgradeErrors()
105149
{
106-
Uri uri = new Uri(_requestUri + "WebSocketUpgradeFails");
150+
Uri uri = new Uri(Fixture.DeploymentResult.ApplicationBaseUri + "WebSocketUpgradeFails");
107151
using TcpClient client = new TcpClient();
108152

109153
await client.ConnectAsync(uri.Host, uri.Port);
@@ -148,6 +192,7 @@ private async Task SendMessage(ClientWebSocket webSocket, string message)
148192

149193
private async Task ReceiveMessage(ClientWebSocket webSocket, string expectedMessage)
150194
{
195+
Debug.Assert(expectedMessage.Length > 0);
151196
var received = new byte[expectedMessage.Length];
152197

153198
var offset = 0;
@@ -156,7 +201,7 @@ private async Task ReceiveMessage(ClientWebSocket webSocket, string expectedMess
156201
{
157202
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(received, offset, received.Length - offset), default);
158203
offset += result.Count;
159-
} while (!result.EndOfMessage);
204+
} while (!result.EndOfMessage && result.CloseStatus is null && received.Length - offset > 0);
160205

161206
Assert.Equal(expectedMessage, Encoding.ASCII.GetString(received));
162207
}

src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
1212
</PropertyGroup>
1313

14-
1514
<ItemGroup>
1615
<Reference Include="Microsoft.AspNetCore.Server.IIS" />
1716
<ProjectReference Include="..\testassets\IIS.Common.TestLib\IIS.Common.TestLib.csproj" />

src/Servers/IIS/IIS/test/testassets/InProcessWebSite/InProcessWebSite.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<Reference Include="Microsoft.AspNetCore.Server.IISIntegration" />
2929
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
3030
<Reference Include="Microsoft.AspNetCore.HttpsPolicy" />
31+
<Reference Include="Microsoft.AspNetCore.WebSockets" />
3132
<Reference Include="Microsoft.AspNetCore.WebUtilities" />
3233
<Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
3334
<Reference Include="Microsoft.Extensions.Configuration.Json" />

0 commit comments

Comments
 (0)