4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-07-03 08:27:44 +00:00

Update direct dependencies where possible

This commit is contained in:
Duco van Amstel
2018-11-18 17:55:05 +00:00
committed by Wim
parent f716b8fc0f
commit 09875fe160
356 changed files with 27318 additions and 11078 deletions

View File

@ -1,7 +1,7 @@
language: go
go:
- 1.8.x
- 1.9.x
- 1.10.x
- tip
install:
- make dependency

View File

@ -10,26 +10,26 @@
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
revision = "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
version = "v3.0.0"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]]
name = "github.com/labstack/gommon"
packages = ["bytes","color","log","random"]
revision = "1121fd3e243c202482226a7afe4dcd07ffc4139a"
version = "v0.2.1"
revision = "6fe1405d73ec4bd4cd8a4ac8e2a2b2bf95d03954"
version = "0.2.4"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
revision = "d228849504861217f796da67fae4f6e347643f15"
version = "v0.0.7"
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "fc9e8d8ef48496124e79ae0df75490096eccf6fe"
version = "v0.0.2"
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
name = "github.com/pmezard/go-difflib"
@ -40,8 +40,8 @@
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert"]
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
version = "v1.1.4"
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
[[projects]]
branch = "master"
@ -59,17 +59,17 @@
branch = "master"
name = "golang.org/x/crypto"
packages = ["acme","acme/autocert"]
revision = "e1a4589e7d3ea14a3352255d04b6f1a418845e5e"
revision = "182114d582623c1caa54f73de9c7224e23a48487"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "b90f89a1e7a9c1f6b918820b3daa7f08488c8594"
revision = "c28acc882ebcbfbe8ce9f0f14b9ac26ee138dd51"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "5f74a2a2ba5b07475ad0faa1b4c021b973ad40b2ae749e3d94e15fe839bb440e"
inputs-digest = "9c7b45e80fe353405800cf01f429b3a203cfb8d4468a04c64a908e11a98ea764"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -1,82 +1,37 @@
## Gopkg.toml example (these lines may be deleted)
## "metadata" defines metadata about the project that could be used by other independent
## systems. The metadata defined here will be ignored by dep.
# [metadata]
# key1 = "value that convey data to other systems"
# system1-data = "value that is used by a system"
# system2-data = "value that is used by another system"
## "required" lists a set of packages (not projects) that must be included in
## Gopkg.lock. This list is merged with the set of packages imported by the current
## project. Use it when your project needs a package it doesn't explicitly import -
## including "main" packages.
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
## "ignored" lists a set of packages (not projects) that are ignored when
## dep statically analyzes source code. Ignored packages can be in this project,
## or in a dependency.
# ignored = ["github.com/user/project/badpkg"]
## Constraints are rules for how directly imported projects
## may be incorporated into the depgraph. They are respected by
## dep whether coming from the Gopkg.toml of the current project or a dependency.
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
## Required: the root import path of the project being constrained.
# name = "github.com/user/project"
# name = "github.com/user/project"
# version = "1.0.0"
#
## Recommended: the version constraint to enforce for the project.
## Only one of "branch", "version" or "revision" can be specified.
# version = "1.0.0"
# branch = "master"
# revision = "abc123"
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
## Optional: an alternate location (URL or import path) for the project's source.
# source = "https://github.com/myfork/package.git"
#
## "metadata" defines metadata about the dependency or override that could be used
## by other independent systems. The metadata defined here will be ignored by dep.
# [metadata]
# key1 = "value that convey data to other systems"
# system1-data = "value that is used by a system"
# system2-data = "value that is used by another system"
## Overrides have the same structure as [[constraint]], but supersede all
## [[constraint]] declarations from all projects. Only [[override]] from
## the current project's are applied.
##
## Overrides are a sledgehammer. Use them only as a last resort.
# [[override]]
## Required: the root import path of the project being constrained.
# name = "github.com/user/project"
#
## Optional: specifying a version constraint override will cause all other
## constraints on this project to be ignored; only the overridden constraint
## need be satisfied.
## Again, only one of "branch", "version" or "revision" can be specified.
# version = "1.0.0"
# branch = "master"
# revision = "abc123"
#
## Optional: specifying an alternate source location as an override will
## enforce that the alternate location is used for that project, regardless of
## what source location any dependent projects specify.
# source = "https://github.com/myfork/package.git"
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "3.0.0"
version = "3.2.0"
[[constraint]]
name = "github.com/labstack/gommon"
version = "0.2.1"
version = "0.2.4"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.1.4"
version = "1.2.1"
[[constraint]]
branch = "master"
@ -84,4 +39,4 @@
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
name = "golang.org/x/crypto"

View File

@ -11,3 +11,7 @@ test:
go test -race -coverprofile=profile.out -covermode=atomic $$d || exit 1; \
[ -f profile.out ] && cat profile.out >> coverage.txt && rm profile.out; \
done
tag:
@git tag `grep -P '^\tversion = ' echo.go|cut -f2 -d'"'`
@git tag|grep -v ^v

View File

@ -26,9 +26,13 @@
- Automatic TLS via Lets Encrypt
- HTTP/2 support
## Performance
## Benchmarks
<img src="https://api.labstack.com/chart/bar?values=20015,39584,7282,11276&labels=Static,GitHub%20API,Parse%20API,Google%20Plus%20API&x_title=Route&y_title=Time%20(ns/op)&colors=c&dpi=100">
Date: 2018/03/15<br>
Source: https://github.com/vishr/web-framework-benchmark<br>
Lower is better!
<img src="https://api.labstack.com/chart/bar?values=37223,55382,2985,5265|42013,59865,3350,6424&labels=Static,GitHub%20API,Parse%20API,Gplus%20API&titles=Echo,Gin&colors=lightseagreen,goldenrod&x_title=Routes&y_title=ns/op">
## [Guide](https://echo.labstack.com/guide)

View File

@ -80,7 +80,7 @@ func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag
val := reflect.ValueOf(ptr).Elem()
if typ.Kind() != reflect.Struct {
return errors.New("Binding element must be a struct")
return errors.New("binding element must be a struct")
}
for i := 0; i < typ.NumField(); i++ {

View File

@ -206,6 +206,13 @@ const (
indexPage = "index.html"
)
func (c *context) writeContentType(value string) {
header := c.Response().Header()
if header.Get(HeaderContentType) == "" {
header.Set(HeaderContentType, value)
}
}
func (c *context) Request() *http.Request {
return c.request
}
@ -430,7 +437,7 @@ func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
}
func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
c.response.Header().Set(HeaderContentType, MIMEApplicationJavaScriptCharsetUTF8)
c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
c.response.WriteHeader(code)
if _, err = c.response.Write([]byte(callback + "(")); err != nil {
return
@ -463,7 +470,7 @@ func (c *context) XMLPretty(code int, i interface{}, indent string) (err error)
}
func (c *context) XMLBlob(code int, b []byte) (err error) {
c.response.Header().Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
c.writeContentType(MIMEApplicationXMLCharsetUTF8)
c.response.WriteHeader(code)
if _, err = c.response.Write([]byte(xml.Header)); err != nil {
return
@ -473,14 +480,14 @@ func (c *context) XMLBlob(code int, b []byte) (err error) {
}
func (c *context) Blob(code int, contentType string, b []byte) (err error) {
c.response.Header().Set(HeaderContentType, contentType)
c.writeContentType(contentType)
c.response.WriteHeader(code)
_, err = c.response.Write(b)
return
}
func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
c.response.Header().Set(HeaderContentType, contentType)
c.writeContentType(contentType)
c.response.WriteHeader(code)
_, err = io.Copy(c.response, r)
return
@ -509,18 +516,17 @@ func (c *context) File(file string) (err error) {
return
}
func (c *context) Attachment(file, name string) (err error) {
func (c *context) Attachment(file, name string) error {
return c.contentDisposition(file, name, "attachment")
}
func (c *context) Inline(file, name string) (err error) {
func (c *context) Inline(file, name string) error {
return c.contentDisposition(file, name, "inline")
}
func (c *context) contentDisposition(file, name, dispositionType string) (err error) {
func (c *context) contentDisposition(file, name, dispositionType string) error {
c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
c.File(file)
return
return c.File(file)
}
func (c *context) NoContent(code int) error {

View File

@ -38,6 +38,7 @@ package echo
import (
"bytes"
stdContext "context"
"crypto/tls"
"errors"
"fmt"
@ -45,6 +46,7 @@ import (
stdLog "log"
"net"
"net/http"
"net/url"
"path"
"path/filepath"
"reflect"
@ -81,8 +83,7 @@ type (
Binder Binder
Validator Validator
Renderer Renderer
// Mutex sync.RWMutex
Logger Logger
Logger Logger
}
// Route contains a handler and information for matching against requests.
@ -94,9 +95,9 @@ type (
// HTTPError represents an error that occurred while handling a request.
HTTPError struct {
Code int
Message interface{}
Inner error // Stores the error returned by an external dependency
Code int
Message interface{}
Internal error // Stores the error returned by an external dependency
}
// MiddlewareFunc defines a function to process middleware.
@ -129,15 +130,16 @@ type (
// HTTP methods
const (
CONNECT = "CONNECT"
DELETE = "DELETE"
GET = "GET"
HEAD = "HEAD"
OPTIONS = "OPTIONS"
PATCH = "PATCH"
POST = "POST"
PUT = "PUT"
TRACE = "TRACE"
CONNECT = "CONNECT"
DELETE = "DELETE"
GET = "GET"
HEAD = "HEAD"
OPTIONS = "OPTIONS"
PATCH = "PATCH"
POST = "POST"
PROPFIND = "PROPFIND"
PUT = "PUT"
TRACE = "TRACE"
)
// MIME types
@ -191,6 +193,7 @@ const (
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
HeaderXRealIP = "X-Real-IP"
HeaderXRequestID = "X-Request-ID"
HeaderXRequestedWith = "X-Requested-With"
HeaderServer = "Server"
HeaderOrigin = "Origin"
@ -214,7 +217,7 @@ const (
)
const (
version = "3.2.6"
Version = "3.3.5"
website = "https://echo.labstack.com"
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
banner = `
@ -238,6 +241,7 @@ var (
OPTIONS,
PATCH,
POST,
PROPFIND,
PUT,
TRACE,
}
@ -251,10 +255,10 @@ var (
ErrForbidden = NewHTTPError(http.StatusForbidden)
ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
ErrValidatorNotRegistered = errors.New("Validator not registered")
ErrRendererNotRegistered = errors.New("Renderer not registered")
ErrInvalidRedirectCode = errors.New("Invalid redirect status code")
ErrCookieNotFound = errors.New("Cookie not found")
ErrValidatorNotRegistered = errors.New("validator not registered")
ErrRendererNotRegistered = errors.New("renderer not registered")
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
ErrCookieNotFound = errors.New("cookie not found")
)
// Error handlers
@ -321,8 +325,8 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
if he, ok := err.(*HTTPError); ok {
code = he.Code
msg = he.Message
if he.Inner != nil {
msg = fmt.Sprintf("%v, %v", err, he.Inner)
if he.Internal != nil {
msg = fmt.Sprintf("%v, %v", err, he.Internal)
}
} else if e.Debug {
msg = err.Error()
@ -443,7 +447,7 @@ func (e *Echo) Static(prefix, root string) *Route {
func static(i i, prefix, root string) *Route {
h := func(c Context) error {
p, err := PathUnescape(c.Param("*"))
p, err := url.PathUnescape(c.Param("*"))
if err != nil {
return err
}
@ -530,7 +534,7 @@ func (e *Echo) Reverse(name string, params ...interface{}) string {
// Routes returns the registered routes.
func (e *Echo) Routes() []*Route {
routes := []*Route{}
routes := make([]*Route, 0, len(e.router.routes))
for _, v := range e.router.routes {
routes = append(routes, v)
}
@ -551,39 +555,48 @@ func (e *Echo) ReleaseContext(c Context) {
// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Acquire lock
// e.Mutex.RLock()
// defer e.Mutex.RUnlock()
// Acquire context
c := e.pool.Get().(*context)
defer e.pool.Put(c)
c.Reset(r, w)
// Middleware
h := func(c Context) error {
method := r.Method
m := r.Method
h := NotFoundHandler
if e.premiddleware == nil {
path := r.URL.RawPath
if path == "" {
path = r.URL.Path
}
e.router.Find(method, path, c)
h := c.Handler()
e.router.Find(m, getPath(r), c)
h = c.Handler()
for i := len(e.middleware) - 1; i >= 0; i-- {
h = e.middleware[i](h)
}
return h(c)
}
// Premiddleware
for i := len(e.premiddleware) - 1; i >= 0; i-- {
h = e.premiddleware[i](h)
} else {
h = func(c Context) error {
path := r.URL.RawPath
if path == "" {
path = r.URL.Path
}
e.router.Find(m, getPath(r), c)
h := c.Handler()
for i := len(e.middleware) - 1; i >= 0; i-- {
h = e.middleware[i](h)
}
return h(c)
}
for i := len(e.premiddleware) - 1; i >= 0; i-- {
h = e.premiddleware[i](h)
}
}
// Execute chain
if err := h(c); err != nil {
e.HTTPErrorHandler(err, c)
}
// Release context
e.pool.Put(c)
}
// Start starts an HTTP server.
@ -609,6 +622,10 @@ func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
func (e *Echo) StartAutoTLS(address string) error {
if e.Listener == nil {
go http.ListenAndServe(":http", e.AutoTLSManager.HTTPHandler(nil))
}
s := e.TLSServer
s.TLSConfig = new(tls.Config)
s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
@ -635,7 +652,7 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
}
if !e.HideBanner {
e.colorer.Printf(banner, e.colorer.Red("v"+version), e.colorer.Blue(website))
e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
}
if s.TLSConfig == nil {
@ -663,6 +680,24 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
return s.Serve(e.TLSListener)
}
// Close immediately stops the server.
// It internally calls `http.Server#Close()`.
func (e *Echo) Close() error {
if err := e.TLSServer.Close(); err != nil {
return err
}
return e.Server.Close()
}
// Shutdown stops server the gracefully.
// It internally calls `http.Server#Shutdown()`.
func (e *Echo) Shutdown(ctx stdContext.Context) error {
if err := e.TLSServer.Shutdown(ctx); err != nil {
return err
}
return e.Server.Shutdown(ctx)
}
// NewHTTPError creates a new HTTPError instance.
func NewHTTPError(code int, message ...interface{}) *HTTPError {
he := &HTTPError{Code: code, Message: http.StatusText(code)}
@ -698,6 +733,14 @@ func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
}
}
func getPath(r *http.Request) string {
path := r.URL.RawPath
if path == "" {
path = r.URL.Path
}
return path
}
func handlerName(h HandlerFunc) string {
t := reflect.ValueOf(h).Type()
if t.Kind() == reflect.Func {
@ -706,6 +749,11 @@ func handlerName(h HandlerFunc) string {
return t.String()
}
// // PathUnescape is wraps `url.PathUnescape`
// func PathUnescape(s string) (string, error) {
// return url.PathUnescape(s)
// }
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually

View File

@ -1,25 +0,0 @@
// +build go1.8
package echo
import (
stdContext "context"
)
// Close immediately stops the server.
// It internally calls `http.Server#Close()`.
func (e *Echo) Close() error {
if err := e.TLSServer.Close(); err != nil {
return err
}
return e.Server.Close()
}
// Shutdown stops server the gracefully.
// It internally calls `http.Server#Shutdown()`.
func (e *Echo) Shutdown(ctx stdContext.Context) error {
if err := e.TLSServer.Shutdown(ctx); err != nil {
return err
}
return e.Server.Shutdown(ctx)
}

View File

@ -92,7 +92,7 @@ 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 {
m := []MiddlewareFunc{}
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...)
@ -113,7 +113,7 @@ func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...Midd
// Combine into a new slice to avoid accidentally passing the same slice for
// multiple routes, which would lead to later add() calls overwriting the
// middleware from earlier calls.
m := []MiddlewareFunc{}
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...)

View File

@ -93,10 +93,8 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
}
}
realm := ""
if config.Realm == defaultRealm {
realm = defaultRealm
} else {
realm := defaultRealm
if config.Realm != defaultRealm {
realm = strconv.Quote(config.Realm)
}

View File

@ -3,12 +3,11 @@ package middleware
import (
"bufio"
"bytes"
"io"
"io/ioutil"
"net"
"net/http"
"io"
"github.com/labstack/echo"
)

View File

@ -105,6 +105,7 @@ func (r *limitedReader) Close() error {
func (r *limitedReader) Reset(reader io.ReadCloser, context echo.Context) {
r.reader = reader
r.context = context
r.read = 0
}
func limitedReaderPool(c BodyLimitConfig) sync.Pool {

View File

@ -126,8 +126,8 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
k, err := c.Cookie(config.CookieName)
token := ""
// Generate token
if err != nil {
// Generate token
token = random.String(config.TokenLength)
} else {
// Reuse token
@ -143,7 +143,7 @@ func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if !validateCSRFToken(token, clientToken) {
return echo.NewHTTPError(http.StatusForbidden, "Invalid csrf token")
return echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
}
}
@ -187,7 +187,7 @@ func csrfTokenFromForm(param string) csrfTokenExtractor {
return func(c echo.Context) (string, error) {
token := c.FormValue(param)
if token == "" {
return "", errors.New("Missing csrf token in the form parameter")
return "", errors.New("missing csrf token in the form parameter")
}
return token, nil
}
@ -199,7 +199,7 @@ func csrfTokenFromQuery(param string) csrfTokenExtractor {
return func(c echo.Context) (string, error) {
token := c.QueryParam(param)
if token == "" {
return "", errors.New("Missing csrf token in the query string")
return "", errors.New("missing csrf token in the query string")
}
return token, nil
}

View File

@ -58,8 +58,8 @@ const (
// Errors
var (
ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "Missing or malformed jwt")
ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "Invalid or expired jwt")
ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
)
var (
@ -116,7 +116,7 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
config.keyFunc = func(t *jwt.Token) (interface{}, error) {
// Check the signing method
if t.Method.Alg() != config.SigningMethod {
return nil, fmt.Errorf("Unexpected jwt signing method=%v", t.Header["alg"])
return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
}
return config.SigningKey, nil
}
@ -156,9 +156,9 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
return next(c)
}
return &echo.HTTPError{
Code: ErrJWTInvalid.Code,
Message: ErrJWTInvalid.Message,
Inner: err,
Code: ErrJWTInvalid.Code,
Message: ErrJWTInvalid.Message,
Internal: err,
}
}
}

View File

@ -114,14 +114,14 @@ func keyFromHeader(header string, authScheme string) keyExtractor {
return func(c echo.Context) (string, error) {
auth := c.Request().Header.Get(header)
if auth == "" {
return "", errors.New("Missing key in request header")
return "", errors.New("missing key in request header")
}
if header == echo.HeaderAuthorization {
l := len(authScheme)
if len(auth) > l+1 && auth[:l] == authScheme {
return auth[l+1:], nil
}
return "", errors.New("Invalid key in the request header")
return "", errors.New("invalid key in the request header")
}
return auth, nil
}
@ -132,7 +132,7 @@ func keyFromQuery(param string) keyExtractor {
return func(c echo.Context) (string, error) {
key := c.QueryParam(param)
if key == "" {
return "", errors.New("Missing key in the query string")
return "", errors.New("missing key in the query string")
}
return key, nil
}
@ -143,7 +143,7 @@ func keyFromForm(param string) keyExtractor {
return func(c echo.Context) (string, error) {
key := c.FormValue(param)
if key == "" {
return "", errors.New("Missing key in the form")
return "", errors.New("missing key in the form")
}
return key, nil
}

View File

@ -47,7 +47,7 @@ type (
// Example "${remote_ip} ${status}"
//
// Optional. Default value DefaultLoggerConfig.Format.
Format string `yaml:"format"`
Format string `yaml:"format"`
// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
CustomTimeFormat string `yaml:"custom_time_format"`
@ -70,9 +70,9 @@ var (
`"method":"${method}","uri":"${uri}","status":${status}, "latency":${latency},` +
`"latency_human":"${latency_human}","bytes_in":${bytes_in},` +
`"bytes_out":${bytes_out}}` + "\n",
CustomTimeFormat:"2006-01-02 15:04:05.00000",
Output: os.Stdout,
colorer: color.New(),
CustomTimeFormat: "2006-01-02 15:04:05.00000",
Output: os.Stdout,
colorer: color.New(),
}
)

View File

@ -108,15 +108,15 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
return
}
errc := make(chan error, 2)
errCh := make(chan error, 2)
cp := func(dst io.Writer, src io.Reader) {
_, err := io.Copy(dst, src)
errc <- err
_, err = io.Copy(dst, src)
errCh <- err
}
go cp(out, in)
go cp(in, out)
err = <-errc
err = <-errCh
if err != nil && err != io.EOF {
c.Logger().Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err)
}

View File

@ -2,13 +2,16 @@ package middleware
import (
"fmt"
"html/template"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"github.com/labstack/echo"
"github.com/labstack/gommon/bytes"
)
type (
@ -36,6 +39,78 @@ type (
}
)
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ .Name }}</title>
<style>
body {
font-family: Menlo, Consolas, monospace;
padding: 48px;
}
header {
padding: 4px 16px;
font-size: 24px;
}
ul {
list-style-type: none;
margin: 0;
padding: 20px 0 0 0;
display: flex;
flex-wrap: wrap;
}
li {
width: 300px;
padding: 16px;
}
li a {
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-decoration: none;
transition: opacity 0.25s;
}
li span {
color: #707070;
font-size: 12px;
}
li a:hover {
opacity: 0.50;
}
.dir {
color: #E91E63;
}
.file {
color: #673AB7;
}
</style>
</head>
<body>
<header>
{{ .Name }}
</header>
<ul>
{{ range .Files }}
<li>
{{ if .Dir }}
{{ $name := print .Name "/" }}
<a class="dir" href="{{ $name }}">{{ $name }}</a>
{{ else }}
<a class="file" href="{{ .Name }}">{{ .Name }}</a>
<span>{{ .Size }}</span>
{{ end }}
</li>
{{ end }}
</ul>
</body>
</html>
`
var (
// DefaultStaticConfig is the default Static middleware config.
DefaultStaticConfig = StaticConfig{
@ -66,6 +141,12 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
config.Index = DefaultStaticConfig.Index
}
// Index template
t, err := template.New("index").Parse(html)
if err != nil {
panic(fmt.Sprintf("echo: %v", err))
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) (err error) {
if config.Skipper(c) {
@ -76,7 +157,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
p = c.Param("*")
}
p, err = echo.PathUnescape(p)
p, err = url.PathUnescape(p)
if err != nil {
return
}
@ -103,7 +184,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
if err != nil {
if config.Browse {
return listDir(name, c.Response())
return listDir(t, name, c.Response())
}
if os.IsNotExist(err) {
return next(c)
@ -119,32 +200,30 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
}
}
func listDir(name string, res *echo.Response) (err error) {
dir, err := os.Open(name)
func listDir(t *template.Template, name string, res *echo.Response) (err error) {
file, err := os.Open(name)
if err != nil {
return
}
dirs, err := dir.Readdir(-1)
files, err := file.Readdir(-1)
if err != nil {
return
}
// Create a directory index
// Create directory index
res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
return
data := struct {
Name string
Files []interface{}
}{
Name: name,
}
for _, d := range dirs {
name := d.Name()
color := "#212121"
if d.IsDir() {
color = "#e91e63"
name += "/"
}
if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
return
}
for _, f := range files {
data.Files = append(data.Files, struct {
Name string
Dir bool
Size string
}{f.Name(), f.IsDir(), bytes.Format(f.Size())})
}
_, err = fmt.Fprintf(res, "</pre>\n")
return
return t.Execute(res, data)
}

View File

@ -4,7 +4,6 @@ import (
"bufio"
"net"
"net/http"
"strconv"
)
type (
@ -12,14 +11,13 @@ type (
// by an HTTP handler to construct an HTTP response.
// See: https://golang.org/pkg/net/http/#ResponseWriter
Response struct {
echo *Echo
contentLength int64
beforeFuncs []func()
afterFuncs []func()
Writer http.ResponseWriter
Status int
Size int64
Committed bool
echo *Echo
beforeFuncs []func()
afterFuncs []func()
Writer http.ResponseWriter
Status int
Size int64
Committed bool
}
)
@ -64,7 +62,6 @@ func (r *Response) WriteHeader(code int) {
r.Status = code
r.Writer.WriteHeader(code)
r.Committed = true
r.contentLength, _ = strconv.ParseInt(r.Header().Get(HeaderContentLength), 10, 0)
}
// Write writes the data to the connection as part of an HTTP reply.
@ -74,10 +71,8 @@ func (r *Response) Write(b []byte) (n int, err error) {
}
n, err = r.Writer.Write(b)
r.Size += int64(n)
if r.Size == r.contentLength {
for _, fn := range r.afterFuncs {
fn()
}
for _, fn := range r.afterFuncs {
fn()
}
return
}
@ -106,7 +101,6 @@ func (r *Response) CloseNotify() <-chan bool {
}
func (r *Response) reset(w http.ResponseWriter) {
r.contentLength = 0
r.beforeFuncs = nil
r.afterFuncs = nil
r.Writer = w

View File

@ -21,15 +21,16 @@ type (
kind uint8
children []*node
methodHandler struct {
connect HandlerFunc
delete HandlerFunc
get HandlerFunc
head HandlerFunc
options HandlerFunc
patch HandlerFunc
post HandlerFunc
put HandlerFunc
trace HandlerFunc
connect HandlerFunc
delete HandlerFunc
get HandlerFunc
head HandlerFunc
options HandlerFunc
patch HandlerFunc
post HandlerFunc
propfind HandlerFunc
put HandlerFunc
trace HandlerFunc
}
)
@ -59,8 +60,8 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
if path[0] != '/' {
path = "/" + path
}
ppath := path // Pristine path
pnames := []string{} // Param names
ppath := path // Pristine path
for i, l := 0, len(path); i < l; i++ {
if path[i] == ':' {
@ -225,22 +226,24 @@ func (n *node) findChildByKind(t kind) *node {
func (n *node) addHandler(method string, h HandlerFunc) {
switch method {
case GET:
n.methodHandler.get = h
case POST:
n.methodHandler.post = h
case PUT:
n.methodHandler.put = h
case DELETE:
n.methodHandler.delete = h
case PATCH:
n.methodHandler.patch = h
case OPTIONS:
n.methodHandler.options = h
case HEAD:
n.methodHandler.head = h
case CONNECT:
n.methodHandler.connect = h
case DELETE:
n.methodHandler.delete = h
case GET:
n.methodHandler.get = h
case HEAD:
n.methodHandler.head = h
case OPTIONS:
n.methodHandler.options = h
case PATCH:
n.methodHandler.patch = h
case POST:
n.methodHandler.post = h
case PROPFIND:
n.methodHandler.propfind = h
case PUT:
n.methodHandler.put = h
case TRACE:
n.methodHandler.trace = h
}
@ -248,22 +251,24 @@ func (n *node) addHandler(method string, h HandlerFunc) {
func (n *node) findHandler(method string) HandlerFunc {
switch method {
case GET:
return n.methodHandler.get
case POST:
return n.methodHandler.post
case PUT:
return n.methodHandler.put
case DELETE:
return n.methodHandler.delete
case PATCH:
return n.methodHandler.patch
case OPTIONS:
return n.methodHandler.options
case HEAD:
return n.methodHandler.head
case CONNECT:
return n.methodHandler.connect
case DELETE:
return n.methodHandler.delete
case GET:
return n.methodHandler.get
case HEAD:
return n.methodHandler.head
case OPTIONS:
return n.methodHandler.options
case PATCH:
return n.methodHandler.patch
case POST:
return n.methodHandler.post
case PROPFIND:
return n.methodHandler.propfind
case PUT:
return n.methodHandler.put
case TRACE:
return n.methodHandler.trace
default:

View File

@ -1,12 +0,0 @@
// +build go1.7, !go1.8
package echo
import (
"net/url"
)
// PathUnescape is wraps `url.QueryUnescape`
func PathUnescape(s string) (string, error) {
return url.QueryUnescape(s)
}

View File

@ -1,10 +0,0 @@
// +build go1.8
package echo
import "net/url"
// PathUnescape is wraps `url.PathUnescape`
func PathUnescape(s string) (string, error) {
return url.PathUnescape(s)
}