summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack')
-rw-r--r--vendor/github.com/labstack/echo/v4/CHANGELOG.md24
-rw-r--r--vendor/github.com/labstack/echo/v4/echo.go12
-rw-r--r--vendor/github.com/labstack/echo/v4/echo_fs_go1.16.go40
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/extractor.go4
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/recover.go4
-rw-r--r--vendor/github.com/labstack/echo/v4/middleware/timeout.go130
6 files changed, 153 insertions, 61 deletions
diff --git a/vendor/github.com/labstack/echo/v4/CHANGELOG.md b/vendor/github.com/labstack/echo/v4/CHANGELOG.md
index 461ac89c..ba75d71f 100644
--- a/vendor/github.com/labstack/echo/v4/CHANGELOG.md
+++ b/vendor/github.com/labstack/echo/v4/CHANGELOG.md
@@ -1,5 +1,29 @@
# Changelog
+## v4.7.2 - 2022-03-16
+
+**Fixes**
+
+* Fix nil pointer exception when calling Start again after address binding error [#2131](https://github.com/labstack/echo/pull/2131)
+* Fix CSRF middleware not being able to extract token from multipart/form-data form [#2136](https://github.com/labstack/echo/pull/2136)
+* Fix Timeout middleware write race [#2126](https://github.com/labstack/echo/pull/2126)
+
+**Enhancements**
+
+* Recover middleware should not log panic for aborted handler [#2134](https://github.com/labstack/echo/pull/2134)
+
+
+## v4.7.1 - 2022-03-13
+
+**Fixes**
+
+* Fix `e.Static`, `.File()`, `c.Attachment()` being picky with paths starting with `./`, `../` and `/` after 4.7.0 introduced echo.Filesystem support (Go1.16+) [#2123](https://github.com/labstack/echo/pull/2123)
+
+**Enhancements**
+
+* Remove some unused code [#2116](https://github.com/labstack/echo/pull/2116)
+
+
## v4.7.0 - 2022-03-01
**Enhancements**
diff --git a/vendor/github.com/labstack/echo/v4/echo.go b/vendor/github.com/labstack/echo/v4/echo.go
index 143f9ffe..8829619c 100644
--- a/vendor/github.com/labstack/echo/v4/echo.go
+++ b/vendor/github.com/labstack/echo/v4/echo.go
@@ -246,7 +246,7 @@ const (
const (
// Version of Echo
- Version = "4.7.0"
+ Version = "4.7.2"
website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = `
@@ -732,7 +732,7 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
return s.Serve(e.Listener)
}
-func (e *Echo) configureServer(s *http.Server) (err error) {
+func (e *Echo) configureServer(s *http.Server) error {
// Setup
e.colorer.SetOutput(e.Logger.Output())
s.ErrorLog = e.StdLogger
@@ -747,10 +747,11 @@ func (e *Echo) configureServer(s *http.Server) (err error) {
if s.TLSConfig == nil {
if e.Listener == nil {
- e.Listener, err = newListener(s.Addr, e.ListenerNetwork)
+ l, err := newListener(s.Addr, e.ListenerNetwork)
if err != nil {
return err
}
+ e.Listener = l
}
if !e.HidePort {
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
@@ -791,7 +792,7 @@ func (e *Echo) TLSListenerAddr() net.Addr {
}
// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
-func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
+func (e *Echo) StartH2CServer(address string, h2s *http2.Server) error {
e.startupMutex.Lock()
// Setup
s := e.Server
@@ -808,11 +809,12 @@ func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
}
if e.Listener == nil {
- e.Listener, err = newListener(s.Addr, e.ListenerNetwork)
+ l, err := newListener(s.Addr, e.ListenerNetwork)
if err != nil {
e.startupMutex.Unlock()
return err
}
+ e.Listener = l
}
if !e.HidePort {
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
diff --git a/vendor/github.com/labstack/echo/v4/echo_fs_go1.16.go b/vendor/github.com/labstack/echo/v4/echo_fs_go1.16.go
index 435459de..eb17768a 100644
--- a/vendor/github.com/labstack/echo/v4/echo_fs_go1.16.go
+++ b/vendor/github.com/labstack/echo/v4/echo_fs_go1.16.go
@@ -10,6 +10,7 @@ import (
"net/url"
"os"
"path/filepath"
+ "runtime"
"strings"
)
@@ -94,10 +95,12 @@ func StaticFileHandler(file string, filesystem fs.FS) HandlerFunc {
}
}
-// defaultFS emulates os.Open behaviour with filesystem opened by `os.DirFs`. Difference between `os.Open` and `fs.Open`
-// is that FS does not allow to open path that start with `..` or `/` etc. For example previously you could have `../images`
-// in your application but `fs := os.DirFS("./")` would not allow you to use `fs.Open("../images")` and this would break
-// all old applications that rely on being able to traverse up from current executable run path.
+// defaultFS exists to preserve pre v4.7.0 behaviour where files were open by `os.Open`.
+// v4.7 introduced `echo.Filesystem` field which is Go1.16+ `fs.Fs` interface.
+// Difference between `os.Open` and `fs.Open` is that FS does not allow opening path that start with `.`, `..` or `/`
+// etc. For example previously you could have `../images` in your application but `fs := os.DirFS("./")` would not
+// allow you to use `fs.Open("../images")` and this would break all old applications that rely on being able to
+// traverse up from current executable run path.
// NB: private because you really should use fs.FS implementation instances
type defaultFS struct {
prefix string
@@ -108,20 +111,26 @@ func newDefaultFS() *defaultFS {
dir, _ := os.Getwd()
return &defaultFS{
prefix: dir,
- fs: os.DirFS(dir),
+ fs: nil,
}
}
func (fs defaultFS) Open(name string) (fs.File, error) {
+ if fs.fs == nil {
+ return os.Open(name)
+ }
return fs.fs.Open(name)
}
func subFS(currentFs fs.FS, root string) (fs.FS, error) {
root = filepath.ToSlash(filepath.Clean(root)) // note: fs.FS operates only with slashes. `ToSlash` is necessary for Windows
if dFS, ok := currentFs.(*defaultFS); ok {
- // we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS to
- // allow cases when root is given as `../somepath` which is not valid for fs.FS
- root = filepath.Join(dFS.prefix, root)
+ // we need to make exception for `defaultFS` instances as it interprets root prefix differently from fs.FS.
+ // fs.Fs.Open does not like relative paths ("./", "../") and absolute paths at all but prior echo.Filesystem we
+ // were able to use paths like `./myfile.log`, `/etc/hosts` and these would work fine with `os.Open` but not with fs.Fs
+ if isRelativePath(root) {
+ root = filepath.Join(dFS.prefix, root)
+ }
return &defaultFS{
prefix: root,
fs: os.DirFS(root),
@@ -130,6 +139,21 @@ func subFS(currentFs fs.FS, root string) (fs.FS, error) {
return fs.Sub(currentFs, root)
}
+func isRelativePath(path string) bool {
+ if path == "" {
+ return true
+ }
+ if path[0] == '/' {
+ return false
+ }
+ if runtime.GOOS == "windows" && strings.IndexByte(path, ':') != -1 {
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#file_and_directory_names
+ // https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
+ return false
+ }
+ return true
+}
+
// MustSubFS creates sub FS from current filesystem or panic on failure.
// Panic happens when `fsRoot` contains invalid path according to `fs.ValidPath` rules.
//
diff --git a/vendor/github.com/labstack/echo/v4/middleware/extractor.go b/vendor/github.com/labstack/echo/v4/middleware/extractor.go
index a57ed4e1..afdfd819 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/extractor.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/extractor.go
@@ -168,8 +168,8 @@ func valuesFromCookie(name string) ValuesExtractor {
// valuesFromForm returns a function that extracts values from the form field.
func valuesFromForm(name string) ValuesExtractor {
return func(c echo.Context) ([]string, error) {
- if parseErr := c.Request().ParseForm(); parseErr != nil {
- return nil, fmt.Errorf("valuesFromForm parse form failed: %w", parseErr)
+ if c.Request().Form == nil {
+ _ = c.Request().ParseMultipartForm(32 << 20) // same what `c.Request().FormValue(name)` does
}
values := c.Request().Form[name]
if len(values) == 0 {
diff --git a/vendor/github.com/labstack/echo/v4/middleware/recover.go b/vendor/github.com/labstack/echo/v4/middleware/recover.go
index a621a9ef..7b612853 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/recover.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/recover.go
@@ -2,6 +2,7 @@ package middleware
import (
"fmt"
+ "net/http"
"runtime"
"github.com/labstack/echo/v4"
@@ -77,6 +78,9 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
defer func() {
if r := recover(); r != nil {
+ if r == http.ErrAbortHandler {
+ panic(r)
+ }
err, ok := r.(error)
if !ok {
err = fmt.Errorf("%v", r)
diff --git a/vendor/github.com/labstack/echo/v4/middleware/timeout.go b/vendor/github.com/labstack/echo/v4/middleware/timeout.go
index 768ef8d7..4e8836c8 100644
--- a/vendor/github.com/labstack/echo/v4/middleware/timeout.go
+++ b/vendor/github.com/labstack/echo/v4/middleware/timeout.go
@@ -2,10 +2,10 @@ package middleware
import (
"context"
+ "github.com/labstack/echo/v4"
"net/http"
+ "sync"
"time"
-
- "github.com/labstack/echo/v4"
)
// ---------------------------------------------------------------------------------------------------------------
@@ -55,29 +55,27 @@ import (
// })
//
-type (
- // TimeoutConfig defines the config for Timeout middleware.
- TimeoutConfig struct {
- // Skipper defines a function to skip middleware.
- Skipper Skipper
-
- // ErrorMessage is written to response on timeout in addition to http.StatusServiceUnavailable (503) status code
- // It can be used to define a custom timeout error message
- ErrorMessage string
-
- // OnTimeoutRouteErrorHandler is an error handler that is executed for error that was returned from wrapped route after
- // request timeouted and we already had sent the error code (503) and message response to the client.
- // NB: do not write headers/body inside this handler. The response has already been sent to the client and response writer
- // will not accept anything no more. If you want to know what actual route middleware timeouted use `c.Path()`
- OnTimeoutRouteErrorHandler func(err error, c echo.Context)
-
- // Timeout configures a timeout for the middleware, defaults to 0 for no timeout
- // NOTE: when difference between timeout duration and handler execution time is almost the same (in range of 100microseconds)
- // the result of timeout does not seem to be reliable - could respond timeout, could respond handler output
- // difference over 500microseconds (0.5millisecond) response seems to be reliable
- Timeout time.Duration
- }
-)
+// TimeoutConfig defines the config for Timeout middleware.
+type TimeoutConfig struct {
+ // Skipper defines a function to skip middleware.
+ Skipper Skipper
+
+ // ErrorMessage is written to response on timeout in addition to http.StatusServiceUnavailable (503) status code
+ // It can be used to define a custom timeout error message
+ ErrorMessage string
+
+ // OnTimeoutRouteErrorHandler is an error handler that is executed for error that was returned from wrapped route after
+ // request timeouted and we already had sent the error code (503) and message response to the client.
+ // NB: do not write headers/body inside this handler. The response has already been sent to the client and response writer
+ // will not accept anything no more. If you want to know what actual route middleware timeouted use `c.Path()`
+ OnTimeoutRouteErrorHandler func(err error, c echo.Context)
+
+ // Timeout configures a timeout for the middleware, defaults to 0 for no timeout
+ // NOTE: when difference between timeout duration and handler execution time is almost the same (in range of 100microseconds)
+ // the result of timeout does not seem to be reliable - could respond timeout, could respond handler output
+ // difference over 500microseconds (0.5millisecond) response seems to be reliable
+ Timeout time.Duration
+}
var (
// DefaultTimeoutConfig is the default Timeout middleware config.
@@ -94,10 +92,17 @@ func Timeout() echo.MiddlewareFunc {
return TimeoutWithConfig(DefaultTimeoutConfig)
}
-// TimeoutWithConfig returns a Timeout middleware with config.
-// See: `Timeout()`.
+// TimeoutWithConfig returns a Timeout middleware with config or panics on invalid configuration.
func TimeoutWithConfig(config TimeoutConfig) echo.MiddlewareFunc {
- // Defaults
+ mw, err := config.ToMiddleware()
+ if err != nil {
+ panic(err)
+ }
+ return mw
+}
+
+// ToMiddleware converts Config to middleware or returns an error for invalid configuration
+func (config TimeoutConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if config.Skipper == nil {
config.Skipper = DefaultTimeoutConfig.Skipper
}
@@ -108,26 +113,29 @@ func TimeoutWithConfig(config TimeoutConfig) echo.MiddlewareFunc {
return next(c)
}
+ errChan := make(chan error, 1)
handlerWrapper := echoHandlerFuncWrapper{
+ writer: &ignorableWriter{ResponseWriter: c.Response().Writer},
ctx: c,
handler: next,
- errChan: make(chan error, 1),
+ errChan: errChan,
errHandler: config.OnTimeoutRouteErrorHandler,
}
handler := http.TimeoutHandler(handlerWrapper, config.Timeout, config.ErrorMessage)
- handler.ServeHTTP(c.Response().Writer, c.Request())
+ handler.ServeHTTP(handlerWrapper.writer, c.Request())
select {
- case err := <-handlerWrapper.errChan:
+ case err := <-errChan:
return err
default:
return nil
}
}
- }
+ }, nil
}
type echoHandlerFuncWrapper struct {
+ writer *ignorableWriter
ctx echo.Context
handler echo.HandlerFunc
errHandler func(err error, c echo.Context)
@@ -160,23 +168,53 @@ func (t echoHandlerFuncWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Reques
}
return // on timeout we can not send handler error to client because `http.TimeoutHandler` has already sent headers
}
- // we restore original writer only for cases we did not timeout. On timeout we have already sent response to client
- // and should not anymore send additional headers/data
- // so on timeout writer stays what http.TimeoutHandler uses and prevents writing headers/body
if err != nil {
- // Error must be written into Writer created in `http.TimeoutHandler` so to get Response into `commited` state.
- // So call global error handler to write error to the client. This is needed or `http.TimeoutHandler` will send
- // status code by itself and after that our tries to write status code will not work anymore and/or create errors in
- // log about `superfluous response.WriteHeader call from`
- t.ctx.Error(err)
- // we pass error from handler to middlewares up in handler chain to act on it if needed. But this means that
- // global error handler is probably be called twice as `t.ctx.Error` already does that.
-
- // NB: later call of the global error handler or middlewares will not take any effect, as echo.Response will be
- // already marked as `committed` because we called global error handler above.
- t.ctx.Response().Writer = originalWriter // make sure we restore before we signal original coroutine about the error
+ // This is needed as `http.TimeoutHandler` will write status code by itself on error and after that our tries to write
+ // status code will not work anymore as Echo.Response thinks it has been already "committed" and further writes
+ // create errors in log about `superfluous response.WriteHeader call from`
+ t.writer.Ignore(true)
+ t.ctx.Response().Writer = originalWriter // make sure we restore writer before we signal original coroutine about the error
+ // we pass error from handler to middlewares up in handler chain to act on it if needed.
t.errChan <- err
return
}
+ // we restore original writer only for cases we did not timeout. On timeout we have already sent response to client
+ // and should not anymore send additional headers/data
+ // so on timeout writer stays what http.TimeoutHandler uses and prevents writing headers/body
t.ctx.Response().Writer = originalWriter
}
+
+// ignorableWriter is ResponseWriter implementations that allows us to mark writer to ignore further write calls. This
+// is handy in cases when you do not have direct control of code being executed (3rd party middleware) but want to make
+// sure that external code will not be able to write response to the client.
+// Writer is coroutine safe for writes.
+type ignorableWriter struct {
+ http.ResponseWriter
+
+ lock sync.Mutex
+ ignoreWrites bool
+}
+
+func (w *ignorableWriter) Ignore(ignore bool) {
+ w.lock.Lock()
+ w.ignoreWrites = ignore
+ w.lock.Unlock()
+}
+
+func (w *ignorableWriter) WriteHeader(code int) {
+ w.lock.Lock()
+ defer w.lock.Unlock()
+ if w.ignoreWrites {
+ return
+ }
+ w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *ignorableWriter) Write(b []byte) (int, error) {
+ w.lock.Lock()
+ defer w.lock.Unlock()
+ if w.ignoreWrites {
+ return len(b), nil
+ }
+ return w.ResponseWriter.Write(b)
+}