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