4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-07-04 05:27:44 +00:00

Update dependencies (#1784)

This commit is contained in:
Wim
2022-04-01 00:23:19 +02:00
committed by GitHub
parent 4ab72acec6
commit c6716e030c
255 changed files with 69606 additions and 58489 deletions

View File

@ -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**

View File

@ -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()))

View File

@ -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.
//

View File

@ -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 {

View File

@ -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)

View File

@ -2,10 +2,10 @@ package middleware
import (
"context"
"net/http"
"time"
"github.com/labstack/echo/v4"
"net/http"
"sync"
"time"
)
// ---------------------------------------------------------------------------------------------------------------
@ -55,29 +55,27 @@ import (
// })
//
type (
// TimeoutConfig defines the config for Timeout middleware.
TimeoutConfig struct {
// Skipper defines a function to skip middleware.
Skipper Skipper
// 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
// 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)
// 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
}
)
// 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)
}