echo.go 21 KB

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