Skip to content

Commit 435bc1e

Browse files
committed
Make UseStatusCodePagesWithReExecute clear Endpoints #13715
1 parent 1937c80 commit 435bc1e

File tree

3 files changed

+181
-106
lines changed

3 files changed

+181
-106
lines changed

src/Middleware/Diagnostics/src/StatusCodePage/StatusCodePagesExtensions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Threading.Tasks;
77
using Microsoft.AspNetCore.Diagnostics;
88
using Microsoft.AspNetCore.Http;
9+
using Microsoft.AspNetCore.Http.Features;
910
using Microsoft.Extensions.Options;
1011

1112
namespace Microsoft.AspNetCore.Builder
@@ -188,6 +189,12 @@ public static IApplicationBuilder UseStatusCodePagesWithReExecute(
188189
OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
189190
});
190191

192+
// An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
193+
// the endpoint and route values to ensure things are re-calculated.
194+
context.HttpContext.SetEndpoint(endpoint: null);
195+
var routeValuesFeature = context.HttpContext.Features.Get<IRouteValuesFeature>();
196+
routeValuesFeature?.RouteValues?.Clear();
197+
191198
context.HttpContext.Request.Path = newPath;
192199
context.HttpContext.Request.QueryString = newQueryString;
193200
try

src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs

Lines changed: 0 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -177,112 +177,6 @@ public async Task ClearsResponseBuffer_BeforeRequestIsReexecuted()
177177
}
178178
}
179179

180-
[Fact]
181-
public async Task Redirect_StatusPage()
182-
{
183-
var expectedStatusCode = 432;
184-
var destination = "/location";
185-
var builder = new WebHostBuilder()
186-
.Configure(app =>
187-
{
188-
app.UseStatusCodePagesWithRedirects("/errorPage?id={0}");
189-
190-
app.Map(destination, (innerAppBuilder) =>
191-
{
192-
innerAppBuilder.Run((httpContext) =>
193-
{
194-
httpContext.Response.StatusCode = expectedStatusCode;
195-
return Task.FromResult(1);
196-
});
197-
});
198-
199-
app.Map("/errorPage", (innerAppBuilder) =>
200-
{
201-
innerAppBuilder.Run(async (httpContext) =>
202-
{
203-
await httpContext.Response.WriteAsync(httpContext.Request.QueryString.Value);
204-
});
205-
});
206-
207-
app.Run((context) =>
208-
{
209-
210-
throw new InvalidOperationException($"Invalid input provided. {context.Request.Path}");
211-
});
212-
});
213-
var expectedQueryString = $"?id={expectedStatusCode}";
214-
var expectedUri = $"/errorPage{expectedQueryString}";
215-
using (var server = new TestServer(builder))
216-
{
217-
218-
var client = server.CreateClient();
219-
var response = await client.GetAsync(destination);
220-
Assert.Equal(HttpStatusCode.Found, response.StatusCode);
221-
Assert.Equal(expectedUri, response.Headers.First(s => s.Key == "Location").Value.First());
222-
223-
response = await client.GetAsync(expectedUri);
224-
var content = await response.Content.ReadAsStringAsync();
225-
Assert.Equal(expectedQueryString, content);
226-
Assert.Equal(expectedQueryString, response.RequestMessage.RequestUri.Query);
227-
}
228-
}
229-
230-
[Fact]
231-
public async Task Reexecute_CanRetrieveInformationAboutOriginalRequest()
232-
{
233-
var expectedStatusCode = 432;
234-
var destination = "/location";
235-
var builder = new WebHostBuilder()
236-
.Configure(app =>
237-
{
238-
app.Use(async (context, next) =>
239-
{
240-
var beforeNext = context.Request.QueryString;
241-
await next();
242-
var afterNext = context.Request.QueryString;
243-
244-
Assert.Equal(beforeNext, afterNext);
245-
});
246-
app.UseStatusCodePagesWithReExecute(pathFormat: "/errorPage", queryFormat: "?id={0}");
247-
248-
app.Map(destination, (innerAppBuilder) =>
249-
{
250-
innerAppBuilder.Run((httpContext) =>
251-
{
252-
httpContext.Response.StatusCode = expectedStatusCode;
253-
return Task.FromResult(1);
254-
});
255-
});
256-
257-
app.Map("/errorPage", (innerAppBuilder) =>
258-
{
259-
innerAppBuilder.Run(async (httpContext) =>
260-
{
261-
var statusCodeReExecuteFeature = httpContext.Features.Get<IStatusCodeReExecuteFeature>();
262-
await httpContext.Response.WriteAsync(
263-
httpContext.Request.QueryString.Value
264-
+ ", "
265-
+ statusCodeReExecuteFeature.OriginalPath
266-
+ ", "
267-
+ statusCodeReExecuteFeature.OriginalQueryString);
268-
});
269-
});
270-
271-
app.Run((context) =>
272-
{
273-
throw new InvalidOperationException("Invalid input provided.");
274-
});
275-
});
276-
277-
using (var server = new TestServer(builder))
278-
{
279-
var client = server.CreateClient();
280-
var response = await client.GetAsync(destination + "?name=James");
281-
var content = await response.Content.ReadAsStringAsync();
282-
Assert.Equal($"?id={expectedStatusCode}, /location, ?name=James", content);
283-
}
284-
}
285-
286180
[Fact]
287181
public async Task ClearsCacheHeaders_SetByReexecutionPathHandlers()
288182
{
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
using System.Net;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Builder;
9+
using Microsoft.AspNetCore.Hosting;
10+
using Microsoft.AspNetCore.Http;
11+
using Microsoft.AspNetCore.TestHost;
12+
using Microsoft.Extensions.DependencyInjection;
13+
using Xunit;
14+
15+
namespace Microsoft.AspNetCore.Diagnostics
16+
{
17+
public class StatusCodeMiddlewareTest
18+
{
19+
[Fact]
20+
public async Task Redirect_StatusPage()
21+
{
22+
var expectedStatusCode = 432;
23+
var destination = "/location";
24+
var builder = new WebHostBuilder()
25+
.Configure(app =>
26+
{
27+
app.UseStatusCodePagesWithRedirects("/errorPage?id={0}");
28+
29+
app.Map(destination, (innerAppBuilder) =>
30+
{
31+
innerAppBuilder.Run((httpContext) =>
32+
{
33+
httpContext.Response.StatusCode = expectedStatusCode;
34+
return Task.FromResult(1);
35+
});
36+
});
37+
38+
app.Map("/errorPage", (innerAppBuilder) =>
39+
{
40+
innerAppBuilder.Run(async (httpContext) =>
41+
{
42+
await httpContext.Response.WriteAsync(httpContext.Request.QueryString.Value);
43+
});
44+
});
45+
46+
app.Run((context) =>
47+
{
48+
throw new InvalidOperationException($"Invalid input provided. {context.Request.Path}");
49+
});
50+
});
51+
var expectedQueryString = $"?id={expectedStatusCode}";
52+
var expectedUri = $"/errorPage{expectedQueryString}";
53+
using var server = new TestServer(builder);
54+
var client = server.CreateClient();
55+
var response = await client.GetAsync(destination);
56+
Assert.Equal(HttpStatusCode.Found, response.StatusCode);
57+
Assert.Equal(expectedUri, response.Headers.First(s => s.Key == "Location").Value.First());
58+
59+
response = await client.GetAsync(expectedUri);
60+
var content = await response.Content.ReadAsStringAsync();
61+
Assert.Equal(expectedQueryString, content);
62+
Assert.Equal(expectedQueryString, response.RequestMessage.RequestUri.Query);
63+
}
64+
65+
[Fact]
66+
public async Task Reexecute_CanRetrieveInformationAboutOriginalRequest()
67+
{
68+
var expectedStatusCode = 432;
69+
var destination = "/location";
70+
var builder = new WebHostBuilder()
71+
.Configure(app =>
72+
{
73+
app.Use(async (context, next) =>
74+
{
75+
var beforeNext = context.Request.QueryString;
76+
await next();
77+
var afterNext = context.Request.QueryString;
78+
79+
Assert.Equal(beforeNext, afterNext);
80+
});
81+
app.UseStatusCodePagesWithReExecute(pathFormat: "/errorPage", queryFormat: "?id={0}");
82+
83+
app.Map(destination, (innerAppBuilder) =>
84+
{
85+
innerAppBuilder.Run((httpContext) =>
86+
{
87+
httpContext.Response.StatusCode = expectedStatusCode;
88+
return Task.FromResult(1);
89+
});
90+
});
91+
92+
app.Map("/errorPage", (innerAppBuilder) =>
93+
{
94+
innerAppBuilder.Run(async (httpContext) =>
95+
{
96+
var statusCodeReExecuteFeature = httpContext.Features.Get<IStatusCodeReExecuteFeature>();
97+
await httpContext.Response.WriteAsync(
98+
httpContext.Request.QueryString.Value
99+
+ ", "
100+
+ statusCodeReExecuteFeature.OriginalPath
101+
+ ", "
102+
+ statusCodeReExecuteFeature.OriginalQueryString);
103+
});
104+
});
105+
106+
app.Run((context) =>
107+
{
108+
throw new InvalidOperationException("Invalid input provided.");
109+
});
110+
});
111+
112+
using var server = new TestServer(builder);
113+
var client = server.CreateClient();
114+
var response = await client.GetAsync(destination + "?name=James");
115+
var content = await response.Content.ReadAsStringAsync();
116+
Assert.Equal($"?id={expectedStatusCode}, /location, ?name=James", content);
117+
}
118+
119+
[Fact]
120+
public async Task Reexecute_ClearsEndpointAndRouteData()
121+
{
122+
var expectedStatusCode = 432;
123+
var destination = "/location";
124+
var builder = new WebHostBuilder()
125+
.Configure(app =>
126+
{
127+
app.UseStatusCodePagesWithReExecute(pathFormat: "/errorPage", queryFormat: "?id={0}");
128+
129+
app.Use((context, next) =>
130+
{
131+
Assert.Empty(context.Request.RouteValues);
132+
Assert.Null(context.GetEndpoint());
133+
return next();
134+
});
135+
136+
app.Map(destination, (innerAppBuilder) =>
137+
{
138+
innerAppBuilder.Run((httpContext) =>
139+
{
140+
httpContext.SetEndpoint(new Endpoint((_) => Task.CompletedTask, new EndpointMetadataCollection(), "Test"));
141+
httpContext.Request.RouteValues["John"] = "Doe";
142+
httpContext.Response.StatusCode = expectedStatusCode;
143+
return Task.CompletedTask;
144+
});
145+
});
146+
147+
app.Map("/errorPage", (innerAppBuilder) =>
148+
{
149+
innerAppBuilder.Run(async (httpContext) =>
150+
{
151+
var statusCodeReExecuteFeature = httpContext.Features.Get<IStatusCodeReExecuteFeature>();
152+
await httpContext.Response.WriteAsync(
153+
httpContext.Request.QueryString.Value
154+
+ ", "
155+
+ statusCodeReExecuteFeature.OriginalPath
156+
+ ", "
157+
+ statusCodeReExecuteFeature.OriginalQueryString);
158+
});
159+
});
160+
161+
app.Run((context) =>
162+
{
163+
throw new InvalidOperationException("Invalid input provided.");
164+
});
165+
});
166+
167+
using var server = new TestServer(builder);
168+
var client = server.CreateClient();
169+
var response = await client.GetAsync(destination + "?name=James");
170+
var content = await response.Content.ReadAsStringAsync();
171+
Assert.Equal($"?id={expectedStatusCode}, /location, ?name=James", content);
172+
}
173+
}
174+
}

0 commit comments

Comments
 (0)