Skip to content

Commit

Permalink
fix: compare RawPath and EscapedPath() without case-sensitivity to so…
Browse files Browse the repository at this point in the history
…lve infinite redirection
  • Loading branch information
iIIusi0n committed Nov 11, 2024
1 parent c8a3adc commit 189f23f
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
45 changes: 44 additions & 1 deletion gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"html/template"
"net"
"net/http"
"net/url"
"os"
"path"
"regexp"
Expand Down Expand Up @@ -643,11 +644,53 @@ func (engine *Engine) HandleContext(c *Context) {
c.index = oldIndexValue
}

// compareRawWithEscaped compares the RawPath with the EscapedPath of a URL.
// It returns true if they are equal, false otherwise.
func compareRawWithEscaped(url *url.URL) bool {
rawPath := url.RawPath
escapedPath := url.EscapedPath()

if len(rawPath) != len(escapedPath) {
return false
}

for i := 0; i < len(rawPath); i++ {
if rawPath[i] != escapedPath[i] {
return false
}

if rawPath[i] == '%' && i+2 < len(rawPath) {
var diff byte
if rawPath[i+1] > escapedPath[i+1] {
diff = rawPath[i+1] - escapedPath[i+1]
} else {
diff = escapedPath[i+1] - rawPath[i+1]
}
if diff != 0 && diff != 32 {
return false
}

if rawPath[i+2] > escapedPath[i+2] {
diff = rawPath[i+2] - escapedPath[i+2]
} else {
diff = escapedPath[i+2] - rawPath[i+2]
}
if diff != 0 && diff != 32 {
return false
}

i += 2
}
}

return true
}

func (engine *Engine) handleHTTPRequest(c *Context) {
httpMethod := c.Request.Method
rPath := c.Request.URL.Path
unescape := false
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 && !compareRawWithEscaped(c.Request.URL) {
rPath = c.Request.URL.RawPath
unescape = engine.UnescapePathValues
}
Expand Down
16 changes: 16 additions & 0 deletions gin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -766,3 +766,19 @@ func TestMethodNotAllowedNoRoute(t *testing.T) {
assert.NotPanics(t, func() { g.ServeHTTP(resp, req) })
assert.Equal(t, http.StatusNotFound, resp.Code)
}

// Test the fix for https://github.com/gin-gonic/gin/issues/4034
func TestLowercasePercentEncodePath(t *testing.T) {
route := Default()
route.UnescapePathValues = false
route.UseRawPath = true
route.RedirectFixedPath = true
route.GET("/핫", func(ctx *Context) {
ctx.JSON(200, H{})
})
req := httptest.NewRequest("GET", "/%ed%95%ab", nil)
w := httptest.NewRecorder()
route.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, "{}", w.Body.String())
}

0 comments on commit 189f23f

Please sign in to comment.