Skip to content

Commit 5fefb7a

Browse files
authored
Implement IHttpUpgradeFeature.IsUpgradableRequest in IIS #23172 (#28121)
1 parent 9375ed2 commit 5fefb7a

File tree

4 files changed

+44
-8
lines changed

4 files changed

+44
-8
lines changed

src/Servers/IIS/IIS/src/Core/IISHttpContext.FeatureCollection.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,10 @@ private async Task CompleteInitializeResponseAwaited(Task initializeTask)
250250
await _writeBodyTask;
251251
}
252252

253-
bool IHttpUpgradeFeature.IsUpgradableRequest => true;
253+
// Http/2 does not support the upgrade mechanic.
254+
// Http/1.x upgrade requests may have a request body, but that's not allowed in our main scenario (WebSockets) and much
255+
// more complicated to support. See https://tools.ietf.org/html/rfc7230#section-6.7, https://tools.ietf.org/html/rfc7540#section-3.2
256+
bool IHttpUpgradeFeature.IsUpgradableRequest => !RequestCanHaveBody && HttpVersion < System.Net.HttpVersion.Version20;
254257

255258
bool IFeatureCollection.IsReadOnly => false;
256259

src/Servers/IIS/IIS/test/IISExpress.FunctionalTests/InProcess/WebSocketTests.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Globalization;
66
using System.Linq;
7+
using System.Net.Http;
78
using System.Net.WebSockets;
89
using System.Text;
910
using System.Threading;
@@ -17,11 +18,30 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
1718
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8, SkipReason = "No WebSocket supported on Win7")]
1819
public class WebSocketsTests
1920
{
21+
private readonly string _requestUri;
2022
private readonly string _webSocketUri;
2123

2224
public WebSocketsTests(IISTestSiteFixture fixture)
2325
{
24-
_webSocketUri = fixture.DeploymentResult.ApplicationBaseUri.Replace("http:", "ws:");
26+
_requestUri = fixture.DeploymentResult.ApplicationBaseUri;
27+
_webSocketUri = _requestUri.Replace("http:", "ws:");
28+
}
29+
30+
[ConditionalFact]
31+
public async Task RequestWithBody_NotUpgradable()
32+
{
33+
using var client = new HttpClient();
34+
using var response = await client.PostAsync(_requestUri + "WebSocketNotUpgradable", new StringContent("Hello World"));
35+
response.EnsureSuccessStatusCode();
36+
}
37+
38+
[ConditionalFact]
39+
public async Task RequestWithoutBody_Upgradable()
40+
{
41+
using var client = new HttpClient();
42+
// POST with Content-Length: 0 counts as not having a body.
43+
using var response = await client.PostAsync(_requestUri + "WebSocketUpgradable", new StringContent(""));
44+
response.EnsureSuccessStatusCode();
2545
}
2646

2747
[ConditionalFact]
@@ -38,7 +58,7 @@ public async Task OnStartedCalledForWebSocket()
3858
public async Task WebReadBeforeUpgrade()
3959
{
4060
var cws = new ClientWebSocket();
41-
await cws.ConnectAsync(new Uri(_webSocketUri + "WebReadBeforeUpgrade"), default);
61+
await cws.ConnectAsync(new Uri(_webSocketUri + "WebSocketReadBeforeUpgrade"), default);
4262

4363
await ReceiveMessage(cws, "Yay");
4464
}

src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.WebSockets.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,27 @@ namespace TestSite
2121
{
2222
public partial class Startup
2323
{
24+
private void WebSocketNotUpgradable(IApplicationBuilder app)
25+
{
26+
app.Run(context => {
27+
28+
var upgradeFeature = context.Features.Get<IHttpUpgradeFeature>();
29+
Assert.False(upgradeFeature.IsUpgradableRequest);
30+
return Task.CompletedTask;
31+
});
32+
}
2433

25-
private void WebsocketRequest(IApplicationBuilder app)
34+
private void WebSocketUpgradable(IApplicationBuilder app)
2635
{
27-
app.Run(async context =>
28-
{
29-
await context.Response.WriteAsync("test");
36+
app.Run(context => {
37+
38+
var upgradeFeature = context.Features.Get<IHttpUpgradeFeature>();
39+
Assert.True(upgradeFeature.IsUpgradableRequest);
40+
return Task.CompletedTask;
3041
});
3142
}
3243

33-
private void WebReadBeforeUpgrade(IApplicationBuilder app)
44+
private void WebSocketReadBeforeUpgrade(IApplicationBuilder app)
3445
{
3546
app.Run(async context => {
3647

src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,8 @@ public Task Http2_MethodsRequestWithoutData_Success(HttpContext httpContext)
14881488
Assert.Equal("HTTP/2", httpContext.Request.Protocol);
14891489
#if !FORWARDCOMPAT
14901490
Assert.False(httpContext.Request.CanHaveBody());
1491+
var feature = httpContext.Features.Get<IHttpUpgradeFeature>();
1492+
Assert.False(feature.IsUpgradableRequest);
14911493
#endif
14921494
Assert.Null(httpContext.Request.ContentLength);
14931495
Assert.False(httpContext.Request.Headers.ContainsKey(HeaderNames.TransferEncoding));

0 commit comments

Comments
 (0)