From 8bbad70f08efbdded77aa25d5c32e799c7deb632 Mon Sep 17 00:00:00 2001 From: Taichi Sasaki Date: Mon, 27 Nov 2023 19:36:24 +0900 Subject: [PATCH 1/2] Lazy initialization for default Goa mux --- http/mux.go | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/http/mux.go b/http/mux.go index 7f27210ffb..ad3b779f47 100644 --- a/http/mux.go +++ b/http/mux.go @@ -71,6 +71,10 @@ type ( // mux is the default Muxer implementation. mux struct { chi.Router + // protect access to middlewares and handlers + mu sync.Mutex + // middlewares to be registered before handlers + middlewares []func(http.Handler) http.Handler // wildcards maps a method and a pattern to the name of the wildcard // this is needed because chi does not expose the name of the wildcard wildcards sync.Map @@ -79,14 +83,11 @@ type ( // NewMuxer returns a Muxer implementation based on a Chi router. func NewMuxer() ResolverMuxer { - r := chi.NewRouter() - r.NotFound(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - ctx := context.WithValue(req.Context(), AcceptTypeKey, req.Header.Get("Accept")) - enc := ResponseEncoder(ctx, w) - w.WriteHeader(http.StatusNotFound) - enc.Encode(NewErrorResponse(ctx, fmt.Errorf("404 page not found"))) // nolint:errcheck - })) - return &mux{Router: r, wildcards: sync.Map{}} + return &mux{ + Router: chi.NewRouter(), + wildcards: sync.Map{}, + middlewares: []func(http.Handler) http.Handler{}, + } } // wildPath matches a wildcard path segment. @@ -94,6 +95,20 @@ var wildPath = regexp.MustCompile(`/{\*([a-zA-Z0-9_]+)}`) // Handle registers the handler function for the given method and pattern. func (m *mux) Handle(method, pattern string, handler http.HandlerFunc) { + m.mu.Lock() + defer m.mu.Unlock() + if m.middlewares != nil { + for _, middleware := range m.middlewares { + m.Router.Use(middleware) + } + m.NotFound(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + ctx := context.WithValue(req.Context(), AcceptTypeKey, req.Header.Get("Accept")) + enc := ResponseEncoder(ctx, w) + w.WriteHeader(http.StatusNotFound) + enc.Encode(NewErrorResponse(ctx, fmt.Errorf("404 page not found"))) // nolint:errcheck + })) + m.middlewares = nil + } if wildcards := wildPath.FindStringSubmatch(pattern); len(wildcards) > 0 { if len(wildcards) > 2 { panic("too many wildcards") @@ -138,6 +153,12 @@ func unescape(s string) string { // Use appends a middleware to the list of middlewares to be applied // downstream the Muxer. func (m *mux) Use(f func(http.Handler) http.Handler) { + m.mu.Lock() + defer m.mu.Unlock() + if m.middlewares != nil { + m.middlewares = append(m.middlewares, f) + return + } m.Router.Use(f) } From 454877d77083a7fd98f72fb29549d6e28ff05bbb Mon Sep 17 00:00:00 2001 From: Taichi Sasaki Date: Mon, 27 Nov 2023 19:38:54 +0900 Subject: [PATCH 2/2] Revert "Use sync.Map for http.mux.wildcards (#3417)" This reverts commit ab8c54d84db5d832a3f8e62be07b42c4075d4612. --- http/mux.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/http/mux.go b/http/mux.go index ad3b779f47..522400a215 100644 --- a/http/mux.go +++ b/http/mux.go @@ -77,7 +77,7 @@ type ( middlewares []func(http.Handler) http.Handler // wildcards maps a method and a pattern to the name of the wildcard // this is needed because chi does not expose the name of the wildcard - wildcards sync.Map + wildcards map[string]string } ) @@ -85,7 +85,7 @@ type ( func NewMuxer() ResolverMuxer { return &mux{ Router: chi.NewRouter(), - wildcards: sync.Map{}, + wildcards: make(map[string]string), middlewares: []func(http.Handler) http.Handler{}, } } @@ -114,7 +114,7 @@ func (m *mux) Handle(method, pattern string, handler http.HandlerFunc) { panic("too many wildcards") } pattern = wildPath.ReplaceAllString(pattern, "/*") - m.wildcards.Store(method+"::"+pattern, wildcards[1]) + m.wildcards[method+"::"+pattern] = wildcards[1] } m.Method(method, pattern, handler) } @@ -132,9 +132,8 @@ func (m *mux) Vars(r *http.Request) map[string]string { vars := make(map[string]string, len(params.Keys)) for i, k := range params.Keys { if k == "*" { - if wildcard, ok := m.wildcards.Load(r.Method + "::" + ctx.RoutePattern()); ok { - vars[wildcard.(string)] = unescape(params.Values[i]) - } + wildcard := m.wildcards[r.Method+"::"+ctx.RoutePattern()] + vars[wildcard] = unescape(params.Values[i]) continue } vars[k] = unescape(params.Values[i]) @@ -175,8 +174,8 @@ func (m *mux) ResolvePattern(r *http.Request) string { // resolveWildcard returns the route pattern with the wildcard replaced by the // name of the wildcard. func (m *mux) resolveWildcard(method, pattern string) string { - if wildcard, ok := m.wildcards.Load(method + "::" + pattern); ok { - return pattern[:len(pattern)-2] + "/{*" + wildcard.(string) + "}" + if wildcard, ok := m.wildcards[method+"::"+pattern]; ok { + return pattern[:len(pattern)-2] + "/{*" + wildcard + "}" } return pattern }