summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/labstack/echo/v4/echo.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/labstack/echo/v4/echo.go')
-rw-r--r--vendor/github.com/labstack/echo/v4/echo.go151
1 files changed, 106 insertions, 45 deletions
diff --git a/vendor/github.com/labstack/echo/v4/echo.go b/vendor/github.com/labstack/echo/v4/echo.go
index 0fe6880f..56b2cf8c 100644
--- a/vendor/github.com/labstack/echo/v4/echo.go
+++ b/vendor/github.com/labstack/echo/v4/echo.go
@@ -43,6 +43,7 @@ import (
"errors"
"fmt"
"io"
+ "io/ioutil"
stdLog "log"
"net"
"net/http"
@@ -56,18 +57,21 @@ import (
"github.com/labstack/gommon/color"
"github.com/labstack/gommon/log"
+ "golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert"
)
type (
// Echo is the top-level framework instance.
Echo struct {
+ common
StdLogger *stdLog.Logger
colorer *color.Color
premiddleware []MiddlewareFunc
middleware []MiddlewareFunc
maxParam *int
router *Router
+ routers map[string]*Router
notFoundHandler HandlerFunc
pool sync.Pool
Server *http.Server
@@ -122,10 +126,8 @@ type (
// 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
- }
+ // Common struct for Echo & Group.
+ common struct{}
)
// HTTP methods
@@ -168,6 +170,8 @@ const (
charsetUTF8 = "charset=UTF-8"
// PROPFIND Method can be used on collection and property resources.
PROPFIND = "PROPFIND"
+ // REPORT Method can be used to get information about a resource, see rfc 3253
+ REPORT = "REPORT"
)
// Headers
@@ -211,17 +215,18 @@ const (
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"
+ HeaderStrictTransportSecurity = "Strict-Transport-Security"
+ HeaderXContentTypeOptions = "X-Content-Type-Options"
+ HeaderXXSSProtection = "X-XSS-Protection"
+ HeaderXFrameOptions = "X-Frame-Options"
+ HeaderContentSecurityPolicy = "Content-Security-Policy"
+ HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
+ HeaderXCSRFToken = "X-CSRF-Token"
)
const (
// Version of Echo
- Version = "4.0.0"
+ Version = "4.1.5"
website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = `
@@ -248,6 +253,7 @@ var (
PROPFIND,
http.MethodPut,
http.MethodTrace,
+ REPORT,
}
)
@@ -269,6 +275,7 @@ var (
ErrRendererNotRegistered = errors.New("renderer not registered")
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
ErrCookieNotFound = errors.New("cookie not found")
+ ErrInvalidCertOrKeyType = errors.New("invalid cert or key type, must be string or []byte")
)
// Error handlers
@@ -304,6 +311,7 @@ func New() (e *Echo) {
return e.NewContext(nil, nil)
}
e.router = NewRouter(e)
+ e.routers = map[string]*Router{}
return
}
@@ -319,11 +327,16 @@ func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
}
}
-// Router returns router.
+// Router returns the default router.
func (e *Echo) Router() *Router {
return e.router
}
+// Routers returns the map of host => router.
+func (e *Echo) Routers() map[string]*Router {
+ return e.routers
+}
+
// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
// with status code.
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
@@ -450,10 +463,10 @@ func (e *Echo) Static(prefix, root string) *Route {
if root == "" {
root = "." // For security we want to restrict to CWD.
}
- return static(e, prefix, root)
+ return e.static(prefix, root, e.GET)
}
-func static(i i, prefix, root string) *Route {
+func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route {
h := func(c Context) error {
p, err := url.PathUnescape(c.Param("*"))
if err != nil {
@@ -462,26 +475,28 @@ func static(i i, prefix, root string) *Route {
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 get(prefix+"*", h)
}
+ return get(prefix+"/*", h)
+}
- return i.GET(prefix+"/*", h)
+func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route,
+ m ...MiddlewareFunc) *Route {
+ return get(path, func(c Context) error {
+ return c.File(file)
+ }, m...)
}
// 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...)
+ return e.file(path, file, e.GET, 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 {
+func (e *Echo) add(host, method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
name := handlerName(handler)
- e.router.Add(method, path, func(c Context) error {
+ router := e.findRouter(host)
+ router.Add(method, path, func(c Context) error {
h := handler
// Chain middleware
for i := len(middleware) - 1; i >= 0; i-- {
@@ -498,6 +513,20 @@ func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...Middl
return r
}
+// 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 {
+ return e.add("", method, path, handler, middleware...)
+}
+
+// Host creates a new router group for the provided host and optional host-level middleware.
+func (e *Echo) Host(name string, m ...MiddlewareFunc) (g *Group) {
+ e.routers[name] = NewRouter(e)
+ g = &Group{host: name, echo: e}
+ g.Use(m...)
+ return
+}
+
// 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}
@@ -570,23 +599,17 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h := NotFoundHandler
if e.premiddleware == nil {
- e.router.Find(r.Method, getPath(r), c)
+ e.findRouter(r.Host).Find(r.Method, getPath(r), c)
h = c.Handler()
- for i := len(e.middleware) - 1; i >= 0; i-- {
- h = e.middleware[i](h)
- }
+ h = applyMiddleware(h, e.middleware...)
} else {
h = func(c Context) error {
- e.router.Find(r.Method, getPath(r), c)
+ e.findRouter(r.Host).Find(r.Method, getPath(r), c)
h := c.Handler()
- for i := len(e.middleware) - 1; i >= 0; i-- {
- h = e.middleware[i](h)
- }
+ h = applyMiddleware(h, e.middleware...)
return h(c)
}
- for i := len(e.premiddleware) - 1; i >= 0; i-- {
- h = e.premiddleware[i](h)
- }
+ h = applyMiddleware(h, e.premiddleware...)
}
// Execute chain
@@ -605,25 +628,46 @@ func (e *Echo) Start(address string) error {
}
// 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")
+// If `certFile` or `keyFile` is `string` the values are treated as file paths.
+// If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.
+func (e *Echo) StartTLS(address string, certFile, keyFile interface{}) (err error) {
+ var cert []byte
+ if cert, err = filepathOrContent(certFile); err != nil {
+ return
+ }
+
+ var key []byte
+ if key, err = filepathOrContent(keyFile); err != nil {
+ return
}
+
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 {
+ if s.TLSConfig.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
return
}
+
return e.startTLS(address)
}
+func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
+ switch v := fileOrContent.(type) {
+ case string:
+ return ioutil.ReadFile(v)
+ case []byte:
+ return v, nil
+ default:
+ return nil, ErrInvalidCertOrKeyType
+ }
+}
+
// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
func (e *Echo) StartAutoTLS(address string) error {
s := e.TLSServer
s.TLSConfig = new(tls.Config)
s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto)
return e.startTLS(address)
}
@@ -742,6 +786,15 @@ func getPath(r *http.Request) string {
return path
}
+func (e *Echo) findRouter(host string) *Router {
+ if len(e.routers) > 0 {
+ if r, ok := e.routers[host]; ok {
+ return r
+ }
+ }
+ return e.router
+}
+
func handlerName(h HandlerFunc) string {
t := reflect.ValueOf(h).Type()
if t.Kind() == reflect.Func {
@@ -764,13 +817,14 @@ type tcpKeepAliveListener struct {
}
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
- tc, err := ln.AcceptTCP()
- if err != nil {
+ if c, err = ln.AcceptTCP(); err != nil {
+ return
+ } else if err = c.(*net.TCPConn).SetKeepAlive(true); err != nil {
+ return
+ } else if err = c.(*net.TCPConn).SetKeepAlivePeriod(3 * time.Minute); err != nil {
return
}
- tc.SetKeepAlive(true)
- tc.SetKeepAlivePeriod(3 * time.Minute)
- return tc, nil
+ return
}
func newListener(address string) (*tcpKeepAliveListener, error) {
@@ -780,3 +834,10 @@ func newListener(address string) (*tcpKeepAliveListener, error) {
}
return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
}
+
+func applyMiddleware(h HandlerFunc, middleware ...MiddlewareFunc) HandlerFunc {
+ for i := len(middleware) - 1; i >= 0; i-- {
+ h = middleware[i](h)
+ }
+ return h
+}