Skip to content

Commit e7b1358

Browse files
committed
Merge pull request #191 from labstack/issue-190
StripTrailingSlash is now an option
2 parents 9b36def + 507c69e commit e7b1358

File tree

8 files changed

+57
-87
lines changed

8 files changed

+57
-87
lines changed

echo.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type (
3434
renderer Renderer
3535
pool sync.Pool
3636
debug bool
37+
stripTrailingSlash bool
3738
router *Router
3839
}
3940

@@ -248,14 +249,14 @@ func (e *Echo) SetRenderer(r Renderer) {
248249
e.renderer = r
249250
}
250251

251-
// SetDebug sets debug mode.
252-
func (e *Echo) SetDebug(on bool) {
253-
e.debug = on
252+
// Debug enables debug mode.
253+
func (e *Echo) Debug() {
254+
e.debug = true
254255
}
255256

256-
// Debug returns debug mode.
257-
func (e *Echo) Debug() bool {
258-
return e.debug
257+
// StripTrailingSlash enables removing trailing slash from the request path.
258+
func (e *Echo) StripTrailingSlash() {
259+
e.stripTrailingSlash = true
259260
}
260261

261262
// Use adds handler to the middleware chain.

echo_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ func TestEcho(t *testing.T) {
3333
assert.NotNil(t, e.Router())
3434

3535
// Debug
36-
e.SetDebug(true)
37-
assert.True(t, e.Debug())
36+
e.Debug()
37+
assert.True(t, e.debug)
3838

3939
// DefaultHTTPErrorHandler
4040
e.DefaultHTTPErrorHandler(errors.New("error"), c)
@@ -403,6 +403,15 @@ func TestEchoServer(t *testing.T) {
403403
assert.IsType(t, &http.Server{}, s)
404404
}
405405

406+
func TestStripTrailingSlash(t *testing.T) {
407+
e := New()
408+
e.StripTrailingSlash()
409+
r, _ := http.NewRequest(GET, "/users/", nil)
410+
w := httptest.NewRecorder()
411+
e.ServeHTTP(w, r)
412+
assert.Equal(t, http.StatusNotFound, w.Code)
413+
}
414+
406415
func testMethod(t *testing.T, method, path string, e *Echo) {
407416
m := fmt.Sprintf("%c%s", method[0], strings.ToLower(method[1:]))
408417
p := reflect.ValueOf(path)

examples/middleware/server.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func main() {
1717
e := echo.New()
1818

1919
// Debug mode
20-
e.SetDebug(true)
20+
e.Debug()
2121

2222
//------------
2323
// Middleware
@@ -37,16 +37,6 @@ func main() {
3737
return false
3838
}))
3939

40-
//-------
41-
// Slash
42-
//-------
43-
44-
e.Use(mw.StripTrailingSlash())
45-
46-
// or
47-
48-
// e.Use(mw.RedirectToSlash())
49-
5040
// Gzip
5141
e.Use(mw.Gzip())
5242

middleware/recover_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
func TestRecover(t *testing.T) {
1313
e := echo.New()
14-
e.SetDebug(true)
14+
e.Debug()
1515
req, _ := http.NewRequest(echo.GET, "/", nil)
1616
rec := httptest.NewRecorder()
1717
c := echo.NewContext(req, echo.NewResponse(rec), e)

middleware/slash.go

Lines changed: 0 additions & 16 deletions
This file was deleted.

middleware/slash_test.go

Lines changed: 0 additions & 18 deletions
This file was deleted.

router.go

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (r *Router) Add(method, path string, h HandlerFunc, e *Echo) {
7575
} else if path[i] == '*' {
7676
r.insert(method, path[:i], nil, stype, nil, e)
7777
pnames = append(pnames, "_name")
78-
r.insert(method, path[:i+1], h, mtype, pnames, e)
78+
r.insert(method, path[:i + 1], h, mtype, pnames, e)
7979
return
8080
}
8181
}
@@ -215,59 +215,59 @@ func (n *node) findChildWithType(t ntype) *node {
215215
func (r *Router) findTree(method string) (n *node) {
216216
switch method[0] {
217217
case 'G': // GET
218-
m := uint32(method[2])<<8 | uint32(method[1])<<16 | uint32(method[0])<<24
218+
m := uint32(method[2]) << 8 | uint32(method[1]) << 16 | uint32(method[0]) << 24
219219
if m == 0x47455400 {
220220
n = r.getTree
221221
}
222222
case 'P': // POST, PUT or PATCH
223223
switch method[1] {
224224
case 'O': // POST
225-
m := uint32(method[3]) | uint32(method[2])<<8 | uint32(method[1])<<16 |
226-
uint32(method[0])<<24
225+
m := uint32(method[3]) | uint32(method[2]) << 8 | uint32(method[1]) << 16 |
226+
uint32(method[0]) << 24
227227
if m == 0x504f5354 {
228228
n = r.postTree
229229
}
230230
case 'U': // PUT
231-
m := uint32(method[2])<<8 | uint32(method[1])<<16 | uint32(method[0])<<24
231+
m := uint32(method[2]) << 8 | uint32(method[1]) << 16 | uint32(method[0]) << 24
232232
if m == 0x50555400 {
233233
n = r.putTree
234234
}
235235
case 'A': // PATCH
236-
m := uint64(method[4])<<24 | uint64(method[3])<<32 | uint64(method[2])<<40 |
237-
uint64(method[1])<<48 | uint64(method[0])<<56
236+
m := uint64(method[4]) << 24 | uint64(method[3]) << 32 | uint64(method[2]) << 40 |
237+
uint64(method[1]) << 48 | uint64(method[0]) << 56
238238
if m == 0x5041544348000000 {
239239
n = r.patchTree
240240
}
241241
}
242242
case 'D': // DELETE
243-
m := uint64(method[5])<<16 | uint64(method[4])<<24 | uint64(method[3])<<32 |
244-
uint64(method[2])<<40 | uint64(method[1])<<48 | uint64(method[0])<<56
243+
m := uint64(method[5]) << 16 | uint64(method[4]) << 24 | uint64(method[3]) << 32 |
244+
uint64(method[2]) << 40 | uint64(method[1]) << 48 | uint64(method[0]) << 56
245245
if m == 0x44454c4554450000 {
246246
n = r.deleteTree
247247
}
248248
case 'C': // CONNECT
249-
m := uint64(method[6])<<8 | uint64(method[5])<<16 | uint64(method[4])<<24 |
250-
uint64(method[3])<<32 | uint64(method[2])<<40 | uint64(method[1])<<48 |
251-
uint64(method[0])<<56
249+
m := uint64(method[6]) << 8 | uint64(method[5]) << 16 | uint64(method[4]) << 24 |
250+
uint64(method[3]) << 32 | uint64(method[2]) << 40 | uint64(method[1]) << 48 |
251+
uint64(method[0]) << 56
252252
if m == 0x434f4e4e45435400 {
253253
n = r.connectTree
254254
}
255255
case 'H': // HEAD
256-
m := uint32(method[3]) | uint32(method[2])<<8 | uint32(method[1])<<16 |
257-
uint32(method[0])<<24
256+
m := uint32(method[3]) | uint32(method[2]) << 8 | uint32(method[1]) << 16 |
257+
uint32(method[0]) << 24
258258
if m == 0x48454144 {
259259
n = r.headTree
260260
}
261261
case 'O': // OPTIONS
262-
m := uint64(method[6])<<8 | uint64(method[5])<<16 | uint64(method[4])<<24 |
263-
uint64(method[3])<<32 | uint64(method[2])<<40 | uint64(method[1])<<48 |
264-
uint64(method[0])<<56
262+
m := uint64(method[6]) << 8 | uint64(method[5]) << 16 | uint64(method[4]) << 24 |
263+
uint64(method[3]) << 32 | uint64(method[2]) << 40 | uint64(method[1]) << 48 |
264+
uint64(method[0]) << 56
265265
if m == 0x4f5054494f4e5300 {
266266
n = r.optionsTree
267267
}
268268
case 'T': // TRACE
269-
m := uint64(method[4])<<24 | uint64(method[3])<<32 | uint64(method[2])<<40 |
270-
uint64(method[1])<<48 | uint64(method[0])<<56
269+
m := uint64(method[4]) << 24 | uint64(method[3]) << 32 | uint64(method[2]) << 40 |
270+
uint64(method[1]) << 48 | uint64(method[0]) << 56
271271
if m == 0x5452414345000000 {
272272
n = r.traceTree
273273
}
@@ -282,11 +282,19 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo
282282
h = badRequestHandler
283283
return
284284
}
285-
search := path
285+
286+
// Strip trailing slash
287+
if r.echo.stripTrailingSlash {
288+
l := len(path)
289+
if path[l - 1] == '/' {
290+
path = path[:l - 1]
291+
}
292+
}
286293

287294
var (
295+
search = path
288296
c *node // Child node
289-
n int // Param counter
297+
n int // Param counter
290298
nt ntype // Next type
291299
nn *node // Next node
292300
ns string // Next search
@@ -361,7 +369,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo
361369
}
362370

363371
// Param node
364-
Param:
372+
Param:
365373
c = cn.findChildWithType(ptype)
366374
if c != nil {
367375
// Save next
@@ -381,7 +389,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo
381389
}
382390

383391
// Match-any node
384-
MatchAny:
392+
MatchAny:
385393
// c = cn.getChild()
386394
c = cn.findChildWithType(mtype)
387395
if c != nil {

website/docs/guide.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ Enables debug mode.
5050

5151
`Echo.DisableColoredLog()`
5252

53+
### StripTrailingSlash
54+
55+
StripTrailingSlash enables removing trailing slash from the request path.
56+
57+
`e.StripTrailingSlash()`
58+
5359
## Routing
5460

5561
Echo's router is [fast, optimized](https://github.com/labstack/echo#benchmark) and
@@ -210,16 +216,6 @@ to the centralized [HTTPErrorHandler](#error-handling).
210216
e.Use(mw.Recover())
211217
```
212218

213-
### StripTrailingSlash
214-
215-
StripTrailingSlash middleware removes the trailing slash from request path.
216-
217-
*Example*
218-
219-
```go
220-
e.Use(mw.StripTrailingSlash())
221-
```
222-
223219
[Examples](https://github.com/labstack/echo/tree/master/examples/middleware)
224220

225221
## Request

0 commit comments

Comments
 (0)