From 5c919e6bffbf5dbe057623323effdbed2e82189e Mon Sep 17 00:00:00 2001
From: Wim <wim@42.be>
Date: Thu, 7 Dec 2017 23:00:56 +0100
Subject: Update vendor labstack/echo

---
 vendor/github.com/labstack/echo/context.go         |  11 +-
 vendor/github.com/labstack/echo/echo.go            | 136 ++++++++++++---------
 vendor/github.com/labstack/echo/group.go           |  47 +++----
 .../labstack/echo/middleware/basic_auth.go         |   7 +-
 .../labstack/echo/middleware/body_dump.go          | 112 +++++++++++++++++
 .../labstack/echo/middleware/body_limit.go         |   4 +-
 .../labstack/echo/middleware/compress.go           |   3 +-
 vendor/github.com/labstack/echo/middleware/jwt.go  |  26 ++--
 .../labstack/echo/middleware/key_auth.go           |   2 +-
 .../github.com/labstack/echo/middleware/proxy.go   |  42 +++++--
 .../github.com/labstack/echo/middleware/recover.go |  10 +-
 .../github.com/labstack/echo/middleware/static.go  |  33 +++--
 vendor/github.com/labstack/echo/response.go        |  19 ++-
 vendor/github.com/labstack/echo/router.go          |   2 +-
 vendor/github.com/labstack/echo/util_go17.go       |  12 ++
 vendor/github.com/labstack/echo/util_go18.go       |  10 ++
 vendor/manifest                                    |   2 +-
 17 files changed, 335 insertions(+), 143 deletions(-)
 create mode 100644 vendor/github.com/labstack/echo/middleware/body_dump.go
 create mode 100644 vendor/github.com/labstack/echo/util_go17.go
 create mode 100644 vendor/github.com/labstack/echo/util_go18.go

(limited to 'vendor')

diff --git a/vendor/github.com/labstack/echo/context.go b/vendor/github.com/labstack/echo/context.go
index 242eec26..54fa71ad 100644
--- a/vendor/github.com/labstack/echo/context.go
+++ b/vendor/github.com/labstack/echo/context.go
@@ -494,14 +494,9 @@ func (c *context) Stream(code int, contentType string, r io.Reader) (err error)
 }
 
 func (c *context) File(file string) (err error) {
-	file, err = url.QueryUnescape(file) // Issue #839
-	if err != nil {
-		return
-	}
-
 	f, err := os.Open(file)
 	if err != nil {
-		return ErrNotFound
+		return NotFoundHandler(c)
 	}
 	defer f.Close()
 
@@ -510,7 +505,7 @@ func (c *context) File(file string) (err error) {
 		file = filepath.Join(file, indexPage)
 		f, err = os.Open(file)
 		if err != nil {
-			return ErrNotFound
+			return NotFoundHandler(c)
 		}
 		defer f.Close()
 		if fi, err = f.Stat(); err != nil {
@@ -530,7 +525,7 @@ func (c *context) Inline(file, name string) (err error) {
 }
 
 func (c *context) contentDisposition(file, name, dispositionType string) (err error) {
-	c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%s", dispositionType, name))
+	c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
 	c.File(file)
 	return
 }
diff --git a/vendor/github.com/labstack/echo/echo.go b/vendor/github.com/labstack/echo/echo.go
index baa92fde..77c238d0 100644
--- a/vendor/github.com/labstack/echo/echo.go
+++ b/vendor/github.com/labstack/echo/echo.go
@@ -72,6 +72,7 @@ type (
 		TLSServer        *http.Server
 		Listener         net.Listener
 		TLSListener      net.Listener
+		AutoTLSManager   autocert.Manager
 		DisableHTTP2     bool
 		Debug            bool
 		HideBanner       bool
@@ -79,22 +80,22 @@ type (
 		Binder           Binder
 		Validator        Validator
 		Renderer         Renderer
-		AutoTLSManager   autocert.Manager
 		// Mutex            sync.RWMutex
 		Logger Logger
 	}
 
 	// Route contains a handler and information for matching against requests.
 	Route struct {
-		Method  string `json:"method"`
-		Path    string `json:"path"`
-		Handler string `json:"handler"`
+		Method string `json:"method"`
+		Path   string `json:"path"`
+		Name   string `json:"name"`
 	}
 
 	// HTTPError represents an error that occurred while handling a request.
 	HTTPError struct {
 		Code    int
 		Message interface{}
+		Inner   error // Stores the error returned by an external dependency
 	}
 
 	// MiddlewareFunc defines a function to process middleware.
@@ -121,7 +122,7 @@ type (
 
 	// i is the interface for Echo and Group.
 	i interface {
-		GET(string, HandlerFunc, ...MiddlewareFunc)
+		GET(string, HandlerFunc, ...MiddlewareFunc) *Route
 	}
 )
 
@@ -212,7 +213,7 @@ const (
 )
 
 const (
-	version = "3.1.0"
+	version = "3.2.5"
 	website = "https://echo.labstack.com"
 	// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
 	banner = `
@@ -282,7 +283,7 @@ func New() (e *Echo) {
 	e.TLSServer.Handler = e
 	e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
 	e.Binder = &DefaultBinder{}
-	e.Logger.SetLevel(log.OFF)
+	e.Logger.SetLevel(log.ERROR)
 	e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
 	e.pool.New = func() interface{} {
 		return e.NewContext(nil, nil)
@@ -319,6 +320,9 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
 	if he, ok := err.(*HTTPError); ok {
 		code = he.Code
 		msg = he.Message
+		if he.Inner != nil {
+			msg = fmt.Sprintf("%v, %v", err, he.Inner)
+		}
 	} else if e.Debug {
 		msg = err.Error()
 	} else {
@@ -328,19 +332,19 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
 		msg = Map{"message": msg}
 	}
 
+	e.Logger.Error(err)
+
+	// Send response
 	if !c.Response().Committed {
 		if c.Request().Method == HEAD { // Issue #608
-			if err := c.NoContent(code); err != nil {
-				goto ERROR
-			}
+			err = c.NoContent(code)
 		} else {
-			if err := c.JSON(code, msg); err != nil {
-				goto ERROR
-			}
+			err = c.JSON(code, msg)
+		}
+		if err != nil {
+			e.Logger.Error(err)
 		}
 	}
-ERROR:
-	e.Logger.Error(err)
 }
 
 // Pre adds middleware to the chain which is run before router.
@@ -355,104 +359,114 @@ func (e *Echo) Use(middleware ...MiddlewareFunc) {
 
 // CONNECT registers a new CONNECT route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(CONNECT, path, h, m...)
+func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(CONNECT, path, h, m...)
 }
 
 // DELETE registers a new DELETE route for a path with matching handler in the router
 // with optional route-level middleware.
-func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(DELETE, path, h, m...)
+func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(DELETE, path, h, m...)
 }
 
 // GET registers a new GET route for a path with matching handler in the router
 // with optional route-level middleware.
-func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(GET, path, h, m...)
+func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(GET, path, h, m...)
 }
 
 // HEAD registers a new HEAD route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(HEAD, path, h, m...)
+func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(HEAD, path, h, m...)
 }
 
 // OPTIONS registers a new OPTIONS route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(OPTIONS, path, h, m...)
+func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(OPTIONS, path, h, m...)
 }
 
 // PATCH registers a new PATCH route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(PATCH, path, h, m...)
+func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(PATCH, path, h, m...)
 }
 
 // POST registers a new POST route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(POST, path, h, m...)
+func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(POST, path, h, m...)
 }
 
 // PUT registers a new PUT route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(PUT, path, h, m...)
+func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(PUT, path, h, m...)
 }
 
 // TRACE registers a new TRACE route for a path with matching handler in the
 // router with optional route-level middleware.
-func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	e.add(TRACE, path, h, m...)
+func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return e.Add(TRACE, path, h, m...)
 }
 
 // Any registers a new route for all HTTP methods and path with matching handler
 // in the router with optional route-level middleware.
-func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
+func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+	routes := make([]*Route, 0)
 	for _, m := range methods {
-		e.add(m, path, handler, middleware...)
+		routes = append(routes, e.Add(m, path, handler, middleware...))
 	}
+	return routes
 }
 
 // Match registers a new route for multiple HTTP methods and path with matching
 // handler in the router with optional route-level middleware.
-func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
+func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+	routes := make([]*Route, 0)
 	for _, m := range methods {
-		e.add(m, path, handler, middleware...)
+		routes = append(routes, e.Add(m, path, handler, middleware...))
 	}
+	return routes
 }
 
 // Static registers a new route with path prefix to serve static files from the
 // provided root directory.
-func (e *Echo) Static(prefix, root string) {
+func (e *Echo) Static(prefix, root string) *Route {
 	if root == "" {
 		root = "." // For security we want to restrict to CWD.
 	}
-	static(e, prefix, root)
+	return static(e, prefix, root)
 }
 
-func static(i i, prefix, root string) {
+func static(i i, prefix, root string) *Route {
 	h := func(c Context) error {
-		name := filepath.Join(root, path.Clean("/"+c.Param("*"))) // "/"+ for security
+		p, err := PathUnescape(c.Param("*"))
+		if err != nil {
+			return err
+		}
+		name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
 		return c.File(name)
 	}
 	i.GET(prefix, h)
 	if prefix == "/" {
-		i.GET(prefix+"*", h)
-	} else {
-		i.GET(prefix+"/*", h)
+		return i.GET(prefix+"*", h)
 	}
+
+	return i.GET(prefix+"/*", h)
 }
 
 // File registers a new route with path to serve a static file.
-func (e *Echo) File(path, file string) {
-	e.GET(path, func(c Context) error {
+func (e *Echo) File(path, file string) *Route {
+	return e.GET(path, func(c Context) error {
 		return c.File(file)
 	})
 }
 
-func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
+// Add registers a new route for an HTTP method and path with matching handler
+// in the router with optional route-level middleware.
+func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
 	name := handlerName(handler)
 	e.router.Add(method, path, func(c Context) error {
 		h := handler
@@ -463,11 +477,12 @@ func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...Middl
 		return h(c)
 	})
 	r := &Route{
-		Method:  method,
-		Path:    path,
-		Handler: name,
+		Method: method,
+		Path:   path,
+		Name:   name,
 	}
 	e.router.routes[method+path] = r
+	return r
 }
 
 // Group creates a new router group with prefix and optional group-level middleware.
@@ -479,12 +494,22 @@ func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
 
 // URI generates a URI from handler.
 func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
+	name := handlerName(handler)
+	return e.Reverse(name, params...)
+}
+
+// URL is an alias for `URI` function.
+func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
+	return e.URI(h, params...)
+}
+
+// Reverse generates an URL from route name and provided parameters.
+func (e *Echo) Reverse(name string, params ...interface{}) string {
 	uri := new(bytes.Buffer)
 	ln := len(params)
 	n := 0
-	name := handlerName(handler)
 	for _, r := range e.router.routes {
-		if r.Handler == name {
+		if r.Name == name {
 			for i, l := 0, len(r.Path); i < l; i++ {
 				if r.Path[i] == ':' && n < ln {
 					for ; i < l && r.Path[i] != '/'; i++ {
@@ -502,11 +527,6 @@ func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
 	return uri.String()
 }
 
-// URL is an alias for `URI` function.
-func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
-	return e.URI(h, params...)
-}
-
 // Routes returns the registered routes.
 func (e *Echo) Routes() []*Route {
 	routes := []*Route{}
@@ -653,7 +673,7 @@ func NewHTTPError(code int, message ...interface{}) *HTTPError {
 
 // Error makes it compatible with `error` interface.
 func (he *HTTPError) Error() string {
-	return fmt.Sprintf("code=%d, message=%s", he.Code, he.Message)
+	return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
 }
 
 // WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
diff --git a/vendor/github.com/labstack/echo/group.go b/vendor/github.com/labstack/echo/group.go
index 799a8f90..6ae32372 100644
--- a/vendor/github.com/labstack/echo/group.go
+++ b/vendor/github.com/labstack/echo/group.go
@@ -21,66 +21,66 @@ func (g *Group) Use(middleware ...MiddlewareFunc) {
 	// Allow all requests to reach the group as they might get dropped if router
 	// doesn't find a match, making none of the group middleware process.
 	g.echo.Any(path.Clean(g.prefix+"/*"), func(c Context) error {
-		return ErrNotFound
+		return NotFoundHandler(c)
 	}, g.middleware...)
 }
 
 // CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
-func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(CONNECT, path, h, m...)
+func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(CONNECT, path, h, m...)
 }
 
 // DELETE implements `Echo#DELETE()` for sub-routes within the Group.
-func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(DELETE, path, h, m...)
+func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(DELETE, path, h, m...)
 }
 
 // GET implements `Echo#GET()` for sub-routes within the Group.
-func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(GET, path, h, m...)
+func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(GET, path, h, m...)
 }
 
 // HEAD implements `Echo#HEAD()` for sub-routes within the Group.
-func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(HEAD, path, h, m...)
+func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(HEAD, path, h, m...)
 }
 
 // OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
-func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(OPTIONS, path, h, m...)
+func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(OPTIONS, path, h, m...)
 }
 
 // PATCH implements `Echo#PATCH()` for sub-routes within the Group.
-func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(PATCH, path, h, m...)
+func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(PATCH, path, h, m...)
 }
 
 // POST implements `Echo#POST()` for sub-routes within the Group.
-func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(POST, path, h, m...)
+func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(POST, path, h, m...)
 }
 
 // PUT implements `Echo#PUT()` for sub-routes within the Group.
-func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(PUT, path, h, m...)
+func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(PUT, path, h, m...)
 }
 
 // TRACE implements `Echo#TRACE()` for sub-routes within the Group.
-func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) {
-	g.add(TRACE, path, h, m...)
+func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+	return g.Add(TRACE, path, h, m...)
 }
 
 // Any implements `Echo#Any()` for sub-routes within the Group.
 func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
 	for _, m := range methods {
-		g.add(m, path, handler, middleware...)
+		g.Add(m, path, handler, middleware...)
 	}
 }
 
 // Match implements `Echo#Match()` for sub-routes within the Group.
 func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
 	for _, m := range methods {
-		g.add(m, path, handler, middleware...)
+		g.Add(m, path, handler, middleware...)
 	}
 }
 
@@ -102,12 +102,13 @@ func (g *Group) File(path, file string) {
 	g.echo.File(g.prefix+path, file)
 }
 
-func (g *Group) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
+// Add implements `Echo#Add()` for sub-routes within the Group.
+func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
 	// Combine into a new slice to avoid accidentally passing the same slice for
 	// multiple routes, which would lead to later add() calls overwriting the
 	// middleware from earlier calls.
 	m := []MiddlewareFunc{}
 	m = append(m, g.middleware...)
 	m = append(m, middleware...)
-	g.echo.add(method, g.prefix+path, handler, m...)
+	return g.echo.Add(method, g.prefix+path, handler, m...)
 }
diff --git a/vendor/github.com/labstack/echo/middleware/basic_auth.go b/vendor/github.com/labstack/echo/middleware/basic_auth.go
index c1f34c8f..ae80da95 100644
--- a/vendor/github.com/labstack/echo/middleware/basic_auth.go
+++ b/vendor/github.com/labstack/echo/middleware/basic_auth.go
@@ -3,6 +3,7 @@ package middleware
 import (
 	"encoding/base64"
 	"strconv"
+	"strings"
 
 	"github.com/labstack/echo"
 )
@@ -27,7 +28,7 @@ type (
 )
 
 const (
-	basic        = "Basic"
+	basic        = "basic"
 	defaultRealm = "Restricted"
 )
 
@@ -54,7 +55,7 @@ func BasicAuth(fn BasicAuthValidator) echo.MiddlewareFunc {
 func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
 	// Defaults
 	if config.Validator == nil {
-		panic("basic-auth middleware requires a validator function")
+		panic("echo: basic-auth middleware requires a validator function")
 	}
 	if config.Skipper == nil {
 		config.Skipper = DefaultBasicAuthConfig.Skipper
@@ -72,7 +73,7 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
 			auth := c.Request().Header.Get(echo.HeaderAuthorization)
 			l := len(basic)
 
-			if len(auth) > l+1 && auth[:l] == basic {
+			if len(auth) > l+1 && strings.ToLower(auth[:l]) == basic {
 				b, err := base64.StdEncoding.DecodeString(auth[l+1:])
 				if err != nil {
 					return err
diff --git a/vendor/github.com/labstack/echo/middleware/body_dump.go b/vendor/github.com/labstack/echo/middleware/body_dump.go
new file mode 100644
index 00000000..88b75ee1
--- /dev/null
+++ b/vendor/github.com/labstack/echo/middleware/body_dump.go
@@ -0,0 +1,112 @@
+package middleware
+
+import (
+	"bufio"
+	"bytes"
+	"io/ioutil"
+	"net"
+	"net/http"
+
+	"io"
+
+	"github.com/labstack/echo"
+)
+
+type (
+	// BodyDumpConfig defines the config for BodyDump middleware.
+	BodyDumpConfig struct {
+		// Skipper defines a function to skip middleware.
+		Skipper Skipper
+
+		// Handler receives request and response payload.
+		// Required.
+		Handler BodyDumpHandler
+	}
+
+	// BodyDumpHandler receives the request and response payload.
+	BodyDumpHandler func(echo.Context, []byte, []byte)
+
+	bodyDumpResponseWriter struct {
+		io.Writer
+		http.ResponseWriter
+	}
+)
+
+var (
+	// DefaultBodyDumpConfig is the default Gzip middleware config.
+	DefaultBodyDumpConfig = BodyDumpConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
+// BodyDump returns a BodyDump middleware.
+//
+// BodyLimit middleware captures the request and response payload and calls the
+// registered handler.
+func BodyDump(handler BodyDumpHandler) echo.MiddlewareFunc {
+	c := DefaultBodyDumpConfig
+	c.Handler = handler
+	return BodyDumpWithConfig(c)
+}
+
+// BodyDumpWithConfig returns a BodyDump middleware with config.
+// See: `BodyDump()`.
+func BodyDumpWithConfig(config BodyDumpConfig) echo.MiddlewareFunc {
+	// Defaults
+	if config.Handler == nil {
+		panic("echo: body-dump middleware requires a handler function")
+	}
+	if config.Skipper == nil {
+		config.Skipper = DefaultBodyDumpConfig.Skipper
+	}
+
+	return func(next echo.HandlerFunc) echo.HandlerFunc {
+		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
+			// Request
+			reqBody := []byte{}
+			if c.Request().Body != nil { // Read
+				reqBody, _ = ioutil.ReadAll(c.Request().Body)
+			}
+			c.Request().Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset
+
+			// Response
+			resBody := new(bytes.Buffer)
+			mw := io.MultiWriter(c.Response().Writer, resBody)
+			writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
+			c.Response().Writer = writer
+
+			if err = next(c); err != nil {
+				c.Error(err)
+			}
+
+			// Callback
+			config.Handler(c, reqBody, resBody.Bytes())
+
+			return
+		}
+	}
+}
+
+func (w *bodyDumpResponseWriter) WriteHeader(code int) {
+	w.ResponseWriter.WriteHeader(code)
+}
+
+func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
+	return w.Writer.Write(b)
+}
+
+func (w *bodyDumpResponseWriter) Flush() {
+	w.ResponseWriter.(http.Flusher).Flush()
+}
+
+func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	return w.ResponseWriter.(http.Hijacker).Hijack()
+}
+
+func (w *bodyDumpResponseWriter) CloseNotify() <-chan bool {
+	return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
+}
diff --git a/vendor/github.com/labstack/echo/middleware/body_limit.go b/vendor/github.com/labstack/echo/middleware/body_limit.go
index a2ff8d62..b964cd29 100644
--- a/vendor/github.com/labstack/echo/middleware/body_limit.go
+++ b/vendor/github.com/labstack/echo/middleware/body_limit.go
@@ -30,7 +30,7 @@ type (
 )
 
 var (
-	// DefaultBodyLimitConfig is the default Gzip middleware config.
+	// DefaultBodyLimitConfig is the default BodyLimit middleware config.
 	DefaultBodyLimitConfig = BodyLimitConfig{
 		Skipper: DefaultSkipper,
 	}
@@ -60,7 +60,7 @@ func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
 
 	limit, err := bytes.Parse(config.Limit)
 	if err != nil {
-		panic(fmt.Errorf("invalid body-limit=%s", config.Limit))
+		panic(fmt.Errorf("echo: invalid body-limit=%s", config.Limit))
 	}
 	config.limit = limit
 	pool := limitedReaderPool(config)
diff --git a/vendor/github.com/labstack/echo/middleware/compress.go b/vendor/github.com/labstack/echo/middleware/compress.go
index cffadbd1..1615624c 100644
--- a/vendor/github.com/labstack/echo/middleware/compress.go
+++ b/vendor/github.com/labstack/echo/middleware/compress.go
@@ -67,7 +67,7 @@ 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().Add(echo.HeaderContentEncoding, gzipScheme) // Issue #806
+				res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
 				rw := res.Writer
 				w, err := gzip.NewWriterLevel(rw, config.Level)
 				if err != nil {
@@ -98,6 +98,7 @@ func (w *gzipResponseWriter) WriteHeader(code int) {
 	if code == http.StatusNoContent { // Issue #489
 		w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)
 	}
+	w.Header().Del(echo.HeaderContentLength) // Issue #444
 	w.ResponseWriter.WriteHeader(code)
 }
 
diff --git a/vendor/github.com/labstack/echo/middleware/jwt.go b/vendor/github.com/labstack/echo/middleware/jwt.go
index 5d2072e7..47d885b0 100644
--- a/vendor/github.com/labstack/echo/middleware/jwt.go
+++ b/vendor/github.com/labstack/echo/middleware/jwt.go
@@ -1,7 +1,6 @@
 package middleware
 
 import (
-	"errors"
 	"fmt"
 	"net/http"
 	"reflect"
@@ -57,6 +56,12 @@ const (
 	AlgorithmHS256 = "HS256"
 )
 
+// Errors
+var (
+	ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "Missing or malformed jwt")
+	ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "Invalid or expired jwt")
+)
+
 var (
 	// DefaultJWTConfig is the default JWT auth middleware config.
 	DefaultJWTConfig = JWTConfig{
@@ -77,7 +82,7 @@ var (
 //
 // See: https://jwt.io/introduction
 // See `JWTConfig.TokenLookup`
-func JWT(key []byte) echo.MiddlewareFunc {
+func JWT(key interface{}) echo.MiddlewareFunc {
 	c := DefaultJWTConfig
 	c.SigningKey = key
 	return JWTWithConfig(c)
@@ -134,14 +139,15 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
 
 			auth, err := extractor(c)
 			if err != nil {
-				return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+				return err
 			}
 			token := new(jwt.Token)
 			// Issue #647, #656
 			if _, ok := config.Claims.(jwt.MapClaims); ok {
 				token, err = jwt.Parse(auth, config.keyFunc)
 			} else {
-				claims := reflect.ValueOf(config.Claims).Interface().(jwt.Claims)
+				t := reflect.ValueOf(config.Claims).Type().Elem()
+				claims := reflect.New(t).Interface().(jwt.Claims)
 				token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
 			}
 			if err == nil && token.Valid {
@@ -149,7 +155,11 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
 				c.Set(config.ContextKey, token)
 				return next(c)
 			}
-			return echo.ErrUnauthorized
+			return &echo.HTTPError{
+				Code:    ErrJWTInvalid.Code,
+				Message: ErrJWTInvalid.Message,
+				Inner:   err,
+			}
 		}
 	}
 }
@@ -162,7 +172,7 @@ func jwtFromHeader(header string, authScheme string) jwtExtractor {
 		if len(auth) > l+1 && auth[:l] == authScheme {
 			return auth[l+1:], nil
 		}
-		return "", errors.New("Missing or invalid jwt in the request header")
+		return "", ErrJWTMissing
 	}
 }
 
@@ -171,7 +181,7 @@ func jwtFromQuery(param string) jwtExtractor {
 	return func(c echo.Context) (string, error) {
 		token := c.QueryParam(param)
 		if token == "" {
-			return "", errors.New("Missing jwt in the query string")
+			return "", ErrJWTMissing
 		}
 		return token, nil
 	}
@@ -182,7 +192,7 @@ func jwtFromCookie(name string) jwtExtractor {
 	return func(c echo.Context) (string, error) {
 		cookie, err := c.Cookie(name)
 		if err != nil {
-			return "", errors.New("Missing jwt in the cookie")
+			return "", ErrJWTMissing
 		}
 		return cookie.Value, nil
 	}
diff --git a/vendor/github.com/labstack/echo/middleware/key_auth.go b/vendor/github.com/labstack/echo/middleware/key_auth.go
index 5ef87e3d..24625260 100644
--- a/vendor/github.com/labstack/echo/middleware/key_auth.go
+++ b/vendor/github.com/labstack/echo/middleware/key_auth.go
@@ -72,7 +72,7 @@ func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
 		config.KeyLookup = DefaultKeyAuthConfig.KeyLookup
 	}
 	if config.Validator == nil {
-		panic("key-auth middleware requires a validator function")
+		panic("echo: key-auth middleware requires a validator function")
 	}
 
 	// Initialize
diff --git a/vendor/github.com/labstack/echo/middleware/proxy.go b/vendor/github.com/labstack/echo/middleware/proxy.go
index 7eb24abf..4f55f39d 100644
--- a/vendor/github.com/labstack/echo/middleware/proxy.go
+++ b/vendor/github.com/labstack/echo/middleware/proxy.go
@@ -1,7 +1,6 @@
 package middleware
 
 import (
-	"errors"
 	"fmt"
 	"io"
 	"math/rand"
@@ -54,35 +53,38 @@ type (
 	}
 )
 
+var (
+	// DefaultProxyConfig is the default Proxy middleware config.
+	DefaultProxyConfig = ProxyConfig{
+		Skipper: DefaultSkipper,
+	}
+)
+
 func proxyHTTP(t *ProxyTarget) http.Handler {
 	return httputil.NewSingleHostReverseProxy(t.URL)
 }
 
 func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		h, ok := w.(http.Hijacker)
-		if !ok {
-			c.Error(errors.New("proxy raw, not a hijacker"))
-			return
-		}
-		in, _, err := h.Hijack()
+		in, _, err := c.Response().Hijack()
 		if err != nil {
-			c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", r.URL, err))
+			c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", t.URL, err))
 			return
 		}
 		defer in.Close()
 
 		out, err := net.Dial("tcp", t.URL.Host)
 		if err != nil {
-			he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", r.URL, err))
+			he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err))
 			c.Error(he)
 			return
 		}
 		defer out.Close()
 
+		// Write header
 		err = r.Write(out)
 		if err != nil {
-			he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request copy error=%v, url=%s", r.URL, err))
+			he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err))
 			c.Error(he)
 			return
 		}
@@ -97,7 +99,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
 		go cp(in, out)
 		err = <-errc
 		if err != nil && err != io.EOF {
-			c.Logger().Errorf("proxy raw, error=%v, url=%s", r.URL, err)
+			c.Logger().Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err)
 		}
 	})
 }
@@ -118,8 +120,18 @@ func (r *RoundRobinBalancer) Next() *ProxyTarget {
 	return t
 }
 
-// Proxy returns an HTTP/WebSocket reverse proxy middleware.
-func Proxy(config ProxyConfig) echo.MiddlewareFunc {
+// Proxy returns a Proxy middleware.
+//
+// Proxy middleware forwards the request to upstream server using a configured load balancing technique.
+func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
+	c := DefaultProxyConfig
+	c.Balancer = balancer
+	return ProxyWithConfig(c)
+}
+
+// ProxyWithConfig returns a Proxy middleware with config.
+// See: `Proxy()`
+func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
 	// Defaults
 	if config.Skipper == nil {
 		config.Skipper = DefaultLoggerConfig.Skipper
@@ -130,6 +142,10 @@ func Proxy(config ProxyConfig) echo.MiddlewareFunc {
 
 	return func(next echo.HandlerFunc) echo.HandlerFunc {
 		return func(c echo.Context) (err error) {
+			if config.Skipper(c) {
+				return next(c)
+			}
+
 			req := c.Request()
 			res := c.Response()
 			tgt := config.Balancer.Next()
diff --git a/vendor/github.com/labstack/echo/middleware/recover.go b/vendor/github.com/labstack/echo/middleware/recover.go
index 96fa62c9..687a198a 100644
--- a/vendor/github.com/labstack/echo/middleware/recover.go
+++ b/vendor/github.com/labstack/echo/middleware/recover.go
@@ -5,7 +5,6 @@ import (
 	"runtime"
 
 	"github.com/labstack/echo"
-	"github.com/labstack/gommon/color"
 )
 
 type (
@@ -64,17 +63,14 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
 
 			defer func() {
 				if r := recover(); r != nil {
-					var err error
-					switch r := r.(type) {
-					case error:
-						err = r
-					default:
+					err, ok := r.(error)
+					if !ok {
 						err = fmt.Errorf("%v", r)
 					}
 					stack := make([]byte, config.StackSize)
 					length := runtime.Stack(stack, !config.DisableStackAll)
 					if !config.DisablePrintStack {
-						c.Logger().Printf("[%s] %s %s\n", color.Red("PANIC RECOVER"), err, stack[:length])
+						c.Logger().Printf("[PANIC RECOVER] %v %s\n", err, stack[:length])
 					}
 					c.Error(err)
 				}
diff --git a/vendor/github.com/labstack/echo/middleware/static.go b/vendor/github.com/labstack/echo/middleware/static.go
index e715c1c4..29686e0c 100644
--- a/vendor/github.com/labstack/echo/middleware/static.go
+++ b/vendor/github.com/labstack/echo/middleware/static.go
@@ -2,6 +2,7 @@ package middleware
 
 import (
 	"fmt"
+	"net/http"
 	"os"
 	"path"
 	"path/filepath"
@@ -66,7 +67,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 	}
 
 	return func(next echo.HandlerFunc) echo.HandlerFunc {
-		return func(c echo.Context) error {
+		return func(c echo.Context) (err error) {
 			if config.Skipper(c) {
 				return next(c)
 			}
@@ -75,17 +76,25 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 			if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
 				p = c.Param("*")
 			}
+			p, err = echo.PathUnescape(p)
+			if err != nil {
+				return
+			}
 			name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
 
 			fi, err := os.Stat(name)
 			if err != nil {
 				if os.IsNotExist(err) {
-					if config.HTML5 && path.Ext(p) == "" {
-						return c.File(filepath.Join(config.Root, config.Index))
+					if err = next(c); err != nil {
+						if he, ok := err.(*echo.HTTPError); ok {
+							if config.HTML5 && he.Code == http.StatusNotFound {
+								return c.File(filepath.Join(config.Root, config.Index))
+							}
+						}
+						return
 					}
-					return next(c)
 				}
-				return err
+				return
 			}
 
 			if fi.IsDir() {
@@ -99,7 +108,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 					if os.IsNotExist(err) {
 						return next(c)
 					}
-					return err
+					return
 				}
 
 				return c.File(index)
@@ -110,20 +119,20 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
 	}
 }
 
-func listDir(name string, res *echo.Response) error {
+func listDir(name string, res *echo.Response) (err error) {
 	dir, err := os.Open(name)
 	if err != nil {
-		return err
+		return
 	}
 	dirs, err := dir.Readdir(-1)
 	if err != nil {
-		return err
+		return
 	}
 
 	// Create a directory index
 	res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
 	if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
-		return err
+		return
 	}
 	for _, d := range dirs {
 		name := d.Name()
@@ -133,9 +142,9 @@ func listDir(name string, res *echo.Response) error {
 			name += "/"
 		}
 		if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
-			return err
+			return
 		}
 	}
 	_, err = fmt.Fprintf(res, "</pre>\n")
-	return err
+	return
 }
diff --git a/vendor/github.com/labstack/echo/response.go b/vendor/github.com/labstack/echo/response.go
index 2c70d213..b23931ae 100644
--- a/vendor/github.com/labstack/echo/response.go
+++ b/vendor/github.com/labstack/echo/response.go
@@ -11,11 +11,12 @@ type (
 	// by an HTTP handler to construct an HTTP response.
 	// See: https://golang.org/pkg/net/http/#ResponseWriter
 	Response struct {
-		Writer    http.ResponseWriter
-		Status    int
-		Size      int64
-		Committed bool
-		echo      *Echo
+		echo        *Echo
+		beforeFuncs []func()
+		Writer      http.ResponseWriter
+		Status      int
+		Size        int64
+		Committed   bool
 	}
 )
 
@@ -34,6 +35,11 @@ func (r *Response) Header() http.Header {
 	return r.Writer.Header()
 }
 
+// Before registers a function which is called just before the response is written.
+func (r *Response) Before(fn func()) {
+	r.beforeFuncs = append(r.beforeFuncs, fn)
+}
+
 // WriteHeader sends an HTTP response header with status code. If WriteHeader is
 // not called explicitly, the first call to Write will trigger an implicit
 // WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
@@ -43,6 +49,9 @@ func (r *Response) WriteHeader(code int) {
 		r.echo.Logger.Warn("response already committed")
 		return
 	}
+	for _, fn := range r.beforeFuncs {
+		fn()
+	}
 	r.Status = code
 	r.Writer.WriteHeader(code)
 	r.Committed = true
diff --git a/vendor/github.com/labstack/echo/router.go b/vendor/github.com/labstack/echo/router.go
index 2ef904e0..626fe225 100644
--- a/vendor/github.com/labstack/echo/router.go
+++ b/vendor/github.com/labstack/echo/router.go
@@ -394,7 +394,7 @@ func (r *Router) Find(method, path string, c Context) {
 		if cn = cn.findChildByKind(akind); cn == nil {
 			if nn != nil {
 				cn = nn
-				nn = nil // Next
+				nn = cn.parent // Next (Issue #954)
 				search = ns
 				if nk == pkind {
 					goto Param
diff --git a/vendor/github.com/labstack/echo/util_go17.go b/vendor/github.com/labstack/echo/util_go17.go
new file mode 100644
index 00000000..eaae17e3
--- /dev/null
+++ b/vendor/github.com/labstack/echo/util_go17.go
@@ -0,0 +1,12 @@
+// +build go1.7, !go1.8
+
+package echo
+
+import (
+	"net/url"
+)
+
+// PathUnescape is wraps `url.QueryUnescape`
+func PathUnescape(s string) (string, error) {
+	return url.QueryUnescape(s)
+}
diff --git a/vendor/github.com/labstack/echo/util_go18.go b/vendor/github.com/labstack/echo/util_go18.go
new file mode 100644
index 00000000..8a37785b
--- /dev/null
+++ b/vendor/github.com/labstack/echo/util_go18.go
@@ -0,0 +1,10 @@
+// +build go1.8
+
+package echo
+
+import "net/url"
+
+// PathUnescape is wraps `url.PathUnescape`
+func PathUnescape(s string) (string, error) {
+	return url.PathUnescape(s)
+}
diff --git a/vendor/manifest b/vendor/manifest
index 1423a0b7..78bc2b9a 100644
--- a/vendor/manifest
+++ b/vendor/manifest
@@ -238,7 +238,7 @@
 			"importpath": "github.com/labstack/echo",
 			"repository": "https://github.com/labstack/echo",
 			"vcs": "git",
-			"revision": "c3887ebb131d996411cf13a9688ab02c8dba599e",
+			"revision": "0473c51f1dbd83487effce00702571d19033a6e5",
 			"branch": "master",
 			"notests": true
 		},
-- 
cgit v1.2.3