Skip to content

Commit 4cee78f

Browse files
authored
Fix #3500 Add escape logic for header (#3503)
1 parent fc1c432 commit 4cee78f

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

gin.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import (
99
"html/template"
1010
"net"
1111
"net/http"
12-
"net/url"
1312
"os"
1413
"path"
14+
"regexp"
1515
"strings"
1616
"sync"
1717

@@ -41,6 +41,9 @@ var defaultTrustedCIDRs = []*net.IPNet{
4141
},
4242
}
4343

44+
var regSafePrefix = regexp.MustCompile("[^a-zA-Z0-9/-]+")
45+
var regRemoveRepeatedChar = regexp.MustCompile("/{2,}")
46+
4447
// HandlerFunc defines the handler used by gin middleware as return value.
4548
type HandlerFunc func(*Context)
4649

@@ -669,8 +672,8 @@ func redirectTrailingSlash(c *Context) {
669672
req := c.Request
670673
p := req.URL.Path
671674
if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." {
672-
prefix = url.QueryEscape(prefix)
673-
prefix = strings.ReplaceAll(prefix, "%2F", "/")
675+
prefix = regSafePrefix.ReplaceAllString(prefix, "")
676+
prefix = regRemoveRepeatedChar.ReplaceAllString(prefix, "/")
674677

675678
p = prefix + "/" + req.URL.Path
676679
}

routes_test.go

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,52 @@ func TestRouteRedirectTrailingSlash(t *testing.T) {
185185
w = PerformRequest(router, http.MethodGet, "/path2/", header{Key: "X-Forwarded-Prefix", Value: "/api/"})
186186
assert.Equal(t, 200, w.Code)
187187

188-
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "../../bug#?"})
189-
assert.Equal(t, "../../../bug%2523%253F/path", w.Header().Get("Location"))
188+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "../../api#?"})
189+
assert.Equal(t, "/api/path", w.Header().Get("Location"))
190+
assert.Equal(t, 301, w.Code)
191+
192+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "../../api"})
193+
assert.Equal(t, "/api/path", w.Header().Get("Location"))
194+
assert.Equal(t, 301, w.Code)
195+
196+
w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "../../api"})
197+
assert.Equal(t, "/api/path2/", w.Header().Get("Location"))
198+
assert.Equal(t, 301, w.Code)
199+
200+
w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/../../api"})
201+
assert.Equal(t, "/api/path2/", w.Header().Get("Location"))
202+
assert.Equal(t, 301, w.Code)
203+
204+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "api/../../"})
205+
assert.Equal(t, "//path", w.Header().Get("Location"))
206+
assert.Equal(t, 301, w.Code)
207+
208+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "api/../../../"})
209+
assert.Equal(t, "/path", w.Header().Get("Location"))
210+
assert.Equal(t, 301, w.Code)
211+
212+
w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "../../gin-gonic.com"})
213+
assert.Equal(t, "/gin-goniccom/path2/", w.Header().Get("Location"))
214+
assert.Equal(t, 301, w.Code)
215+
216+
w = PerformRequest(router, http.MethodGet, "/path2", header{Key: "X-Forwarded-Prefix", Value: "/../../gin-gonic.com"})
217+
assert.Equal(t, "/gin-goniccom/path2/", w.Header().Get("Location"))
190218
assert.Equal(t, 301, w.Code)
191219

192220
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "https://gin-gonic.com/#"})
193-
assert.Equal(t, "https%3A/gin-gonic.com/%23/https%253A/gin-gonic.com/%2523/path", w.Header().Get("Location"))
221+
assert.Equal(t, "https/gin-goniccom/https/gin-goniccom/path", w.Header().Get("Location"))
222+
assert.Equal(t, 301, w.Code)
223+
224+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "#api"})
225+
assert.Equal(t, "api/api/path", w.Header().Get("Location"))
226+
assert.Equal(t, 301, w.Code)
227+
228+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "/nor-mal/#?a=1"})
229+
assert.Equal(t, "/nor-mal/a1/path", w.Header().Get("Location"))
194230
assert.Equal(t, 301, w.Code)
195231

196-
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "#bug"})
197-
assert.Equal(t, "%23bug/%2523bug/path", w.Header().Get("Location"))
232+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "/nor-mal/%2e%2e/"})
233+
assert.Equal(t, "/nor-mal/2e2e/path", w.Header().Get("Location"))
198234
assert.Equal(t, 301, w.Code)
199235

200236
router.RedirectTrailingSlash = false

0 commit comments

Comments
 (0)