Open
Description
Issue Description
I think I found a bug in how RouteNotFound
handler is propagated to route groups.
When using groups with a dedicated middleware there is no fallback to the root RouteNotFound
handler, while that happens when no middleware is specified.
Checklist
- Dependencies installed (not sure what this means)
- No typos
- Searched existing issues and docs
Expected behaviour
The root RouteNotFound
handler is used.
Actual behaviour
An internal(?) handler is used
Steps to reproduce
Put the code below in a test file, run go test ./...
Working code to debug
This is a test file that reproduce the issue.
package main_test
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/require"
)
func server() http.Handler {
e := echo.New()
e.HideBanner = true
e.HidePort = true
// expect this handler is used as fallback unless a more specific is present
e.RouteNotFound("/*", missingRouteHandler)
// addig a middleware to the group overrides the RouteNotFound handler
v0 := e.Group("/v0", func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
return next(c)
}
})
// adding this would make it work
// v0.RouteNotFound("/*", missingRouteHandler)
v0.POST("/resource", handler)
// the same does not happen when no middleware is set
v1 := e.Group("/v1")
v1.POST("/resource", handler)
return e
}
func missingRouteHandler(c echo.Context) error {
return c.NoContent(http.StatusNotFound)
}
func handler(c echo.Context) error {
return nil
}
func TestMissing(t *testing.T) {
srv := httptest.NewServer(server())
routes := []string{
// this is successful
"/foo",
// this fails
// Error Trace: /home/endorama/code/REDACTED/main_test.go:68
// Error: "{"message":"Not Found"}
// " should have 0 item(s), but has 24
// Test: TestMissing//v0/foo
"/v0/foo",
// this is successful
"/v1/foo",
}
for _, path := range routes {
t.Run(path, func(t *testing.T) {
req, _ := http.NewRequest("POST", srv.URL+path, nil)
resp, err := srv.Client().Do(req)
require.NoError(t, err)
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, http.StatusNotFound, resp.StatusCode)
require.Len(t, b, 0)
require.Equal(t, "0", resp.Header.Get("Content-Length"))
})
}
}
Version/commit
github.com/labstack/echo/v4 v4.11.1