@marcel91200 / caddy Mirror · read-only / commits / 07ad4655
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

rewrite: Make URI modifications more transactional (#2891)

Before, modifying the path might have affected how a new query string was built if the query string relied on the path. Now, we build each component in isolation and only change the URI on the request later. Also, prevent trailing & in query string.

Matthew Holt committed Jan 15, 2020 at 11:44 UTC 07ad4655db5d37635edf36fa91d997d166d306b0
2 files changed +31 -5
modules/caddyhttp/rewrite/rewrite.go
+21 -5
@@ -112,7 +112,7 @@ func (rewr Rewrite) rewrite(r *http.Request, repl *caddy.Replacer, logger *zap.L
112 r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, ""))
113 }
114
115 - // uri (path, query string, and fragment just because)
115 + // uri (path, query string, and fragment... because why not)
116 if uri := rewr.URI; uri != "" {
117 // find the bounds of each part of the URI that exist
118 pathStart, qsStart, fragStart := -1, -1, -1
@@ -134,14 +134,30 @@ func (rewr Rewrite) rewrite(r *http.Request, repl *caddy.Replacer, logger *zap.L
134 qsEnd = len(uri)
135 }
136
137 + // build components which are specified, and store them
138 + // in a temporary variable so that they all read the
139 + // same version of the URI
140 + var newPath, newQuery, newFrag string
141 if pathStart >= 0 {
138 - r.URL.Path = repl.ReplaceAll(uri[pathStart:pathEnd], "")
142 + newPath = repl.ReplaceAll(uri[pathStart:pathEnd], "")
143 }
144 if qsStart >= 0 {
141 - r.URL.RawQuery = buildQueryString(uri[qsStart:qsEnd], repl)
145 + newQuery = buildQueryString(uri[qsStart:qsEnd], repl)
146 }
147 if fragStart >= 0 {
144 - r.URL.Fragment = repl.ReplaceAll(uri[fragStart:], "")
148 + newFrag = repl.ReplaceAll(uri[fragStart:], "")
149 + }
150 +
151 + // update the URI with the new components
152 + // only after building them
153 + if pathStart >= 0 {
154 + r.URL.Path = newPath
155 + }
156 + if qsStart >= 0 {
157 + r.URL.RawQuery = newQuery
158 + }
159 + if fragStart >= 0 {
160 + r.URL.Fragment = newFrag
161 }
162 }
163
@@ -206,7 +222,7 @@ func buildQueryString(qs string, repl *caddy.Replacer) string {
222 // if previous iteration wrote a value,
223 // that means we are writing a key
224 if wroteVal {
209 - if sb.Len() > 0 {
225 + if sb.Len() > 0 && len(comp) > 0 {
226 sb.WriteRune('&')
227 }
228 } else {
modules/caddyhttp/rewrite/rewrite_test.go
+10
@@ -63,6 +63,16 @@ func TestRewrite(t *testing.T) {
63 input: newRequest(t, "GET", "/bar"),
64 expect: newRequest(t, "GET", "/foo/bar"),
65 },
66 + {
67 + rule: Rewrite{URI: "/index.php?p={http.request.uri.path}"},
68 + input: newRequest(t, "GET", "/foo/bar"),
69 + expect: newRequest(t, "GET", "/index.php?p=%2Ffoo%2Fbar"),
70 + },
71 + {
72 + rule: Rewrite{URI: "?a=b&{http.request.uri.query}"},
73 + input: newRequest(t, "GET", "/"),
74 + expect: newRequest(t, "GET", "/?a=b"),
75 + },
76 {
77 rule: Rewrite{URI: "/?c=d"},
78 input: newRequest(t, "GET", "/"),