| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 | 
							- /*
 
- 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 serve 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.6"
 
- 	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 {
 
- 			err = fmt.Errorf("%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}
 
- 	}
 
- 	// 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 with optional route-level middleware.
 
- func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
 
- 	return e.GET(path, func(c Context) error {
 
- 		return c.File(file)
 
- 	}, m...)
 
- }
 
- // 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)
 
- 	h := NotFoundHandler
 
- 	if e.premiddleware == nil {
 
- 		e.router.Find(r.Method, 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 {
 
- 			e.router.Find(r.Method, 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
 
- }
 
 
  |