1
0

Updated libraries

This commit is contained in:
konrad
2019-05-07 21:42:24 +02:00
parent 2b160b73c3
commit 3d7fd9ca20
313 changed files with 37947 additions and 6783 deletions

View File

@ -1,6 +1,7 @@
language: go
go:
- 1.11.x
- 1.12.x
- tip
env:
- GO111MODULE=on

View File

@ -4,12 +4,26 @@
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/labstack/echo)
[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
[![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo)
[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://forum.labstack.com)
[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
## Supported Go versions
As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
Therefore a Go version capable of understanding /vN suffixed imports is required:
- 1.9.7+
- 1.10.3+
- 1.11+
Any of these versions will allow you to import Echo as `github.com/labstack/echo/v4` which is the recommended
way of using Echo going forward.
For older versions, please use the latest v3 tag.
## Feature Overview
- Optimized HTTP router which smartly prioritize routes
@ -44,8 +58,8 @@ package main
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
@ -90,6 +104,7 @@ func hello(c echo.Context) error {
- Improve/fix documentation
## Credits
- [Vishal Rana](https://github.com/vishr) - Author
- [Nitin Rana](https://github.com/nr17) - Consultant
- [Contributors](https://github.com/labstack/echo/graphs/contributors)

View File

@ -47,10 +47,8 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
} else if se, ok := err.(*json.SyntaxError); ok {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())).SetInternal(err)
} else {
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
return NewHTTPError(http.StatusBadRequest, err.Error())
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
@ -58,10 +56,8 @@ func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
} else if se, ok := err.(*xml.SyntaxError); ok {
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
} else {
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
return NewHTTPError(http.StatusBadRequest, err.Error())
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
}
case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
params, err := c.FormParams()

View File

@ -13,6 +13,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
)
type (
@ -198,6 +199,7 @@ type (
handler HandlerFunc
store Map
echo *Echo
lock sync.RWMutex
}
)
@ -232,7 +234,7 @@ func (c *context) IsTLS() bool {
func (c *context) IsWebSocket() bool {
upgrade := c.request.Header.Get(HeaderUpgrade)
return upgrade == "websocket" || upgrade == "Websocket"
return strings.ToLower(upgrade) == "websocket"
}
func (c *context) Scheme() string {
@ -360,10 +362,15 @@ func (c *context) Cookies() []*http.Cookie {
}
func (c *context) Get(key string) interface{} {
c.lock.RLock()
defer c.lock.RUnlock()
return c.store[key]
}
func (c *context) Set(key string, val interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
if c.store == nil {
c.store = make(Map)
}
@ -597,4 +604,3 @@ func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
// c.pvalues = nil
}

View File

@ -8,8 +8,8 @@ Example:
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
// Handler
@ -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
@ -211,17 +213,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 = "3.3.10-dev"
Version = "4.1.5"
website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = `
@ -269,6 +272,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 +308,7 @@ func New() (e *Echo) {
return e.NewContext(nil, nil)
}
e.router = NewRouter(e)
e.routers = map[string]*Router{}
return
}
@ -319,11 +324,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 +460,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 +472,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 i.GET(prefix+"/*", h)
return 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 {
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...)
}
// 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 {
// 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.file(path, file, e.GET, m...)
}
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 +510,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 +596,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 +625,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 +783,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 +814,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 +831,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
}

13
vendor/github.com/labstack/echo/v4/go.mod generated vendored Normal file
View File

@ -0,0 +1,13 @@
module github.com/labstack/echo/v4
go 1.12
require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/labstack/gommon v0.2.8
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/stretchr/testify v1.3.0
github.com/valyala/fasttemplate v1.0.1
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734
)

31
vendor/github.com/labstack/echo/v4/go.sum generated vendored Normal file
View File

@ -0,0 +1,31 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0=
github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -2,7 +2,6 @@ package echo
import (
"net/http"
"path"
)
type (
@ -10,6 +9,8 @@ type (
// routes that share a common middleware or functionality that should be separate
// from the parent echo instance while still inheriting from it.
Group struct {
common
host string
prefix string
middleware []MiddlewareFunc
echo *Echo
@ -19,13 +20,13 @@ type (
// Use implements `Echo#Use()` for sub-routes within the Group.
func (g *Group) Use(middleware ...MiddlewareFunc) {
g.middleware = append(g.middleware, middleware...)
if len(g.middleware) == 0 {
return
}
// Allow all requests to reach the group as they might get dropped if router
// doesn't find a match, making none of the group middleware process.
for _, p := range []string{"", "/*"} {
g.echo.Any(path.Clean(g.prefix+p), func(c Context) error {
return NotFoundHandler(c)
}, g.middleware...)
}
g.Any("", NotFoundHandler)
g.Any("/*", NotFoundHandler)
}
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
@ -92,21 +93,23 @@ func (g *Group) Match(methods []string, path string, handler HandlerFunc, middle
}
// Group creates a new sub-group with prefix and optional sub-group-level middleware.
func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) *Group {
func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) (sg *Group) {
m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
m = append(m, g.middleware...)
m = append(m, middleware...)
return g.echo.Group(g.prefix+prefix, m...)
sg = g.echo.Group(g.prefix+prefix, m...)
sg.host = g.host
return
}
// Static implements `Echo#Static()` for sub-routes within the Group.
func (g *Group) Static(prefix, root string) {
static(g, prefix, root)
g.static(prefix, root, g.GET)
}
// File implements `Echo#File()` for sub-routes within the Group.
func (g *Group) File(path, file string) {
g.echo.File(g.prefix+path, file)
g.file(g.prefix+path, file, g.GET)
}
// Add implements `Echo#Add()` for sub-routes within the Group.
@ -117,5 +120,5 @@ func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...Midd
m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
m = append(m, g.middleware...)
m = append(m, middleware...)
return g.echo.Add(method, g.prefix+path, handler, m...)
return g.echo.add(g.host, method, g.prefix+path, handler, m...)
}

View File

@ -5,7 +5,7 @@ import (
"strconv"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -8,7 +8,7 @@ import (
"net"
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (
@ -105,7 +105,3 @@ func (w *bodyDumpResponseWriter) Flush() {
func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return w.ResponseWriter.(http.Hijacker).Hijack()
}
func (w *bodyDumpResponseWriter) CloseNotify() <-chan bool {
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

View File

@ -5,7 +5,7 @@ import (
"io"
"sync"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/bytes"
)

View File

@ -9,7 +9,7 @@ import (
"net/http"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (
@ -111,12 +111,11 @@ func (w *gzipResponseWriter) Write(b []byte) (int, error) {
func (w *gzipResponseWriter) Flush() {
w.Writer.(*gzip.Writer).Flush()
if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
flusher.Flush()
}
}
func (w *gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return w.ResponseWriter.(http.Hijacker).Hijack()
}
func (w *gzipResponseWriter) CloseNotify() <-chan bool {
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

View File

@ -5,7 +5,7 @@ import (
"strconv"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (
@ -102,6 +102,10 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
allowOrigin = o
break
}
if matchSubdomain(origin, o) {
allowOrigin = origin
break
}
}
// Simple request

View File

@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/random"
)

View File

@ -7,7 +7,7 @@ import (
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -5,7 +5,7 @@ import (
"net/http"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -2,6 +2,7 @@ package middleware
import (
"bytes"
"encoding/json"
"io"
"os"
"strconv"
@ -9,7 +10,7 @@ import (
"sync"
"time"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/color"
"github.com/valyala/fasttemplate"
)
@ -20,7 +21,7 @@ type (
// Skipper defines a function to skip middleware.
Skipper Skipper
// Tags to constructed the logger format.
// Tags to construct the logger format.
//
// - time_unix
// - time_unix_nano
@ -175,7 +176,10 @@ func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
return buf.WriteString(s)
case "error":
if err != nil {
return buf.WriteString(err.Error())
// Error may contain invalid JSON e.g. `"`
b, _ := json.Marshal(err.Error())
b = b[1 : len(b)-1]
return buf.Write(b)
}
case "latency":
l := stop.Sub(start)

View File

@ -3,7 +3,7 @@ package middleware
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -5,7 +5,7 @@ import (
"strconv"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -13,7 +13,7 @@ import (
"sync/atomic"
"time"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
// TODO: Handle TLS proxy
@ -37,11 +37,11 @@ type (
// "/users/*/orders/*": "/user/$1/order/$2",
Rewrite map[string]string
// Context key to store selected ProxyTarget into context.
// Context key to store selected ProxyTarget into context.
// Optional. Default value "target".
ContextKey string
// To customize the transport to remote.
// To customize the transport to remote.
// Examples: If custom TLS certificates are required.
Transport http.RoundTripper
@ -200,7 +200,7 @@ func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
// Defaults
if config.Skipper == nil {
config.Skipper = DefaultLoggerConfig.Skipper
config.Skipper = DefaultProxyConfig.Skipper
}
if config.Balancer == nil {
panic("echo: proxy middleware requires balancer")

View File

@ -7,7 +7,7 @@ import (
"net/http"
"net/http/httputil"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
func proxyHTTP(tgt *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {

View File

@ -3,9 +3,10 @@
package middleware
import (
"github.com/labstack/echo"
"net/http"
"net/http/httputil"
"github.com/labstack/echo/v4"
)
func proxyHTTP(t *ProxyTarget, c echo.Context, config ProxyConfig) http.Handler {

View File

@ -4,7 +4,7 @@ import (
"fmt"
"runtime"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -3,7 +3,7 @@ package middleware
import (
"net/http"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
// RedirectConfig defines the config for Redirect middleware.
@ -21,7 +21,7 @@ type RedirectConfig struct {
// 2) return the appropriate redirect url.
type redirectLogic func(scheme, host, uri string) (ok bool, url string)
const www = "www"
const www = "www."
// DefaultRedirectConfig is the default Redirect middleware config.
var DefaultRedirectConfig = RedirectConfig{
@ -60,7 +60,7 @@ func HTTPSWWWRedirect() echo.MiddlewareFunc {
// See `HTTPSWWWRedirect()`.
func HTTPSWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
if ok = scheme != "https" && host[:3] != www; ok {
if ok = scheme != "https" && host[:4] != www; ok {
url = "https://www." + host + uri
}
return
@ -80,7 +80,7 @@ func HTTPSNonWWWRedirect() echo.MiddlewareFunc {
func HTTPSNonWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
if ok = scheme != "https"; ok {
if host[:3] == www {
if host[:4] == www {
host = host[4:]
}
url = "https://" + host + uri
@ -101,7 +101,7 @@ func WWWRedirect() echo.MiddlewareFunc {
// See `WWWRedirect()`.
func WWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
if ok = host[:3] != www; ok {
if ok = host[:4] != www; ok {
url = scheme + "://www." + host + uri
}
return
@ -120,7 +120,7 @@ func NonWWWRedirect() echo.MiddlewareFunc {
// See `NonWWWRedirect()`.
func NonWWWRedirectWithConfig(config RedirectConfig) echo.MiddlewareFunc {
return redirect(config, func(scheme, host, uri string) (ok bool, url string) {
if ok = host[:3] == www; ok {
if ok = host[:4] == www; ok {
url = scheme + "://" + host[4:] + uri
}
return

View File

@ -1,7 +1,7 @@
package middleware
import (
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/random"
)

View File

@ -4,7 +4,7 @@ import (
"regexp"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (

View File

@ -3,7 +3,7 @@ package middleware
import (
"fmt"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
)
type (
@ -53,6 +53,19 @@ type (
// trusted web page context.
// Optional. Default value "".
ContentSecurityPolicy string `yaml:"content_security_policy"`
// CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead
// of the `Content-Security-Policy` header. This allows iterative updates of the
// content security policy by only reporting the violations that would
// have occurred instead of blocking the resource.
// Optional. Default value false.
CSPReportOnly bool `yaml:"csp_report_only"`
// HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security`
// header, which enables the domain to be included in the HSTS preload list
// maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
// Optional. Default value false.
HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"`
}
)
@ -63,6 +76,7 @@ var (
XSSProtection: "1; mode=block",
ContentTypeNosniff: "nosniff",
XFrameOptions: "SAMEORIGIN",
HSTSPreloadEnabled: false,
}
)
@ -105,10 +119,17 @@ func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
if !config.HSTSExcludeSubdomains {
subdomains = "; includeSubdomains"
}
if config.HSTSPreloadEnabled {
subdomains = fmt.Sprintf("%s; preload", subdomains)
}
res.Header().Set(echo.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", config.HSTSMaxAge, subdomains))
}
if config.ContentSecurityPolicy != "" {
res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
if config.CSPReportOnly {
res.Header().Set(echo.HeaderContentSecurityPolicyReportOnly, config.ContentSecurityPolicy)
} else {
res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
}
}
return next(c)
}

View File

@ -1,7 +1,9 @@
package middleware
import (
"github.com/labstack/echo"
"strings"
"github.com/labstack/echo/v4"
)
type (
@ -49,7 +51,7 @@ func AddTrailingSlashWithConfig(config TrailingSlashConfig) echo.MiddlewareFunc
url := req.URL
path := url.Path
qs := c.QueryString()
if path != "/" && path[len(path)-1] != '/' {
if !strings.HasSuffix(path, "/") {
path += "/"
uri := path
if qs != "" {
@ -97,7 +99,7 @@ func RemoveTrailingSlashWithConfig(config TrailingSlashConfig) echo.MiddlewareFu
path := url.Path
qs := c.QueryString()
l := len(path) - 1
if l >= 0 && path != "/" && path[l] == '/' {
if l > 0 && strings.HasSuffix(path, "/") {
path = path[:l]
uri := path
if qs != "" {

View File

@ -10,7 +10,7 @@ import (
"path/filepath"
"strings"
"github.com/labstack/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/gommon/bytes"
)
@ -76,7 +76,7 @@ const html = `
transition: opacity 0.25s;
}
li span {
color: #707070;
color: #707070;
font-size: 12px;
}
li a:hover {

54
vendor/github.com/labstack/echo/v4/middleware/util.go generated vendored Normal file
View File

@ -0,0 +1,54 @@
package middleware
import (
"strings"
)
func matchScheme(domain, pattern string) bool {
didx := strings.Index(domain, ":")
pidx := strings.Index(pattern, ":")
return didx != -1 && pidx != -1 && domain[:didx] == pattern[:pidx]
}
// matchSubdomain compares authority with wildcard
func matchSubdomain(domain, pattern string) bool {
if !matchScheme(domain, pattern) {
return false
}
didx := strings.Index(domain, "://")
pidx := strings.Index(pattern, "://")
if didx == -1 || pidx == -1 {
return false
}
domAuth := domain[didx+3:]
// to avoid long loop by invalid long domain
if len(domAuth) > 253 {
return false
}
patAuth := pattern[pidx+3:]
domComp := strings.Split(domAuth, ".")
patComp := strings.Split(patAuth, ".")
for i := len(domComp)/2 - 1; i >= 0; i-- {
opp := len(domComp) - 1 - i
domComp[i], domComp[opp] = domComp[opp], domComp[i]
}
for i := len(patComp)/2 - 1; i >= 0; i-- {
opp := len(patComp) - 1 - i
patComp[i], patComp[opp] = patComp[opp], patComp[i]
}
for i, v := range domComp {
if len(patComp) <= i {
return false
}
p := patComp[i]
if p == "*" {
return true
}
if p != v {
return false
}
}
return false
}

View File

@ -91,15 +91,6 @@ func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return r.Writer.(http.Hijacker).Hijack()
}
// CloseNotify implements the http.CloseNotifier interface to allow detecting
// when the underlying connection has gone away.
// This mechanism can be used to cancel long operations on the server if the
// client has disconnected before the response is ready.
// See [http.CloseNotifier](https://golang.org/pkg/net/http/#CloseNotifier)
func (r *Response) CloseNotify() <-chan bool {
return r.Writer.(http.CloseNotifier).CloseNotify()
}
func (r *Response) reset(w http.ResponseWriter) {
r.beforeFuncs = nil
r.afterFuncs = nil

View File

@ -57,7 +57,7 @@ func NewRouter(e *Echo) *Router {
func (r *Router) Add(method, path string, h HandlerFunc) {
// Validate path
if path == "" {
panic("echo: path cannot be empty")
path = "/"
}
if path[0] != '/' {
path = "/" + path
@ -79,14 +79,13 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
if i == l {
r.insert(method, path[:i], h, pkind, ppath, pnames)
return
} else {
r.insert(method, path[:i], nil, pkind, "", nil)
}
r.insert(method, path[:i], nil, pkind, "", nil)
} else if path[i] == '*' {
r.insert(method, path[:i], nil, skind, "", nil)
pnames = append(pnames, "*")
r.insert(method, path[:i+1], h, akind, ppath, pnames)
return
}
}