Allow query string on ReExecuting status code page

This commit is contained in:
Ryan Brandenburg 2016-04-25 15:08:40 -07:00
parent 0ed54e9165
commit 48b436ec8a
3 changed files with 116 additions and 2 deletions

View File

@ -158,8 +158,12 @@ namespace Microsoft.AspNetCore.Builder
/// </summary>
/// <param name="app"></param>
/// <param name="pathFormat"></param>
/// <param name="queryFormat"></param>
/// <returns></returns>
public static IApplicationBuilder UseStatusCodePagesWithReExecute(this IApplicationBuilder app, string pathFormat)
public static IApplicationBuilder UseStatusCodePagesWithReExecute(
this IApplicationBuilder app,
string pathFormat,
string queryFormat = null)
{
if (app == null)
{
@ -168,23 +172,31 @@ namespace Microsoft.AspNetCore.Builder
return app.UseStatusCodePages(async context =>
{
var newPath = new PathString(string.Format(CultureInfo.InvariantCulture, pathFormat, context.HttpContext.Response.StatusCode));
var newPath = new PathString(
string.Format(CultureInfo.InvariantCulture, pathFormat, context.HttpContext.Response.StatusCode));
var formatedQueryString = queryFormat == null ? null :
string.Format(CultureInfo.InvariantCulture, queryFormat, context.HttpContext.Response.StatusCode);
var newQueryString = queryFormat == null ? QueryString.Empty : new QueryString(formatedQueryString);
var originalPath = context.HttpContext.Request.Path;
var originalQueryString = context.HttpContext.Request.QueryString;
// Store the original paths so the app can check it.
context.HttpContext.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
{
OriginalPathBase = context.HttpContext.Request.PathBase.Value,
OriginalPath = originalPath.Value,
OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
});
context.HttpContext.Request.Path = newPath;
context.HttpContext.Request.QueryString = newQueryString;
try
{
await context.Next(context.HttpContext);
}
finally
{
context.HttpContext.Request.QueryString = originalQueryString;
context.HttpContext.Request.Path = originalPath;
context.HttpContext.Features.Set<IStatusCodeReExecuteFeature>(null);
}

View File

@ -8,5 +8,7 @@ namespace Microsoft.AspNetCore.Diagnostics
public string OriginalPath { get; set; }
public string OriginalPathBase { get; set; }
public string OriginalQueryString { get; set; }
}
}

View File

@ -175,6 +175,106 @@ namespace Microsoft.AspNetCore.Diagnostics
}
}
[Fact]
public async Task Redirect_StatusPage()
{
var expectedStatusCode = 432;
var destination = "/location";
var builder = new WebHostBuilder()
.Configure(app =>
{
app.UseStatusCodePagesWithRedirects("/errorPage?id={0}");
app.Map(destination, (innerAppBuilder) =>
{
innerAppBuilder.Run((httpContext) =>
{
httpContext.Response.StatusCode = expectedStatusCode;
return Task.FromResult(1);
});
});
app.Map("/errorPage", (innerAppBuilder) =>
{
innerAppBuilder.Run(async (httpContext) =>
{
await httpContext.Response.WriteAsync(httpContext.Request.QueryString.Value);
});
});
app.Run((context) =>
{
throw new InvalidOperationException($"Invalid input provided. {context.Request.Path}");
});
});
var expectedQueryString = $"?id={expectedStatusCode}";
var expectedUri = $"/errorPage{expectedQueryString}";
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var response = await client.GetAsync(destination);
Assert.Equal(HttpStatusCode.Found, response.StatusCode);
Assert.Equal(expectedUri, response.Headers.First(s => s.Key == "Location").Value.First());
response = await client.GetAsync(expectedUri);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal(expectedQueryString, content);
Assert.Equal(expectedQueryString, response.RequestMessage.RequestUri.Query);
}
}
[Fact]
public async Task Reexecute_RequestWithQueryString()
{
var expectedStatusCode = 432;
var destination = "/location";
var builder = new WebHostBuilder()
.Configure(app =>
{
app.Use(async (context, next) =>
{
var beforeNext = context.Request.QueryString;
await next();
var afterNext = context.Request.QueryString;
Assert.Equal(beforeNext, afterNext);
});
app.UseStatusCodePagesWithReExecute("/errorPage", "?id={0}");
app.Map(destination, (innerAppBuilder) =>
{
innerAppBuilder.Run((httpContext) =>
{
httpContext.Response.StatusCode = expectedStatusCode;
return Task.FromResult(1);
});
});
app.Map("/errorPage", (innerAppBuilder) =>
{
innerAppBuilder.Run(async (httpContext) =>
{
await httpContext.Response.WriteAsync(httpContext.Request.QueryString.Value);
});
});
app.Run((context) =>
{
throw new InvalidOperationException("Invalid input provided.");
});
});
using (var server = new TestServer(builder))
{
var client = server.CreateClient();
var response = await client.GetAsync(destination);
var content = await response.Content.ReadAsStringAsync();
Assert.Equal($"?id={expectedStatusCode}", content);
}
}
[Fact]
public async Task ClearsCacheHeaders_SetByReexecutionPathHandlers()
{