src: Add DMA localagent
[barometer.git] / src / dma / vendor / github.com / labstack / echo / echo.go
1 /*
2 Package echo implements high performance, minimalist Go web framework.
3
4 Example:
5
6   package main
7
8   import (
9     "net/http"
10
11     "github.com/labstack/echo"
12     "github.com/labstack/echo/middleware"
13   )
14
15   // Handler
16   func hello(c echo.Context) error {
17     return c.String(http.StatusOK, "Hello, World!")
18   }
19
20   func main() {
21     // Echo instance
22     e := echo.New()
23
24     // Middleware
25     e.Use(middleware.Logger())
26     e.Use(middleware.Recover())
27
28     // Routes
29     e.GET("/", hello)
30
31     // Start server
32     e.Logger.Fatal(e.Start(":1323"))
33   }
34
35 Learn more at https://echo.labstack.com
36 */
37 package echo
38
39 import (
40         "bytes"
41         stdContext "context"
42         "crypto/tls"
43         "errors"
44         "fmt"
45         "io"
46         stdLog "log"
47         "net"
48         "net/http"
49         "net/url"
50         "path"
51         "path/filepath"
52         "reflect"
53         "runtime"
54         "sync"
55         "time"
56
57         "github.com/labstack/gommon/color"
58         "github.com/labstack/gommon/log"
59         "golang.org/x/crypto/acme/autocert"
60 )
61
62 type (
63         // Echo is the top-level framework instance.
64         Echo struct {
65                 stdLogger        *stdLog.Logger
66                 colorer          *color.Color
67                 premiddleware    []MiddlewareFunc
68                 middleware       []MiddlewareFunc
69                 maxParam         *int
70                 router           *Router
71                 notFoundHandler  HandlerFunc
72                 pool             sync.Pool
73                 Server           *http.Server
74                 TLSServer        *http.Server
75                 Listener         net.Listener
76                 TLSListener      net.Listener
77                 AutoTLSManager   autocert.Manager
78                 DisableHTTP2     bool
79                 Debug            bool
80                 HideBanner       bool
81                 HidePort         bool
82                 HTTPErrorHandler HTTPErrorHandler
83                 Binder           Binder
84                 Validator        Validator
85                 Renderer         Renderer
86                 Logger           Logger
87         }
88
89         // Route contains a handler and information for matching against requests.
90         Route struct {
91                 Method string `json:"method"`
92                 Path   string `json:"path"`
93                 Name   string `json:"name"`
94         }
95
96         // HTTPError represents an error that occurred while handling a request.
97         HTTPError struct {
98                 Code     int
99                 Message  interface{}
100                 Internal error // Stores the error returned by an external dependency
101         }
102
103         // MiddlewareFunc defines a function to process middleware.
104         MiddlewareFunc func(HandlerFunc) HandlerFunc
105
106         // HandlerFunc defines a function to server HTTP requests.
107         HandlerFunc func(Context) error
108
109         // HTTPErrorHandler is a centralized HTTP error handler.
110         HTTPErrorHandler func(error, Context)
111
112         // Validator is the interface that wraps the Validate function.
113         Validator interface {
114                 Validate(i interface{}) error
115         }
116
117         // Renderer is the interface that wraps the Render function.
118         Renderer interface {
119                 Render(io.Writer, string, interface{}, Context) error
120         }
121
122         // Map defines a generic map of type `map[string]interface{}`.
123         Map map[string]interface{}
124
125         // i is the interface for Echo and Group.
126         i interface {
127                 GET(string, HandlerFunc, ...MiddlewareFunc) *Route
128         }
129 )
130
131 // HTTP methods
132 const (
133         CONNECT  = "CONNECT"
134         DELETE   = "DELETE"
135         GET      = "GET"
136         HEAD     = "HEAD"
137         OPTIONS  = "OPTIONS"
138         PATCH    = "PATCH"
139         POST     = "POST"
140         PROPFIND = "PROPFIND"
141         PUT      = "PUT"
142         TRACE    = "TRACE"
143 )
144
145 // MIME types
146 const (
147         MIMEApplicationJSON                  = "application/json"
148         MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + charsetUTF8
149         MIMEApplicationJavaScript            = "application/javascript"
150         MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
151         MIMEApplicationXML                   = "application/xml"
152         MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + charsetUTF8
153         MIMETextXML                          = "text/xml"
154         MIMETextXMLCharsetUTF8               = MIMETextXML + "; " + charsetUTF8
155         MIMEApplicationForm                  = "application/x-www-form-urlencoded"
156         MIMEApplicationProtobuf              = "application/protobuf"
157         MIMEApplicationMsgpack               = "application/msgpack"
158         MIMETextHTML                         = "text/html"
159         MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + charsetUTF8
160         MIMETextPlain                        = "text/plain"
161         MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + charsetUTF8
162         MIMEMultipartForm                    = "multipart/form-data"
163         MIMEOctetStream                      = "application/octet-stream"
164 )
165
166 const (
167         charsetUTF8 = "charset=UTF-8"
168 )
169
170 // Headers
171 const (
172         HeaderAccept              = "Accept"
173         HeaderAcceptEncoding      = "Accept-Encoding"
174         HeaderAllow               = "Allow"
175         HeaderAuthorization       = "Authorization"
176         HeaderContentDisposition  = "Content-Disposition"
177         HeaderContentEncoding     = "Content-Encoding"
178         HeaderContentLength       = "Content-Length"
179         HeaderContentType         = "Content-Type"
180         HeaderCookie              = "Cookie"
181         HeaderSetCookie           = "Set-Cookie"
182         HeaderIfModifiedSince     = "If-Modified-Since"
183         HeaderLastModified        = "Last-Modified"
184         HeaderLocation            = "Location"
185         HeaderUpgrade             = "Upgrade"
186         HeaderVary                = "Vary"
187         HeaderWWWAuthenticate     = "WWW-Authenticate"
188         HeaderXForwardedFor       = "X-Forwarded-For"
189         HeaderXForwardedProto     = "X-Forwarded-Proto"
190         HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
191         HeaderXForwardedSsl       = "X-Forwarded-Ssl"
192         HeaderXUrlScheme          = "X-Url-Scheme"
193         HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
194         HeaderXRealIP             = "X-Real-IP"
195         HeaderXRequestID          = "X-Request-ID"
196         HeaderXRequestedWith      = "X-Requested-With"
197         HeaderServer              = "Server"
198         HeaderOrigin              = "Origin"
199
200         // Access control
201         HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
202         HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
203         HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
204         HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
205         HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
206         HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
207         HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
208         HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
209
210         // Security
211         HeaderStrictTransportSecurity = "Strict-Transport-Security"
212         HeaderXContentTypeOptions     = "X-Content-Type-Options"
213         HeaderXXSSProtection          = "X-XSS-Protection"
214         HeaderXFrameOptions           = "X-Frame-Options"
215         HeaderContentSecurityPolicy   = "Content-Security-Policy"
216         HeaderXCSRFToken              = "X-CSRF-Token"
217 )
218
219 const (
220         Version = "3.3.5"
221         website = "https://echo.labstack.com"
222         // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
223         banner = `
224    ____    __
225   / __/___/ /  ___
226  / _// __/ _ \/ _ \
227 /___/\__/_//_/\___/ %s
228 High performance, minimalist Go web framework
229 %s
230 ____________________________________O/_______
231                                     O\
232 `
233 )
234
235 var (
236         methods = [...]string{
237                 CONNECT,
238                 DELETE,
239                 GET,
240                 HEAD,
241                 OPTIONS,
242                 PATCH,
243                 POST,
244                 PROPFIND,
245                 PUT,
246                 TRACE,
247         }
248 )
249
250 // Errors
251 var (
252         ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)
253         ErrNotFound                    = NewHTTPError(http.StatusNotFound)
254         ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)
255         ErrForbidden                   = NewHTTPError(http.StatusForbidden)
256         ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)
257         ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
258         ErrValidatorNotRegistered      = errors.New("validator not registered")
259         ErrRendererNotRegistered       = errors.New("renderer not registered")
260         ErrInvalidRedirectCode         = errors.New("invalid redirect status code")
261         ErrCookieNotFound              = errors.New("cookie not found")
262 )
263
264 // Error handlers
265 var (
266         NotFoundHandler = func(c Context) error {
267                 return ErrNotFound
268         }
269
270         MethodNotAllowedHandler = func(c Context) error {
271                 return ErrMethodNotAllowed
272         }
273 )
274
275 // New creates an instance of Echo.
276 func New() (e *Echo) {
277         e = &Echo{
278                 Server:    new(http.Server),
279                 TLSServer: new(http.Server),
280                 AutoTLSManager: autocert.Manager{
281                         Prompt: autocert.AcceptTOS,
282                 },
283                 Logger:   log.New("echo"),
284                 colorer:  color.New(),
285                 maxParam: new(int),
286         }
287         e.Server.Handler = e
288         e.TLSServer.Handler = e
289         e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
290         e.Binder = &DefaultBinder{}
291         e.Logger.SetLevel(log.ERROR)
292         e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
293         e.pool.New = func() interface{} {
294                 return e.NewContext(nil, nil)
295         }
296         e.router = NewRouter(e)
297         return
298 }
299
300 // NewContext returns a Context instance.
301 func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
302         return &context{
303                 request:  r,
304                 response: NewResponse(w, e),
305                 store:    make(Map),
306                 echo:     e,
307                 pvalues:  make([]string, *e.maxParam),
308                 handler:  NotFoundHandler,
309         }
310 }
311
312 // Router returns router.
313 func (e *Echo) Router() *Router {
314         return e.router
315 }
316
317 // DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
318 // with status code.
319 func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
320         var (
321                 code = http.StatusInternalServerError
322                 msg  interface{}
323         )
324
325         if he, ok := err.(*HTTPError); ok {
326                 code = he.Code
327                 msg = he.Message
328                 if he.Internal != nil {
329                         msg = fmt.Sprintf("%v, %v", err, he.Internal)
330                 }
331         } else if e.Debug {
332                 msg = err.Error()
333         } else {
334                 msg = http.StatusText(code)
335         }
336         if _, ok := msg.(string); ok {
337                 msg = Map{"message": msg}
338         }
339
340         e.Logger.Error(err)
341
342         // Send response
343         if !c.Response().Committed {
344                 if c.Request().Method == HEAD { // Issue #608
345                         err = c.NoContent(code)
346                 } else {
347                         err = c.JSON(code, msg)
348                 }
349                 if err != nil {
350                         e.Logger.Error(err)
351                 }
352         }
353 }
354
355 // Pre adds middleware to the chain which is run before router.
356 func (e *Echo) Pre(middleware ...MiddlewareFunc) {
357         e.premiddleware = append(e.premiddleware, middleware...)
358 }
359
360 // Use adds middleware to the chain which is run after router.
361 func (e *Echo) Use(middleware ...MiddlewareFunc) {
362         e.middleware = append(e.middleware, middleware...)
363 }
364
365 // CONNECT registers a new CONNECT route for a path with matching handler in the
366 // router with optional route-level middleware.
367 func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
368         return e.Add(CONNECT, path, h, m...)
369 }
370
371 // DELETE registers a new DELETE route for a path with matching handler in the router
372 // with optional route-level middleware.
373 func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
374         return e.Add(DELETE, path, h, m...)
375 }
376
377 // GET registers a new GET route for a path with matching handler in the router
378 // with optional route-level middleware.
379 func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
380         return e.Add(GET, path, h, m...)
381 }
382
383 // HEAD registers a new HEAD route for a path with matching handler in the
384 // router with optional route-level middleware.
385 func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
386         return e.Add(HEAD, path, h, m...)
387 }
388
389 // OPTIONS registers a new OPTIONS route for a path with matching handler in the
390 // router with optional route-level middleware.
391 func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
392         return e.Add(OPTIONS, path, h, m...)
393 }
394
395 // PATCH registers a new PATCH route for a path with matching handler in the
396 // router with optional route-level middleware.
397 func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
398         return e.Add(PATCH, path, h, m...)
399 }
400
401 // POST registers a new POST route for a path with matching handler in the
402 // router with optional route-level middleware.
403 func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
404         return e.Add(POST, path, h, m...)
405 }
406
407 // PUT registers a new PUT route for a path with matching handler in the
408 // router with optional route-level middleware.
409 func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
410         return e.Add(PUT, path, h, m...)
411 }
412
413 // TRACE registers a new TRACE route for a path with matching handler in the
414 // router with optional route-level middleware.
415 func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
416         return e.Add(TRACE, path, h, m...)
417 }
418
419 // Any registers a new route for all HTTP methods and path with matching handler
420 // in the router with optional route-level middleware.
421 func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
422         routes := make([]*Route, len(methods))
423         for i, m := range methods {
424                 routes[i] = e.Add(m, path, handler, middleware...)
425         }
426         return routes
427 }
428
429 // Match registers a new route for multiple HTTP methods and path with matching
430 // handler in the router with optional route-level middleware.
431 func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
432         routes := make([]*Route, len(methods))
433         for i, m := range methods {
434                 routes[i] = e.Add(m, path, handler, middleware...)
435         }
436         return routes
437 }
438
439 // Static registers a new route with path prefix to serve static files from the
440 // provided root directory.
441 func (e *Echo) Static(prefix, root string) *Route {
442         if root == "" {
443                 root = "." // For security we want to restrict to CWD.
444         }
445         return static(e, prefix, root)
446 }
447
448 func static(i i, prefix, root string) *Route {
449         h := func(c Context) error {
450                 p, err := url.PathUnescape(c.Param("*"))
451                 if err != nil {
452                         return err
453                 }
454                 name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
455                 return c.File(name)
456         }
457         i.GET(prefix, h)
458         if prefix == "/" {
459                 return i.GET(prefix+"*", h)
460         }
461
462         return i.GET(prefix+"/*", h)
463 }
464
465 // File registers a new route with path to serve a static file.
466 func (e *Echo) File(path, file string) *Route {
467         return e.GET(path, func(c Context) error {
468                 return c.File(file)
469         })
470 }
471
472 // Add registers a new route for an HTTP method and path with matching handler
473 // in the router with optional route-level middleware.
474 func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
475         name := handlerName(handler)
476         e.router.Add(method, path, func(c Context) error {
477                 h := handler
478                 // Chain middleware
479                 for i := len(middleware) - 1; i >= 0; i-- {
480                         h = middleware[i](h)
481                 }
482                 return h(c)
483         })
484         r := &Route{
485                 Method: method,
486                 Path:   path,
487                 Name:   name,
488         }
489         e.router.routes[method+path] = r
490         return r
491 }
492
493 // Group creates a new router group with prefix and optional group-level middleware.
494 func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
495         g = &Group{prefix: prefix, echo: e}
496         g.Use(m...)
497         return
498 }
499
500 // URI generates a URI from handler.
501 func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
502         name := handlerName(handler)
503         return e.Reverse(name, params...)
504 }
505
506 // URL is an alias for `URI` function.
507 func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
508         return e.URI(h, params...)
509 }
510
511 // Reverse generates an URL from route name and provided parameters.
512 func (e *Echo) Reverse(name string, params ...interface{}) string {
513         uri := new(bytes.Buffer)
514         ln := len(params)
515         n := 0
516         for _, r := range e.router.routes {
517                 if r.Name == name {
518                         for i, l := 0, len(r.Path); i < l; i++ {
519                                 if r.Path[i] == ':' && n < ln {
520                                         for ; i < l && r.Path[i] != '/'; i++ {
521                                         }
522                                         uri.WriteString(fmt.Sprintf("%v", params[n]))
523                                         n++
524                                 }
525                                 if i < l {
526                                         uri.WriteByte(r.Path[i])
527                                 }
528                         }
529                         break
530                 }
531         }
532         return uri.String()
533 }
534
535 // Routes returns the registered routes.
536 func (e *Echo) Routes() []*Route {
537         routes := make([]*Route, 0, len(e.router.routes))
538         for _, v := range e.router.routes {
539                 routes = append(routes, v)
540         }
541         return routes
542 }
543
544 // AcquireContext returns an empty `Context` instance from the pool.
545 // You must return the context by calling `ReleaseContext()`.
546 func (e *Echo) AcquireContext() Context {
547         return e.pool.Get().(Context)
548 }
549
550 // ReleaseContext returns the `Context` instance back to the pool.
551 // You must call it after `AcquireContext()`.
552 func (e *Echo) ReleaseContext(c Context) {
553         e.pool.Put(c)
554 }
555
556 // ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
557 func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
558         // Acquire context
559         c := e.pool.Get().(*context)
560         c.Reset(r, w)
561
562         m := r.Method
563         h := NotFoundHandler
564
565         if e.premiddleware == nil {
566                 path := r.URL.RawPath
567                 if path == "" {
568                         path = r.URL.Path
569                 }
570                 e.router.Find(m, getPath(r), c)
571                 h = c.Handler()
572                 for i := len(e.middleware) - 1; i >= 0; i-- {
573                         h = e.middleware[i](h)
574                 }
575         } else {
576                 h = func(c Context) error {
577                         path := r.URL.RawPath
578                         if path == "" {
579                                 path = r.URL.Path
580                         }
581                         e.router.Find(m, getPath(r), c)
582                         h := c.Handler()
583                         for i := len(e.middleware) - 1; i >= 0; i-- {
584                                 h = e.middleware[i](h)
585                         }
586                         return h(c)
587                 }
588                 for i := len(e.premiddleware) - 1; i >= 0; i-- {
589                         h = e.premiddleware[i](h)
590                 }
591         }
592
593         // Execute chain
594         if err := h(c); err != nil {
595                 e.HTTPErrorHandler(err, c)
596         }
597
598         // Release context
599         e.pool.Put(c)
600 }
601
602 // Start starts an HTTP server.
603 func (e *Echo) Start(address string) error {
604         e.Server.Addr = address
605         return e.StartServer(e.Server)
606 }
607
608 // StartTLS starts an HTTPS server.
609 func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
610         if certFile == "" || keyFile == "" {
611                 return errors.New("invalid tls configuration")
612         }
613         s := e.TLSServer
614         s.TLSConfig = new(tls.Config)
615         s.TLSConfig.Certificates = make([]tls.Certificate, 1)
616         s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
617         if err != nil {
618                 return
619         }
620         return e.startTLS(address)
621 }
622
623 // StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
624 func (e *Echo) StartAutoTLS(address string) error {
625         if e.Listener == nil {
626                 go http.ListenAndServe(":http", e.AutoTLSManager.HTTPHandler(nil))
627         }
628
629         s := e.TLSServer
630         s.TLSConfig = new(tls.Config)
631         s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
632         return e.startTLS(address)
633 }
634
635 func (e *Echo) startTLS(address string) error {
636         s := e.TLSServer
637         s.Addr = address
638         if !e.DisableHTTP2 {
639                 s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
640         }
641         return e.StartServer(e.TLSServer)
642 }
643
644 // StartServer starts a custom http server.
645 func (e *Echo) StartServer(s *http.Server) (err error) {
646         // Setup
647         e.colorer.SetOutput(e.Logger.Output())
648         s.ErrorLog = e.stdLogger
649         s.Handler = e
650         if e.Debug {
651                 e.Logger.SetLevel(log.DEBUG)
652         }
653
654         if !e.HideBanner {
655                 e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
656         }
657
658         if s.TLSConfig == nil {
659                 if e.Listener == nil {
660                         e.Listener, err = newListener(s.Addr)
661                         if err != nil {
662                                 return err
663                         }
664                 }
665                 if !e.HidePort {
666                         e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
667                 }
668                 return s.Serve(e.Listener)
669         }
670         if e.TLSListener == nil {
671                 l, err := newListener(s.Addr)
672                 if err != nil {
673                         return err
674                 }
675                 e.TLSListener = tls.NewListener(l, s.TLSConfig)
676         }
677         if !e.HidePort {
678                 e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
679         }
680         return s.Serve(e.TLSListener)
681 }
682
683 // Close immediately stops the server.
684 // It internally calls `http.Server#Close()`.
685 func (e *Echo) Close() error {
686         if err := e.TLSServer.Close(); err != nil {
687                 return err
688         }
689         return e.Server.Close()
690 }
691
692 // Shutdown stops server the gracefully.
693 // It internally calls `http.Server#Shutdown()`.
694 func (e *Echo) Shutdown(ctx stdContext.Context) error {
695         if err := e.TLSServer.Shutdown(ctx); err != nil {
696                 return err
697         }
698         return e.Server.Shutdown(ctx)
699 }
700
701 // NewHTTPError creates a new HTTPError instance.
702 func NewHTTPError(code int, message ...interface{}) *HTTPError {
703         he := &HTTPError{Code: code, Message: http.StatusText(code)}
704         if len(message) > 0 {
705                 he.Message = message[0]
706         }
707         return he
708 }
709
710 // Error makes it compatible with `error` interface.
711 func (he *HTTPError) Error() string {
712         return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
713 }
714
715 // WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
716 func WrapHandler(h http.Handler) HandlerFunc {
717         return func(c Context) error {
718                 h.ServeHTTP(c.Response(), c.Request())
719                 return nil
720         }
721 }
722
723 // WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
724 func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
725         return func(next HandlerFunc) HandlerFunc {
726                 return func(c Context) (err error) {
727                         m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
728                                 c.SetRequest(r)
729                                 err = next(c)
730                         })).ServeHTTP(c.Response(), c.Request())
731                         return
732                 }
733         }
734 }
735
736 func getPath(r *http.Request) string {
737         path := r.URL.RawPath
738         if path == "" {
739                 path = r.URL.Path
740         }
741         return path
742 }
743
744 func handlerName(h HandlerFunc) string {
745         t := reflect.ValueOf(h).Type()
746         if t.Kind() == reflect.Func {
747                 return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
748         }
749         return t.String()
750 }
751
752 // // PathUnescape is wraps `url.PathUnescape`
753 // func PathUnescape(s string) (string, error) {
754 //      return url.PathUnescape(s)
755 // }
756
757 // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
758 // connections. It's used by ListenAndServe and ListenAndServeTLS so
759 // dead TCP connections (e.g. closing laptop mid-download) eventually
760 // go away.
761 type tcpKeepAliveListener struct {
762         *net.TCPListener
763 }
764
765 func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
766         tc, err := ln.AcceptTCP()
767         if err != nil {
768                 return
769         }
770         tc.SetKeepAlive(true)
771         tc.SetKeepAlivePeriod(3 * time.Minute)
772         return tc, nil
773 }
774
775 func newListener(address string) (*tcpKeepAliveListener, error) {
776         l, err := net.Listen("tcp", address)
777         if err != nil {
778                 return nil, err
779         }
780         return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
781 }