From bb22ad2329bd711941204c99d5fa2a3605496c73 Mon Sep 17 00:00:00 2001 From: Matthias Neugebauer Date: Thu, 3 Feb 2022 15:09:46 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20Feature:=20Add=20ability=20to=20?= =?UTF-8?q?restart=20route=20handling=20(#1739)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔥 Feature: Add ability to restart route handling * Change test names Co-authored-by: RW --- ctx.go | 8 +++++++ ctx_test.go | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/ctx.go b/ctx.go index c14b3a2773a..ab1a9eaa333 100644 --- a/ctx.go +++ b/ctx.go @@ -783,6 +783,14 @@ func (c *Ctx) Next() (err error) { return err } +// RestartRouting instead of going to the next handler. This may be usefull after +// changing the request path. Note that handlers might be executed again. +func (c *Ctx) RestartRouting() error { + c.indexRoute = -1 + _, err := c.app.next(c) + return err +} + // OriginalURL contains the original request URL. // Returned value is only valid within the handler. Do not store any references. // Make copies or use the Immutable setting to use the value outside the Handler. diff --git a/ctx_test.go b/ctx_test.go index 3a790bf315a..1e857143b8e 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -2108,6 +2108,69 @@ func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) { utils.AssertEqual(t, "

Hello, World!

", string(c.Response().Body())) } +// go test -run Test_Ctx_RestartRouting +func Test_Ctx_RestartRouting(t *testing.T) { + app := New() + calls := 0 + app.Get("/", func(c *Ctx) error { + calls++ + if calls < 3 { + return c.RestartRouting() + } + return nil + }) + resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") + utils.AssertEqual(t, 3, calls, "Number of calls") +} + +// go test -run Test_Ctx_RestartRoutingWithChangedPath +func Test_Ctx_RestartRoutingWithChangedPath(t *testing.T) { + app := New() + executedOldHandler := false + executedNewHandler := false + + app.Get("/old", func(c *Ctx) error { + c.Path("/new") + return c.RestartRouting() + }) + app.Get("/old", func(c *Ctx) error { + executedOldHandler = true + return nil + }) + app.Get("/new", func(c *Ctx) error { + executedNewHandler = true + return nil + }) + + resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/old", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") + utils.AssertEqual(t, false, executedOldHandler, "Executed old handler") + utils.AssertEqual(t, true, executedNewHandler, "Executed new handler") +} + +// go test -run Test_Ctx_RestartRoutingWithChangedPathAnd404 +func Test_Ctx_RestartRoutingWithChangedPathAndCatchAll(t *testing.T) { + app := New() + app.Get("/new", func(c *Ctx) error { + return nil + }) + app.Use(func(c *Ctx) error { + c.Path("/new") + // c.Next() would fail this test as a 404 is returned from the next handler + return c.RestartRouting() + }) + app.Use(func(c *Ctx) error { + return ErrNotFound + }) + + resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/old", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") +} + type testTemplateEngine struct { templates *template.Template }