From 11995b3b1e41db5df9b8c7715b5ee12f30dc7cc7 Mon Sep 17 00:00:00 2001 From: Rafi Muhammad Date: Tue, 20 Sep 2022 13:34:43 +0700 Subject: [PATCH 1/9] Implementing register custom methods --- app.go | 7 ++++++- app_test.go | 32 ++++++++++++++++++++++++++------ helpers.go | 27 ++++++--------------------- router.go | 3 ++- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/app.go b/app.go index 033de56cdf..f9f45aa7ef 100644 --- a/app.go +++ b/app.go @@ -555,6 +555,11 @@ func New(config ...Config) *App { return app } +func (app *App) updateStack() { + app.stack = append(app.stack, []*Route{}) + app.treeStack = append(app.treeStack, map[string][]*Route{}) +} + // Adds an ip address to trustedProxyRanges or trustedProxiesMap based on whether it is an IP range or not func (app *App) handleTrustedProxy(ipAddress string) { if strings.Contains(ipAddress, "/") { @@ -844,7 +849,7 @@ func (app *App) Hooks() *Hooks { // Timeout is optional and defaults to 1s, -1 will disable it completely. func (app *App) Test(req *http.Request, msTimeout ...int) (resp *http.Response, err error) { // Set timeout - timeout := 1000 + timeout := 1000000000 if len(msTimeout) > 0 { timeout = msTimeout[0] } diff --git a/app_test.go b/app_test.go index 9c12963868..8e9d88ea6d 100644 --- a/app_test.go +++ b/app_test.go @@ -491,12 +491,24 @@ func Test_App_Use_StrictRouting(t *testing.T) { func Test_App_Add_Method_Test(t *testing.T) { app := New() - defer func() { - if err := recover(); err != nil { - utils.AssertEqual(t, "add: invalid http method JOHN\n", fmt.Sprintf("%v", err)) - } - }() app.Add("JOHN", "/doe", testEmptyHandler) + app.Add("JANE", "/doe", testEmptyHandler) + + resp, err := app.Test(httptest.NewRequest("JOHN", "/doe", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") + + resp, err = app.Test(httptest.NewRequest("JANE", "/doe", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") + + resp, err = app.Test(httptest.NewRequest(MethodGet, "/doe", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusMethodNotAllowed, resp.StatusCode, "Status code") + + resp, err = app.Test(httptest.NewRequest("UNKNOWN", "/doe", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusBadRequest, resp.StatusCode, "Status code") } // go test -run Test_App_GETOnly @@ -1301,7 +1313,7 @@ func Test_App_Stack(t *testing.T) { app.Post("/path3", testEmptyHandler) stack := app.Stack() - utils.AssertEqual(t, 9, len(stack)) + utils.AssertEqual(t, len(intMethod), len(stack)) utils.AssertEqual(t, 3, len(stack[methodInt(MethodGet)])) utils.AssertEqual(t, 3, len(stack[methodInt(MethodHead)])) utils.AssertEqual(t, 2, len(stack[methodInt(MethodPost)])) @@ -1647,3 +1659,11 @@ func Test_App_SetTLSHandler(t *testing.T) { utils.AssertEqual(t, "example.golang", c.ClientHelloInfo().ServerName) } + +func Test_App_UpdateStact(t *testing.T) { + app := New() + utils.AssertEqual(t, len(app.stack), len(intMethod)) + + app.updateStack() + utils.AssertEqual(t, len(app.stack), len(intMethod)+1) +} diff --git a/helpers.go b/helpers.go index c3360ad032..027fee0bfb 100644 --- a/helpers.go +++ b/helpers.go @@ -332,28 +332,13 @@ var getBytesImmutable = func(s string) (b []byte) { // HTTP methods and their unique INTs func methodInt(s string) int { - switch s { - case MethodGet: - return 0 - case MethodHead: - return 1 - case MethodPost: - return 2 - case MethodPut: - return 3 - case MethodDelete: - return 4 - case MethodConnect: - return 5 - case MethodOptions: - return 6 - case MethodTrace: - return 7 - case MethodPatch: - return 8 - default: - return -1 + for i, v := range intMethod { + if s == v { + return i + } } + + return -1 } // HTTP methods slice diff --git a/router.go b/router.go index 69cc3c00da..e498bb69e3 100644 --- a/router.go +++ b/router.go @@ -216,7 +216,8 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) Router { method = utils.ToUpper(method) // Check if the HTTP method is valid unless it's USE if method != methodUse && methodInt(method) == -1 { - panic(fmt.Sprintf("add: invalid http method %s\n", method)) + intMethod = append(intMethod, method) + app.updateStack() } // A route requires atleast one ctx handler if len(handlers) == 0 { From a9ba0cf0829c81994cafc8e8ad965a9806e73a6b Mon Sep 17 00:00:00 2001 From: Rafi Muhammad Date: Tue, 20 Sep 2022 14:18:02 +0700 Subject: [PATCH 2/9] Return timout time to 1000 --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index f9f45aa7ef..e38b72a74d 100644 --- a/app.go +++ b/app.go @@ -849,7 +849,7 @@ func (app *App) Hooks() *Hooks { // Timeout is optional and defaults to 1s, -1 will disable it completely. func (app *App) Test(req *http.Request, msTimeout ...int) (resp *http.Response, err error) { // Set timeout - timeout := 1000000000 + timeout := 1000 if len(msTimeout) > 0 { timeout = msTimeout[0] } From 8e42f7b628b8bfce46d1c0038fd1707bf3e00a46 Mon Sep 17 00:00:00 2001 From: RW Date: Wed, 5 Oct 2022 15:58:25 +0200 Subject: [PATCH 3/9] Update app_test.go --- app_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app_test.go b/app_test.go index 8e9d88ea6d..f1a7af46d4 100644 --- a/app_test.go +++ b/app_test.go @@ -1660,7 +1660,7 @@ func Test_App_SetTLSHandler(t *testing.T) { utils.AssertEqual(t, "example.golang", c.ClientHelloInfo().ServerName) } -func Test_App_UpdateStact(t *testing.T) { +func Test_App_UpdateStack(t *testing.T) { app := New() utils.AssertEqual(t, len(app.stack), len(intMethod)) From 3554c36adf0b47b3cf13d063f9a390bffe084e14 Mon Sep 17 00:00:00 2001 From: Rafi Muhammad Date: Wed, 5 Oct 2022 21:41:10 +0700 Subject: [PATCH 4/9] Change update stack to add custom request method --- app.go | 3 ++- app_test.go | 4 ++-- helpers.go | 30 +++++++++++++++++++++++++----- router.go | 3 +-- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/app.go b/app.go index e38b72a74d..848cc0f008 100644 --- a/app.go +++ b/app.go @@ -555,9 +555,10 @@ func New(config ...Config) *App { return app } -func (app *App) updateStack() { +func (app *App) addCustomRequestMethod(newMethodName string) { app.stack = append(app.stack, []*Route{}) app.treeStack = append(app.treeStack, map[string][]*Route{}) + intMethod = append(intMethod, newMethodName) } // Adds an ip address to trustedProxyRanges or trustedProxiesMap based on whether it is an IP range or not diff --git a/app_test.go b/app_test.go index f1a7af46d4..cdbc85a982 100644 --- a/app_test.go +++ b/app_test.go @@ -1664,6 +1664,6 @@ func Test_App_UpdateStack(t *testing.T) { app := New() utils.AssertEqual(t, len(app.stack), len(intMethod)) - app.updateStack() - utils.AssertEqual(t, len(app.stack), len(intMethod)+1) + app.addCustomRequestMethod("test") + utils.AssertEqual(t, len(app.stack), len(intMethod)) } diff --git a/helpers.go b/helpers.go index 027fee0bfb..598697f217 100644 --- a/helpers.go +++ b/helpers.go @@ -332,13 +332,33 @@ var getBytesImmutable = func(s string) (b []byte) { // HTTP methods and their unique INTs func methodInt(s string) int { - for i, v := range intMethod { - if s == v { - return i + switch s { + case MethodGet: + return 0 + case MethodHead: + return 1 + case MethodPost: + return 2 + case MethodPut: + return 3 + case MethodDelete: + return 4 + case MethodConnect: + return 5 + case MethodOptions: + return 6 + case MethodTrace: + return 7 + case MethodPatch: + return 8 + default: + for i, v := range intMethod[8:] { + if s == v { + return i + 8 + } } + return -1 } - - return -1 } // HTTP methods slice diff --git a/router.go b/router.go index e498bb69e3..1b02750cdf 100644 --- a/router.go +++ b/router.go @@ -216,8 +216,7 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) Router { method = utils.ToUpper(method) // Check if the HTTP method is valid unless it's USE if method != methodUse && methodInt(method) == -1 { - intMethod = append(intMethod, method) - app.updateStack() + app.addCustomRequestMethod(method) } // A route requires atleast one ctx handler if len(handlers) == 0 { From 960936185c1ce5a5c9b4f2be2e7e77ea6033848e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Thu, 6 Oct 2022 16:39:39 +0200 Subject: [PATCH 5/9] Feat: Register custom methods #2107 --- app_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app_test.go b/app_test.go index 8d8df22fd4..b790ea4a9f 100644 --- a/app_test.go +++ b/app_test.go @@ -1666,12 +1666,14 @@ func Test_App_SetTLSHandler(t *testing.T) { utils.AssertEqual(t, "example.golang", c.ClientHelloInfo().ServerName) } -func Test_App_UpdateStack(t *testing.T) { +func Test_App_AddCustomRequestMethod(t *testing.T) { app := New() utils.AssertEqual(t, len(app.stack), len(intMethod)) - app.addCustomRequestMethod("test") + // method name is always uppercase - https://datatracker.ietf.org/doc/html/rfc7231#section-4.1 + app.addCustomRequestMethod("TEST") utils.AssertEqual(t, len(app.stack), len(intMethod)) + utils.AssertEqual(t, "TEST", intMethod[len(intMethod)-1]) } func TestApp_GetRoutes(t *testing.T) { From 83b1b67a1b157fb78bf8d1e45afd20d005ec016e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Thu, 6 Oct 2022 16:58:39 +0200 Subject: [PATCH 6/9] Feat: Register custom methods #2107 --- app_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app_test.go b/app_test.go index b790ea4a9f..cd69887af1 100644 --- a/app_test.go +++ b/app_test.go @@ -1687,7 +1687,7 @@ func TestApp_GetRoutes(t *testing.T) { app.Delete("/delete", handler).Name("delete") app.Post("/post", handler).Name("post") routes := app.GetRoutes(false) - utils.AssertEqual(t, 11, len(routes)) + utils.AssertEqual(t, 2+len(intMethod), len(routes)) methodMap := map[string]string{"/delete": "delete", "/post": "post"} for _, route := range routes { name, ok := methodMap[route.Path] From 030a8c0ad7e2632d3b4613ea20469199c1e93bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Efe=20=C3=87etin?= Date: Wed, 9 Nov 2022 18:47:38 +0300 Subject: [PATCH 7/9] update logic --- app.go | 36 ++++++++++++++++++++++++++---------- app_test.go | 50 ++++++++++++++++++++++++++++++++------------------ ctx.go | 4 ++-- group.go | 2 +- helpers.go | 43 ++++++++++++------------------------------- router.go | 14 +++++++------- 6 files changed, 80 insertions(+), 69 deletions(-) diff --git a/app.go b/app.go index af56172cfd..72e386542a 100644 --- a/app.go +++ b/app.go @@ -384,6 +384,11 @@ type Config struct { // // Optional. Default: DefaultColors ColorScheme Colors `json:"color_scheme"` + + // RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish. + // + // Optional. Defaukt: DefaultMethods + RequestMethods []string } // Static defines configuration options when defining static assets. @@ -444,6 +449,19 @@ const ( DefaultCompressedFileSuffix = ".fiber.gz" ) +// HTTP methods enabled by default +var DefaultMethods = []string{ + MethodGet, + MethodHead, + MethodPost, + MethodPut, + MethodDelete, + MethodConnect, + MethodOptions, + MethodTrace, + MethodPatch, +} + // DefaultErrorHandler that process return errors from handlers var DefaultErrorHandler = func(c *Ctx, err error) error { code := StatusInternalServerError @@ -468,9 +486,6 @@ var DefaultErrorHandler = func(c *Ctx, err error) error { func New(config ...Config) *App { // Create a new app app := &App{ - // Create router stack - stack: make([][]*Route, len(intMethod)), - treeStack: make([]map[string][]*Route, len(intMethod)), // Create Ctx pool pool: sync.Pool{ New: func() interface{} { @@ -536,12 +551,19 @@ func New(config ...Config) *App { if app.config.Network == "" { app.config.Network = NetworkTCP4 } + if len(app.config.RequestMethods) == 0 { + app.config.RequestMethods = DefaultMethods + } app.config.trustedProxiesMap = make(map[string]struct{}, len(app.config.TrustedProxies)) for _, ipAddress := range app.config.TrustedProxies { app.handleTrustedProxy(ipAddress) } + // Create router stack + app.stack = make([][]*Route, len(app.config.RequestMethods)) + app.treeStack = make([]map[string][]*Route, len(app.config.RequestMethods)) + // Override colors app.config.ColorScheme = defaultColors(app.config.ColorScheme) @@ -555,12 +577,6 @@ func New(config ...Config) *App { return app } -func (app *App) addCustomRequestMethod(newMethodName string) { - app.stack = append(app.stack, []*Route{}) - app.treeStack = append(app.treeStack, map[string][]*Route{}) - intMethod = append(intMethod, newMethodName) -} - // Adds an ip address to trustedProxyRanges or trustedProxiesMap based on whether it is an IP range or not func (app *App) handleTrustedProxy(ipAddress string) { if strings.Contains(ipAddress, "/") { @@ -759,7 +775,7 @@ func (app *App) Static(prefix, root string, config ...Static) Router { // All will register the handler on all HTTP methods func (app *App) All(path string, handlers ...Handler) Router { - for _, method := range intMethod { + for _, method := range app.config.RequestMethods { _ = app.Add(method, path, handlers...) } return app diff --git a/app_test.go b/app_test.go index cd69887af1..ae69ff9107 100644 --- a/app_test.go +++ b/app_test.go @@ -490,7 +490,17 @@ func Test_App_Use_StrictRouting(t *testing.T) { } func Test_App_Add_Method_Test(t *testing.T) { - app := New() + defer func() { + if err := recover(); err != nil { + utils.AssertEqual(t, "add: invalid http method JANE\n", fmt.Sprintf("%v", err)) + } + }() + + methods := append(DefaultMethods, "JOHN") + app := New(Config{ + RequestMethods: methods, + }) + app.Add("JOHN", "/doe", testEmptyHandler) app.Add("JANE", "/doe", testEmptyHandler) @@ -554,7 +564,7 @@ func Test_App_Chaining(t *testing.T) { return c.SendStatus(202) }) // check handler count for registered HEAD route - utils.AssertEqual(t, 5, len(app.stack[methodInt(MethodHead)][0].Handlers), "app.Test(req)") + utils.AssertEqual(t, 5, len(app.stack[app.methodInt(MethodHead)][0].Handlers), "app.Test(req)") req := httptest.NewRequest(MethodPost, "/john", nil) @@ -1313,16 +1323,17 @@ func Test_App_Stack(t *testing.T) { app.Post("/path3", testEmptyHandler) stack := app.Stack() - utils.AssertEqual(t, len(intMethod), len(stack)) - utils.AssertEqual(t, 3, len(stack[methodInt(MethodGet)])) - utils.AssertEqual(t, 3, len(stack[methodInt(MethodHead)])) - utils.AssertEqual(t, 2, len(stack[methodInt(MethodPost)])) - utils.AssertEqual(t, 1, len(stack[methodInt(MethodPut)])) - utils.AssertEqual(t, 1, len(stack[methodInt(MethodPatch)])) - utils.AssertEqual(t, 1, len(stack[methodInt(MethodDelete)])) - utils.AssertEqual(t, 1, len(stack[methodInt(MethodConnect)])) - utils.AssertEqual(t, 1, len(stack[methodInt(MethodOptions)])) - utils.AssertEqual(t, 1, len(stack[methodInt(MethodTrace)])) + methodList := app.config.RequestMethods + utils.AssertEqual(t, len(methodList), len(stack)) + utils.AssertEqual(t, 3, len(stack[app.methodInt(MethodGet)])) + utils.AssertEqual(t, 3, len(stack[app.methodInt(MethodHead)])) + utils.AssertEqual(t, 2, len(stack[app.methodInt(MethodPost)])) + utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodPut)])) + utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodPatch)])) + utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodDelete)])) + utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodConnect)])) + utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodOptions)])) + utils.AssertEqual(t, 1, len(stack[app.methodInt(MethodTrace)])) } // go test -run Test_App_HandlersCount @@ -1667,13 +1678,16 @@ func Test_App_SetTLSHandler(t *testing.T) { } func Test_App_AddCustomRequestMethod(t *testing.T) { - app := New() - utils.AssertEqual(t, len(app.stack), len(intMethod)) + methods := append(DefaultMethods, "TEST") + app := New(Config{ + RequestMethods: methods, + }) + appMethods := app.config.RequestMethods // method name is always uppercase - https://datatracker.ietf.org/doc/html/rfc7231#section-4.1 - app.addCustomRequestMethod("TEST") - utils.AssertEqual(t, len(app.stack), len(intMethod)) - utils.AssertEqual(t, "TEST", intMethod[len(intMethod)-1]) + utils.AssertEqual(t, len(app.stack), len(appMethods)) + utils.AssertEqual(t, len(app.stack), len(appMethods)) + utils.AssertEqual(t, "TEST", appMethods[len(appMethods)-1]) } func TestApp_GetRoutes(t *testing.T) { @@ -1687,7 +1701,7 @@ func TestApp_GetRoutes(t *testing.T) { app.Delete("/delete", handler).Name("delete") app.Post("/post", handler).Name("post") routes := app.GetRoutes(false) - utils.AssertEqual(t, 2+len(intMethod), len(routes)) + utils.AssertEqual(t, 2+len(app.config.RequestMethods), len(routes)) methodMap := map[string]string{"/delete": "delete", "/post": "post"} for _, route := range routes { name, ok := methodMap[route.Path] diff --git a/ctx.go b/ctx.go index b5bc5f0153..ca54ca61bc 100644 --- a/ctx.go +++ b/ctx.go @@ -164,7 +164,7 @@ func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx { c.pathOriginal = app.getString(fctx.URI().PathOriginal()) // Set method c.method = app.getString(fctx.Request.Header.Method()) - c.methodINT = methodInt(c.method) + c.methodINT = app.methodInt(c.method) // Attach *fasthttp.RequestCtx to ctx c.fasthttp = fctx // reset base uri @@ -867,7 +867,7 @@ func (c *Ctx) Location(path string) { func (c *Ctx) Method(override ...string) string { if len(override) > 0 { method := utils.ToUpper(override[0]) - mINT := methodInt(method) + mINT := c.app.methodInt(method) if mINT == -1 { return c.method } diff --git a/group.go b/group.go index ab74b80e92..872c4d1a6e 100644 --- a/group.go +++ b/group.go @@ -164,7 +164,7 @@ func (grp *Group) Static(prefix, root string, config ...Static) Router { // All will register the handler on all HTTP methods func (grp *Group) All(path string, handlers ...Handler) Router { - for _, method := range intMethod { + for _, method := range grp.app.config.RequestMethods { _ = grp.Add(method, path, handlers...) } return grp diff --git a/helpers.go b/helpers.go index 598697f217..0eef91283e 100644 --- a/helpers.go +++ b/helpers.go @@ -78,8 +78,9 @@ func (app *App) quoteString(raw string) string { } // Scan stack if other methods match the request -func methodExist(ctx *Ctx) (exist bool) { - for i := 0; i < len(intMethod); i++ { +func (app *App) methodExist(ctx *Ctx) (exist bool) { + methods := app.config.RequestMethods + for i := 0; i < len(methods); i++ { // Skip original method if ctx.methodINT == i { continue @@ -109,7 +110,7 @@ func methodExist(ctx *Ctx) (exist bool) { // We matched exist = true // Add method to Allow header - ctx.Append(HeaderAllow, intMethod[i]) + ctx.Append(HeaderAllow, methods[i]) // Break stack loop break } @@ -331,38 +332,18 @@ var getBytesImmutable = func(s string) (b []byte) { } // HTTP methods and their unique INTs -func methodInt(s string) int { - switch s { - case MethodGet: - return 0 - case MethodHead: - return 1 - case MethodPost: - return 2 - case MethodPut: - return 3 - case MethodDelete: - return 4 - case MethodConnect: - return 5 - case MethodOptions: - return 6 - case MethodTrace: - return 7 - case MethodPatch: - return 8 - default: - for i, v := range intMethod[8:] { - if s == v { - return i + 8 - } +func (app *App) methodInt(s string) int { + for i, v := range app.config.RequestMethods { + if s == v { + return i } - return -1 } + + return -1 } // HTTP methods slice -var intMethod = []string{ +/*var intMethod = []string{ MethodGet, MethodHead, MethodPost, @@ -372,7 +353,7 @@ var intMethod = []string{ MethodOptions, MethodTrace, MethodPatch, -} +}*/ // HTTP methods were copied from net/http. const ( diff --git a/router.go b/router.go index 1696d30ea6..75a9e825aa 100644 --- a/router.go +++ b/router.go @@ -138,7 +138,7 @@ func (app *App) next(c *Ctx) (match bool, err error) { // If no match, scan stack again if other methods match the request // Moved from app.handler because middleware may break the route chain - if !c.matched && methodExist(c) { + if !c.matched && app.methodExist(c) { err = ErrMethodNotAllowed } return @@ -215,8 +215,8 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) Router { // Uppercase HTTP methods method = utils.ToUpper(method) // Check if the HTTP method is valid unless it's USE - if method != methodUse && methodInt(method) == -1 { - app.addCustomRequestMethod(method) + if method != methodUse && app.methodInt(method) == -1 { + panic(fmt.Sprintf("add: invalid http method %s\n", method)) } // A route requires atleast one ctx handler if len(handlers) == 0 { @@ -273,7 +273,7 @@ func (app *App) register(method, pathRaw string, handlers ...Handler) Router { // Middleware route matches all HTTP methods if isUse { // Add route to all HTTP methods stack - for _, m := range intMethod { + for _, m := range app.config.RequestMethods { // Create a route copy to avoid duplicates during compression r := route app.addRoute(m, &r) @@ -420,7 +420,7 @@ func (app *App) registerStatic(prefix, root string, config ...Static) Router { func (app *App) addRoute(method string, route *Route) { // Get unique HTTP method identifier - m := methodInt(method) + m := app.methodInt(method) // prevent identically route registration l := len(app.stack[m]) @@ -450,7 +450,7 @@ func (app *App) buildTree() *App { return app } // loop all the methods and stacks and create the prefix tree - for m := range intMethod { + for m := range app.config.RequestMethods { tsMap := make(map[string][]*Route) for _, route := range app.stack[m] { treePath := "" @@ -463,7 +463,7 @@ func (app *App) buildTree() *App { app.treeStack[m] = tsMap } // loop the methods and tree stacks and add global stack and sort everything - for m := range intMethod { + for m := range app.config.RequestMethods { tsMap := app.treeStack[m] for treePart := range tsMap { if treePart != "" { From 34e3d7da0f3cdb0c36955d07b9932d6be4085b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Efe=20=C3=87etin?= Date: Wed, 9 Nov 2022 22:48:31 +0300 Subject: [PATCH 8/9] optimization. --- app.go | 4 ++++ helpers.go | 40 +++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/app.go b/app.go index 72e386542a..6955a042fc 100644 --- a/app.go +++ b/app.go @@ -116,6 +116,8 @@ type App struct { latestGroup *Group // TLS handler tlsHandler *TLSHandler + // custom method check + customMethod bool } // Config is a struct holding the server settings. @@ -553,6 +555,8 @@ func New(config ...Config) *App { } if len(app.config.RequestMethods) == 0 { app.config.RequestMethods = DefaultMethods + } else { + app.customMethod = true } app.config.trustedProxiesMap = make(map[string]struct{}, len(app.config.TrustedProxies)) diff --git a/helpers.go b/helpers.go index 0eef91283e..8ce989e649 100644 --- a/helpers.go +++ b/helpers.go @@ -333,6 +333,33 @@ var getBytesImmutable = func(s string) (b []byte) { // HTTP methods and their unique INTs func (app *App) methodInt(s string) int { + // For better performance + if app.customMethod { + switch s { + case MethodGet: + return 0 + case MethodHead: + return 1 + case MethodPost: + return 2 + case MethodPut: + return 3 + case MethodDelete: + return 4 + case MethodConnect: + return 5 + case MethodOptions: + return 6 + case MethodTrace: + return 7 + case MethodPatch: + return 8 + default: + return -1 + } + } + + // For method customization for i, v := range app.config.RequestMethods { if s == v { return i @@ -342,19 +369,6 @@ func (app *App) methodInt(s string) int { return -1 } -// HTTP methods slice -/*var intMethod = []string{ - MethodGet, - MethodHead, - MethodPost, - MethodPut, - MethodDelete, - MethodConnect, - MethodOptions, - MethodTrace, - MethodPatch, -}*/ - // HTTP methods were copied from net/http. const ( MethodGet = "GET" // RFC 7231, 4.3.1 From 22ebccbcac33e09cae3ba196c122c1fa1fae9342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammed=20Efe=20=C3=87etin?= Date: Thu, 10 Nov 2022 22:37:57 +0300 Subject: [PATCH 9/9] fix --- app_test.go | 7 ++----- helpers.go | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app_test.go b/app_test.go index 6ebf83dcc5..c3b6565757 100644 --- a/app_test.go +++ b/app_test.go @@ -447,16 +447,11 @@ func Test_App_Add_Method_Test(t *testing.T) { }) app.Add("JOHN", "/doe", testEmptyHandler) - app.Add("JANE", "/doe", testEmptyHandler) resp, err := app.Test(httptest.NewRequest("JOHN", "/doe", nil)) utils.AssertEqual(t, nil, err, "app.Test(req)") utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") - resp, err = app.Test(httptest.NewRequest("JANE", "/doe", nil)) - utils.AssertEqual(t, nil, err, "app.Test(req)") - utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") - resp, err = app.Test(httptest.NewRequest(MethodGet, "/doe", nil)) utils.AssertEqual(t, nil, err, "app.Test(req)") utils.AssertEqual(t, StatusMethodNotAllowed, resp.StatusCode, "Status code") @@ -464,6 +459,8 @@ func Test_App_Add_Method_Test(t *testing.T) { resp, err = app.Test(httptest.NewRequest("UNKNOWN", "/doe", nil)) utils.AssertEqual(t, nil, err, "app.Test(req)") utils.AssertEqual(t, StatusBadRequest, resp.StatusCode, "Status code") + + app.Add("JANE", "/doe", testEmptyHandler) } // go test -run Test_App_GETOnly diff --git a/helpers.go b/helpers.go index 4e0391d88c..aa9511da82 100644 --- a/helpers.go +++ b/helpers.go @@ -334,7 +334,7 @@ var getBytesImmutable = func(s string) (b []byte) { // HTTP methods and their unique INTs func (app *App) methodInt(s string) int { // For better performance - if app.customMethod { + if !app.customMethod { switch s { case MethodGet: return 0