diff --git a/ctx.go b/ctx.go
index af2032ac080..951da55245d 100644
--- a/ctx.go
+++ b/ctx.go
@@ -782,6 +782,14 @@ func (c *Ctx) Next() (err error) {
return err
}
+// Restart request handling instead of going to next handler. This may be usefull
+// after changing the request path. Note that handlers might be executed again.
+func (c *Ctx) Restart() 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 f5149dbb02d..8a1a5f56b84 100644
--- a/ctx_test.go
+++ b/ctx_test.go
@@ -2065,6 +2065,69 @@ func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
utils.AssertEqual(t, "
Hello, World!
", string(c.Response().Body()))
}
+// go test -run Test_Ctx_Restart
+func Test_Ctx_Restart(t *testing.T) {
+ app := New()
+ calls := 0
+ app.Get("/", func(c *Ctx) error {
+ calls++
+ if calls < 3 {
+ return c.Restart()
+ }
+ 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_RestartWithChangedPath
+func Test_Ctx_RestartWithChangedPath(t *testing.T) {
+ app := New()
+ executedOldHandler := false
+ executedNewHandler := false
+
+ app.Get("/old", func(c *Ctx) error {
+ c.Path("/new")
+ return c.Restart()
+ })
+ 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_RestartWithChangedPathAnd404
+func Test_Ctx_RestartWithChangedPathAndCatchAll(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.Restart()
+ })
+ 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
}