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 https://github.com/golang/go/issues/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: https://github.com/gin-gonic/gin/blob/cc4e11438cd6c0bcc632fe3492d3817dfa21c337/gin.go#L650-L653

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