go-chi / go-chi/chi

Returning A Singleton Middleware Handler Breaks Routing

Open
#995 2 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.