mirror of https://github.com/gin-gonic/gin.git
fix: case-insensitive RawPath comparison to prevent infinite redirect
This commit is contained in:
parent
c8a3adc657
commit
01c7c95fc1
49
gin.go
49
gin.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -643,11 +644,57 @@ func (engine *Engine) HandleContext(c *Context) {
|
||||||
c.index = oldIndexValue
|
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) {
|
||||||
|
if rawPath[i+1] == '2' && (rawPath[i+2] == 'F' || rawPath[i+2] == 'f') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||||
httpMethod := c.Request.Method
|
httpMethod := c.Request.Method
|
||||||
rPath := c.Request.URL.Path
|
rPath := c.Request.URL.Path
|
||||||
unescape := false
|
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
|
rPath = c.Request.URL.RawPath
|
||||||
unescape = engine.UnescapePathValues
|
unescape = engine.UnescapePathValues
|
||||||
}
|
}
|
||||||
|
|
|
@ -789,3 +789,19 @@ func TestEngineHandleMethodNotAllowedCornerCase(t *testing.T) {
|
||||||
w := PerformRequest(r, "GET", "/base/v1/user/groups")
|
w := PerformRequest(r, "GET", "/base/v1/user/groups")
|
||||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
assert.Equal(t, http.StatusNotFound, w.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())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue