Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] UnescapePathValues = false still unescapes path values #4033

Open
ALX99 opened this issue Aug 20, 2024 · 0 comments · May be fixed by #4036
Open

[Bug] UnescapePathValues = false still unescapes path values #4033

ALX99 opened this issue Aug 20, 2024 · 0 comments · May be fixed by #4036

Comments

@ALX99
Copy link

ALX99 commented Aug 20, 2024

Description

Even despite setting

UnescapePathValues = false
UseRawPath = true

the URL path value is still unescaped.

This is probably related to that gin sometimes routes request based on either URL.Path or URL.RawPath when UseRawPath is true. URL.RawPath is not always populated (See golang/go#33596), so when it is missing, it falls back to route on URL.Path instead. To me, gin should not fall back to using URL.Path since this path is unescaped, and not raw when UseRawPath is enabled.

Reference:

gin/gin.go

Lines 650 to 653 in cc4e114

if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
rPath = c.Request.URL.RawPath
unescape = engine.UnescapePathValues
}

To fix this issue, gin should use URL.EscapedPath() which should return URL.RawPath if it is non empty, or compute an escaped path if it is empty.

It is possible to work around this issue by ensuring that URL.RawPath always exists when the gin router handles the request.

Example Workaround

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/testy/:name", func(c *gin.Context) {
		n := c.Param("name")
		c.Writer.Write([]byte(n))
	})

	r.UnescapePathValues = false
	r.UseRawPath = true

	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		req.URL.RawPath = req.URL.EscapedPath()
		r.Handler().ServeHTTP(w, req)
	})

	http.ListenAndServe(":8181", mux)
}

How to reproduce

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/testy/:name", func(c *gin.Context) {
		n := c.Param("name")
		c.Writer.Write([]byte(n))
	})

	r.UnescapePathValues = false
	r.UseRawPath = true
	r.Run(":8181")
}

Expectations

$ curl 'localhost:8181/testy/hi%2Fworld'
hi%2Fworld
$ curl 'localhost:8181/testy/%E3%81%82'
%E3%81%82

Actual result

$ curl 'localhost:8181/testy/hi%2Fworld'
hi%2Fworld
$ curl 'localhost:8181/testy/%E3%81%82'
あ

Environment

  • go version: 1.23.0
  • gin version (or commit ref): v1.10.0
  • operating system: macOS Sequoia
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant