From 507c69ec80e6a6d8417231b4db93f7d9554e09cc Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Tue, 1 Sep 2015 08:03:01 -0700 Subject: [PATCH] StripTrailingSlash is now an option Signed-off-by: Vishal Rana --- echo.go | 13 +++++---- echo_test.go | 13 +++++++-- examples/middleware/server.go | 12 +------- middleware/recover_test.go | 2 +- middleware/slash.go | 16 ----------- middleware/slash_test.go | 18 ------------ router.go | 54 ++++++++++++++++++++--------------- website/docs/guide.md | 16 ++++------- 8 files changed, 57 insertions(+), 87 deletions(-) delete mode 100644 middleware/slash.go delete mode 100644 middleware/slash_test.go diff --git a/echo.go b/echo.go index 54d3ce2a..ba8c9c41 100644 --- a/echo.go +++ b/echo.go @@ -34,6 +34,7 @@ type ( renderer Renderer pool sync.Pool debug bool + stripTrailingSlash bool router *Router } @@ -248,14 +249,14 @@ func (e *Echo) SetRenderer(r Renderer) { e.renderer = r } -// SetDebug sets debug mode. -func (e *Echo) SetDebug(on bool) { - e.debug = on +// Debug enables debug mode. +func (e *Echo) Debug() { + e.debug = true } -// Debug returns debug mode. -func (e *Echo) Debug() bool { - return e.debug +// StripTrailingSlash enables removing trailing slash from the request path. +func (e *Echo) StripTrailingSlash() { + e.stripTrailingSlash = true } // Use adds handler to the middleware chain. diff --git a/echo_test.go b/echo_test.go index 49ad612b..aec0b056 100644 --- a/echo_test.go +++ b/echo_test.go @@ -33,8 +33,8 @@ func TestEcho(t *testing.T) { assert.NotNil(t, e.Router()) // Debug - e.SetDebug(true) - assert.True(t, e.Debug()) + e.Debug() + assert.True(t, e.debug) // DefaultHTTPErrorHandler e.DefaultHTTPErrorHandler(errors.New("error"), c) @@ -403,6 +403,15 @@ func TestEchoServer(t *testing.T) { assert.IsType(t, &http.Server{}, s) } +func TestStripTrailingSlash(t *testing.T) { + e := New() + e.StripTrailingSlash() + r, _ := http.NewRequest(GET, "/users/", nil) + w := httptest.NewRecorder() + e.ServeHTTP(w, r) + assert.Equal(t, http.StatusNotFound, w.Code) +} + func testMethod(t *testing.T, method, path string, e *Echo) { m := fmt.Sprintf("%c%s", method[0], strings.ToLower(method[1:])) p := reflect.ValueOf(path) diff --git a/examples/middleware/server.go b/examples/middleware/server.go index 503210c3..98fa0d75 100644 --- a/examples/middleware/server.go +++ b/examples/middleware/server.go @@ -17,7 +17,7 @@ func main() { e := echo.New() // Debug mode - e.SetDebug(true) + e.Debug() //------------ // Middleware @@ -37,16 +37,6 @@ func main() { return false })) - //------- - // Slash - //------- - - e.Use(mw.StripTrailingSlash()) - - // or - - // e.Use(mw.RedirectToSlash()) - // Gzip e.Use(mw.Gzip()) diff --git a/middleware/recover_test.go b/middleware/recover_test.go index 003c7519..0dd2f5f9 100644 --- a/middleware/recover_test.go +++ b/middleware/recover_test.go @@ -11,7 +11,7 @@ import ( func TestRecover(t *testing.T) { e := echo.New() - e.SetDebug(true) + e.Debug() req, _ := http.NewRequest(echo.GET, "/", nil) rec := httptest.NewRecorder() c := echo.NewContext(req, echo.NewResponse(rec), e) diff --git a/middleware/slash.go b/middleware/slash.go deleted file mode 100644 index 3c8989db..00000000 --- a/middleware/slash.go +++ /dev/null @@ -1,16 +0,0 @@ -package middleware - -import "github.com/labstack/echo" - -// StripTrailingSlash returns a middleware which removes trailing slash from request -// path. -func StripTrailingSlash() echo.HandlerFunc { - return func(c *echo.Context) error { - p := c.Request().URL.Path - l := len(p) - if p[l-1] == '/' { - c.Request().URL.Path = p[:l-1] - } - return nil - } -} diff --git a/middleware/slash_test.go b/middleware/slash_test.go deleted file mode 100644 index 7031f401..00000000 --- a/middleware/slash_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package middleware - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/labstack/echo" - "github.com/stretchr/testify/assert" -) - -func TestStripTrailingSlash(t *testing.T) { - req, _ := http.NewRequest(echo.GET, "/users/", nil) - rec := httptest.NewRecorder() - c := echo.NewContext(req, echo.NewResponse(rec), echo.New()) - StripTrailingSlash()(c) - assert.Equal(t, "/users", c.Request().URL.Path) -} diff --git a/router.go b/router.go index ba57b85c..82a57282 100644 --- a/router.go +++ b/router.go @@ -75,7 +75,7 @@ func (r *Router) Add(method, path string, h HandlerFunc, e *Echo) { } else if path[i] == '*' { r.insert(method, path[:i], nil, stype, nil, e) pnames = append(pnames, "_name") - r.insert(method, path[:i+1], h, mtype, pnames, e) + r.insert(method, path[:i + 1], h, mtype, pnames, e) return } } @@ -215,59 +215,59 @@ func (n *node) findChildWithType(t ntype) *node { func (r *Router) findTree(method string) (n *node) { switch method[0] { case 'G': // GET - m := uint32(method[2])<<8 | uint32(method[1])<<16 | uint32(method[0])<<24 + m := uint32(method[2]) << 8 | uint32(method[1]) << 16 | uint32(method[0]) << 24 if m == 0x47455400 { n = r.getTree } case 'P': // POST, PUT or PATCH switch method[1] { case 'O': // POST - m := uint32(method[3]) | uint32(method[2])<<8 | uint32(method[1])<<16 | - uint32(method[0])<<24 + m := uint32(method[3]) | uint32(method[2]) << 8 | uint32(method[1]) << 16 | + uint32(method[0]) << 24 if m == 0x504f5354 { n = r.postTree } case 'U': // PUT - m := uint32(method[2])<<8 | uint32(method[1])<<16 | uint32(method[0])<<24 + m := uint32(method[2]) << 8 | uint32(method[1]) << 16 | uint32(method[0]) << 24 if m == 0x50555400 { n = r.putTree } case 'A': // PATCH - m := uint64(method[4])<<24 | uint64(method[3])<<32 | uint64(method[2])<<40 | - uint64(method[1])<<48 | uint64(method[0])<<56 + m := uint64(method[4]) << 24 | uint64(method[3]) << 32 | uint64(method[2]) << 40 | + uint64(method[1]) << 48 | uint64(method[0]) << 56 if m == 0x5041544348000000 { n = r.patchTree } } case 'D': // DELETE - m := uint64(method[5])<<16 | uint64(method[4])<<24 | uint64(method[3])<<32 | - uint64(method[2])<<40 | uint64(method[1])<<48 | uint64(method[0])<<56 + m := uint64(method[5]) << 16 | uint64(method[4]) << 24 | uint64(method[3]) << 32 | + uint64(method[2]) << 40 | uint64(method[1]) << 48 | uint64(method[0]) << 56 if m == 0x44454c4554450000 { n = r.deleteTree } case 'C': // CONNECT - m := uint64(method[6])<<8 | uint64(method[5])<<16 | uint64(method[4])<<24 | - uint64(method[3])<<32 | uint64(method[2])<<40 | uint64(method[1])<<48 | - uint64(method[0])<<56 + m := uint64(method[6]) << 8 | uint64(method[5]) << 16 | uint64(method[4]) << 24 | + uint64(method[3]) << 32 | uint64(method[2]) << 40 | uint64(method[1]) << 48 | + uint64(method[0]) << 56 if m == 0x434f4e4e45435400 { n = r.connectTree } case 'H': // HEAD - m := uint32(method[3]) | uint32(method[2])<<8 | uint32(method[1])<<16 | - uint32(method[0])<<24 + m := uint32(method[3]) | uint32(method[2]) << 8 | uint32(method[1]) << 16 | + uint32(method[0]) << 24 if m == 0x48454144 { n = r.headTree } case 'O': // OPTIONS - m := uint64(method[6])<<8 | uint64(method[5])<<16 | uint64(method[4])<<24 | - uint64(method[3])<<32 | uint64(method[2])<<40 | uint64(method[1])<<48 | - uint64(method[0])<<56 + m := uint64(method[6]) << 8 | uint64(method[5]) << 16 | uint64(method[4]) << 24 | + uint64(method[3]) << 32 | uint64(method[2]) << 40 | uint64(method[1]) << 48 | + uint64(method[0]) << 56 if m == 0x4f5054494f4e5300 { n = r.optionsTree } case 'T': // TRACE - m := uint64(method[4])<<24 | uint64(method[3])<<32 | uint64(method[2])<<40 | - uint64(method[1])<<48 | uint64(method[0])<<56 + m := uint64(method[4]) << 24 | uint64(method[3]) << 32 | uint64(method[2]) << 40 | + uint64(method[1]) << 48 | uint64(method[0]) << 56 if m == 0x5452414345000000 { n = r.traceTree } @@ -282,11 +282,19 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo h = badRequestHandler return } - search := path + + // Strip trailing slash + if r.echo.stripTrailingSlash { + l := len(path) + if path[l - 1] == '/' { + path = path[:l - 1] + } + } var ( + search = path c *node // Child node - n int // Param counter + n int // Param counter nt ntype // Next type nn *node // Next node ns string // Next search @@ -361,7 +369,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo } // Param node - Param: + Param: c = cn.findChildWithType(ptype) if c != nil { // Save next @@ -381,7 +389,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo } // Match-any node - MatchAny: + MatchAny: // c = cn.getChild() c = cn.findChildWithType(mtype) if c != nil { diff --git a/website/docs/guide.md b/website/docs/guide.md index 67f28d77..16db2d28 100644 --- a/website/docs/guide.md +++ b/website/docs/guide.md @@ -50,6 +50,12 @@ Enables debug mode. `Echo.DisableColoredLog()` +### StripTrailingSlash + +StripTrailingSlash enables removing trailing slash from the request path. + +`e.StripTrailingSlash()` + ## Routing Echo's router is [fast, optimized](https://github.com/labstack/echo#benchmark) and @@ -210,16 +216,6 @@ to the centralized [HTTPErrorHandler](#error-handling). e.Use(mw.Recover()) ``` -### StripTrailingSlash - -StripTrailingSlash middleware removes the trailing slash from request path. - -*Example* - -```go -e.Use(mw.StripTrailingSlash()) -``` - [Examples](https://github.com/labstack/echo/tree/master/examples/middleware) ## Request