echo.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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 = "0.1"
  192. website = "https://zicloud.com"
  193. // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
  194. banner = `
  195. ZiCloud-API %s
  196. High performance, minimalist API written with Go web framework
  197. %s
  198. ____________________________________O/_______
  199. O\
  200. `
  201. )
  202. var (
  203. methods = [...]string{
  204. CONNECT,
  205. DELETE,
  206. GET,
  207. HEAD,
  208. OPTIONS,
  209. PATCH,
  210. POST,
  211. PROPFIND,
  212. PUT,
  213. TRACE,
  214. }
  215. )
  216. // Errors
  217. var (
  218. ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
  219. ErrNotFound = NewHTTPError(http.StatusNotFound)
  220. ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
  221. ErrForbidden = NewHTTPError(http.StatusForbidden)
  222. ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
  223. ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
  224. ErrValidatorNotRegistered = errors.New("validator not registered")
  225. ErrRendererNotRegistered = errors.New("renderer not registered")
  226. ErrInvalidRedirectCode = errors.New("invalid redirect status code")
  227. ErrCookieNotFound = errors.New("cookie not found")
  228. )
  229. // Error handlers
  230. var (
  231. NotFoundHandler = func(c Context) error {
  232. return ErrNotFound
  233. }
  234. MethodNotAllowedHandler = func(c Context) error {
  235. return ErrMethodNotAllowed
  236. }
  237. )
  238. // New creates an instance of Echo.
  239. func New() (e *Echo) {
  240. e = &Echo{
  241. Server: new(http.Server),
  242. TLSServer: new(http.Server),
  243. AutoTLSManager: autocert.Manager{
  244. Prompt: autocert.AcceptTOS,
  245. },
  246. Logger: log.New("echo"),
  247. colorer: color.New(),
  248. maxParam: new(int),
  249. }
  250. e.Server.Handler = e
  251. e.TLSServer.Handler = e
  252. e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
  253. e.Binder = &DefaultBinder{}
  254. e.Logger.SetLevel(log.ERROR)
  255. e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
  256. e.pool.New = func() interface{} {
  257. return e.NewContext(nil, nil)
  258. }
  259. e.router = NewRouter(e)
  260. return
  261. }
  262. // NewContext returns a Context instance.
  263. func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
  264. return &context{
  265. request: r,
  266. response: NewResponse(w, e),
  267. store: make(Map),
  268. echo: e,
  269. pvalues: make([]string, *e.maxParam),
  270. handler: NotFoundHandler,
  271. }
  272. }
  273. // Router returns router.
  274. func (e *Echo) Router() *Router {
  275. return e.router
  276. }
  277. // DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
  278. // with status code.
  279. func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
  280. var (
  281. code = http.StatusInternalServerError
  282. msg interface{}
  283. )
  284. if he, ok := err.(*HTTPError); ok {
  285. code = he.Code
  286. msg = he.Message
  287. if he.Internal != nil {
  288. err = fmt.Errorf("%v, %v", err, he.Internal)
  289. }
  290. } else if e.Debug {
  291. msg = err.Error()
  292. } else {
  293. msg = http.StatusText(code)
  294. }
  295. if _, ok := msg.(string); ok {
  296. msg = Map{"message": msg}
  297. }
  298. // Send response
  299. if !c.Response().Committed {
  300. if c.Request().Method == HEAD { // Issue #608
  301. err = c.NoContent(code)
  302. } else {
  303. err = c.JSON(code, msg)
  304. }
  305. if err != nil {
  306. e.Logger.Error(err)
  307. }
  308. }
  309. }
  310. // Pre adds middleware to the chain which is run before router.
  311. func (e *Echo) Pre(middleware ...MiddlewareFunc) {
  312. e.premiddleware = append(e.premiddleware, middleware...)
  313. }
  314. // Use adds middleware to the chain which is run after router.
  315. func (e *Echo) Use(middleware ...MiddlewareFunc) {
  316. e.middleware = append(e.middleware, middleware...)
  317. }
  318. // CONNECT registers a new CONNECT route for a path with matching handler in the
  319. // router with optional route-level middleware.
  320. func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  321. return e.Add(CONNECT, path, h, m...)
  322. }
  323. // DELETE registers a new DELETE route for a path with matching handler in the router
  324. // with optional route-level middleware.
  325. func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  326. return e.Add(DELETE, path, h, m...)
  327. }
  328. // GET registers a new GET route for a path with matching handler in the router
  329. // with optional route-level middleware.
  330. func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  331. return e.Add(GET, path, h, m...)
  332. }
  333. // HEAD registers a new HEAD route for a path with matching handler in the
  334. // router with optional route-level middleware.
  335. func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  336. return e.Add(HEAD, path, h, m...)
  337. }
  338. // OPTIONS registers a new OPTIONS route for a path with matching handler in the
  339. // router with optional route-level middleware.
  340. func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  341. return e.Add(OPTIONS, path, h, m...)
  342. }
  343. // PATCH registers a new PATCH route for a path with matching handler in the
  344. // router with optional route-level middleware.
  345. func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  346. return e.Add(PATCH, path, h, m...)
  347. }
  348. // POST registers a new POST route for a path with matching handler in the
  349. // router with optional route-level middleware.
  350. func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  351. return e.Add(POST, path, h, m...)
  352. }
  353. // PUT registers a new PUT route for a path with matching handler in the
  354. // router with optional route-level middleware.
  355. func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  356. return e.Add(PUT, path, h, m...)
  357. }
  358. // TRACE registers a new TRACE route for a path with matching handler in the
  359. // router with optional route-level middleware.
  360. func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
  361. return e.Add(TRACE, path, h, m...)
  362. }
  363. // Any registers a new route for all HTTP methods and path with matching handler
  364. // in the router with optional route-level middleware.
  365. func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
  366. routes := make([]*Route, len(methods))
  367. for i, m := range methods {
  368. routes[i] = e.Add(m, path, handler, middleware...)
  369. }
  370. return routes
  371. }
  372. // Match registers a new route for multiple HTTP methods and path with matching
  373. // handler in the router with optional route-level middleware.
  374. func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
  375. routes := make([]*Route, len(methods))
  376. for i, m := range methods {
  377. routes[i] = e.Add(m, path, handler, middleware...)
  378. }
  379. return routes
  380. }
  381. // Static registers a new route with path prefix to serve static files from the
  382. // provided root directory.
  383. func (e *Echo) Static(prefix, root string) *Route {
  384. if root == "" {
  385. root = "." // For security we want to restrict to CWD.
  386. }
  387. return static(e, prefix, root)
  388. }
  389. func static(i i, prefix, root string) *Route {
  390. h := func(c Context) error {
  391. p, err := url.PathUnescape(c.Param("*"))
  392. if err != nil {
  393. return err
  394. }
  395. name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
  396. return c.File(name)
  397. }
  398. i.GET(prefix, h)
  399. if prefix == "/" {
  400. return i.GET(prefix+"*", h)
  401. }
  402. return i.GET(prefix+"/*", h)
  403. }
  404. // File registers a new route with path to serve a static file with optional route-level middleware.
  405. func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
  406. return e.GET(path, func(c Context) error {
  407. return c.File(file)
  408. }, m...)
  409. }
  410. // Add registers a new route for an HTTP method and path with matching handler
  411. // in the router with optional route-level middleware.
  412. func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
  413. name := handlerName(handler)
  414. e.router.Add(method, path, func(c Context) error {
  415. h := handler
  416. // Chain middleware
  417. for i := len(middleware) - 1; i >= 0; i-- {
  418. h = middleware[i](h)
  419. }
  420. return h(c)
  421. })
  422. r := &Route{
  423. Method: method,
  424. Path: path,
  425. Name: name,
  426. }
  427. e.router.routes[method+path] = r
  428. return r
  429. }
  430. // Group creates a new router group with prefix and optional group-level middleware.
  431. func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
  432. g = &Group{prefix: prefix, echo: e}
  433. g.Use(m...)
  434. return
  435. }
  436. // URI generates a URI from handler.
  437. func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
  438. name := handlerName(handler)
  439. return e.Reverse(name, params...)
  440. }
  441. // URL is an alias for `URI` function.
  442. func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
  443. return e.URI(h, params...)
  444. }
  445. // Reverse generates an URL from route name and provided parameters.
  446. func (e *Echo) Reverse(name string, params ...interface{}) string {
  447. uri := new(bytes.Buffer)
  448. ln := len(params)
  449. n := 0
  450. for _, r := range e.router.routes {
  451. if r.Name == name {
  452. for i, l := 0, len(r.Path); i < l; i++ {
  453. if r.Path[i] == ':' && n < ln {
  454. for ; i < l && r.Path[i] != '/'; i++ {
  455. }
  456. uri.WriteString(fmt.Sprintf("%v", params[n]))
  457. n++
  458. }
  459. if i < l {
  460. uri.WriteByte(r.Path[i])
  461. }
  462. }
  463. break
  464. }
  465. }
  466. return uri.String()
  467. }
  468. // Routes returns the registered routes.
  469. func (e *Echo) Routes() []*Route {
  470. routes := make([]*Route, 0, len(e.router.routes))
  471. for _, v := range e.router.routes {
  472. routes = append(routes, v)
  473. }
  474. return routes
  475. }
  476. // AcquireContext returns an empty `Context` instance from the pool.
  477. // You must return the context by calling `ReleaseContext()`.
  478. func (e *Echo) AcquireContext() Context {
  479. return e.pool.Get().(Context)
  480. }
  481. // ReleaseContext returns the `Context` instance back to the pool.
  482. // You must call it after `AcquireContext()`.
  483. func (e *Echo) ReleaseContext(c Context) {
  484. e.pool.Put(c)
  485. }
  486. // ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
  487. func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  488. // Acquire context
  489. c := e.pool.Get().(*context)
  490. c.Reset(r, w)
  491. h := NotFoundHandler
  492. if e.premiddleware == nil {
  493. e.router.Find(r.Method, getPath(r), c)
  494. h = c.Handler()
  495. for i := len(e.middleware) - 1; i >= 0; i-- {
  496. h = e.middleware[i](h)
  497. }
  498. } else {
  499. h = func(c Context) error {
  500. e.router.Find(r.Method, getPath(r), c)
  501. h := c.Handler()
  502. for i := len(e.middleware) - 1; i >= 0; i-- {
  503. h = e.middleware[i](h)
  504. }
  505. return h(c)
  506. }
  507. for i := len(e.premiddleware) - 1; i >= 0; i-- {
  508. h = e.premiddleware[i](h)
  509. }
  510. }
  511. // Execute chain
  512. if err := h(c); err != nil {
  513. e.HTTPErrorHandler(err, c)
  514. }
  515. // Release context
  516. e.pool.Put(c)
  517. }
  518. // Start starts an HTTP server.
  519. func (e *Echo) Start(address string) error {
  520. e.Server.Addr = address
  521. return e.StartServer(e.Server)
  522. }
  523. // StartTLS starts an HTTPS server.
  524. func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
  525. if certFile == "" || keyFile == "" {
  526. return errors.New("invalid tls configuration")
  527. }
  528. s := e.TLSServer
  529. s.TLSConfig = new(tls.Config)
  530. s.TLSConfig.Certificates = make([]tls.Certificate, 1)
  531. s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
  532. if err != nil {
  533. return
  534. }
  535. return e.startTLS(address)
  536. }
  537. // StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
  538. func (e *Echo) StartAutoTLS(address string) error {
  539. if e.Listener == nil {
  540. go http.ListenAndServe(":http", e.AutoTLSManager.HTTPHandler(nil))
  541. }
  542. s := e.TLSServer
  543. s.TLSConfig = new(tls.Config)
  544. s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
  545. return e.startTLS(address)
  546. }
  547. func (e *Echo) startTLS(address string) error {
  548. s := e.TLSServer
  549. s.Addr = address
  550. if !e.DisableHTTP2 {
  551. s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
  552. }
  553. return e.StartServer(e.TLSServer)
  554. }
  555. // StartServer starts a custom http server.
  556. func (e *Echo) StartServer(s *http.Server) (err error) {
  557. // Setup
  558. e.colorer.SetOutput(e.Logger.Output())
  559. s.ErrorLog = e.stdLogger
  560. s.Handler = e
  561. if e.Debug {
  562. e.Logger.SetLevel(log.DEBUG)
  563. }
  564. if !e.HideBanner {
  565. e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
  566. }
  567. if s.TLSConfig == nil {
  568. if e.Listener == nil {
  569. e.Listener, err = newListener(s.Addr)
  570. if err != nil {
  571. return err
  572. }
  573. }
  574. if !e.HidePort {
  575. e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
  576. }
  577. return s.Serve(e.Listener)
  578. }
  579. if e.TLSListener == nil {
  580. l, err := newListener(s.Addr)
  581. if err != nil {
  582. return err
  583. }
  584. e.TLSListener = tls.NewListener(l, s.TLSConfig)
  585. }
  586. if !e.HidePort {
  587. e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
  588. }
  589. return s.Serve(e.TLSListener)
  590. }
  591. // Close immediately stops the server.
  592. // It internally calls `http.Server#Close()`.
  593. func (e *Echo) Close() error {
  594. if err := e.TLSServer.Close(); err != nil {
  595. return err
  596. }
  597. return e.Server.Close()
  598. }
  599. // Shutdown stops server the gracefully.
  600. // It internally calls `http.Server#Shutdown()`.
  601. func (e *Echo) Shutdown(ctx stdContext.Context) error {
  602. if err := e.TLSServer.Shutdown(ctx); err != nil {
  603. return err
  604. }
  605. return e.Server.Shutdown(ctx)
  606. }
  607. // NewHTTPError creates a new HTTPError instance.
  608. func NewHTTPError(code int, message ...interface{}) *HTTPError {
  609. he := &HTTPError{Code: code, Message: http.StatusText(code)}
  610. if len(message) > 0 {
  611. he.Message = message[0]
  612. }
  613. return he
  614. }
  615. // Error makes it compatible with `error` interface.
  616. func (he *HTTPError) Error() string {
  617. return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
  618. }
  619. // WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
  620. func WrapHandler(h http.Handler) HandlerFunc {
  621. return func(c Context) error {
  622. h.ServeHTTP(c.Response(), c.Request())
  623. return nil
  624. }
  625. }
  626. // WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
  627. func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
  628. return func(next HandlerFunc) HandlerFunc {
  629. return func(c Context) (err error) {
  630. m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  631. c.SetRequest(r)
  632. err = next(c)
  633. })).ServeHTTP(c.Response(), c.Request())
  634. return
  635. }
  636. }
  637. }
  638. func getPath(r *http.Request) string {
  639. path := r.URL.RawPath
  640. if path == "" {
  641. path = r.URL.Path
  642. }
  643. return path
  644. }
  645. func handlerName(h HandlerFunc) string {
  646. t := reflect.ValueOf(h).Type()
  647. if t.Kind() == reflect.Func {
  648. return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
  649. }
  650. return t.String()
  651. }
  652. // // PathUnescape is wraps `url.PathUnescape`
  653. // func PathUnescape(s string) (string, error) {
  654. // return url.PathUnescape(s)
  655. // }
  656. // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
  657. // connections. It's used by ListenAndServe and ListenAndServeTLS so
  658. // dead TCP connections (e.g. closing laptop mid-download) eventually
  659. // go away.
  660. type tcpKeepAliveListener struct {
  661. *net.TCPListener
  662. }
  663. func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
  664. tc, err := ln.AcceptTCP()
  665. if err != nil {
  666. return
  667. }
  668. tc.SetKeepAlive(true)
  669. tc.SetKeepAlivePeriod(3 * time.Minute)
  670. return tc, nil
  671. }
  672. func newListener(address string) (*tcpKeepAliveListener, error) {
  673. l, err := net.Listen("tcp", address)
  674. if err != nil {
  675. return nil, err
  676. }
  677. return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
  678. }