summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/v4/middleware
diff options
context:
space:
mode:
authorWim <wim@42.be>2023-08-05 20:43:19 +0200
committerGitHub <noreply@github.com>2023-08-05 20:43:19 +0200
commit56e7bd01ca09ad52b0c4f48f146a20a4f1b78696 (patch)
treeb1355645342667209263cbd355dc0b4254f1e8fe /vendor/github.com/labstack/echo/v4/middleware
parent9459495484d6e06a3d46de64fccd8d06f7ccc72c (diff)
downloadmatterbridge-msglm-master.tar.gz
matterbridge-msglm-master.tar.bz2
matterbridge-msglm-master.zip
Update dependencies and remove old matterclient lib (#2067)HEADmaster
Diffstat (limited to 'vendor/github.com/labstack/echo/v4/middleware')
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/basic_auth.go2
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/compress.go97
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/cors.go4
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/decompress.go6
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/middleware.go4
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/proxy.go213
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go21
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/recover.go28
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/request_logger.go4
9 files changed, 288 insertions, 91 deletions
diff --git a/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go b/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
index 52ef1042..f9e8caaf 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/basic_auth.go
@@ -2,9 +2,9 @@ package middleware
import (
"encoding/base64"
+ "net/http"
"strconv"
"strings"
- "net/http"
"github.com/labstack/echo/v4"
)
diff --git a/vendor/github.com/labstack/echo/v4/middleware/compress.go b/vendor/github.com/labstack/echo/v4/middleware/compress.go
index 9e5f6106..3e9bd320 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/compress.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/compress.go
@@ -2,6 +2,7 @@ package middleware
import (
"bufio"
+ "bytes"
"compress/gzip"
"io"
"net"
@@ -21,12 +22,30 @@ type (
// Gzip compression level.
// Optional. Default value -1.
Level int `yaml:"level"`
+
+ // Length threshold before gzip compression is applied.
+ // Optional. Default value 0.
+ //
+ // Most of the time you will not need to change the default. Compressing
+ // a short response might increase the transmitted data because of the
+ // gzip format overhead. Compressing the response will also consume CPU
+ // and time on the server and the client (for decompressing). Depending on
+ // your use case such a threshold might be useful.
+ //
+ // See also:
+ // https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits
+ MinLength int
}
gzipResponseWriter struct {
io.Writer
http.ResponseWriter
- wroteBody bool
+ wroteHeader bool
+ wroteBody bool
+ minLength int
+ minLengthExceeded bool
+ buffer *bytes.Buffer
+ code int
}
)
@@ -37,8 +56,9 @@ const (
var (
// DefaultGzipConfig is the default Gzip middleware config.
DefaultGzipConfig = GzipConfig{
- Skipper: DefaultSkipper,
- Level: -1,
+ Skipper: DefaultSkipper,
+ Level: -1,
+ MinLength: 0,
}
)
@@ -58,8 +78,12 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
if config.Level == 0 {
config.Level = DefaultGzipConfig.Level
}
+ if config.MinLength < 0 {
+ config.MinLength = DefaultGzipConfig.MinLength
+ }
pool := gzipCompressPool(config)
+ bpool := bufferPool()
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
@@ -70,7 +94,6 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
res := c.Response()
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
- res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
i := pool.Get()
w, ok := i.(*gzip.Writer)
if !ok {
@@ -78,19 +101,38 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
}
rw := res.Writer
w.Reset(rw)
- grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw}
+
+ buf := bpool.Get().(*bytes.Buffer)
+ buf.Reset()
+
+ grw := &gzipResponseWriter{Writer: w, ResponseWriter: rw, minLength: config.MinLength, buffer: buf}
defer func() {
+ // There are different reasons for cases when we have not yet written response to the client and now need to do so.
+ // a) handler response had only response code and no response body (ala 404 or redirects etc). Response code need to be written now.
+ // b) body is shorter than our minimum length threshold and being buffered currently and needs to be written
if !grw.wroteBody {
if res.Header().Get(echo.HeaderContentEncoding) == gzipScheme {
res.Header().Del(echo.HeaderContentEncoding)
}
+ if grw.wroteHeader {
+ rw.WriteHeader(grw.code)
+ }
// We have to reset response to it's pristine state when
// nothing is written to body or error is returned.
// See issue #424, #407.
res.Writer = rw
w.Reset(io.Discard)
+ } else if !grw.minLengthExceeded {
+ // Write uncompressed response
+ res.Writer = rw
+ if grw.wroteHeader {
+ grw.ResponseWriter.WriteHeader(grw.code)
+ }
+ grw.buffer.WriteTo(rw)
+ w.Reset(io.Discard)
}
w.Close()
+ bpool.Put(buf)
pool.Put(w)
}()
res.Writer = grw
@@ -102,7 +144,11 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
func (w *gzipResponseWriter) WriteHeader(code int) {
w.Header().Del(echo.HeaderContentLength) // Issue #444
- w.ResponseWriter.WriteHeader(code)
+
+ w.wroteHeader = true
+
+ // Delay writing of the header until we know if we'll actually compress the response
+ w.code = code
}
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
@@ -110,10 +156,40 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) {
w.Header().Set(echo.HeaderContentType, http.DetectContentType(b))
}
w.wroteBody = true
+
+ if !w.minLengthExceeded {
+ n, err := w.buffer.Write(b)
+
+ if w.buffer.Len() >= w.minLength {
+ w.minLengthExceeded = true
+
+ // The minimum length is exceeded, add Content-Encoding header and write the header
+ w.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
+ if w.wroteHeader {
+ w.ResponseWriter.WriteHeader(w.code)
+ }
+
+ return w.Writer.Write(w.buffer.Bytes())
+ }
+
+ return n, err
+ }
+
return w.Writer.Write(b)
}
func (w *gzipResponseWriter) Flush() {
+ if !w.minLengthExceeded {
+ // Enforce compression because we will not know how much more data will come
+ w.minLengthExceeded = true
+ w.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
+ if w.wroteHeader {
+ w.ResponseWriter.WriteHeader(w.code)
+ }
+
+ w.Writer.Write(w.buffer.Bytes())
+ }
+
w.Writer.(*gzip.Writer).Flush()
if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
flusher.Flush()
@@ -142,3 +218,12 @@ func gzipCompressPool(config GzipConfig) sync.Pool {
},
}
}
+
+func bufferPool() sync.Pool {
+ return sync.Pool{
+ New: func() interface{} {
+ b := &bytes.Buffer{}
+ return b
+ },
+ }
+}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/cors.go b/vendor/github.com/labstack/echo/v4/middleware/cors.go
index 149de347..6ddb540a 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/cors.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/cors.go
@@ -150,8 +150,8 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
allowOriginPatterns := []string{}
for _, origin := range config.AllowOrigins {
pattern := regexp.QuoteMeta(origin)
- pattern = strings.Replace(pattern, "\\*", ".*", -1)
- pattern = strings.Replace(pattern, "\\?", ".", -1)
+ pattern = strings.ReplaceAll(pattern, "\\*", ".*")
+ pattern = strings.ReplaceAll(pattern, "\\?", ".")
pattern = "^" + pattern + "$"
allowOriginPatterns = append(allowOriginPatterns, pattern)
}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/decompress.go b/vendor/github.com/labstack/echo/v4/middleware/decompress.go
index 88ec7098..a73c9738 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/decompress.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/decompress.go
@@ -20,7 +20,7 @@ type (
}
)
-//GZIPEncoding content-encoding header if set to "gzip", decompress body contents.
+// GZIPEncoding content-encoding header if set to "gzip", decompress body contents.
const GZIPEncoding string = "gzip"
// Decompressor is used to get the sync.Pool used by the middleware to get Gzip readers
@@ -44,12 +44,12 @@ func (d *DefaultGzipDecompressPool) gzipDecompressPool() sync.Pool {
return sync.Pool{New: func() interface{} { return new(gzip.Reader) }}
}
-//Decompress decompresses request body based if content encoding type is set to "gzip" with default config
+// Decompress decompresses request body based if content encoding type is set to "gzip" with default config
func Decompress() echo.MiddlewareFunc {
return DecompressWithConfig(DefaultDecompressConfig)
}
-//DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
+// DecompressWithConfig decompresses request body based if content encoding type is set to "gzip" with config
func DecompressWithConfig(config DecompressConfig) echo.MiddlewareFunc {
// Defaults
if config.Skipper == nil {
diff --git a/vendor/github.com/labstack/echo/v4/middleware/middleware.go b/vendor/github.com/labstack/echo/v4/middleware/middleware.go
index f250ca49..664f71f4 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/middleware.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/middleware.go
@@ -38,9 +38,9 @@ func rewriteRulesRegex(rewrite map[string]string) map[*regexp.Regexp]string {
rulesRegex := map[*regexp.Regexp]string{}
for k, v := range rewrite {
k = regexp.QuoteMeta(k)
- k = strings.Replace(k, `\*`, "(.*?)", -1)
+ k = strings.ReplaceAll(k, `\*`, "(.*?)")
if strings.HasPrefix(k, `\^`) {
- k = strings.Replace(k, `\^`, "^", -1)
+ k = strings.ReplaceAll(k, `\^`, "^")
}
k = k + "$"
rulesRegex[regexp.MustCompile(k)] = v
diff --git a/vendor/github.com/labstack/echo/v4/middleware/proxy.go b/vendor/github.com/labstack/echo/v4/middleware/proxy.go
index d2cd2aa6..e4f98d9e 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/proxy.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/proxy.go
@@ -12,7 +12,6 @@ import (
"regexp"
"strings"
"sync"
- "sync/atomic"
"time"
"github.com/labstack/echo/v4"
@@ -30,6 +29,33 @@ type (
// Required.
Balancer ProxyBalancer
+ // RetryCount defines the number of times a failed proxied request should be retried
+ // using the next available ProxyTarget. Defaults to 0, meaning requests are never retried.
+ RetryCount int
+
+ // RetryFilter defines a function used to determine if a failed request to a
+ // ProxyTarget should be retried. The RetryFilter will only be called when the number
+ // of previous retries is less than RetryCount. If the function returns true, the
+ // request will be retried. The provided error indicates the reason for the request
+ // failure. When the ProxyTarget is unavailable, the error will be an instance of
+ // echo.HTTPError with a Code of http.StatusBadGateway. In all other cases, the error
+ // will indicate an internal error in the Proxy middleware. When a RetryFilter is not
+ // specified, all requests that fail with http.StatusBadGateway will be retried. A custom
+ // RetryFilter can be provided to only retry specific requests. Note that RetryFilter is
+ // only called when the request to the target fails, or an internal error in the Proxy
+ // middleware has occurred. Successful requests that return a non-200 response code cannot
+ // be retried.
+ RetryFilter func(c echo.Context, e error) bool
+
+ // ErrorHandler defines a function which can be used to return custom errors from
+ // the Proxy middleware. ErrorHandler is only invoked when there has been
+ // either an internal error in the Proxy middleware or the ProxyTarget is
+ // unavailable. Due to the way requests are proxied, ErrorHandler is not invoked
+ // when a ProxyTarget returns a non-200 response. In these cases, the response
+ // is already written so errors cannot be modified. ErrorHandler is only
+ // invoked after all retry attempts have been exhausted.
+ ErrorHandler func(c echo.Context, err error) error
+
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be
// retrieved by index e.g. $1, $2 and so on.
// Examples:
@@ -72,26 +98,28 @@ type (
Next(echo.Context) *ProxyTarget
}
- // TargetProvider defines an interface that gives the opportunity for balancer to return custom errors when selecting target.
+ // TargetProvider defines an interface that gives the opportunity for balancer
+ // to return custom errors when selecting target.
TargetProvider interface {
NextTarget(echo.Context) (*ProxyTarget, error)
}
commonBalancer struct {
targets []*ProxyTarget
- mutex sync.RWMutex
+ mutex sync.Mutex
}
// RandomBalancer implements a random load balancing technique.
randomBalancer struct {
- *commonBalancer
+ commonBalancer
random *rand.Rand
}
// RoundRobinBalancer implements a round-robin load balancing technique.
roundRobinBalancer struct {
- *commonBalancer
- i uint32
+ commonBalancer
+ // tracking the index on `targets` slice for the next `*ProxyTarget` to be used
+ i int
}
)
@@ -107,14 +135,14 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
in, _, err := c.Response().Hijack()
if err != nil {
- c.Set("_error", fmt.Sprintf("proxy raw, hijack error=%v, url=%s", t.URL, err))
+ c.Set("_error", fmt.Errorf("proxy raw, hijack error=%w, url=%s", err, t.URL))
return
}
defer in.Close()
out, err := net.Dial("tcp", t.URL.Host)
if err != nil {
- c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err)))
+ c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", err, t.URL)))
return
}
defer out.Close()
@@ -122,7 +150,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
// Write header
err = r.Write(out)
if err != nil {
- c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err)))
+ c.Set("_error", echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", err, t.URL)))
return
}
@@ -136,39 +164,44 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
go cp(in, out)
err = <-errCh
if err != nil && err != io.EOF {
- c.Set("_error", fmt.Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err))
+ c.Set("_error", fmt.Errorf("proxy raw, copy body error=%w, url=%s", err, t.URL))
}
})
}
// NewRandomBalancer returns a random proxy balancer.
func NewRandomBalancer(targets []*ProxyTarget) ProxyBalancer {
- b := &randomBalancer{commonBalancer: new(commonBalancer)}
+ b := randomBalancer{}
b.targets = targets
- return b
+ b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
+ return &b
}
// NewRoundRobinBalancer returns a round-robin proxy balancer.
func NewRoundRobinBalancer(targets []*ProxyTarget) ProxyBalancer {
- b := &roundRobinBalancer{commonBalancer: new(commonBalancer)}
+ b := roundRobinBalancer{}
b.targets = targets
- return b
+ return &b
}
-// AddTarget adds an upstream target to the list.
+// AddTarget adds an upstream target to the list and returns `true`.
+//
+// However, if a target with the same name already exists then the operation is aborted returning `false`.
func (b *commonBalancer) AddTarget(target *ProxyTarget) bool {
+ b.mutex.Lock()
+ defer b.mutex.Unlock()
for _, t := range b.targets {
if t.Name == target.Name {
return false
}
}
- b.mutex.Lock()
- defer b.mutex.Unlock()
b.targets = append(b.targets, target)
return true
}
-// RemoveTarget removes an upstream target from the list.
+// RemoveTarget removes an upstream target from the list by name.
+//
+// Returns `true` on success, `false` if no target with the name is found.
func (b *commonBalancer) RemoveTarget(name string) bool {
b.mutex.Lock()
defer b.mutex.Unlock()
@@ -182,21 +215,58 @@ func (b *commonBalancer) RemoveTarget(name string) bool {
}
// Next randomly returns an upstream target.
+//
+// Note: `nil` is returned in case upstream target list is empty.
func (b *randomBalancer) Next(c echo.Context) *ProxyTarget {
- if b.random == nil {
- b.random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
+ b.mutex.Lock()
+ defer b.mutex.Unlock()
+ if len(b.targets) == 0 {
+ return nil
+ } else if len(b.targets) == 1 {
+ return b.targets[0]
}
- b.mutex.RLock()
- defer b.mutex.RUnlock()
return b.targets[b.random.Intn(len(b.targets))]
}
-// Next returns an upstream target using round-robin technique.
+// Next returns an upstream target using round-robin technique. In the case
+// where a previously failed request is being retried, the round-robin
+// balancer will attempt to use the next target relative to the original
+// request. If the list of targets held by the balancer is modified while a
+// failed request is being retried, it is possible that the balancer will
+// return the original failed target.
+//
+// Note: `nil` is returned in case upstream target list is empty.
func (b *roundRobinBalancer) Next(c echo.Context) *ProxyTarget {
- b.i = b.i % uint32(len(b.targets))
- t := b.targets[b.i]
- atomic.AddUint32(&b.i, 1)
- return t
+ b.mutex.Lock()
+ defer b.mutex.Unlock()
+ if len(b.targets) == 0 {
+ return nil
+ } else if len(b.targets) == 1 {
+ return b.targets[0]
+ }
+
+ var i int
+ const lastIdxKey = "_round_robin_last_index"
+ // This request is a retry, start from the index of the previous
+ // target to ensure we don't attempt to retry the request with
+ // the same failed target
+ if c.Get(lastIdxKey) != nil {
+ i = c.Get(lastIdxKey).(int)
+ i++
+ if i >= len(b.targets) {
+ i = 0
+ }
+ } else {
+ // This is a first time request, use the global index
+ if b.i >= len(b.targets) {
+ b.i = 0
+ }
+ i = b.i
+ b.i++
+ }
+
+ c.Set(lastIdxKey, i)
+ return b.targets[i]
}
// Proxy returns a Proxy middleware.
@@ -211,14 +281,26 @@ func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
// ProxyWithConfig returns a Proxy middleware with config.
// See: `Proxy()`
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
+ if config.Balancer == nil {
+ panic("echo: proxy middleware requires balancer")
+ }
// Defaults
if config.Skipper == nil {
config.Skipper = DefaultProxyConfig.Skipper
}
- if config.Balancer == nil {
- panic("echo: proxy middleware requires balancer")
+ if config.RetryFilter == nil {
+ config.RetryFilter = func(c echo.Context, e error) bool {
+ if httpErr, ok := e.(*echo.HTTPError); ok {
+ return httpErr.Code == http.StatusBadGateway
+ }
+ return false
+ }
+ }
+ if config.ErrorHandler == nil {
+ config.ErrorHandler = func(c echo.Context, err error) error {
+ return err
+ }
}
-
if config.Rewrite != nil {
if config.RegexRewrite == nil {
config.RegexRewrite = make(map[*regexp.Regexp]string)
@@ -229,28 +311,17 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
}
provider, isTargetProvider := config.Balancer.(TargetProvider)
+
return func(next echo.HandlerFunc) echo.HandlerFunc {
- return func(c echo.Context) (err error) {
+ return func(c echo.Context) error {
if config.Skipper(c) {
return next(c)
}
req := c.Request()
res := c.Response()
-
- var tgt *ProxyTarget
- if isTargetProvider {
- tgt, err = provider.NextTarget(c)
- if err != nil {
- return err
- }
- } else {
- tgt = config.Balancer.Next(c)
- }
- c.Set(config.ContextKey, tgt)
-
if err := rewriteURL(config.RegexRewrite, req); err != nil {
- return err
+ return config.ErrorHandler(c, err)
}
// Fix header
@@ -266,19 +337,49 @@ func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
req.Header.Set(echo.HeaderXForwardedFor, c.RealIP())
}
- // Proxy
- switch {
- case c.IsWebSocket():
- proxyRaw(tgt, c).ServeHTTP(res, req)
- case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
- default:
- proxyHTTP(tgt, c, config).ServeHTTP(res, req)
- }
- if e, ok := c.Get("_error").(error); ok {
- err = e
- }
+ retries := config.RetryCount
+ for {
+ var tgt *ProxyTarget
+ var err error
+ if isTargetProvider {
+ tgt, err = provider.NextTarget(c)
+ if err != nil {
+ return config.ErrorHandler(c, err)
+ }
+ } else {
+ tgt = config.Balancer.Next(c)
+ }
- return
+ c.Set(config.ContextKey, tgt)
+
+ //If retrying a failed request, clear any previous errors from
+ //context here so that balancers have the option to check for
+ //errors that occurred using previous target
+ if retries < config.RetryCount {
+ c.Set("_error", nil)
+ }
+
+ // Proxy
+ switch {
+ case c.IsWebSocket():
+ proxyRaw(tgt, c).ServeHTTP(res, req)
+ case req.Header.Get(echo.HeaderAccept) == "text/event-stream":
+ default:
+ proxyHTTP(tgt, c, config).ServeHTTP(res, req)
+ }
+
+ err, hasError := c.Get("_error").(error)
+ if !hasError {
+ return nil
+ }
+
+ retry := retries > 0 && config.RetryFilter(c, err)
+ if !retry {
+ return config.ErrorHandler(c, err)
+ }
+
+ retries--
+ }
}
}
}
diff --git a/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go b/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
index f7fae83c..1d24df52 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/rate_limiter.go
@@ -160,6 +160,8 @@ type (
burst int
expiresIn time.Duration
lastCleanup time.Time
+
+ timeNow func() time.Time
}
// Visitor signifies a unique user's limiter details
Visitor struct {
@@ -219,7 +221,8 @@ func NewRateLimiterMemoryStoreWithConfig(config RateLimiterMemoryStoreConfig) (s
store.burst = int(config.Rate)
}
store.visitors = make(map[string]*Visitor)
- store.lastCleanup = now()
+ store.timeNow = time.Now
+ store.lastCleanup = store.timeNow()
return
}
@@ -244,12 +247,13 @@ func (store *RateLimiterMemoryStore) Allow(identifier string) (bool, error) {
limiter.Limiter = rate.NewLimiter(store.rate, store.burst)
store.visitors[identifier] = limiter
}
- limiter.lastSeen = now()
- if now().Sub(store.lastCleanup) > store.expiresIn {
+ now := store.timeNow()
+ limiter.lastSeen = now
+ if now.Sub(store.lastCleanup) > store.expiresIn {
store.cleanupStaleVisitors()
}
store.mutex.Unlock()
- return limiter.AllowN(now(), 1), nil
+ return limiter.AllowN(store.timeNow(), 1), nil
}
/*
@@ -258,14 +262,9 @@ of users who haven't visited again after the configured expiry time has elapsed
*/
func (store *RateLimiterMemoryStore) cleanupStaleVisitors() {
for id, visitor := range store.visitors {
- if now().Sub(visitor.lastSeen) > store.expiresIn {
+ if store.timeNow().Sub(visitor.lastSeen) > store.expiresIn {
delete(store.visitors, id)
}
}
- store.lastCleanup = now()
+ store.lastCleanup = store.timeNow()
}
-
-/*
-actual time method which is mocked in test file
-*/
-var now = time.Now
diff --git a/vendor/github.com/labstack/echo/v4/middleware/recover.go b/vendor/github.com/labstack/echo/v4/middleware/recover.go
index 7b612853..0466cfe5 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/recover.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/recover.go
@@ -37,19 +37,26 @@ type (
// LogErrorFunc defines a function for custom logging in the middleware.
// If it's set you don't need to provide LogLevel for config.
+ // If this function returns nil, the centralized HTTPErrorHandler will not be called.
LogErrorFunc LogErrorFunc
+
+ // DisableErrorHandler disables the call to centralized HTTPErrorHandler.
+ // The recovered error is then passed back to upstream middleware, instead of swallowing the error.
+ // Optional. Default value false.
+ DisableErrorHandler bool `yaml:"disable_error_handler"`
}
)
var (
// DefaultRecoverConfig is the default Recover middleware config.
DefaultRecoverConfig = RecoverConfig{
- Skipper: DefaultSkipper,
- StackSize: 4 << 10, // 4 KB
- DisableStackAll: false,
- DisablePrintStack: false,
- LogLevel: 0,
- LogErrorFunc: nil,
+ Skipper: DefaultSkipper,
+ StackSize: 4 << 10, // 4 KB
+ DisableStackAll: false,
+ DisablePrintStack: false,
+ LogLevel: 0,
+ LogErrorFunc: nil,
+ DisableErrorHandler: false,
}
)
@@ -71,7 +78,7 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
- return func(c echo.Context) error {
+ return func(c echo.Context) (returnErr error) {
if config.Skipper(c) {
return next(c)
}
@@ -113,7 +120,12 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
c.Logger().Print(msg)
}
}
- c.Error(err)
+
+ if err != nil && !config.DisableErrorHandler {
+ c.Error(err)
+ } else {
+ returnErr = err
+ }
}
}()
return next(c)
diff --git a/vendor/github.com/labstack/echo/v4/middleware/request_logger.go b/vendor/github.com/labstack/echo/v4/middleware/request_logger.go
index b9e36925..ce76230c 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/request_logger.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/request_logger.go
@@ -225,7 +225,7 @@ func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if config.Skipper == nil {
config.Skipper = DefaultSkipper
}
- now = time.Now
+ now := time.Now
if config.timeNow != nil {
now = config.timeNow
}
@@ -257,7 +257,7 @@ func (config RequestLoggerConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
config.BeforeNextFunc(c)
}
err := next(c)
- if config.HandleError {
+ if err != nil && config.HandleError {
c.Error(err)
}