mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-05 08:38:26 +03:00
rewrite: Fix for rewrites with URI placeholders (#3209)
If a placeholder in the path component injects a query string such as the {http.request.uri} placeholder is wont to do, we need to separate it out from the path.
This commit is contained in:
parent
9fb0b1e838
commit
809e72792c
2 changed files with 63 additions and 7 deletions
|
@ -114,7 +114,7 @@ func (rewr Rewrite) rewrite(r *http.Request, repl *caddy.Replacer, logger *zap.L
|
||||||
r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, ""))
|
r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
// uri (path, query string, and fragment... because why not)
|
// uri (path, query string and... fragment, because why not)
|
||||||
if uri := rewr.URI; uri != "" {
|
if uri := rewr.URI; uri != "" {
|
||||||
// find the bounds of each part of the URI that exist
|
// find the bounds of each part of the URI that exist
|
||||||
pathStart, qsStart, fragStart := -1, -1, -1
|
pathStart, qsStart, fragStart := -1, -1, -1
|
||||||
|
@ -136,18 +136,43 @@ func (rewr Rewrite) rewrite(r *http.Request, repl *caddy.Replacer, logger *zap.L
|
||||||
qsEnd = len(uri)
|
qsEnd = len(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isolate the three main components of the URI
|
||||||
|
var path, query, frag string
|
||||||
|
if pathStart > -1 {
|
||||||
|
path = uri[pathStart:pathEnd]
|
||||||
|
}
|
||||||
|
if qsStart > -1 {
|
||||||
|
query = uri[qsStart:qsEnd]
|
||||||
|
}
|
||||||
|
if fragStart > -1 {
|
||||||
|
frag = uri[fragStart:]
|
||||||
|
}
|
||||||
|
|
||||||
// build components which are specified, and store them
|
// build components which are specified, and store them
|
||||||
// in a temporary variable so that they all read the
|
// in a temporary variable so that they all read the
|
||||||
// same version of the URI
|
// same version of the URI
|
||||||
var newPath, newQuery, newFrag string
|
var newPath, newQuery, newFrag string
|
||||||
if pathStart >= 0 {
|
if path != "" {
|
||||||
newPath = repl.ReplaceAll(uri[pathStart:pathEnd], "")
|
newPath = repl.ReplaceAll(path, "")
|
||||||
}
|
}
|
||||||
if qsStart >= 0 {
|
|
||||||
newQuery = buildQueryString(uri[qsStart:qsEnd], repl)
|
// before continuing, we need to check if a query string
|
||||||
|
// snuck into the path component during replacements
|
||||||
|
if quPos := strings.Index(newPath, "?"); quPos > -1 {
|
||||||
|
// recompute; new path contains a query string
|
||||||
|
var injectedQuery string
|
||||||
|
newPath, injectedQuery = newPath[:quPos], newPath[quPos+1:]
|
||||||
|
// don't overwrite explicitly-configured query string
|
||||||
|
if query == "" {
|
||||||
|
query = injectedQuery
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if fragStart >= 0 {
|
|
||||||
newFrag = repl.ReplaceAll(uri[fragStart:], "")
|
if query != "" {
|
||||||
|
newQuery = buildQueryString(query, repl)
|
||||||
|
}
|
||||||
|
if frag != "" {
|
||||||
|
newFrag = repl.ReplaceAll(frag, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the URI with the new components
|
// update the URI with the new components
|
||||||
|
|
|
@ -158,6 +158,36 @@ func TestRewrite(t *testing.T) {
|
||||||
input: newRequest(t, "GET", "/foo/bar?a=b"),
|
input: newRequest(t, "GET", "/foo/bar?a=b"),
|
||||||
expect: newRequest(t, "GET", "/foo?a=b#frag"),
|
expect: newRequest(t, "GET", "/foo?a=b#frag"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
rule: Rewrite{URI: "/foo{http.request.uri}"},
|
||||||
|
input: newRequest(t, "GET", "/bar?a=b"),
|
||||||
|
expect: newRequest(t, "GET", "/foo/bar?a=b"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: Rewrite{URI: "/foo{http.request.uri}"},
|
||||||
|
input: newRequest(t, "GET", "/bar"),
|
||||||
|
expect: newRequest(t, "GET", "/foo/bar"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: Rewrite{URI: "/foo{http.request.uri}?c=d"},
|
||||||
|
input: newRequest(t, "GET", "/bar?a=b"),
|
||||||
|
expect: newRequest(t, "GET", "/foo/bar?c=d"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: Rewrite{URI: "/foo{http.request.uri}?{http.request.uri.query}&c=d"},
|
||||||
|
input: newRequest(t, "GET", "/bar?a=b"),
|
||||||
|
expect: newRequest(t, "GET", "/foo/bar?a=b&c=d"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: Rewrite{URI: "{http.request.uri}"},
|
||||||
|
input: newRequest(t, "GET", "/bar?a=b"),
|
||||||
|
expect: newRequest(t, "GET", "/bar?a=b"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: Rewrite{URI: "{http.request.uri.path}bar?c=d"},
|
||||||
|
input: newRequest(t, "GET", "/foo/?a=b"),
|
||||||
|
expect: newRequest(t, "GET", "/foo/bar?c=d"),
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
rule: Rewrite{StripPathPrefix: "/prefix"},
|
rule: Rewrite{StripPathPrefix: "/prefix"},
|
||||||
|
@ -211,6 +241,7 @@ func TestRewrite(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate the replacer just enough for our tests
|
// populate the replacer just enough for our tests
|
||||||
|
repl.Set("http.request.uri", tc.input.RequestURI)
|
||||||
repl.Set("http.request.uri.path", tc.input.URL.Path)
|
repl.Set("http.request.uri.path", tc.input.URL.Path)
|
||||||
repl.Set("http.request.uri.query", tc.input.URL.RawQuery)
|
repl.Set("http.request.uri.query", tc.input.URL.RawQuery)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue