Skip to content

Commit f32e33a

Browse files
committed
Merge branch 'master' into panic_router_find_fails_on_params_with_no_root
2 parents 5cadf45 + 6caec30 commit f32e33a

25 files changed

+849
-128
lines changed

.github/stale.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
# Number of days of inactivity before an issue becomes stale
22
daysUntilStale: 60
33
# Number of days of inactivity before a stale issue is closed
4-
daysUntilClose: 7
4+
daysUntilClose: 30
55
# Issues with these labels will never be considered stale
66
exemptLabels:
77
- pinned
88
- security
9+
- bug
10+
- enhancement
911
# Label to use when marking an issue as stale
10-
staleLabel: wontfix
12+
staleLabel: stale
1113
# Comment to post when marking an issue as stale. Set to `false` to disable
1214
markComment: >
1315
This issue has been automatically marked as stale because it has not had
14-
recent activity. It will be closed if no further activity occurs. Thank you
15-
for your contributions.
16+
recent activity. It will be closed within a month if no further activity occurs.
17+
Thank you for your contributions.
1618
# Comment to post when closing a stale issue. Set to `false` to disable
17-
closeComment: false
19+
closeComment: false

.github/workflows/echo.yml

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,28 @@ on:
44
push:
55
branches:
66
- master
7+
paths:
8+
- '**.go'
9+
- 'go.*'
10+
- '_fixture/**'
11+
- '.github/**'
12+
- 'codecov.yml'
713
pull_request:
814
branches:
915
- master
10-
11-
env:
12-
GO111MODULE: on
13-
GOPROXY: https://proxy.golang.org
16+
paths:
17+
- '**.go'
18+
- 'go.*'
19+
- '_fixture/**'
20+
- '.github/**'
21+
- 'codecov.yml'
1422

1523
jobs:
1624
test:
1725
strategy:
1826
matrix:
1927
os: [ubuntu-latest, macos-latest, windows-latest]
20-
go: [1.12, 1.13, 1.14]
28+
go: [1.12, 1.13, 1.14, 1.15]
2129
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
2230
runs-on: ${{ matrix.os }}
2331
steps:
@@ -28,10 +36,15 @@ jobs:
2836

2937
- name: Set GOPATH and PATH
3038
run: |
31-
echo "::set-env name=GOPATH::$(dirname $GITHUB_WORKSPACE)"
32-
echo "::add-path::$(dirname $GITHUB_WORKSPACE)/bin"
39+
echo "GOPATH=$(dirname $GITHUB_WORKSPACE)" >> $GITHUB_ENV
40+
echo "$(dirname $GITHUB_WORKSPACE)/bin" >> $GITHUB_PATH
3341
shell: bash
3442

43+
- name: Set build variables
44+
run: |
45+
echo "GOPROXY=https://proxy.golang.org" >> $GITHUB_ENV
46+
echo "GO111MODULE=on" >> $GITHUB_ENV
47+
3548
- name: Checkout Code
3649
uses: actions/checkout@v1
3750
with:
@@ -51,3 +64,55 @@ jobs:
5164
with:
5265
token:
5366
fail_ci_if_error: false
67+
benchmark:
68+
needs: test
69+
strategy:
70+
matrix:
71+
os: [ubuntu-latest]
72+
go: [1.15]
73+
name: Benchmark comparison ${{ matrix.os }} @ Go ${{ matrix.go }}
74+
runs-on: ${{ matrix.os }}
75+
steps:
76+
- name: Set up Go ${{ matrix.go }}
77+
uses: actions/setup-go@v1
78+
with:
79+
go-version: ${{ matrix.go }}
80+
81+
- name: Set GOPATH and PATH
82+
run: |
83+
echo "GOPATH=$(dirname $GITHUB_WORKSPACE)" >> $GITHUB_ENV
84+
echo "$(dirname $GITHUB_WORKSPACE)/bin" >> $GITHUB_PATH
85+
shell: bash
86+
87+
- name: Set build variables
88+
run: |
89+
echo "GOPROXY=https://proxy.golang.org" >> $GITHUB_ENV
90+
echo "GO111MODULE=on" >> $GITHUB_ENV
91+
92+
- name: Checkout Code (Previous)
93+
uses: actions/checkout@v2
94+
with:
95+
ref: ${{ github.base_ref }}
96+
path: previous
97+
98+
- name: Checkout Code (New)
99+
uses: actions/checkout@v2
100+
with:
101+
path: new
102+
103+
- name: Install Dependencies
104+
run: go get -v golang.org/x/perf/cmd/benchstat
105+
106+
- name: Run Benchmark (Previous)
107+
run: |
108+
cd previous
109+
go test -run="-" -bench=".*" -count=8 ./... > benchmark.txt
110+
111+
- name: Run Benchmark (New)
112+
run: |
113+
cd new
114+
go test -run="-" -bench=".*" -count=8 ./... > benchmark.txt
115+
116+
- name: Run Benchstat
117+
run: |
118+
benchstat previous/benchmark.txt new/benchmark.txt

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
arch:
2+
- amd64
3+
- ppc64le
4+
15
language: go
26
go:
37
- 1.14.x

_fixture/_fixture/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This directory is used for the static middleware test

codecov.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
coverage:
2+
status:
3+
project:
4+
default:
5+
threshold: 1%
6+
patch:
7+
default:
8+
threshold: 1%
9+
10+
comment:
11+
require_changes: true

context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
365365
if err != nil {
366366
return nil, err
367367
}
368-
defer f.Close()
368+
f.Close()
369369
return fh, nil
370370
}
371371

echo.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,12 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
362362
// Issue #1426
363363
code := he.Code
364364
message := he.Message
365-
if e.Debug {
366-
message = err.Error()
367-
} else if m, ok := message.(string); ok {
368-
message = Map{"message": m}
365+
if m, ok := he.Message.(string); ok {
366+
if e.Debug {
367+
message = Map{"message": m, "error": err.Error()}
368+
} else {
369+
message = Map{"message": m}
370+
}
369371
}
370372

371373
// Send response
@@ -570,7 +572,7 @@ func (e *Echo) Reverse(name string, params ...interface{}) string {
570572
for _, r := range e.router.routes {
571573
if r.Name == name {
572574
for i, l := 0, len(r.Path); i < l; i++ {
573-
if r.Path[i] == ':' && n < ln {
575+
if (r.Path[i] == ':' || r.Path[i] == '*') && n < ln {
574576
for ; i < l && r.Path[i] != '/'; i++ {
575577
}
576578
uri.WriteString(fmt.Sprintf("%v", params[n]))

echo_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,12 @@ func TestEchoURL(t *testing.T) {
277277
e := New()
278278
static := func(Context) error { return nil }
279279
getUser := func(Context) error { return nil }
280+
getAny := func(Context) error { return nil }
280281
getFile := func(Context) error { return nil }
281282

282283
e.GET("/static/file", static)
283284
e.GET("/users/:id", getUser)
285+
e.GET("/documents/*", getAny)
284286
g := e.Group("/group")
285287
g.GET("/users/:uid/files/:fid", getFile)
286288

@@ -289,6 +291,9 @@ func TestEchoURL(t *testing.T) {
289291
assert.Equal("/static/file", e.URL(static))
290292
assert.Equal("/users/:id", e.URL(getUser))
291293
assert.Equal("/users/1", e.URL(getUser, "1"))
294+
assert.Equal("/users/1", e.URL(getUser, "1"))
295+
assert.Equal("/documents/foo.txt", e.URL(getAny, "foo.txt"))
296+
assert.Equal("/documents/*", e.URL(getAny))
292297
assert.Equal("/group/users/1/files/:fid", e.URL(getFile, "1"))
293298
assert.Equal("/group/users/1/files/1", e.URL(getFile, "1", "1"))
294299
}
@@ -568,6 +573,49 @@ func TestHTTPError(t *testing.T) {
568573
})
569574
}
570575

576+
func TestDefaultHTTPErrorHandler(t *testing.T) {
577+
e := New()
578+
e.Debug = true
579+
e.Any("/plain", func(c Context) error {
580+
return errors.New("An error occurred")
581+
})
582+
e.Any("/badrequest", func(c Context) error {
583+
return NewHTTPError(http.StatusBadRequest, "Invalid request")
584+
})
585+
e.Any("/servererror", func(c Context) error {
586+
return NewHTTPError(http.StatusInternalServerError, map[string]interface{}{
587+
"code": 33,
588+
"message": "Something bad happened",
589+
"error": "stackinfo",
590+
})
591+
})
592+
// With Debug=true plain response contains error message
593+
c, b := request(http.MethodGet, "/plain", e)
594+
assert.Equal(t, http.StatusInternalServerError, c)
595+
assert.Equal(t, "{\n \"error\": \"An error occurred\",\n \"message\": \"Internal Server Error\"\n}\n", b)
596+
// and special handling for HTTPError
597+
c, b = request(http.MethodGet, "/badrequest", e)
598+
assert.Equal(t, http.StatusBadRequest, c)
599+
assert.Equal(t, "{\n \"error\": \"code=400, message=Invalid request\",\n \"message\": \"Invalid request\"\n}\n", b)
600+
// complex errors are serialized to pretty JSON
601+
c, b = request(http.MethodGet, "/servererror", e)
602+
assert.Equal(t, http.StatusInternalServerError, c)
603+
assert.Equal(t, "{\n \"code\": 33,\n \"error\": \"stackinfo\",\n \"message\": \"Something bad happened\"\n}\n", b)
604+
605+
e.Debug = false
606+
// With Debug=false the error response is shortened
607+
c, b = request(http.MethodGet, "/plain", e)
608+
assert.Equal(t, http.StatusInternalServerError, c)
609+
assert.Equal(t, "{\"message\":\"Internal Server Error\"}\n", b)
610+
c, b = request(http.MethodGet, "/badrequest", e)
611+
assert.Equal(t, http.StatusBadRequest, c)
612+
assert.Equal(t, "{\"message\":\"Invalid request\"}\n", b)
613+
// No difference for error response with non plain string errors
614+
c, b = request(http.MethodGet, "/servererror", e)
615+
assert.Equal(t, http.StatusInternalServerError, c)
616+
assert.Equal(t, "{\"code\":33,\"error\":\"stackinfo\",\"message\":\"Something bad happened\"}\n", b)
617+
}
618+
571619
func TestEchoClose(t *testing.T) {
572620
e := New()
573621
errCh := make(chan error)
@@ -609,3 +657,28 @@ func TestEchoShutdown(t *testing.T) {
609657
err := <-errCh
610658
assert.Equal(t, err.Error(), "http: Server closed")
611659
}
660+
661+
func TestEchoReverse(t *testing.T) {
662+
assert := assert.New(t)
663+
664+
e := New()
665+
dummyHandler := func(Context) error { return nil }
666+
667+
e.GET("/static", dummyHandler).Name = "/static"
668+
e.GET("/static/*", dummyHandler).Name = "/static/*"
669+
e.GET("/params/:foo", dummyHandler).Name = "/params/:foo"
670+
e.GET("/params/:foo/bar/:qux", dummyHandler).Name = "/params/:foo/bar/:qux"
671+
e.GET("/params/:foo/bar/:qux/*", dummyHandler).Name = "/params/:foo/bar/:qux/*"
672+
673+
assert.Equal("/static", e.Reverse("/static"))
674+
assert.Equal("/static", e.Reverse("/static", "missing param"))
675+
assert.Equal("/static/*", e.Reverse("/static/*"))
676+
assert.Equal("/static/foo.txt", e.Reverse("/static/*", "foo.txt"))
677+
678+
assert.Equal("/params/:foo", e.Reverse("/params/:foo"))
679+
assert.Equal("/params/one", e.Reverse("/params/:foo", "one"))
680+
assert.Equal("/params/:foo/bar/:qux", e.Reverse("/params/:foo/bar/:qux"))
681+
assert.Equal("/params/one/bar/:qux", e.Reverse("/params/:foo/bar/:qux", "one"))
682+
assert.Equal("/params/one/bar/two", e.Reverse("/params/:foo/bar/:qux", "one", "two"))
683+
assert.Equal("/params/one/bar/two/three", e.Reverse("/params/:foo/bar/:qux/*", "one", "two", "three"))
684+
}

middleware/compress.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net"
99
"net/http"
1010
"strings"
11+
"sync"
1112

1213
"github.com/labstack/echo/v4"
1314
)
@@ -58,6 +59,8 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
5859
config.Level = DefaultGzipConfig.Level
5960
}
6061

62+
pool := gzipPool(config)
63+
6164
return func(next echo.HandlerFunc) echo.HandlerFunc {
6265
return func(c echo.Context) error {
6366
if config.Skipper(c) {
@@ -68,11 +71,13 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
6871
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
6972
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
7073
res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
71-
rw := res.Writer
72-
w, err := gzip.NewWriterLevel(rw, config.Level)
73-
if err != nil {
74-
return err
74+
i := pool.Get()
75+
w, ok := i.(*gzip.Writer)
76+
if !ok {
77+
return echo.NewHTTPError(http.StatusInternalServerError, i.(error).Error())
7578
}
79+
rw := res.Writer
80+
w.Reset(rw)
7681
defer func() {
7782
if res.Size == 0 {
7883
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
@@ -85,6 +90,7 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
8590
w.Reset(ioutil.Discard)
8691
}
8792
w.Close()
93+
pool.Put(w)
8894
}()
8995
grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
9096
res.Writer = grw
@@ -126,3 +132,15 @@ func (w *gzipResponseWriter) Push(target string, opts *http.PushOptions) error {
126132
}
127133
return http.ErrNotSupported
128134
}
135+
136+
func gzipPool(config GzipConfig) sync.Pool {
137+
return sync.Pool{
138+
New: func() interface{} {
139+
w, err := gzip.NewWriterLevel(ioutil.Discard, config.Level)
140+
if err != nil {
141+
return err
142+
}
143+
return w
144+
},
145+
}
146+
}

0 commit comments

Comments
 (0)