src: Add DMA localagent
[barometer.git] / src / dma / vendor / github.com / labstack / echo / echo.go
diff --git a/src/dma/vendor/github.com/labstack/echo/echo.go b/src/dma/vendor/github.com/labstack/echo/echo.go
new file mode 100644 (file)
index 0000000..41ac6b5
--- /dev/null
@@ -0,0 +1,781 @@
+/*
+Package echo implements high performance, minimalist Go web framework.
+
+Example:
+
+  package main
+
+  import (
+    "net/http"
+
+    "github.com/labstack/echo"
+    "github.com/labstack/echo/middleware"
+  )
+
+  // Handler
+  func hello(c echo.Context) error {
+    return c.String(http.StatusOK, "Hello, World!")
+  }
+
+  func main() {
+    // Echo instance
+    e := echo.New()
+
+    // Middleware
+    e.Use(middleware.Logger())
+    e.Use(middleware.Recover())
+
+    // Routes
+    e.GET("/", hello)
+
+    // Start server
+    e.Logger.Fatal(e.Start(":1323"))
+  }
+
+Learn more at https://echo.labstack.com
+*/
+package echo
+
+import (
+       "bytes"
+       stdContext "context"
+       "crypto/tls"
+       "errors"
+       "fmt"
+       "io"
+       stdLog "log"
+       "net"
+       "net/http"
+       "net/url"
+       "path"
+       "path/filepath"
+       "reflect"
+       "runtime"
+       "sync"
+       "time"
+
+       "github.com/labstack/gommon/color"
+       "github.com/labstack/gommon/log"
+       "golang.org/x/crypto/acme/autocert"
+)
+
+type (
+       // Echo is the top-level framework instance.
+       Echo struct {
+               stdLogger        *stdLog.Logger
+               colorer          *color.Color
+               premiddleware    []MiddlewareFunc
+               middleware       []MiddlewareFunc
+               maxParam         *int
+               router           *Router
+               notFoundHandler  HandlerFunc
+               pool             sync.Pool
+               Server           *http.Server
+               TLSServer        *http.Server
+               Listener         net.Listener
+               TLSListener      net.Listener
+               AutoTLSManager   autocert.Manager
+               DisableHTTP2     bool
+               Debug            bool
+               HideBanner       bool
+               HidePort         bool
+               HTTPErrorHandler HTTPErrorHandler
+               Binder           Binder
+               Validator        Validator
+               Renderer         Renderer
+               Logger           Logger
+       }
+
+       // Route contains a handler and information for matching against requests.
+       Route struct {
+               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{}
+               Internal error // Stores the error returned by an external dependency
+       }
+
+       // MiddlewareFunc defines a function to process middleware.
+       MiddlewareFunc func(HandlerFunc) HandlerFunc
+
+       // HandlerFunc defines a function to server HTTP requests.
+       HandlerFunc func(Context) error
+
+       // HTTPErrorHandler is a centralized HTTP error handler.
+       HTTPErrorHandler func(error, Context)
+
+       // Validator is the interface that wraps the Validate function.
+       Validator interface {
+               Validate(i interface{}) error
+       }
+
+       // Renderer is the interface that wraps the Render function.
+       Renderer interface {
+               Render(io.Writer, string, interface{}, Context) error
+       }
+
+       // Map defines a generic map of type `map[string]interface{}`.
+       Map map[string]interface{}
+
+       // i is the interface for Echo and Group.
+       i interface {
+               GET(string, HandlerFunc, ...MiddlewareFunc) *Route
+       }
+)
+
+// HTTP methods
+const (
+       CONNECT  = "CONNECT"
+       DELETE   = "DELETE"
+       GET      = "GET"
+       HEAD     = "HEAD"
+       OPTIONS  = "OPTIONS"
+       PATCH    = "PATCH"
+       POST     = "POST"
+       PROPFIND = "PROPFIND"
+       PUT      = "PUT"
+       TRACE    = "TRACE"
+)
+
+// MIME types
+const (
+       MIMEApplicationJSON                  = "application/json"
+       MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + charsetUTF8
+       MIMEApplicationJavaScript            = "application/javascript"
+       MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
+       MIMEApplicationXML                   = "application/xml"
+       MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + charsetUTF8
+       MIMETextXML                          = "text/xml"
+       MIMETextXMLCharsetUTF8               = MIMETextXML + "; " + charsetUTF8
+       MIMEApplicationForm                  = "application/x-www-form-urlencoded"
+       MIMEApplicationProtobuf              = "application/protobuf"
+       MIMEApplicationMsgpack               = "application/msgpack"
+       MIMETextHTML                         = "text/html"
+       MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + charsetUTF8
+       MIMETextPlain                        = "text/plain"
+       MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + charsetUTF8
+       MIMEMultipartForm                    = "multipart/form-data"
+       MIMEOctetStream                      = "application/octet-stream"
+)
+
+const (
+       charsetUTF8 = "charset=UTF-8"
+)
+
+// Headers
+const (
+       HeaderAccept              = "Accept"
+       HeaderAcceptEncoding      = "Accept-Encoding"
+       HeaderAllow               = "Allow"
+       HeaderAuthorization       = "Authorization"
+       HeaderContentDisposition  = "Content-Disposition"
+       HeaderContentEncoding     = "Content-Encoding"
+       HeaderContentLength       = "Content-Length"
+       HeaderContentType         = "Content-Type"
+       HeaderCookie              = "Cookie"
+       HeaderSetCookie           = "Set-Cookie"
+       HeaderIfModifiedSince     = "If-Modified-Since"
+       HeaderLastModified        = "Last-Modified"
+       HeaderLocation            = "Location"
+       HeaderUpgrade             = "Upgrade"
+       HeaderVary                = "Vary"
+       HeaderWWWAuthenticate     = "WWW-Authenticate"
+       HeaderXForwardedFor       = "X-Forwarded-For"
+       HeaderXForwardedProto     = "X-Forwarded-Proto"
+       HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
+       HeaderXForwardedSsl       = "X-Forwarded-Ssl"
+       HeaderXUrlScheme          = "X-Url-Scheme"
+       HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
+       HeaderXRealIP             = "X-Real-IP"
+       HeaderXRequestID          = "X-Request-ID"
+       HeaderXRequestedWith      = "X-Requested-With"
+       HeaderServer              = "Server"
+       HeaderOrigin              = "Origin"
+
+       // Access control
+       HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
+       HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
+       HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
+       HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
+       HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
+       HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
+       HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
+       HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
+
+       // Security
+       HeaderStrictTransportSecurity = "Strict-Transport-Security"
+       HeaderXContentTypeOptions     = "X-Content-Type-Options"
+       HeaderXXSSProtection          = "X-XSS-Protection"
+       HeaderXFrameOptions           = "X-Frame-Options"
+       HeaderContentSecurityPolicy   = "Content-Security-Policy"
+       HeaderXCSRFToken              = "X-CSRF-Token"
+)
+
+const (
+       Version = "3.3.5"
+       website = "https://echo.labstack.com"
+       // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
+       banner = `
+   ____    __
+  / __/___/ /  ___
+ / _// __/ _ \/ _ \
+/___/\__/_//_/\___/ %s
+High performance, minimalist Go web framework
+%s
+____________________________________O/_______
+                                    O\
+`
+)
+
+var (
+       methods = [...]string{
+               CONNECT,
+               DELETE,
+               GET,
+               HEAD,
+               OPTIONS,
+               PATCH,
+               POST,
+               PROPFIND,
+               PUT,
+               TRACE,
+       }
+)
+
+// Errors
+var (
+       ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)
+       ErrNotFound                    = NewHTTPError(http.StatusNotFound)
+       ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)
+       ErrForbidden                   = NewHTTPError(http.StatusForbidden)
+       ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)
+       ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
+       ErrValidatorNotRegistered      = errors.New("validator not registered")
+       ErrRendererNotRegistered       = errors.New("renderer not registered")
+       ErrInvalidRedirectCode         = errors.New("invalid redirect status code")
+       ErrCookieNotFound              = errors.New("cookie not found")
+)
+
+// Error handlers
+var (
+       NotFoundHandler = func(c Context) error {
+               return ErrNotFound
+       }
+
+       MethodNotAllowedHandler = func(c Context) error {
+               return ErrMethodNotAllowed
+       }
+)
+
+// New creates an instance of Echo.
+func New() (e *Echo) {
+       e = &Echo{
+               Server:    new(http.Server),
+               TLSServer: new(http.Server),
+               AutoTLSManager: autocert.Manager{
+                       Prompt: autocert.AcceptTOS,
+               },
+               Logger:   log.New("echo"),
+               colorer:  color.New(),
+               maxParam: new(int),
+       }
+       e.Server.Handler = e
+       e.TLSServer.Handler = e
+       e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
+       e.Binder = &DefaultBinder{}
+       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)
+       }
+       e.router = NewRouter(e)
+       return
+}
+
+// NewContext returns a Context instance.
+func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
+       return &context{
+               request:  r,
+               response: NewResponse(w, e),
+               store:    make(Map),
+               echo:     e,
+               pvalues:  make([]string, *e.maxParam),
+               handler:  NotFoundHandler,
+       }
+}
+
+// Router returns router.
+func (e *Echo) Router() *Router {
+       return e.router
+}
+
+// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
+// with status code.
+func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
+       var (
+               code = http.StatusInternalServerError
+               msg  interface{}
+       )
+
+       if he, ok := err.(*HTTPError); ok {
+               code = he.Code
+               msg = he.Message
+               if he.Internal != nil {
+                       msg = fmt.Sprintf("%v, %v", err, he.Internal)
+               }
+       } else if e.Debug {
+               msg = err.Error()
+       } else {
+               msg = http.StatusText(code)
+       }
+       if _, ok := msg.(string); ok {
+               msg = Map{"message": msg}
+       }
+
+       e.Logger.Error(err)
+
+       // Send response
+       if !c.Response().Committed {
+               if c.Request().Method == HEAD { // Issue #608
+                       err = c.NoContent(code)
+               } else {
+                       err = c.JSON(code, msg)
+               }
+               if err != nil {
+                       e.Logger.Error(err)
+               }
+       }
+}
+
+// Pre adds middleware to the chain which is run before router.
+func (e *Echo) Pre(middleware ...MiddlewareFunc) {
+       e.premiddleware = append(e.premiddleware, middleware...)
+}
+
+// Use adds middleware to the chain which is run after router.
+func (e *Echo) Use(middleware ...MiddlewareFunc) {
+       e.middleware = append(e.middleware, middleware...)
+}
+
+// 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) *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) *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) *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) *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) *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) *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) *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) *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) *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) []*Route {
+       routes := make([]*Route, len(methods))
+       for i, m := range methods {
+               routes[i] = 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) []*Route {
+       routes := make([]*Route, len(methods))
+       for i, m := range methods {
+               routes[i] = 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) *Route {
+       if root == "" {
+               root = "." // For security we want to restrict to CWD.
+       }
+       return static(e, prefix, root)
+}
+
+func static(i i, prefix, root string) *Route {
+       h := func(c Context) error {
+               p, err := url.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 == "/" {
+               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) *Route {
+       return e.GET(path, func(c Context) error {
+               return c.File(file)
+       })
+}
+
+// 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
+               // Chain middleware
+               for i := len(middleware) - 1; i >= 0; i-- {
+                       h = middleware[i](h)
+               }
+               return h(c)
+       })
+       r := &Route{
+               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.
+func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
+       g = &Group{prefix: prefix, echo: e}
+       g.Use(m...)
+       return
+}
+
+// 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
+       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 {
+                                       for ; i < l && r.Path[i] != '/'; i++ {
+                                       }
+                                       uri.WriteString(fmt.Sprintf("%v", params[n]))
+                                       n++
+                               }
+                               if i < l {
+                                       uri.WriteByte(r.Path[i])
+                               }
+                       }
+                       break
+               }
+       }
+       return uri.String()
+}
+
+// Routes returns the registered routes.
+func (e *Echo) Routes() []*Route {
+       routes := make([]*Route, 0, len(e.router.routes))
+       for _, v := range e.router.routes {
+               routes = append(routes, v)
+       }
+       return routes
+}
+
+// AcquireContext returns an empty `Context` instance from the pool.
+// You must return the context by calling `ReleaseContext()`.
+func (e *Echo) AcquireContext() Context {
+       return e.pool.Get().(Context)
+}
+
+// ReleaseContext returns the `Context` instance back to the pool.
+// You must call it after `AcquireContext()`.
+func (e *Echo) ReleaseContext(c Context) {
+       e.pool.Put(c)
+}
+
+// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
+func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+       // Acquire context
+       c := e.pool.Get().(*context)
+       c.Reset(r, w)
+
+       m := r.Method
+       h := NotFoundHandler
+
+       if e.premiddleware == nil {
+               path := r.URL.RawPath
+               if path == "" {
+                       path = r.URL.Path
+               }
+               e.router.Find(m, getPath(r), c)
+               h = c.Handler()
+               for i := len(e.middleware) - 1; i >= 0; i-- {
+                       h = e.middleware[i](h)
+               }
+       } else {
+               h = func(c Context) error {
+                       path := r.URL.RawPath
+                       if path == "" {
+                               path = r.URL.Path
+                       }
+                       e.router.Find(m, getPath(r), c)
+                       h := c.Handler()
+                       for i := len(e.middleware) - 1; i >= 0; i-- {
+                               h = e.middleware[i](h)
+                       }
+                       return h(c)
+               }
+               for i := len(e.premiddleware) - 1; i >= 0; i-- {
+                       h = e.premiddleware[i](h)
+               }
+       }
+
+       // Execute chain
+       if err := h(c); err != nil {
+               e.HTTPErrorHandler(err, c)
+       }
+
+       // Release context
+       e.pool.Put(c)
+}
+
+// Start starts an HTTP server.
+func (e *Echo) Start(address string) error {
+       e.Server.Addr = address
+       return e.StartServer(e.Server)
+}
+
+// StartTLS starts an HTTPS server.
+func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
+       if certFile == "" || keyFile == "" {
+               return errors.New("invalid tls configuration")
+       }
+       s := e.TLSServer
+       s.TLSConfig = new(tls.Config)
+       s.TLSConfig.Certificates = make([]tls.Certificate, 1)
+       s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+       if err != nil {
+               return
+       }
+       return e.startTLS(address)
+}
+
+// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
+func (e *Echo) StartAutoTLS(address string) error {
+       if e.Listener == nil {
+               go http.ListenAndServe(":http", e.AutoTLSManager.HTTPHandler(nil))
+       }
+
+       s := e.TLSServer
+       s.TLSConfig = new(tls.Config)
+       s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
+       return e.startTLS(address)
+}
+
+func (e *Echo) startTLS(address string) error {
+       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) {
+       // Setup
+       e.colorer.SetOutput(e.Logger.Output())
+       s.ErrorLog = e.stdLogger
+       s.Handler = e
+       if e.Debug {
+               e.Logger.SetLevel(log.DEBUG)
+       }
+
+       if !e.HideBanner {
+               e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
+       }
+
+       if s.TLSConfig == nil {
+               if e.Listener == nil {
+                       e.Listener, err = newListener(s.Addr)
+                       if err != nil {
+                               return err
+                       }
+               }
+               if !e.HidePort {
+                       e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
+               }
+               return s.Serve(e.Listener)
+       }
+       if e.TLSListener == nil {
+               l, err := newListener(s.Addr)
+               if err != nil {
+                       return err
+               }
+               e.TLSListener = tls.NewListener(l, s.TLSConfig)
+       }
+       if !e.HidePort {
+               e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
+       }
+       return s.Serve(e.TLSListener)
+}
+
+// Close immediately stops the server.
+// It internally calls `http.Server#Close()`.
+func (e *Echo) Close() error {
+       if err := e.TLSServer.Close(); err != nil {
+               return err
+       }
+       return e.Server.Close()
+}
+
+// Shutdown stops server the gracefully.
+// It internally calls `http.Server#Shutdown()`.
+func (e *Echo) Shutdown(ctx stdContext.Context) error {
+       if err := e.TLSServer.Shutdown(ctx); err != nil {
+               return err
+       }
+       return e.Server.Shutdown(ctx)
+}
+
+// NewHTTPError creates a new HTTPError instance.
+func NewHTTPError(code int, message ...interface{}) *HTTPError {
+       he := &HTTPError{Code: code, Message: http.StatusText(code)}
+       if len(message) > 0 {
+               he.Message = message[0]
+       }
+       return he
+}
+
+// Error makes it compatible with `error` interface.
+func (he *HTTPError) Error() string {
+       return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
+}
+
+// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
+func WrapHandler(h http.Handler) HandlerFunc {
+       return func(c Context) error {
+               h.ServeHTTP(c.Response(), c.Request())
+               return nil
+       }
+}
+
+// WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
+func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
+       return func(next HandlerFunc) HandlerFunc {
+               return func(c Context) (err error) {
+                       m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+                               c.SetRequest(r)
+                               err = next(c)
+                       })).ServeHTTP(c.Response(), c.Request())
+                       return
+               }
+       }
+}
+
+func getPath(r *http.Request) string {
+       path := r.URL.RawPath
+       if path == "" {
+               path = r.URL.Path
+       }
+       return path
+}
+
+func handlerName(h HandlerFunc) string {
+       t := reflect.ValueOf(h).Type()
+       if t.Kind() == reflect.Func {
+               return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
+       }
+       return t.String()
+}
+
+// // PathUnescape is wraps `url.PathUnescape`
+// func PathUnescape(s string) (string, error) {
+//     return url.PathUnescape(s)
+// }
+
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+       *net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+       tc, err := ln.AcceptTCP()
+       if err != nil {
+               return
+       }
+       tc.SetKeepAlive(true)
+       tc.SetKeepAlivePeriod(3 * time.Minute)
+       return tc, nil
+}
+
+func newListener(address string) (*tcpKeepAliveListener, error) {
+       l, err := net.Listen("tcp", address)
+       if err != nil {
+               return nil, err
+       }
+       return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
+}