summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/v4/echo.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack/echo/v4/echo.go')
-rw-r--r--vendor/github.com/labstack/echo/v4/echo.go135
1 files changed, 109 insertions, 26 deletions
diff --git a/vendor/github.com/labstack/echo/v4/echo.go b/vendor/github.com/labstack/echo/v4/echo.go
index 18c11016..3fccaf64 100644
--- a/vendor/github.com/labstack/echo/v4/echo.go
+++ b/vendor/github.com/labstack/echo/v4/echo.go
@@ -49,7 +49,6 @@ import (
"net/http"
"net/url"
"os"
- "path"
"path/filepath"
"reflect"
"runtime"
@@ -68,6 +67,9 @@ type (
// Echo is the top-level framework instance.
Echo struct {
common
+ // startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
+ // listener address info (on which interface/port was listener binded) without having data races.
+ startupMutex sync.RWMutex
StdLogger *stdLog.Logger
colorer *color.Color
premiddleware []MiddlewareFunc
@@ -92,6 +94,7 @@ type (
Renderer Renderer
Logger Logger
IPExtractor IPExtractor
+ ListenerNetwork string
}
// Route contains a handler and information for matching against requests.
@@ -231,7 +234,7 @@ const (
const (
// Version of Echo
- Version = "4.1.17"
+ Version = "4.2.1"
website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = `
@@ -281,6 +284,7 @@ var (
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
ErrCookieNotFound = errors.New("cookie not found")
ErrInvalidCertOrKeyType = errors.New("invalid cert or key type, must be string or []byte")
+ ErrInvalidListenerNetwork = errors.New("invalid listener network")
)
// Error handlers
@@ -302,9 +306,10 @@ func New() (e *Echo) {
AutoTLSManager: autocert.Manager{
Prompt: autocert.AcceptTOS,
},
- Logger: log.New("echo"),
- colorer: color.New(),
- maxParam: new(int),
+ Logger: log.New("echo"),
+ colorer: color.New(),
+ maxParam: new(int),
+ ListenerNetwork: "tcp",
}
e.Server.Handler = e
e.TLSServer.Handler = e
@@ -362,10 +367,12 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
// Issue #1426
code := he.Code
message := he.Message
- if e.Debug {
- message = err.Error()
- } else if m, ok := message.(string); ok {
- message = Map{"message": m}
+ if m, ok := he.Message.(string); ok {
+ if e.Debug {
+ message = Map{"message": m, "error": err.Error()}
+ } else {
+ message = Map{"message": m}
+ }
}
// Send response
@@ -481,7 +488,7 @@ func (common) static(prefix, root string, get func(string, HandlerFunc, ...Middl
return err
}
- name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
+ name := filepath.Join(root, filepath.Clean("/"+p)) // "/"+ for security
fi, err := os.Stat(name)
if err != nil {
// The access path does not exist
@@ -496,8 +503,15 @@ func (common) static(prefix, root string, get func(string, HandlerFunc, ...Middl
}
return c.File(name)
}
- if prefix == "/" {
- return get(prefix+"*", h)
+ // Handle added routes based on trailing slash:
+ // /prefix => exact route "/prefix" + any route "/prefix/*"
+ // /prefix/ => only any route "/prefix/*"
+ if prefix != "" {
+ if prefix[len(prefix)-1] == '/' {
+ // Only add any route for intentional trailing slash
+ return get(prefix+"*", h)
+ }
+ get(prefix, h)
}
return get(prefix+"/*", h)
}
@@ -570,7 +584,7 @@ func (e *Echo) Reverse(name string, params ...interface{}) string {
for _, r := range e.router.routes {
if r.Name == name {
for i, l := 0, len(r.Path); i < l; i++ {
- if r.Path[i] == ':' && n < ln {
+ if (r.Path[i] == ':' || r.Path[i] == '*') && n < ln {
for ; i < l && r.Path[i] != '/'; i++ {
}
uri.WriteString(fmt.Sprintf("%v", params[n]))
@@ -612,7 +626,6 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Acquire context
c := e.pool.Get().(*context)
c.Reset(r, w)
-
h := NotFoundHandler
if e.premiddleware == nil {
@@ -640,21 +653,30 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Start starts an HTTP server.
func (e *Echo) Start(address string) error {
+ e.startupMutex.Lock()
e.Server.Addr = address
- return e.StartServer(e.Server)
+ if err := e.configureServer(e.Server); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.startupMutex.Unlock()
+ return e.Server.Serve(e.Listener)
}
// StartTLS starts an HTTPS server.
// If `certFile` or `keyFile` is `string` the values are treated as file paths.
// If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.
func (e *Echo) StartTLS(address string, certFile, keyFile interface{}) (err error) {
+ e.startupMutex.Lock()
var cert []byte
if cert, err = filepathOrContent(certFile); err != nil {
+ e.startupMutex.Unlock()
return
}
var key []byte
if key, err = filepathOrContent(keyFile); err != nil {
+ e.startupMutex.Unlock()
return
}
@@ -662,10 +684,17 @@ func (e *Echo) StartTLS(address string, certFile, keyFile interface{}) (err erro
s.TLSConfig = new(tls.Config)
s.TLSConfig.Certificates = make([]tls.Certificate, 1)
if s.TLSConfig.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
+ e.startupMutex.Unlock()
return
}
- return e.startTLS(address)
+ e.configureTLS(address)
+ if err := e.configureServer(s); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.TLSListener)
}
func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
@@ -681,24 +710,45 @@ func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
func (e *Echo) StartAutoTLS(address string) error {
+ e.startupMutex.Lock()
s := e.TLSServer
s.TLSConfig = new(tls.Config)
s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto)
- return e.startTLS(address)
+
+ e.configureTLS(address)
+ if err := e.configureServer(s); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.TLSListener)
}
-func (e *Echo) startTLS(address string) error {
+func (e *Echo) configureTLS(address string) {
s := e.TLSServer
s.Addr = address
if !e.DisableHTTP2 {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
}
- return e.StartServer(e.TLSServer)
}
// StartServer starts a custom http server.
func (e *Echo) StartServer(s *http.Server) (err error) {
+ e.startupMutex.Lock()
+ if err := e.configureServer(s); err != nil {
+ e.startupMutex.Unlock()
+ return err
+ }
+ if s.TLSConfig != nil {
+ e.startupMutex.Unlock()
+ return s.Serve(e.TLSListener)
+ }
+ e.startupMutex.Unlock()
+ return s.Serve(e.Listener)
+}
+
+func (e *Echo) configureServer(s *http.Server) (err error) {
// Setup
e.colorer.SetOutput(e.Logger.Output())
s.ErrorLog = e.StdLogger
@@ -713,7 +763,7 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
if s.TLSConfig == nil {
if e.Listener == nil {
- e.Listener, err = newListener(s.Addr)
+ e.Listener, err = newListener(s.Addr, e.ListenerNetwork)
if err != nil {
return err
}
@@ -721,10 +771,10 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
if !e.HidePort {
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
}
- return s.Serve(e.Listener)
+ return nil
}
if e.TLSListener == nil {
- l, err := newListener(s.Addr)
+ l, err := newListener(s.Addr, e.ListenerNetwork)
if err != nil {
return err
}
@@ -733,11 +783,32 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
if !e.HidePort {
e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
}
- return s.Serve(e.TLSListener)
+ return nil
+}
+
+// ListenerAddr returns net.Addr for Listener
+func (e *Echo) ListenerAddr() net.Addr {
+ e.startupMutex.RLock()
+ defer e.startupMutex.RUnlock()
+ if e.Listener == nil {
+ return nil
+ }
+ return e.Listener.Addr()
+}
+
+// TLSListenerAddr returns net.Addr for TLSListener
+func (e *Echo) TLSListenerAddr() net.Addr {
+ e.startupMutex.RLock()
+ defer e.startupMutex.RUnlock()
+ if e.TLSListener == nil {
+ return nil
+ }
+ return e.TLSListener.Addr()
}
// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
+ e.startupMutex.Lock()
// Setup
s := e.Server
s.Addr = address
@@ -753,20 +824,24 @@ func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
}
if e.Listener == nil {
- e.Listener, err = newListener(s.Addr)
+ e.Listener, err = newListener(s.Addr, e.ListenerNetwork)
if err != nil {
+ e.startupMutex.Unlock()
return err
}
}
if !e.HidePort {
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
}
+ e.startupMutex.Unlock()
return s.Serve(e.Listener)
}
// Close immediately stops the server.
// It internally calls `http.Server#Close()`.
func (e *Echo) Close() error {
+ e.startupMutex.Lock()
+ defer e.startupMutex.Unlock()
if err := e.TLSServer.Close(); err != nil {
return err
}
@@ -776,6 +851,8 @@ func (e *Echo) Close() error {
// Shutdown stops the server gracefully.
// It internally calls `http.Server#Shutdown()`.
func (e *Echo) Shutdown(ctx stdContext.Context) error {
+ e.startupMutex.Lock()
+ defer e.startupMutex.Unlock()
if err := e.TLSServer.Shutdown(ctx); err != nil {
return err
}
@@ -833,6 +910,9 @@ func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
}
// GetPath returns RawPath, if it's empty returns Path from URL
+// Difference between RawPath and Path is:
+// * Path is where request path is stored. Value is stored in decoded form: /%47%6f%2f becomes /Go/.
+// * RawPath is an optional field which only gets set if the default encoding is different from Path.
func GetPath(r *http.Request) string {
path := r.URL.RawPath
if path == "" {
@@ -883,8 +963,11 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
return
}
-func newListener(address string) (*tcpKeepAliveListener, error) {
- l, err := net.Listen("tcp", address)
+func newListener(address, network string) (*tcpKeepAliveListener, error) {
+ if network != "tcp" && network != "tcp4" && network != "tcp6" {
+ return nil, ErrInvalidListenerNetwork
+ }
+ l, err := net.Listen(network, address)
if err != nil {
return nil, err
}