Skip to content

Commit d3290c1

Browse files
authored
HttpSys log correct statuscode when application throws (#42223)
1 parent 9a74d3b commit d3290c1

File tree

4 files changed

+72
-7
lines changed

4 files changed

+72
-7
lines changed

src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ protected void SetFatalResponse(int status)
254254
{
255255
Response.StatusCode = status;
256256
Response.ContentLength = 0;
257-
Dispose();
258257
}
259258

260259
internal unsafe void Delegate(DelegationRule destination)

src/Servers/HttpSys/src/RequestProcessing/RequestContextOfT.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ public override async Task ExecuteAsync()
3232
if (messagePump.Stopping)
3333
{
3434
SetFatalResponse(503);
35+
Dispose();
3536
return;
3637
}
3738

3839
TContext? context = default;
40+
Exception? applicationException = null;
3941
messagePump.IncrementOutstandingRequest();
4042
try
4143
{
@@ -49,16 +51,12 @@ public override async Task ExecuteAsync()
4951
{
5052
await OnCompleted();
5153
}
52-
application.DisposeContext(context, null);
53-
Dispose();
5454
}
5555
catch (Exception ex)
5656
{
57+
applicationException = ex;
58+
5759
Log.RequestProcessError(Logger, ex);
58-
if (context != null)
59-
{
60-
application.DisposeContext(context, ex);
61-
}
6260
if (Response.HasStarted)
6361
{
6462
// Otherwise the default is Cancel = 0x8 (h2) or 0x010c (h3).
@@ -94,11 +92,18 @@ public override async Task ExecuteAsync()
9492
}
9593
finally
9694
{
95+
if (context != null)
96+
{
97+
application.DisposeContext(context, applicationException);
98+
}
99+
97100
if (messagePump.DecrementOutstandingRequest() == 0 && messagePump.Stopping)
98101
{
99102
Log.RequestsDrained(Logger);
100103
messagePump.SetShutdownSignal();
101104
}
105+
106+
Dispose();
102107
}
103108
}
104109
catch (Exception ex)

src/Servers/test/FunctionalTests/HelloWorldTest.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Net;
56
using System.Threading.Tasks;
67
using Microsoft.AspNetCore.Server.IntegrationTesting;
78
using Microsoft.AspNetCore.Testing;
@@ -108,4 +109,56 @@ public async Task HelloWorld(TestVariant variant)
108109
}
109110
}
110111
}
112+
113+
public static TestMatrix SelfHostTestVariants
114+
=> TestMatrix.ForServers(ServerType.Kestrel, ServerType.HttpSys)
115+
.WithTfms(Tfm.Default)
116+
.WithApplicationTypes(ApplicationType.Portable)
117+
.WithAllHostingModels()
118+
.WithAllArchitectures();
119+
120+
[ConditionalTheory]
121+
[MemberData(nameof(SelfHostTestVariants))]
122+
public async Task ApplicationException(TestVariant variant)
123+
{
124+
var testName = $"ApplicationException_{variant.Server}_{variant.Tfm}_{variant.Architecture}_{variant.ApplicationType}";
125+
using (StartLog(out var loggerFactory, LogLevel.Debug, testName))
126+
{
127+
var logger = loggerFactory.CreateLogger("ApplicationException");
128+
129+
var deploymentParameters = new DeploymentParameters(variant)
130+
{
131+
ApplicationPath = Helpers.GetApplicationPath()
132+
};
133+
134+
var output = string.Empty;
135+
using (var deployer = new SelfHostDeployer(deploymentParameters, loggerFactory))
136+
{
137+
deployer.ProcessOutputListener = (data) =>
138+
{
139+
if (!string.IsNullOrWhiteSpace(data))
140+
{
141+
output += data + '\n';
142+
}
143+
};
144+
145+
var deploymentResult = await deployer.DeployAsync();
146+
147+
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
148+
using (var response = await RetryHelper.RetryRequest(() =>
149+
{
150+
return deploymentResult.HttpClient.GetAsync("/throwexception");
151+
}, logger, deploymentResult.HostShutdownToken))
152+
{
153+
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
154+
155+
var body = await response.Content.ReadAsStringAsync();
156+
Assert.Empty(body);
157+
}
158+
}
159+
// Output should contain the ApplicationException and the 500 status code
160+
Assert.Contains("System.ApplicationException: Application exception", output);
161+
Assert.Contains("/throwexception - - - 500", output);
162+
}
163+
}
111164
}

src/Servers/testassets/ServerComparison.TestSites/Startup.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ public class Startup
1212
{
1313
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
1414
{
15+
app.Map("/throwexception", subApp =>
16+
{
17+
subApp.Run(context =>
18+
{
19+
throw new ApplicationException("Application exception");
20+
});
21+
});
22+
1523
app.Run(ctx =>
1624
{
1725
return ctx.Response.WriteAsync("Hello World " + RuntimeInformation.ProcessArchitecture);

0 commit comments

Comments
 (0)