Returning A Singleton Middleware Handler Breaks Routing
- Dominant language
- Go
- Stars
- 22.8k
- Forks
- 1.2k
- Avg merge
- 5h 17m
- Merged PRs (30d)
- 10
Description
Middlewares register with chi by providing a `func(next http.Handler) http.Handler` function that returns a `http.Handler` that is expected to call the given `next` argument to pass the request on.
When using `.Group(…)`, chi calls the given middleware function multiple times to create copies of the middleware stack for the group, the godoc says "Group creates a new inline-Mux with a copy of middleware stack."
Returning the same instance of `http.Handler` for each call results in all routing being broken and all requests being passed to the last group that was registered. The request is passed to a handler within the final group _even if the path does not match_.
Expected behaviour: The same instance of http.Handler can be returned and the routing will be correct.
Reproduction:
Run the following server and request `http://localhost/`, `http://localhost/foo`, and `http://localhost/bar`.
The expected responses would be `Hello World!`, `Hello Foo!`, and `Hello Bar!` but all responses are `Hello Bar!`.
``` golang
package main
import (
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
)
func hello(text string) func(http.ResponseWriter, *http.Request) {
output := fmt.Sprintf("Hello %s\n", text)
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println(output)
w.Header().Add("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte(output))
}
}
type middleware struct {
next http.Handler
}
func (m *middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
m.next.ServeHTTP(w, r)
}
var singleton = middleware{}
func Middleware(next http.Handler) http.Handler {
singleton.next = next
return &singleton
}
func main() {
roothandler := chi.NewRouter()
roothandler.Group(func(topgroup chi.Router) {
topgroup.Use(Middleware)
topgroup.Get("/", hello("World!"))
topgroup.Group(func(foogroup chi.Router) {
foogroup.Get("/foo", hello("Foo!"))
})
topgroup.Group(func(bargroup chi.Router) {
bargroup.Get("/bar", hello("Bar!"))
})
})
server := http.Server{
Handler: roothandler,
}
server.ListenAndServe()
}
```
Contributor guide
Assessment
This issue has not been assessed yet.