Skip to content

Commit

Permalink
StripTrailingSlash is now an option
Browse files Browse the repository at this point in the history
Signed-off-by: Vishal Rana <[email protected]>
  • Loading branch information
vishr committed Sep 1, 2015
1 parent 9b36def commit 507c69e
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 87 deletions.
13 changes: 7 additions & 6 deletions echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type (
renderer Renderer
pool sync.Pool
debug bool
stripTrailingSlash bool
router *Router
}

Expand Down Expand Up @@ -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.
Expand Down
13 changes: 11 additions & 2 deletions echo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 1 addition & 11 deletions examples/middleware/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func main() {
e := echo.New()

// Debug mode
e.SetDebug(true)
e.Debug()

//------------
// Middleware
Expand All @@ -37,16 +37,6 @@ func main() {
return false
}))

//-------
// Slash
//-------

e.Use(mw.StripTrailingSlash())

// or

// e.Use(mw.RedirectToSlash())

// Gzip
e.Use(mw.Gzip())

Expand Down
2 changes: 1 addition & 1 deletion middleware/recover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 0 additions & 16 deletions middleware/slash.go

This file was deleted.

18 changes: 0 additions & 18 deletions middleware/slash_test.go

This file was deleted.

54 changes: 31 additions & 23 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down
16 changes: 6 additions & 10 deletions website/docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 507c69e

Please sign in to comment.