Skip to content

Commit 883d2a4

Browse files
authored
Merge middlewares the other way round (#4249)
1 parent 3b51386 commit 883d2a4

File tree

3 files changed

+101
-22
lines changed

3 files changed

+101
-22
lines changed

pkg/api/api.go

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"connectrpc.com/connect"
1616
"github.com/felixge/fgprof"
1717
"github.com/go-kit/log"
18-
"github.com/go-kit/log/level"
1918
"github.com/grafana/dskit/kv/memberlist"
2019
"github.com/grafana/dskit/middleware"
2120
"github.com/grafana/dskit/server"
@@ -89,27 +88,7 @@ func New(cfg Config, s *server.Server, grpcGatewayMux *grpcgw.ServeMux, logger l
8988
//
9089
// Register Options allow to filter the HTTP methods and apply middlewares.
9190
func (a *API) RegisterRoute(path string, handler http.Handler, registerOpts ...RegisterOption) {
92-
opts := applyRegisterOptions(registerOpts...)
93-
94-
level.Debug(a.logger).Log(append([]interface{}{
95-
"msg", "api: registering route"}, opts.logFields(path)...)...)
96-
97-
// handle path prefixing
98-
route := a.server.HTTP.Path(path)
99-
if opts.isPrefix {
100-
route = a.server.HTTP.PathPrefix(path)
101-
}
102-
103-
// limit the route to the given methods
104-
if len(opts.methods) > 0 {
105-
route = route.Methods(opts.methods...)
106-
}
107-
108-
for _, middleware := range opts.middlewares {
109-
handler = middleware.Wrap(handler)
110-
}
111-
112-
route.Handler(handler)
91+
registerRoute(a.logger, a.server.HTTP, path, handler, registerOpts...)
11392
}
11493

11594
// RegisterAPI registers the standard endpoints associated with a running Pyroscope.

pkg/api/register_options.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package api
22

33
import (
4+
"net/http"
45
"strings"
56

7+
"github.com/go-kit/log"
8+
"github.com/go-kit/log/level"
9+
"github.com/gorilla/mux"
610
"github.com/grafana/dskit/middleware"
711

812
"github.com/grafana/pyroscope/pkg/util/gziphandler"
@@ -124,3 +128,29 @@ func (a *API) registerOptionsRingPage() []RegisterOption {
124128
WithMethod("POST"),
125129
}
126130
}
131+
132+
func registerRoute(logger log.Logger, mux *mux.Router, path string, handler http.Handler, registerOpts ...RegisterOption) {
133+
opts := applyRegisterOptions(registerOpts...)
134+
135+
level.Debug(logger).Log(append([]interface{}{
136+
"msg", "api: registering route"}, opts.logFields(path)...)...)
137+
138+
// handle path prefixing
139+
route := mux.Path(path)
140+
if opts.isPrefix {
141+
route = mux.PathPrefix(path)
142+
}
143+
144+
// limit the route to the given methods
145+
if len(opts.methods) > 0 {
146+
route = route.Methods(opts.methods...)
147+
}
148+
149+
// registering the middlewares in reverse order (similar like middleware.Merge)
150+
for idx := range opts.middlewares {
151+
mw := opts.middlewares[len(opts.middlewares)-idx-1]
152+
handler = mw.Wrap(handler)
153+
}
154+
155+
route.Handler(handler)
156+
}

pkg/api/register_options_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package api
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/go-kit/log"
10+
"github.com/gorilla/mux"
11+
"github.com/grafana/dskit/middleware"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
type contextKey uint8
17+
18+
const (
19+
contextKeyTest contextKey = iota
20+
)
21+
22+
func newTestMiddleware(name string) middleware.Interface {
23+
return middleware.Func(func(next http.Handler) http.Handler {
24+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
25+
ctx := r.Context()
26+
middlewares, ok := ctx.Value(contextKeyTest).([]string)
27+
if !ok {
28+
middlewares = []string{}
29+
}
30+
middlewares = append(middlewares, name)
31+
ctx = context.WithValue(ctx, contextKeyTest, middlewares)
32+
next.ServeHTTP(w, r.WithContext(ctx))
33+
})
34+
})
35+
36+
}
37+
38+
func Test_registerRoute(t *testing.T) {
39+
router := mux.NewRouter()
40+
registerRoute(
41+
log.NewNopLogger(),
42+
router,
43+
"/test",
44+
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
middlewares := r.Context().Value(contextKeyTest).([]string)
46+
assert.Equal(t, []string{"outer", "middle", "inner"}, middlewares)
47+
48+
w.WriteHeader(http.StatusOK)
49+
}),
50+
func(r *registerParams) {
51+
r.middlewares = append(r.middlewares, registerMiddleware{newTestMiddleware("outer"), "outer"})
52+
},
53+
func(r *registerParams) {
54+
r.middlewares = append(r.middlewares, registerMiddleware{newTestMiddleware("middle"), "middle"})
55+
},
56+
func(r *registerParams) {
57+
r.middlewares = append(r.middlewares, registerMiddleware{newTestMiddleware("inner"), "inner"})
58+
},
59+
)
60+
61+
testServer := httptest.NewServer(router)
62+
defer testServer.Close()
63+
64+
req, err := http.NewRequest("GET", testServer.URL+"/test", nil)
65+
require.NoError(t, err)
66+
67+
resp, err := testServer.Client().Do(req)
68+
require.NoError(t, err)
69+
assert.Equal(t, http.StatusOK, resp.StatusCode)
70+
}

0 commit comments

Comments
 (0)