Repository: labstack/echo
File: router.go (Go)

Code before:
		tree: &node{
			methods: new(routeMethods),
		},
		routes: map[string]*Route{},
		echo:   e,
	}
}

// Routes returns the registered routes.
func (r *Router) Routes() []*Route {
	routes := make([]*Route, 0, len(r.routes))
	for _, v := range r.routes {
		routes = append(routes, v)
	}
	return routes
}

// Reverse generates an URL from route name and provided parameters.
func (r *Router) Reverse(name string, params ...interface{}) string {
	uri := new(bytes.Buffer)
	ln := len(params)
	n := 0
	for _, route := range r.routes {
		if route.Name == name {
			for i, l := 0, len(route.Path); i < l; i++ {
				if route.Path[i] == '\\' {
					continue
				}
				if ((route.Path[i] == ':' && (i == 0 || route.Path[i-1] != '\\')) || route.Path[i] == '*') && n < ln {
					for ; i < l && route.Path[i] != '/'; i++ {
					}
					uri.WriteString(fmt.Sprintf("%v", params[n]))
					n++
				}
				if i < l {
					uri.WriteByte(route.Path[i])
				}
			}
			break
		}
	}
	return uri.String()
}

func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
	r.Add(method, path, h)

	route := &Route{
		Method: method,
		Path:   path,
		Name:   name,

Review comment (security):
This is little bit problematic. It does not handle backslash correctly. For example this route `e.GET("/a\\b/:x", dummyHandler).Name = "/backslash"`

I propose changing check to that:

```go
			for i, l := 0, len(route.Path); i < l; i++ {
				hasBackslash := route.Path[i] == '\\'
				if hasBackslash && i+1 < l && route.Path[i+1] == ':' {
					i++ // backslash before colon escapes that colon. in that case skip backslash
				}
				if n < ln && (route.Path[i] == '*' || (!hasBackslash && route.Path[i] == ':')) {
					// in case of `*` wildcard or `:` (unescaped colon) param we replace everything till next slash or end of path
					for ; i < l && route.Path[i] != '/'; i++ {
```

Code after:
		tree: &node{
			methods: new(routeMethods),
		},
		routes: map[string]*Route{},
		echo:   e,
	}
}

// Routes returns the registered routes.
func (r *Router) Routes() []*Route {
	routes := make([]*Route, 0, len(r.routes))
	for _, v := range r.routes {
		routes = append(routes, v)
	}
	return routes
}

// Reverse generates an URL from route name and provided parameters.
func (r *Router) Reverse(name string, params ...interface{}) string {
	uri := new(bytes.Buffer)
	ln := len(params)
	n := 0
	for _, route := range r.routes {
		if route.Name == name {
			for i, l := 0, len(route.Path); i < l; i++ {
				hasBackslash := route.Path[i] == '\\'
				if hasBackslash && i+1 < l && route.Path[i+1] == ':' {
					i++ // backslash before colon escapes that colon. in that case skip backslash
				}
				if n < ln && (route.Path[i] == '*' || (!hasBackslash && route.Path[i] == ':')) {
					// in case of `*` wildcard or `:` (unescaped colon) param we replace everything till next slash or end of path
					for ; i < l && route.Path[i] != '/'; i++ {
					}
					uri.WriteString(fmt.Sprintf("%v", params[n]))
					n++
				}
				if i < l {
					uri.WriteByte(route.Path[i])
				}
			}
			break
		}
	}
	return uri.String()
}

func (r *Router) add(method, path, name string, h HandlerFunc) *Route {
	r.Add(method, path, h)

	route := &Route{
		Method: method,