Skip to content

Commit 6e8f186

Browse files
committed
Fix gin-gonic#3500 Add escape logic for header
1 parent 81ac7d5 commit 6e8f186

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed

gin.go

Lines changed: 12 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

@@ -669,8 +669,9 @@ func redirectTrailingSlash(c *Context) {
669669
req := c.Request
670670
p := req.URL.Path
671671
if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." {
672-
prefix = url.QueryEscape(prefix)
673-
prefix = strings.ReplaceAll(prefix, "%2F", "/")
672+
reg := regexp.MustCompile("[^a-zA-Z0-9/-]+")
673+
prefix = reg.ReplaceAllString(prefix, "")
674+
prefix := removeRepeatedChar(prefix, '/')
674675

675676
p = prefix + "/" + req.URL.Path
676677
}
@@ -706,3 +707,11 @@ func redirectRequest(c *Context) {
706707
http.Redirect(c.Writer, req, rURL, code)
707708
c.writermem.WriteHeaderNow()
708709
}
710+
711+
func removeRepeatedChar(s string, c rune) string {
712+
re := regexp.MustCompile(fmt.Sprintf("%c{2,}", c))
713+
result := re.ReplaceAllStringFunc(s, func(match string) string {
714+
return string(c)
715+
})
716+
return result
717+
}

routes_test.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,28 @@ 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"))
190198
assert.Equal(t, 301, w.Code)
191199

192200
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"))
201+
assert.Equal(t, "https/gin-goniccom/https/gin-goniccom/path", 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, "api/api/path", w.Header().Get("Location"))
194206
assert.Equal(t, 301, w.Code)
195207

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"))
208+
w = PerformRequest(router, http.MethodGet, "/path/", header{Key: "X-Forwarded-Prefix", Value: "/nor-mal/#?a=1"})
209+
assert.Equal(t, "/nor-mal/a1/path", w.Header().Get("Location"))
198210
assert.Equal(t, 301, w.Code)
199211

200212
router.RedirectTrailingSlash = false

0 commit comments

Comments
 (0)