Compare commits

...

3 Commits

Author SHA1 Message Date
Asbjørn Ulsberg
602926c1bb
Merge ce6939ce4090aa41861cd93daccce4b68f891b25 into ecb3f7b5e2f3915bf1db240ed5eee572f8dbea36 2025-11-23 12:14:00 +08:00
Bo-Yi Wu
ecb3f7b5e2
chore(deps): upgrade golang.org/x/crypto to v0.45.0 (#4449)
- Update golang.org/x/crypto dependency to version 0.45.0

1. https://avd.aquasec.com/nvd/cve-2025-47914
2. https://avd.aquasec.com/nvd/cve-2025-58181

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-11-23 11:46:13 +08:00
Asbjørn Ulsberg
ce6939ce40
feat: add Engine.PathFor function 2023-04-30 23:12:07 +02:00
5 changed files with 112 additions and 3 deletions

View File

@ -9,6 +9,7 @@
- [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options)
- [Parameters in path](#parameters-in-path)
- [Querystring parameters](#querystring-parameters)
- [Retrieving the path of a registered handler](#retrieving-the-path-of-a-registered-handler)
- [Multipart/Urlencoded Form](#multiparturlencoded-form)
- [Another example: query + post form](#another-example-query--post-form)
- [Map as querystring or postform parameters](#map-as-querystring-or-postform-parameters)
@ -184,6 +185,29 @@ func main() {
}
```
### Retrieving the path of a registered handler
Once a handler is registered with the router, you can retrieve its path with the `PathFor` method:
```go
func main() {
// Creates a gin router with default middleware:
// logger and recovery (crash-free) middleware
router := gin.Default()
getUser := func(c *Context) {
// Handle the GET request.
}
router.GET("/users/:name", getUser)
path := router.PathFor(getUser, ":name", "gopher")
print(path) // Prints /users/gopher
router.Run()
}
router := gin.Default()
```
### Multipart/Urlencoded Form
```go

66
gin.go
View File

@ -392,6 +392,24 @@ func (engine *Engine) Routes() (routes RoutesInfo) {
return routes
}
// Routes returns a slice of registered routes, including some useful information, such as:
// the http method, path and the handler name.
func (engine *Engine) Route(handler HandlerFunc) (route RouteInfo, ok bool) {
handlerName := nameOfFunction(handler)
routes := RoutesInfo{}
for _, tree := range engine.trees {
routes = iterate("", tree.method, routes, tree.root)
for _, route := range routes {
if route.Handler == handlerName {
return route, true
}
}
}
return RouteInfo{}, false
}
func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
path += root.path
if len(root.handlers) > 0 {
@ -685,6 +703,43 @@ func (engine *Engine) HandleContext(c *Context) {
c.handlers = oldHandlers
}
// PathFor returns the path registered for the specified handler function.
// Route values are passed pair-wise as key value.
func (engine *Engine) PathFor(handler HandlerFunc, values ...interface{}) string {
route, ok := engine.Route(handler)
if !ok || len(route.Path) == 0 || len(values)%2 != 0 {
return ""
}
url := route.Path
params := make(map[string]string)
if len(values) > 0 {
key := ""
for k, v := range values {
if k%2 == 0 {
key = fmt.Sprint(v)
} else {
params[key] = fmt.Sprint(v)
}
}
}
urls := strings.Split(url, "/")
for _, v := range urls {
if v == "" {
continue
}
if v[0:1] == ":" {
if u, ok := params[v]; ok {
delete(params, v)
url = strings.Replace(url, v, u, 1)
}
}
}
return url + toQuerystring(params)
}
func (engine *Engine) handleHTTPRequest(c *Context) {
httpMethod := c.Request.Method
rPath := c.Request.URL.Path
@ -813,3 +868,14 @@ func redirectRequest(c *Context) {
http.Redirect(c.Writer, req, rURL, code)
c.writermem.WriteHeaderNow()
}
func toQuerystring(params map[string]string) string {
if len(params) == 0 {
return ""
}
u := "?"
for k, v := range params {
u += k + "=" + v + "&"
}
return strings.TrimRight(u, "&")
}

View File

@ -825,6 +825,25 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
}
}
func TestPathFor(t *testing.T) {
r := New()
getIndex := func(c *Context) {}
r.GET("/", getIndex)
users := r.Group("/users")
postUser := func(c *Context) {}
users.POST("", postUser)
getUser := func(c *Context) {}
users.GET("/:name", getUser)
assert.Equal(t, "/", r.PathFor(getIndex))
assert.Equal(t, "/users", r.PathFor(postUser))
assert.Equal(t, "/users/gopher", r.PathFor(getUser, ":name", "gopher"))
}
func parseCIDR(cidr string) *net.IPNet {
_, parsedCIDR, err := net.ParseCIDR(cidr)
if err != nil {

2
go.mod
View File

@ -35,7 +35,7 @@ require (
github.com/quic-go/qpack v0.5.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.44.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

4
go.sum
View File

@ -74,8 +74,8 @@ go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=