Skip to content

Commit da81c67

Browse files
Call next middleware correctly for rewrite with skip (#35708)
1 parent 67f3bef commit da81c67

File tree

2 files changed

+264
-19
lines changed

2 files changed

+264
-19
lines changed

src/Middleware/Rewrite/src/RewriteMiddleware.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,25 +76,10 @@ public Task Invoke(HttpContext context)
7676

7777
var originalPath = context.Request.Path;
7878

79-
foreach (var rule in _options.Rules)
79+
RunRules(rewriteContext, _options, context, _logger);
80+
if (rewriteContext.Result == RuleResult.EndResponse)
8081
{
81-
rule.ApplyRule(rewriteContext);
82-
switch (rewriteContext.Result)
83-
{
84-
case RuleResult.ContinueRules:
85-
_logger.RewriteMiddlewareRequestContinueResults(context.Request.GetEncodedUrl());
86-
break;
87-
case RuleResult.EndResponse:
88-
_logger.RewriteMiddlewareRequestResponseComplete(
89-
context.Response.Headers.Location,
90-
context.Response.StatusCode);
91-
return Task.CompletedTask;
92-
case RuleResult.SkipRemainingRules:
93-
_logger.RewriteMiddlewareRequestStopRules(context.Request.GetEncodedUrl());
94-
return _next(context);
95-
default:
96-
throw new ArgumentOutOfRangeException($"Invalid rule termination {rewriteContext.Result}");
97-
}
82+
return Task.CompletedTask;
9883
}
9984

10085
// If a rule changed the path we want routing to find a new endpoint
@@ -116,5 +101,29 @@ public Task Invoke(HttpContext context)
116101

117102
return _next(context);
118103
}
104+
105+
static void RunRules(RewriteContext rewriteContext, RewriteOptions options, HttpContext httpContext, ILogger logger)
106+
{
107+
foreach (var rule in options.Rules)
108+
{
109+
rule.ApplyRule(rewriteContext);
110+
switch (rewriteContext.Result)
111+
{
112+
case RuleResult.ContinueRules:
113+
logger.RewriteMiddlewareRequestContinueResults(httpContext.Request.GetEncodedUrl());
114+
break;
115+
case RuleResult.EndResponse:
116+
logger.RewriteMiddlewareRequestResponseComplete(
117+
httpContext.Response.Headers.Location,
118+
httpContext.Response.StatusCode);
119+
return;
120+
case RuleResult.SkipRemainingRules:
121+
logger.RewriteMiddlewareRequestStopRules(httpContext.Request.GetEncodedUrl());
122+
return;
123+
default:
124+
throw new ArgumentOutOfRangeException($"Invalid rule termination {rewriteContext.Result}");
125+
}
126+
}
127+
}
119128
}
120129
}

src/Middleware/Rewrite/test/MiddlewareTests.cs

Lines changed: 237 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,100 @@ public async Task CheckRewritePath()
4747
Assert.Equal("http://example.com/foo", response);
4848
}
4949

50+
[Fact]
51+
public async Task CheckRewritePathWithSkipRemaining()
52+
{
53+
var options = new RewriteOptions().AddRewrite("(.*)", "http://example.com/$1", skipRemainingRules: true);
54+
using var host = new HostBuilder()
55+
.ConfigureWebHost(webHostBuilder =>
56+
{
57+
webHostBuilder
58+
.UseTestServer()
59+
.Configure(app =>
60+
{
61+
app.UseRewriter(options);
62+
app.Run(context => context.Response.WriteAsync(
63+
context.Request.Scheme +
64+
"://" +
65+
context.Request.Host +
66+
context.Request.Path +
67+
context.Request.QueryString));
68+
});
69+
}).Build();
70+
71+
await host.StartAsync();
72+
73+
var server = host.GetTestServer();
74+
75+
var response = await server.CreateClient().GetStringAsync("foo");
76+
77+
Assert.Equal("http://example.com/foo", response);
78+
}
79+
80+
[Fact]
81+
public async Task CheckRewritePath_MultipleRulesWithSkipRemaining()
82+
{
83+
var options = new RewriteOptions()
84+
.AddRewrite("(.*)", "http://example.com/$1", skipRemainingRules: true)
85+
.AddRewrite("(.*)", "http://example.com/42", skipRemainingRules: false);
86+
using var host = new HostBuilder()
87+
.ConfigureWebHost(webHostBuilder =>
88+
{
89+
webHostBuilder
90+
.UseTestServer()
91+
.Configure(app =>
92+
{
93+
app.UseRewriter(options);
94+
app.Run(context => context.Response.WriteAsync(
95+
context.Request.Scheme +
96+
"://" +
97+
context.Request.Host +
98+
context.Request.Path +
99+
context.Request.QueryString));
100+
});
101+
}).Build();
102+
103+
await host.StartAsync();
104+
105+
var server = host.GetTestServer();
106+
107+
var response = await server.CreateClient().GetStringAsync("foo");
108+
109+
Assert.Equal("http://example.com/foo", response);
110+
}
111+
112+
[Fact]
113+
public async Task CheckRewritePath_MultipleRules()
114+
{
115+
var options = new RewriteOptions()
116+
.AddRewrite("(.*)", "http://example.com/$1s", skipRemainingRules: false)
117+
.AddRewrite("(.*)", "http://example.com/$1/42", skipRemainingRules: false);
118+
using var host = new HostBuilder()
119+
.ConfigureWebHost(webHostBuilder =>
120+
{
121+
webHostBuilder
122+
.UseTestServer()
123+
.Configure(app =>
124+
{
125+
app.UseRewriter(options);
126+
app.Run(context => context.Response.WriteAsync(
127+
context.Request.Scheme +
128+
"://" +
129+
context.Request.Host +
130+
context.Request.Path +
131+
context.Request.QueryString));
132+
});
133+
}).Build();
134+
135+
await host.StartAsync();
136+
137+
var server = host.GetTestServer();
138+
139+
var response = await server.CreateClient().GetStringAsync("foo");
140+
141+
Assert.Equal("http://example.com/foos/42", response);
142+
}
143+
50144
[Theory]
51145
[InlineData("(.*)", "http://example.com/$1", null, "path", "http://example.com/path")]
52146
[InlineData("(.*)", "http://example.com", null, "", "http://example.com/")]
@@ -766,8 +860,8 @@ public async Task RewriteFromOptions_WorksAfterUseRoutingIfGlobalRouteBuilderUse
766860
options.AddRewrite(regex, "http://example.com/g", skipRemainingRules: false);
767861
});
768862
await using var app = builder.Build();
769-
app.UseRouting();
770863

864+
app.UseRouting();
771865
app.UseRewriter();
772866

773867
app.UseEndpoints(endpoints =>
@@ -791,5 +885,147 @@ public async Task RewriteFromOptions_WorksAfterUseRoutingIfGlobalRouteBuilderUse
791885

792886
Assert.Equal(output, response);
793887
}
888+
889+
[Fact]
890+
public async Task RewriteSkipRemaing_WorksAfterUseRoutingIfGlobalRouteBuilderUsed()
891+
{
892+
var builder = WebApplication.CreateBuilder();
893+
builder.WebHost.UseTestServer();
894+
builder.Services.Configure<RewriteOptions>(options =>
895+
{
896+
options.AddRewrite("(.*)", "http://example.com/g", skipRemainingRules: true);
897+
});
898+
await using var app = builder.Build();
899+
app.UseRouting();
900+
901+
app.UseRewriter();
902+
903+
app.UseEndpoints(endpoints =>
904+
{
905+
endpoints.MapGet("/foo", context => context.Response.WriteAsync(
906+
"no rule"));
907+
908+
endpoints.MapGet("/g", context => context.Response.WriteAsync(
909+
context.Request.Scheme +
910+
"://" +
911+
context.Request.Host +
912+
context.Request.Path +
913+
context.Request.QueryString));
914+
});
915+
916+
await app.StartAsync();
917+
918+
var server = app.GetTestServer();
919+
920+
var response = await server.CreateClient().GetStringAsync("foo");
921+
922+
Assert.Equal("http://example.com/g", response);
923+
}
924+
925+
[Fact]
926+
public async Task RewriteWithMultipleRules_WorksAfterUseRoutingIfGlobalRouteBuilderUsed()
927+
{
928+
var builder = WebApplication.CreateBuilder();
929+
builder.WebHost.UseTestServer();
930+
builder.Services.Configure<RewriteOptions>(options =>
931+
{
932+
options.AddRewrite("(.*)", "http://example.com/g", skipRemainingRules: false)
933+
.AddRewrite("(.*)", "http://example.com/$1/h", skipRemainingRules: false);
934+
});
935+
await using var app = builder.Build();
936+
app.UseRouting();
937+
938+
app.UseRewriter();
939+
940+
app.UseEndpoints(endpoints =>
941+
{
942+
endpoints.MapGet("/foo", context => context.Response.WriteAsync(
943+
"no rule"));
944+
945+
endpoints.MapGet("/g/h", context => context.Response.WriteAsync(
946+
context.Request.Scheme +
947+
"://" +
948+
context.Request.Host +
949+
context.Request.Path +
950+
context.Request.QueryString));
951+
});
952+
953+
await app.StartAsync();
954+
955+
var server = app.GetTestServer();
956+
957+
var response = await server.CreateClient().GetStringAsync("foo");
958+
959+
Assert.Equal("http://example.com/g/h", response);
960+
}
961+
962+
[Fact]
963+
public async Task RewriteWithMultipleRulesAndSkip_WorksAfterUseRoutingIfGlobalRouteBuilderUsed()
964+
{
965+
var builder = WebApplication.CreateBuilder();
966+
builder.WebHost.UseTestServer();
967+
builder.Services.Configure<RewriteOptions>(options =>
968+
{
969+
options.AddRewrite("(.*)", "http://example.com/g", skipRemainingRules: true)
970+
.AddRewrite("(.*)", "http://example.com/$1/h", skipRemainingRules: false);
971+
});
972+
await using var app = builder.Build();
973+
app.UseRouting();
974+
975+
app.UseRewriter();
976+
977+
app.UseEndpoints(endpoints =>
978+
{
979+
endpoints.MapGet("/foo", context => context.Response.WriteAsync(
980+
"no rule"));
981+
982+
endpoints.MapGet("/g", context => context.Response.WriteAsync(
983+
context.Request.Scheme +
984+
"://" +
985+
context.Request.Host +
986+
context.Request.Path +
987+
context.Request.QueryString));
988+
});
989+
990+
await app.StartAsync();
991+
992+
var server = app.GetTestServer();
993+
994+
var response = await server.CreateClient().GetStringAsync("foo");
995+
996+
Assert.Equal("http://example.com/g", response);
997+
}
998+
999+
[Fact]
1000+
public async Task Rewrite_WorksWithoutUseRoutingWithWebApplication()
1001+
{
1002+
var builder = WebApplication.CreateBuilder();
1003+
builder.WebHost.UseTestServer();
1004+
builder.Services.Configure<RewriteOptions>(options =>
1005+
{
1006+
options.AddRewrite("(.*)", "http://example.com/g", skipRemainingRules: true);
1007+
});
1008+
await using var app = builder.Build();
1009+
1010+
app.UseRewriter();
1011+
1012+
app.MapGet("/foo", context => context.Response.WriteAsync(
1013+
"no rule"));
1014+
1015+
app.MapGet("/g", context => context.Response.WriteAsync(
1016+
context.Request.Scheme +
1017+
"://" +
1018+
context.Request.Host +
1019+
context.Request.Path +
1020+
context.Request.QueryString));
1021+
1022+
await app.StartAsync();
1023+
1024+
var server = app.GetTestServer();
1025+
1026+
var response = await server.CreateClient().GetStringAsync("foo");
1027+
1028+
Assert.Equal("http://example.com/g", response);
1029+
}
7941030
}
7951031
}

0 commit comments

Comments
 (0)