From 55c025c35ca07dc33a1587cd4aa93994262e31dd Mon Sep 17 00:00:00 2001 From: dylanhitt Date: Mon, 25 Mar 2024 10:52:55 -0400 Subject: [PATCH 1/2] fix: ordering in which middleware is registered for a route --- mux.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mux.go b/mux.go index f175d739..65e72f2a 100644 --- a/mux.go +++ b/mux.go @@ -156,8 +156,8 @@ func RegisterStd(s *Server, method string, path string, controller func(http.Res } func withMiddlewares(controller http.Handler, middlewares ...func(http.Handler) http.Handler) http.Handler { - for _, middleware := range middlewares { - controller = middleware(controller) + for i := len(middlewares) - 1; i >= 0; i-- { + controller = middlewares[i](controller) } return controller } From d9fc2b5e0eb834bd44dba3fb468e39dae5e4e851 Mon Sep 17 00:00:00 2001 From: dylanhitt Date: Mon, 25 Mar 2024 17:25:01 -0400 Subject: [PATCH 2/2] WIP: possible test? --- mux.go | 2 +- mux_test.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/mux.go b/mux.go index 65e72f2a..fe64b5f9 100644 --- a/mux.go +++ b/mux.go @@ -88,7 +88,7 @@ func Register[T any, B any, Contexted ctx[B]](s *Server, method string, path str func register[T any, B any](s *Server, method string, path string, controller http.Handler, middlewares ...func(http.Handler) http.Handler) Route[T, B] { fullPath := method + " " + s.basePath + path - allMiddlewares := append(middlewares, s.middlewares...) + allMiddlewares := append(s.middlewares, middlewares...) s.Mux.Handle(fullPath, withMiddlewares(controller, allMiddlewares...)) if s.DisableOpenapi { diff --git a/mux_test.go b/mux_test.go index 4e45e257..496e8e38 100644 --- a/mux_test.go +++ b/mux_test.go @@ -20,6 +20,101 @@ func dummyMiddleware(handler http.Handler) http.Handler { }) } +// orderMiddleware sets the X-Test-Order Header on the request and +// X-Test-Response header on the response. It is +// used to test the order execution of our middleware +func orderMiddleware(s string) func(http.Handler) http.Handler { + return func(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + orderValue := strings.Split(r.Header.Get("X-Test-Order"), ",") + orderValue = append(orderValue, s) + + r.Header.Set("X-Test-Order", strings.Join(orderValue, ",")) + w.Header().Set("X-Test-Response", "response") + handler.ServeHTTP(w, r) + }) + } +} + +// TestUse is used to mainly test the ordering of middleware execution +func TestUse(t *testing.T) { + t.Run("base", func(t *testing.T) { + s := NewServer() + Use(s, orderMiddleware("First!")) + Get(s, "/test", func(ctx *ContextNoBody) (string, error) { + return "test", nil + }) + + r := httptest.NewRequest(http.MethodGet, "/test", nil) + r.Header.Set("X-Test-Order", "Start!") + w := httptest.NewRecorder() + + s.Mux.ServeHTTP(w, r) + + orderValue := strings.Split(r.Header.Get("X-Test-Order"), ",") + require.Equal(t, []string{"Start!", "First!"}, orderValue) + }) + + t.Run("multiple uses of Use", func(t *testing.T) { + s := NewServer() + Use(s, orderMiddleware("First!")) + Use(s, orderMiddleware("Second!")) + Get(s, "/test", func(ctx *ContextNoBody) (string, error) { + return "test", nil + }) + + r := httptest.NewRequest(http.MethodGet, "/test", nil) + r.Header.Set("X-Test-Order", "Start!") + w := httptest.NewRecorder() + + s.Mux.ServeHTTP(w, r) + + orderValue := strings.Split(r.Header.Get("X-Test-Order"), ",") + require.Equal(t, []string{"Start!", "First!", "Second!"}, orderValue) + }) + + t.Run("variadic use of Use", func(t *testing.T) { + s := NewServer() + Use(s, orderMiddleware("First!")) + Use(s, orderMiddleware("Second!"), orderMiddleware("Third!")) + Get(s, "/test", func(ctx *ContextNoBody) (string, error) { + return "test", nil + }) + + r := httptest.NewRequest(http.MethodGet, "/test", nil) + r.Header.Set("X-Test-Order", "Start!") + w := httptest.NewRecorder() + + s.Mux.ServeHTTP(w, r) + + orderValue := strings.Split(r.Header.Get("X-Test-Order"), ",") + require.Equal(t, []string{"Start!", "First!", "Second!", "Third!"}, orderValue) + }) + + t.Run("variadic use of Route Get", func(t *testing.T) { + s := NewServer() + Use(s, orderMiddleware("First!")) + Use(s, orderMiddleware("Second!"), orderMiddleware("Third!")) + Get(s, "/test", func(ctx *ContextNoBody) (string, error) { + return "test", nil + }, orderMiddleware("Fourth!"), orderMiddleware("Fifth!")) + + r := httptest.NewRequest(http.MethodGet, "/test", nil) + r.Header.Set("X-Test-Order", "Start!") + w := httptest.NewRecorder() + + s.Mux.ServeHTTP(w, r) + + orderValue := strings.Split(r.Header.Get("X-Test-Order"), ",") + require.Equal( + t, []string{ + "Start!", "First!", "Second!", "Third!", "Fourth!", "Fifth!", + }, + orderValue, + ) + }) +} + func TestUseStd(t *testing.T) { s := NewServer() UseStd(s, dummyMiddleware)