44using System ;
55using System . Text . RegularExpressions ;
66using Microsoft . AspNetCore . Http ;
7- using Microsoft . Net . Http . Headers ;
7+ using Microsoft . AspNetCore . Http . Extensions ;
88using Microsoft . AspNetCore . Rewrite . Logging ;
9+ using Microsoft . Net . Http . Headers ;
910
1011namespace Microsoft . AspNetCore . Rewrite
1112{
@@ -34,13 +35,14 @@ public RedirectRule(string regex, string replacement, int statusCode)
3435
3536 public virtual void ApplyRule ( RewriteContext context )
3637 {
37- var path = context . HttpContext . Request . Path ;
38- var pathBase = context . HttpContext . Request . PathBase ;
38+ var request = context . HttpContext . Request ;
39+ var path = request . Path ;
40+ var pathBase = request . PathBase ;
3941
4042 Match initMatchResults ;
41- if ( path == PathString . Empty )
43+ if ( ! path . HasValue )
4244 {
43- initMatchResults = InitialMatch . Match ( path . ToString ( ) ) ;
45+ initMatchResults = InitialMatch . Match ( string . Empty ) ;
4446 }
4547 else
4648 {
@@ -56,31 +58,55 @@ public virtual void ApplyRule(RewriteContext context)
5658 response . StatusCode = StatusCode ;
5759 context . Result = RuleResult . EndResponse ;
5860
59- if ( string . IsNullOrEmpty ( newPath ) )
60- {
61- response . Headers [ HeaderNames . Location ] = pathBase . HasValue ? pathBase . Value : "/" ;
62- return ;
63- }
64-
65- if ( newPath . IndexOf ( Uri . SchemeDelimiter , StringComparison . Ordinal ) == - 1 && newPath [ 0 ] != '/' )
66- {
67- newPath = '/' + newPath ;
68- }
61+ string encodedPath ;
6962
70- var split = newPath . IndexOf ( '?' ) ;
71- if ( split >= 0 )
63+ if ( string . IsNullOrEmpty ( newPath ) )
7264 {
73- var query = context . HttpContext . Request . QueryString . Add (
74- QueryString . FromUriComponent (
75- newPath . Substring ( split ) ) ) ;
76- // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308
77- response . Headers [ HeaderNames . Location ] = pathBase + newPath . Substring ( 0 , split ) + query . ToUriComponent ( ) ;
65+ encodedPath = pathBase . HasValue ? pathBase . Value : "/" ;
7866 }
7967 else
8068 {
81- response . Headers [ HeaderNames . Location ] = pathBase + newPath + context . HttpContext . Request . QueryString . ToUriComponent ( ) ;
69+ var host = default ( HostString ) ;
70+ var schemeSplit = newPath . IndexOf ( Uri . SchemeDelimiter , StringComparison . Ordinal ) ;
71+ if ( schemeSplit >= 0 )
72+ {
73+ schemeSplit += Uri . SchemeDelimiter . Length ;
74+ var pathSplit = newPath . IndexOf ( '/' , schemeSplit ) ;
75+
76+ if ( pathSplit == - 1 )
77+ {
78+ host = new HostString ( newPath . Substring ( schemeSplit ) ) ;
79+ newPath = "/" ;
80+ }
81+ else
82+ {
83+ host = new HostString ( newPath . Substring ( schemeSplit , pathSplit - schemeSplit ) ) ;
84+ newPath = newPath . Substring ( pathSplit ) ;
85+ }
86+ }
87+
88+ if ( newPath [ 0 ] != '/' )
89+ {
90+ newPath = '/' + newPath ;
91+ }
92+
93+ var resolvedQuery = request . QueryString ;
94+ var resolvedPath = newPath ;
95+ var querySplit = newPath . IndexOf ( '?' ) ;
96+ if ( querySplit >= 0 )
97+ {
98+ resolvedQuery = request . QueryString . Add ( QueryString . FromUriComponent ( newPath . Substring ( querySplit ) ) ) ;
99+ resolvedPath = newPath . Substring ( 0 , querySplit ) ;
100+ }
101+
102+ encodedPath = host . HasValue
103+ ? UriHelper . BuildAbsolute ( request . Scheme , host , pathBase , resolvedPath , resolvedQuery , default )
104+ : UriHelper . BuildRelative ( pathBase , resolvedPath , resolvedQuery , default ) ;
82105 }
83106
107+ // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308
108+ response . Headers [ HeaderNames . Location ] = encodedPath ;
109+
84110 context . Logger . RedirectedRequest ( newPath ) ;
85111 }
86112 }
0 commit comments