From f44bf53d0fefba756aebc043dcde4dda23a02e0d Mon Sep 17 00:00:00 2001 From: Jonathan Hall Date: Thu, 14 Dec 2023 12:06:08 +0100 Subject: [PATCH] Add function to expose allowed methods for use in custom 405-handlers Fixes #870 --- context.go | 15 +++++++++++++++ context_test.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/context.go b/context.go index 21b1384e..ef1a3c5a 100644 --- a/context.go +++ b/context.go @@ -34,6 +34,21 @@ func NewRouteContext() *Context { return &Context{} } +// WithRouteContext returns the list of methods allowed for the current +// request, based on the current routing context. +func AllowedMethods(ctx context.Context) []string { + if rctx := RouteContext(ctx); rctx != nil { + result := make([]string, 0, len(rctx.methodsAllowed)) + for _, method := range rctx.methodsAllowed { + if method := methodTypString(method); method != "" { + result = append(result, method) + } + } + return result + } + return nil +} + var ( // RouteCtxKey is the context.Context key to store the request context. RouteCtxKey = &contextKey{"RouteContext"} diff --git a/context_test.go b/context_test.go index 4731c709..9261fda8 100644 --- a/context_test.go +++ b/context_test.go @@ -1,6 +1,10 @@ package chi -import "testing" +import ( + "context" + "strings" + "testing" +) // TestRoutePattern tests correct in-the-middle wildcard removals. // If user organizes a router like this: @@ -85,3 +89,32 @@ func TestRoutePattern(t *testing.T) { t.Fatal("unexpected route pattern for root: " + p) } } + +func TestAllowedMethods(t *testing.T) { + t.Run("no chi context", func(t *testing.T) { + got := AllowedMethods(context.Background()) + if got != nil { + t.Errorf("Unexpected allowed methods: %v", got) + } + }) + t.Run("expected methods", func(t *testing.T) { + want := "GET HEAD" + ctx := context.WithValue(context.Background(), RouteCtxKey, &Context{ + methodsAllowed: []methodTyp{mGET, mHEAD}, + }) + got := strings.Join(AllowedMethods(ctx), " ") + if want != got { + t.Errorf("Unexpected allowed methods: %s, want: %s", got, want) + } + }) + t.Run("unexpected methods", func(t *testing.T) { + want := "GET HEAD" + ctx := context.WithValue(context.Background(), RouteCtxKey, &Context{ + methodsAllowed: []methodTyp{mGET, mHEAD, 9000}, + }) + got := strings.Join(AllowedMethods(ctx), " ") + if want != got { + t.Errorf("Unexpected allowed methods: %s, want: %s", got, want) + } + }) +}