1
0
mirror of https://github.com/labstack/echo.git synced 2024-11-24 08:22:21 +02:00

Change type definition blocks to single declarations. This helps copy/pasting Echo code in examples. (#2606)

This commit is contained in:
Martti T 2024-03-09 17:53:07 +02:00 committed by GitHub
parent 5f7bedfb86
commit 3598f295f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 1272 additions and 1370 deletions

28
bind.go
View File

@ -14,23 +14,21 @@ import (
"strings" "strings"
) )
type ( // Binder is the interface that wraps the Bind method.
// Binder is the interface that wraps the Bind method. type Binder interface {
Binder interface { Bind(i interface{}, c Context) error
Bind(i interface{}, c Context) error }
}
// DefaultBinder is the default implementation of the Binder interface. // DefaultBinder is the default implementation of the Binder interface.
DefaultBinder struct{} type DefaultBinder struct{}
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method. // BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
// Types that don't implement this, but do implement encoding.TextUnmarshaler // Types that don't implement this, but do implement encoding.TextUnmarshaler
// will use that interface instead. // will use that interface instead.
BindUnmarshaler interface { type BindUnmarshaler interface {
// UnmarshalParam decodes and assigns a value from an form or query param. // UnmarshalParam decodes and assigns a value from an form or query param.
UnmarshalParam(param string) error UnmarshalParam(param string) error
} }
)
// BindPathParams binds path params to bindable object // BindPathParams binds path params to bindable object
func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error { func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {

View File

@ -22,91 +22,91 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type ( type bindTestStruct struct {
bindTestStruct struct { I int
I int PtrI *int
PtrI *int I8 int8
I8 int8 PtrI8 *int8
PtrI8 *int8 I16 int16
I16 int16 PtrI16 *int16
PtrI16 *int16 I32 int32
I32 int32 PtrI32 *int32
PtrI32 *int32 I64 int64
I64 int64 PtrI64 *int64
PtrI64 *int64 UI uint
UI uint PtrUI *uint
PtrUI *uint UI8 uint8
UI8 uint8 PtrUI8 *uint8
PtrUI8 *uint8 UI16 uint16
UI16 uint16 PtrUI16 *uint16
PtrUI16 *uint16 UI32 uint32
UI32 uint32 PtrUI32 *uint32
PtrUI32 *uint32 UI64 uint64
UI64 uint64 PtrUI64 *uint64
PtrUI64 *uint64 B bool
B bool PtrB *bool
PtrB *bool F32 float32
F32 float32 PtrF32 *float32
PtrF32 *float32 F64 float64
F64 float64 PtrF64 *float64
PtrF64 *float64 S string
S string PtrS *string
PtrS *string cantSet string
cantSet string DoesntExist string
DoesntExist string GoT time.Time
GoT time.Time GoTptr *time.Time
GoTptr *time.Time T Timestamp
T Timestamp Tptr *Timestamp
Tptr *Timestamp SA StringArray
SA StringArray }
}
bindTestStructWithTags struct { type bindTestStructWithTags struct {
I int `json:"I" form:"I"` I int `json:"I" form:"I"`
PtrI *int `json:"PtrI" form:"PtrI"` PtrI *int `json:"PtrI" form:"PtrI"`
I8 int8 `json:"I8" form:"I8"` I8 int8 `json:"I8" form:"I8"`
PtrI8 *int8 `json:"PtrI8" form:"PtrI8"` PtrI8 *int8 `json:"PtrI8" form:"PtrI8"`
I16 int16 `json:"I16" form:"I16"` I16 int16 `json:"I16" form:"I16"`
PtrI16 *int16 `json:"PtrI16" form:"PtrI16"` PtrI16 *int16 `json:"PtrI16" form:"PtrI16"`
I32 int32 `json:"I32" form:"I32"` I32 int32 `json:"I32" form:"I32"`
PtrI32 *int32 `json:"PtrI32" form:"PtrI32"` PtrI32 *int32 `json:"PtrI32" form:"PtrI32"`
I64 int64 `json:"I64" form:"I64"` I64 int64 `json:"I64" form:"I64"`
PtrI64 *int64 `json:"PtrI64" form:"PtrI64"` PtrI64 *int64 `json:"PtrI64" form:"PtrI64"`
UI uint `json:"UI" form:"UI"` UI uint `json:"UI" form:"UI"`
PtrUI *uint `json:"PtrUI" form:"PtrUI"` PtrUI *uint `json:"PtrUI" form:"PtrUI"`
UI8 uint8 `json:"UI8" form:"UI8"` UI8 uint8 `json:"UI8" form:"UI8"`
PtrUI8 *uint8 `json:"PtrUI8" form:"PtrUI8"` PtrUI8 *uint8 `json:"PtrUI8" form:"PtrUI8"`
UI16 uint16 `json:"UI16" form:"UI16"` UI16 uint16 `json:"UI16" form:"UI16"`
PtrUI16 *uint16 `json:"PtrUI16" form:"PtrUI16"` PtrUI16 *uint16 `json:"PtrUI16" form:"PtrUI16"`
UI32 uint32 `json:"UI32" form:"UI32"` UI32 uint32 `json:"UI32" form:"UI32"`
PtrUI32 *uint32 `json:"PtrUI32" form:"PtrUI32"` PtrUI32 *uint32 `json:"PtrUI32" form:"PtrUI32"`
UI64 uint64 `json:"UI64" form:"UI64"` UI64 uint64 `json:"UI64" form:"UI64"`
PtrUI64 *uint64 `json:"PtrUI64" form:"PtrUI64"` PtrUI64 *uint64 `json:"PtrUI64" form:"PtrUI64"`
B bool `json:"B" form:"B"` B bool `json:"B" form:"B"`
PtrB *bool `json:"PtrB" form:"PtrB"` PtrB *bool `json:"PtrB" form:"PtrB"`
F32 float32 `json:"F32" form:"F32"` F32 float32 `json:"F32" form:"F32"`
PtrF32 *float32 `json:"PtrF32" form:"PtrF32"` PtrF32 *float32 `json:"PtrF32" form:"PtrF32"`
F64 float64 `json:"F64" form:"F64"` F64 float64 `json:"F64" form:"F64"`
PtrF64 *float64 `json:"PtrF64" form:"PtrF64"` PtrF64 *float64 `json:"PtrF64" form:"PtrF64"`
S string `json:"S" form:"S"` S string `json:"S" form:"S"`
PtrS *string `json:"PtrS" form:"PtrS"` PtrS *string `json:"PtrS" form:"PtrS"`
cantSet string cantSet string
DoesntExist string `json:"DoesntExist" form:"DoesntExist"` DoesntExist string `json:"DoesntExist" form:"DoesntExist"`
GoT time.Time `json:"GoT" form:"GoT"` GoT time.Time `json:"GoT" form:"GoT"`
GoTptr *time.Time `json:"GoTptr" form:"GoTptr"` GoTptr *time.Time `json:"GoTptr" form:"GoTptr"`
T Timestamp `json:"T" form:"T"` T Timestamp `json:"T" form:"T"`
Tptr *Timestamp `json:"Tptr" form:"Tptr"` Tptr *Timestamp `json:"Tptr" form:"Tptr"`
SA StringArray `json:"SA" form:"SA"` SA StringArray `json:"SA" form:"SA"`
} }
Timestamp time.Time
TA []Timestamp type Timestamp time.Time
StringArray []string type TA []Timestamp
Struct struct { type StringArray []string
Foo string type Struct struct {
} Foo string
Bar struct { }
Baz int `json:"baz" query:"baz"` type Bar struct {
} Baz int `json:"baz" query:"baz"`
) }
func (t *Timestamp) UnmarshalParam(src string) error { func (t *Timestamp) UnmarshalParam(src string) error {
ts, err := time.Parse(time.RFC3339, src) ts, err := time.Parse(time.RFC3339, src)

View File

@ -16,204 +16,202 @@ import (
"sync" "sync"
) )
type ( // Context represents the context of the current HTTP request. It holds request and
// Context represents the context of the current HTTP request. It holds request and // response objects, path, path parameters, data and registered handler.
// response objects, path, path parameters, data and registered handler. type Context interface {
Context interface { // Request returns `*http.Request`.
// Request returns `*http.Request`. Request() *http.Request
Request() *http.Request
// SetRequest sets `*http.Request`. // SetRequest sets `*http.Request`.
SetRequest(r *http.Request) SetRequest(r *http.Request)
// SetResponse sets `*Response`. // SetResponse sets `*Response`.
SetResponse(r *Response) SetResponse(r *Response)
// Response returns `*Response`. // Response returns `*Response`.
Response() *Response Response() *Response
// IsTLS returns true if HTTP connection is TLS otherwise false. // IsTLS returns true if HTTP connection is TLS otherwise false.
IsTLS() bool IsTLS() bool
// IsWebSocket returns true if HTTP connection is WebSocket otherwise false. // IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
IsWebSocket() bool IsWebSocket() bool
// Scheme returns the HTTP protocol scheme, `http` or `https`. // Scheme returns the HTTP protocol scheme, `http` or `https`.
Scheme() string Scheme() string
// RealIP returns the client's network address based on `X-Forwarded-For` // RealIP returns the client's network address based on `X-Forwarded-For`
// or `X-Real-IP` request header. // or `X-Real-IP` request header.
// The behavior can be configured using `Echo#IPExtractor`. // The behavior can be configured using `Echo#IPExtractor`.
RealIP() string RealIP() string
// Path returns the registered path for the handler. // Path returns the registered path for the handler.
Path() string Path() string
// SetPath sets the registered path for the handler. // SetPath sets the registered path for the handler.
SetPath(p string) SetPath(p string)
// Param returns path parameter by name. // Param returns path parameter by name.
Param(name string) string Param(name string) string
// ParamNames returns path parameter names. // ParamNames returns path parameter names.
ParamNames() []string ParamNames() []string
// SetParamNames sets path parameter names. // SetParamNames sets path parameter names.
SetParamNames(names ...string) SetParamNames(names ...string)
// ParamValues returns path parameter values. // ParamValues returns path parameter values.
ParamValues() []string ParamValues() []string
// SetParamValues sets path parameter values. // SetParamValues sets path parameter values.
SetParamValues(values ...string) SetParamValues(values ...string)
// QueryParam returns the query param for the provided name. // QueryParam returns the query param for the provided name.
QueryParam(name string) string QueryParam(name string) string
// QueryParams returns the query parameters as `url.Values`. // QueryParams returns the query parameters as `url.Values`.
QueryParams() url.Values QueryParams() url.Values
// QueryString returns the URL query string. // QueryString returns the URL query string.
QueryString() string QueryString() string
// FormValue returns the form field value for the provided name. // FormValue returns the form field value for the provided name.
FormValue(name string) string FormValue(name string) string
// FormParams returns the form parameters as `url.Values`. // FormParams returns the form parameters as `url.Values`.
FormParams() (url.Values, error) FormParams() (url.Values, error)
// FormFile returns the multipart form file for the provided name. // FormFile returns the multipart form file for the provided name.
FormFile(name string) (*multipart.FileHeader, error) FormFile(name string) (*multipart.FileHeader, error)
// MultipartForm returns the multipart form. // MultipartForm returns the multipart form.
MultipartForm() (*multipart.Form, error) MultipartForm() (*multipart.Form, error)
// Cookie returns the named cookie provided in the request. // Cookie returns the named cookie provided in the request.
Cookie(name string) (*http.Cookie, error) Cookie(name string) (*http.Cookie, error)
// SetCookie adds a `Set-Cookie` header in HTTP response. // SetCookie adds a `Set-Cookie` header in HTTP response.
SetCookie(cookie *http.Cookie) SetCookie(cookie *http.Cookie)
// Cookies returns the HTTP cookies sent with the request. // Cookies returns the HTTP cookies sent with the request.
Cookies() []*http.Cookie Cookies() []*http.Cookie
// Get retrieves data from the context. // Get retrieves data from the context.
Get(key string) interface{} Get(key string) interface{}
// Set saves data in the context. // Set saves data in the context.
Set(key string, val interface{}) Set(key string, val interface{})
// Bind binds path params, query params and the request body into provided type `i`. The default binder // Bind binds path params, query params and the request body into provided type `i`. The default binder
// binds body based on Content-Type header. // binds body based on Content-Type header.
Bind(i interface{}) error Bind(i interface{}) error
// Validate validates provided `i`. It is usually called after `Context#Bind()`. // Validate validates provided `i`. It is usually called after `Context#Bind()`.
// Validator must be registered using `Echo#Validator`. // Validator must be registered using `Echo#Validator`.
Validate(i interface{}) error Validate(i interface{}) error
// Render renders a template with data and sends a text/html response with status // Render renders a template with data and sends a text/html response with status
// code. Renderer must be registered using `Echo.Renderer`. // code. Renderer must be registered using `Echo.Renderer`.
Render(code int, name string, data interface{}) error Render(code int, name string, data interface{}) error
// HTML sends an HTTP response with status code. // HTML sends an HTTP response with status code.
HTML(code int, html string) error HTML(code int, html string) error
// HTMLBlob sends an HTTP blob response with status code. // HTMLBlob sends an HTTP blob response with status code.
HTMLBlob(code int, b []byte) error HTMLBlob(code int, b []byte) error
// String sends a string response with status code. // String sends a string response with status code.
String(code int, s string) error String(code int, s string) error
// JSON sends a JSON response with status code. // JSON sends a JSON response with status code.
JSON(code int, i interface{}) error JSON(code int, i interface{}) error
// JSONPretty sends a pretty-print JSON with status code. // JSONPretty sends a pretty-print JSON with status code.
JSONPretty(code int, i interface{}, indent string) error JSONPretty(code int, i interface{}, indent string) error
// JSONBlob sends a JSON blob response with status code. // JSONBlob sends a JSON blob response with status code.
JSONBlob(code int, b []byte) error JSONBlob(code int, b []byte) error
// JSONP sends a JSONP response with status code. It uses `callback` to construct // JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload. // the JSONP payload.
JSONP(code int, callback string, i interface{}) error JSONP(code int, callback string, i interface{}) error
// JSONPBlob sends a JSONP blob response with status code. It uses `callback` // JSONPBlob sends a JSONP blob response with status code. It uses `callback`
// to construct the JSONP payload. // to construct the JSONP payload.
JSONPBlob(code int, callback string, b []byte) error JSONPBlob(code int, callback string, b []byte) error
// XML sends an XML response with status code. // XML sends an XML response with status code.
XML(code int, i interface{}) error XML(code int, i interface{}) error
// XMLPretty sends a pretty-print XML with status code. // XMLPretty sends a pretty-print XML with status code.
XMLPretty(code int, i interface{}, indent string) error XMLPretty(code int, i interface{}, indent string) error
// XMLBlob sends an XML blob response with status code. // XMLBlob sends an XML blob response with status code.
XMLBlob(code int, b []byte) error XMLBlob(code int, b []byte) error
// Blob sends a blob response with status code and content type. // Blob sends a blob response with status code and content type.
Blob(code int, contentType string, b []byte) error Blob(code int, contentType string, b []byte) error
// Stream sends a streaming response with status code and content type. // Stream sends a streaming response with status code and content type.
Stream(code int, contentType string, r io.Reader) error Stream(code int, contentType string, r io.Reader) error
// File sends a response with the content of the file. // File sends a response with the content of the file.
File(file string) error File(file string) error
// Attachment sends a response as attachment, prompting client to save the // Attachment sends a response as attachment, prompting client to save the
// file. // file.
Attachment(file string, name string) error Attachment(file string, name string) error
// Inline sends a response as inline, opening the file in the browser. // Inline sends a response as inline, opening the file in the browser.
Inline(file string, name string) error Inline(file string, name string) error
// NoContent sends a response with no body and a status code. // NoContent sends a response with no body and a status code.
NoContent(code int) error NoContent(code int) error
// Redirect redirects the request to a provided URL with status code. // Redirect redirects the request to a provided URL with status code.
Redirect(code int, url string) error Redirect(code int, url string) error
// Error invokes the registered global HTTP error handler. Generally used by middleware. // Error invokes the registered global HTTP error handler. Generally used by middleware.
// A side-effect of calling global error handler is that now Response has been committed (sent to the client) and // A side-effect of calling global error handler is that now Response has been committed (sent to the client) and
// middlewares up in chain can not change Response status code or Response body anymore. // middlewares up in chain can not change Response status code or Response body anymore.
// //
// Avoid using this method in handlers as no middleware will be able to effectively handle errors after that. // Avoid using this method in handlers as no middleware will be able to effectively handle errors after that.
Error(err error) Error(err error)
// Handler returns the matched handler by router. // Handler returns the matched handler by router.
Handler() HandlerFunc Handler() HandlerFunc
// SetHandler sets the matched handler by router. // SetHandler sets the matched handler by router.
SetHandler(h HandlerFunc) SetHandler(h HandlerFunc)
// Logger returns the `Logger` instance. // Logger returns the `Logger` instance.
Logger() Logger Logger() Logger
// SetLogger Set the logger // SetLogger Set the logger
SetLogger(l Logger) SetLogger(l Logger)
// Echo returns the `Echo` instance. // Echo returns the `Echo` instance.
Echo() *Echo Echo() *Echo
// Reset resets the context after request completes. It must be called along // Reset resets the context after request completes. It must be called along
// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`. // with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
// See `Echo#ServeHTTP()` // See `Echo#ServeHTTP()`
Reset(r *http.Request, w http.ResponseWriter) Reset(r *http.Request, w http.ResponseWriter)
} }
context struct { type context struct {
request *http.Request request *http.Request
response *Response response *Response
path string path string
pnames []string pnames []string
pvalues []string pvalues []string
query url.Values query url.Values
handler HandlerFunc handler HandlerFunc
store Map store Map
echo *Echo echo *Echo
logger Logger logger Logger
lock sync.RWMutex lock sync.RWMutex
} }
)
const ( const (
// ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain. // ContextKeyHeaderAllow is set by Router for getting value for `Allow` header in later stages of handler call chain.

View File

@ -25,11 +25,9 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type ( type Template struct {
Template struct { templates *template.Template
templates *template.Template }
}
)
var testUser = user{1, "Jon Snow"} var testUser = user{1, "Jon Snow"}

211
echo.go
View File

@ -63,97 +63,95 @@ import (
"golang.org/x/net/http2/h2c" "golang.org/x/net/http2/h2c"
) )
type ( // Echo is the top-level framework instance.
// Echo is the top-level framework instance. //
// // Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these
// Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these // fields from handlers/middlewares and changing field values at the same time leads to data-races.
// fields from handlers/middlewares and changing field values at the same time leads to data-races. // Adding new routes after the server has been started is also not safe!
// Adding new routes after the server has been started is also not safe! type Echo struct {
Echo struct { filesystem
filesystem common
common // startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
// startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get // listener address info (on which interface/port was listener bound) without having data races.
// listener address info (on which interface/port was listener bound) without having data races. startupMutex sync.RWMutex
startupMutex sync.RWMutex colorer *color.Color
colorer *color.Color
// premiddleware are middlewares that are run before routing is done. In case a pre-middleware returns // premiddleware are middlewares that are run before routing is done. In case a pre-middleware returns
// an error the router is not executed and the request will end up in the global error handler. // an error the router is not executed and the request will end up in the global error handler.
premiddleware []MiddlewareFunc premiddleware []MiddlewareFunc
middleware []MiddlewareFunc middleware []MiddlewareFunc
maxParam *int maxParam *int
router *Router router *Router
routers map[string]*Router routers map[string]*Router
pool sync.Pool pool sync.Pool
StdLogger *stdLog.Logger StdLogger *stdLog.Logger
Server *http.Server Server *http.Server
TLSServer *http.Server TLSServer *http.Server
Listener net.Listener Listener net.Listener
TLSListener net.Listener TLSListener net.Listener
AutoTLSManager autocert.Manager AutoTLSManager autocert.Manager
DisableHTTP2 bool DisableHTTP2 bool
Debug bool Debug bool
HideBanner bool HideBanner bool
HidePort bool HidePort bool
HTTPErrorHandler HTTPErrorHandler HTTPErrorHandler HTTPErrorHandler
Binder Binder Binder Binder
JSONSerializer JSONSerializer JSONSerializer JSONSerializer
Validator Validator Validator Validator
Renderer Renderer Renderer Renderer
Logger Logger Logger Logger
IPExtractor IPExtractor IPExtractor IPExtractor
ListenerNetwork string ListenerNetwork string
// OnAddRouteHandler is called when Echo adds new route to specific host router. // OnAddRouteHandler is called when Echo adds new route to specific host router.
OnAddRouteHandler func(host string, route Route, handler HandlerFunc, middleware []MiddlewareFunc) OnAddRouteHandler func(host string, route Route, handler HandlerFunc, middleware []MiddlewareFunc)
} }
// Route contains a handler and information for matching against requests. // Route contains a handler and information for matching against requests.
Route struct { type Route struct {
Method string `json:"method"` Method string `json:"method"`
Path string `json:"path"` Path string `json:"path"`
Name string `json:"name"` Name string `json:"name"`
} }
// HTTPError represents an error that occurred while handling a request. // HTTPError represents an error that occurred while handling a request.
HTTPError struct { type HTTPError struct {
Code int `json:"-"` Code int `json:"-"`
Message interface{} `json:"message"` Message interface{} `json:"message"`
Internal error `json:"-"` // Stores the error returned by an external dependency Internal error `json:"-"` // Stores the error returned by an external dependency
} }
// MiddlewareFunc defines a function to process middleware. // MiddlewareFunc defines a function to process middleware.
MiddlewareFunc func(next HandlerFunc) HandlerFunc type MiddlewareFunc func(next HandlerFunc) HandlerFunc
// HandlerFunc defines a function to serve HTTP requests. // HandlerFunc defines a function to serve HTTP requests.
HandlerFunc func(c Context) error type HandlerFunc func(c Context) error
// HTTPErrorHandler is a centralized HTTP error handler. // HTTPErrorHandler is a centralized HTTP error handler.
HTTPErrorHandler func(err error, c Context) type HTTPErrorHandler func(err error, c Context)
// Validator is the interface that wraps the Validate function. // Validator is the interface that wraps the Validate function.
Validator interface { type Validator interface {
Validate(i interface{}) error Validate(i interface{}) error
} }
// JSONSerializer is the interface that encodes and decodes JSON to and from interfaces. // JSONSerializer is the interface that encodes and decodes JSON to and from interfaces.
JSONSerializer interface { type JSONSerializer interface {
Serialize(c Context, i interface{}, indent string) error Serialize(c Context, i interface{}, indent string) error
Deserialize(c Context, i interface{}) error Deserialize(c Context, i interface{}) error
} }
// Renderer is the interface that wraps the Render function. // Renderer is the interface that wraps the Render function.
Renderer interface { type Renderer interface {
Render(io.Writer, string, interface{}, Context) error Render(io.Writer, string, interface{}, Context) error
} }
// Map defines a generic map of type `map[string]interface{}`. // Map defines a generic map of type `map[string]interface{}`.
Map map[string]interface{} type Map map[string]interface{}
// Common struct for Echo & Group. // Common struct for Echo & Group.
common struct{} type common struct{}
)
// HTTP methods // HTTP methods
// NOTE: Deprecated, please use the stdlib constants directly instead. // NOTE: Deprecated, please use the stdlib constants directly instead.
@ -282,21 +280,19 @@ ____________________________________O/_______
` `
) )
var ( var methods = [...]string{
methods = [...]string{ http.MethodConnect,
http.MethodConnect, http.MethodDelete,
http.MethodDelete, http.MethodGet,
http.MethodGet, http.MethodHead,
http.MethodHead, http.MethodOptions,
http.MethodOptions, http.MethodPatch,
http.MethodPatch, http.MethodPost,
http.MethodPost, PROPFIND,
PROPFIND, http.MethodPut,
http.MethodPut, http.MethodTrace,
http.MethodTrace, REPORT,
REPORT, }
}
)
// Errors // Errors
var ( var (
@ -349,22 +345,23 @@ var (
ErrInvalidListenerNetwork = errors.New("invalid listener network") ErrInvalidListenerNetwork = errors.New("invalid listener network")
) )
// Error handlers // NotFoundHandler is the handler that router uses in case there was no matching route found. Returns an error that results
var ( // HTTP 404 status code.
NotFoundHandler = func(c Context) error { var NotFoundHandler = func(c Context) error {
return ErrNotFound return ErrNotFound
} }
MethodNotAllowedHandler = func(c Context) error { // MethodNotAllowedHandler is the handler thar router uses in case there was no matching route found but there was
// See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed) // another matching routes for that requested URL. Returns an error that results HTTP 405 Method Not Allowed status code.
// response and MAY do so in any other response. For disabled resources an empty Allow header may be returned var MethodNotAllowedHandler = func(c Context) error {
routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string) // See RFC 7231 section 7.4.1: An origin server MUST generate an Allow field in a 405 (Method Not Allowed)
if ok && routerAllowMethods != "" { // response and MAY do so in any other response. For disabled resources an empty Allow header may be returned
c.Response().Header().Set(HeaderAllow, routerAllowMethods) routerAllowMethods, ok := c.Get(ContextKeyHeaderAllow).(string)
} if ok && routerAllowMethods != "" {
return ErrMethodNotAllowed c.Response().Header().Set(HeaderAllow, routerAllowMethods)
} }
) return ErrMethodNotAllowed
}
// New creates an instance of Echo. // New creates an instance of Echo.
func New() (e *Echo) { func New() (e *Echo) {

View File

@ -25,12 +25,10 @@ import (
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
type ( type user struct {
user struct { ID int `json:"id" xml:"id" form:"id" query:"id" param:"id" header:"id"`
ID int `json:"id" xml:"id" form:"id" query:"id" param:"id" header:"id"` Name string `json:"name" xml:"name" form:"name" query:"name" param:"name" header:"name"`
Name string `json:"name" xml:"name" form:"name" query:"name" param:"name" header:"name"` }
}
)
const ( const (
userJSON = `{"id":1,"name":"Jon Snow"}` userJSON = `{"id":1,"name":"Jon Snow"}`

View File

@ -7,18 +7,16 @@ import (
"net/http" "net/http"
) )
type ( // Group is a set of sub-routes for a specified route. It can be used for inner
// Group is a set of sub-routes for a specified route. It can be used for inner // routes that share a common middleware or functionality that should be separate
// routes that share a common middleware or functionality that should be separate // from the parent echo instance while still inheriting from it.
// from the parent echo instance while still inheriting from it. type Group struct {
Group struct { common
common host string
host string prefix string
prefix string middleware []MiddlewareFunc
middleware []MiddlewareFunc echo *Echo
echo *Echo }
}
)
// Use implements `Echo#Use()` for sub-routes within the Group. // Use implements `Echo#Use()` for sub-routes within the Group.
func (g *Group) Use(middleware ...MiddlewareFunc) { func (g *Group) Use(middleware ...MiddlewareFunc) {

67
log.go
View File

@ -4,41 +4,38 @@
package echo package echo
import ( import (
"io"
"github.com/labstack/gommon/log" "github.com/labstack/gommon/log"
"io"
) )
type ( // Logger defines the logging interface.
// Logger defines the logging interface. type Logger interface {
Logger interface { Output() io.Writer
Output() io.Writer SetOutput(w io.Writer)
SetOutput(w io.Writer) Prefix() string
Prefix() string SetPrefix(p string)
SetPrefix(p string) Level() log.Lvl
Level() log.Lvl SetLevel(v log.Lvl)
SetLevel(v log.Lvl) SetHeader(h string)
SetHeader(h string) Print(i ...interface{})
Print(i ...interface{}) Printf(format string, args ...interface{})
Printf(format string, args ...interface{}) Printj(j log.JSON)
Printj(j log.JSON) Debug(i ...interface{})
Debug(i ...interface{}) Debugf(format string, args ...interface{})
Debugf(format string, args ...interface{}) Debugj(j log.JSON)
Debugj(j log.JSON) Info(i ...interface{})
Info(i ...interface{}) Infof(format string, args ...interface{})
Infof(format string, args ...interface{}) Infoj(j log.JSON)
Infoj(j log.JSON) Warn(i ...interface{})
Warn(i ...interface{}) Warnf(format string, args ...interface{})
Warnf(format string, args ...interface{}) Warnj(j log.JSON)
Warnj(j log.JSON) Error(i ...interface{})
Error(i ...interface{}) Errorf(format string, args ...interface{})
Errorf(format string, args ...interface{}) Errorj(j log.JSON)
Errorj(j log.JSON) Fatal(i ...interface{})
Fatal(i ...interface{}) Fatalj(j log.JSON)
Fatalj(j log.JSON) Fatalf(format string, args ...interface{})
Fatalf(format string, args ...interface{}) Panic(i ...interface{})
Panic(i ...interface{}) Panicj(j log.JSON)
Panicj(j log.JSON) Panicf(format string, args ...interface{})
Panicf(format string, args ...interface{}) }
}
)

View File

@ -12,39 +12,35 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // BasicAuthConfig defines the config for BasicAuth middleware.
// BasicAuthConfig defines the config for BasicAuth middleware. type BasicAuthConfig struct {
BasicAuthConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Validator is a function to validate BasicAuth credentials. // Validator is a function to validate BasicAuth credentials.
// Required. // Required.
Validator BasicAuthValidator Validator BasicAuthValidator
// Realm is a string to define realm attribute of BasicAuth. // Realm is a string to define realm attribute of BasicAuth.
// Default value "Restricted". // Default value "Restricted".
Realm string Realm string
} }
// BasicAuthValidator defines a function to validate BasicAuth credentials. // BasicAuthValidator defines a function to validate BasicAuth credentials.
// The function should return a boolean indicating whether the credentials are valid, // The function should return a boolean indicating whether the credentials are valid,
// and an error if any error occurs during the validation process. // and an error if any error occurs during the validation process.
BasicAuthValidator func(string, string, echo.Context) (bool, error) type BasicAuthValidator func(string, string, echo.Context) (bool, error)
)
const ( const (
basic = "basic" basic = "basic"
defaultRealm = "Restricted" defaultRealm = "Restricted"
) )
var ( // DefaultBasicAuthConfig is the default BasicAuth middleware config.
// DefaultBasicAuthConfig is the default BasicAuth middleware config. var DefaultBasicAuthConfig = BasicAuthConfig{
DefaultBasicAuthConfig = BasicAuthConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Realm: defaultRealm,
Realm: defaultRealm, }
}
)
// BasicAuth returns an BasicAuth middleware. // BasicAuth returns an BasicAuth middleware.
// //

View File

@ -14,32 +14,28 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // BodyDumpConfig defines the config for BodyDump middleware.
// BodyDumpConfig defines the config for BodyDump middleware. type BodyDumpConfig struct {
BodyDumpConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Handler receives request and response payload. // Handler receives request and response payload.
// Required. // Required.
Handler BodyDumpHandler Handler BodyDumpHandler
} }
// BodyDumpHandler receives the request and response payload. // BodyDumpHandler receives the request and response payload.
BodyDumpHandler func(echo.Context, []byte, []byte) type BodyDumpHandler func(echo.Context, []byte, []byte)
bodyDumpResponseWriter struct { type bodyDumpResponseWriter struct {
io.Writer io.Writer
http.ResponseWriter http.ResponseWriter
} }
)
var ( // DefaultBodyDumpConfig is the default BodyDump middleware config.
// DefaultBodyDumpConfig is the default BodyDump middleware config. var DefaultBodyDumpConfig = BodyDumpConfig{
DefaultBodyDumpConfig = BodyDumpConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, }
}
)
// BodyDump returns a BodyDump middleware. // BodyDump returns a BodyDump middleware.
// //

View File

@ -12,31 +12,27 @@ import (
"github.com/labstack/gommon/bytes" "github.com/labstack/gommon/bytes"
) )
type ( // BodyLimitConfig defines the config for BodyLimit middleware.
// BodyLimitConfig defines the config for BodyLimit middleware. type BodyLimitConfig struct {
BodyLimitConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Maximum allowed size for a request body, it can be specified // Maximum allowed size for a request body, it can be specified
// as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P. // as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P.
Limit string `yaml:"limit"` Limit string `yaml:"limit"`
limit int64 limit int64
} }
limitedReader struct { type limitedReader struct {
BodyLimitConfig BodyLimitConfig
reader io.ReadCloser reader io.ReadCloser
read int64 read int64
} }
)
var ( // DefaultBodyLimitConfig is the default BodyLimit middleware config.
// DefaultBodyLimitConfig is the default BodyLimit middleware config. var DefaultBodyLimitConfig = BodyLimitConfig{
DefaultBodyLimitConfig = BodyLimitConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, }
}
)
// BodyLimit returns a BodyLimit middleware. // BodyLimit returns a BodyLimit middleware.
// //

View File

@ -16,54 +16,50 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // GzipConfig defines the config for Gzip middleware.
// GzipConfig defines the config for Gzip middleware. type GzipConfig struct {
GzipConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Gzip compression level. // Gzip compression level.
// Optional. Default value -1. // Optional. Default value -1.
Level int `yaml:"level"` Level int `yaml:"level"`
// Length threshold before gzip compression is applied. // Length threshold before gzip compression is applied.
// Optional. Default value 0. // Optional. Default value 0.
// //
// Most of the time you will not need to change the default. Compressing // Most of the time you will not need to change the default. Compressing
// a short response might increase the transmitted data because of the // a short response might increase the transmitted data because of the
// gzip format overhead. Compressing the response will also consume CPU // gzip format overhead. Compressing the response will also consume CPU
// and time on the server and the client (for decompressing). Depending on // and time on the server and the client (for decompressing). Depending on
// your use case such a threshold might be useful. // your use case such a threshold might be useful.
// //
// See also: // See also:
// https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits // https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits
MinLength int MinLength int
} }
gzipResponseWriter struct { type gzipResponseWriter struct {
io.Writer io.Writer
http.ResponseWriter http.ResponseWriter
wroteHeader bool wroteHeader bool
wroteBody bool wroteBody bool
minLength int minLength int
minLengthExceeded bool minLengthExceeded bool
buffer *bytes.Buffer buffer *bytes.Buffer
code int code int
} }
)
const ( const (
gzipScheme = "gzip" gzipScheme = "gzip"
) )
var ( // DefaultGzipConfig is the default Gzip middleware config.
// DefaultGzipConfig is the default Gzip middleware config. var DefaultGzipConfig = GzipConfig{
DefaultGzipConfig = GzipConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Level: -1,
Level: -1, MinLength: 0,
MinLength: 0, }
}
)
// Gzip returns a middleware which compresses HTTP response using gzip compression // Gzip returns a middleware which compresses HTTP response using gzip compression
// scheme. // scheme.

View File

@ -12,113 +12,109 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // CORSConfig defines the config for CORS middleware.
// CORSConfig defines the config for CORS middleware. type CORSConfig struct {
CORSConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// AllowOrigins determines the value of the Access-Control-Allow-Origin // AllowOrigins determines the value of the Access-Control-Allow-Origin
// response header. This header defines a list of origins that may access the // response header. This header defines a list of origins that may access the
// resource. The wildcard characters '*' and '?' are supported and are // resource. The wildcard characters '*' and '?' are supported and are
// converted to regex fragments '.*' and '.' accordingly. // converted to regex fragments '.*' and '.' accordingly.
// //
// Security: use extreme caution when handling the origin, and carefully // Security: use extreme caution when handling the origin, and carefully
// validate any logic. Remember that attackers may register hostile domain names. // validate any logic. Remember that attackers may register hostile domain names.
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html // See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
// //
// Optional. Default value []string{"*"}. // Optional. Default value []string{"*"}.
// //
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
AllowOrigins []string `yaml:"allow_origins"` AllowOrigins []string `yaml:"allow_origins"`
// AllowOriginFunc is a custom function to validate the origin. It takes the // AllowOriginFunc is a custom function to validate the origin. It takes the
// origin as an argument and returns true if allowed or false otherwise. If // origin as an argument and returns true if allowed or false otherwise. If
// an error is returned, it is returned by the handler. If this option is // an error is returned, it is returned by the handler. If this option is
// set, AllowOrigins is ignored. // set, AllowOrigins is ignored.
// //
// Security: use extreme caution when handling the origin, and carefully // Security: use extreme caution when handling the origin, and carefully
// validate any logic. Remember that attackers may register hostile domain names. // validate any logic. Remember that attackers may register hostile domain names.
// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html // See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
// //
// Optional. // Optional.
AllowOriginFunc func(origin string) (bool, error) `yaml:"-"` AllowOriginFunc func(origin string) (bool, error) `yaml:"-"`
// AllowMethods determines the value of the Access-Control-Allow-Methods // AllowMethods determines the value of the Access-Control-Allow-Methods
// response header. This header specified the list of methods allowed when // response header. This header specified the list of methods allowed when
// accessing the resource. This is used in response to a preflight request. // accessing the resource. This is used in response to a preflight request.
// //
// Optional. Default value DefaultCORSConfig.AllowMethods. // Optional. Default value DefaultCORSConfig.AllowMethods.
// If `allowMethods` is left empty, this middleware will fill for preflight // If `allowMethods` is left empty, this middleware will fill for preflight
// request `Access-Control-Allow-Methods` header value // request `Access-Control-Allow-Methods` header value
// from `Allow` header that echo.Router set into context. // from `Allow` header that echo.Router set into context.
// //
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
AllowMethods []string `yaml:"allow_methods"` AllowMethods []string `yaml:"allow_methods"`
// AllowHeaders determines the value of the Access-Control-Allow-Headers // AllowHeaders determines the value of the Access-Control-Allow-Headers
// response header. This header is used in response to a preflight request to // response header. This header is used in response to a preflight request to
// indicate which HTTP headers can be used when making the actual request. // indicate which HTTP headers can be used when making the actual request.
// //
// Optional. Default value []string{}. // Optional. Default value []string{}.
// //
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
AllowHeaders []string `yaml:"allow_headers"` AllowHeaders []string `yaml:"allow_headers"`
// AllowCredentials determines the value of the // AllowCredentials determines the value of the
// Access-Control-Allow-Credentials response header. This header indicates // Access-Control-Allow-Credentials response header. This header indicates
// whether or not the response to the request can be exposed when the // whether or not the response to the request can be exposed when the
// credentials mode (Request.credentials) is true. When used as part of a // credentials mode (Request.credentials) is true. When used as part of a
// response to a preflight request, this indicates whether or not the actual // response to a preflight request, this indicates whether or not the actual
// request can be made using credentials. See also // request can be made using credentials. See also
// [MDN: Access-Control-Allow-Credentials]. // [MDN: Access-Control-Allow-Credentials].
// //
// Optional. Default value false, in which case the header is not set. // Optional. Default value false, in which case the header is not set.
// //
// Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`. // Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
// See "Exploiting CORS misconfigurations for Bitcoins and bounties", // See "Exploiting CORS misconfigurations for Bitcoins and bounties",
// https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html // https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
// //
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
AllowCredentials bool `yaml:"allow_credentials"` AllowCredentials bool `yaml:"allow_credentials"`
// UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials // UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials
// flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header. // flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header.
// //
// This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties) // This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties)
// attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject. // attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject.
// //
// Optional. Default value is false. // Optional. Default value is false.
UnsafeWildcardOriginWithAllowCredentials bool `yaml:"unsafe_wildcard_origin_with_allow_credentials"` UnsafeWildcardOriginWithAllowCredentials bool `yaml:"unsafe_wildcard_origin_with_allow_credentials"`
// ExposeHeaders determines the value of Access-Control-Expose-Headers, which // ExposeHeaders determines the value of Access-Control-Expose-Headers, which
// defines a list of headers that clients are allowed to access. // defines a list of headers that clients are allowed to access.
// //
// Optional. Default value []string{}, in which case the header is not set. // Optional. Default value []string{}, in which case the header is not set.
// //
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
ExposeHeaders []string `yaml:"expose_headers"` ExposeHeaders []string `yaml:"expose_headers"`
// MaxAge determines the value of the Access-Control-Max-Age response header. // MaxAge determines the value of the Access-Control-Max-Age response header.
// This header indicates how long (in seconds) the results of a preflight // This header indicates how long (in seconds) the results of a preflight
// request can be cached. // request can be cached.
// The header is set only if MaxAge != 0, negative value sends "0" which instructs browsers not to cache that response. // The header is set only if MaxAge != 0, negative value sends "0" which instructs browsers not to cache that response.
// //
// Optional. Default value 0 - meaning header is not sent. // Optional. Default value 0 - meaning header is not sent.
// //
// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age // See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
MaxAge int `yaml:"max_age"` MaxAge int `yaml:"max_age"`
} }
)
var ( // DefaultCORSConfig is the default CORS middleware config.
// DefaultCORSConfig is the default CORS middleware config. var DefaultCORSConfig = CORSConfig{
DefaultCORSConfig = CORSConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, AllowOrigins: []string{"*"},
AllowOrigins: []string{"*"}, AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete}, }
}
)
// CORS returns a Cross-Origin Resource Sharing (CORS) middleware. // CORS returns a Cross-Origin Resource Sharing (CORS) middleware.
// See also [MDN: Cross-Origin Resource Sharing (CORS)]. // See also [MDN: Cross-Origin Resource Sharing (CORS)].

View File

@ -11,82 +11,78 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // CSRFConfig defines the config for CSRF middleware.
// CSRFConfig defines the config for CSRF middleware. type CSRFConfig struct {
CSRFConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// TokenLength is the length of the generated token. // TokenLength is the length of the generated token.
TokenLength uint8 `yaml:"token_length"` TokenLength uint8 `yaml:"token_length"`
// Optional. Default value 32. // Optional. Default value 32.
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used // TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
// to extract token from the request. // to extract token from the request.
// Optional. Default value "header:X-CSRF-Token". // Optional. Default value "header:X-CSRF-Token".
// Possible values: // Possible values:
// - "header:<name>" or "header:<name>:<cut-prefix>" // - "header:<name>" or "header:<name>:<cut-prefix>"
// - "query:<name>" // - "query:<name>"
// - "form:<name>" // - "form:<name>"
// Multiple sources example: // Multiple sources example:
// - "header:X-CSRF-Token,query:csrf" // - "header:X-CSRF-Token,query:csrf"
TokenLookup string `yaml:"token_lookup"` TokenLookup string `yaml:"token_lookup"`
// Context key to store generated CSRF token into context. // Context key to store generated CSRF token into context.
// Optional. Default value "csrf". // Optional. Default value "csrf".
ContextKey string `yaml:"context_key"` ContextKey string `yaml:"context_key"`
// Name of the CSRF cookie. This cookie will store CSRF token. // Name of the CSRF cookie. This cookie will store CSRF token.
// Optional. Default value "csrf". // Optional. Default value "csrf".
CookieName string `yaml:"cookie_name"` CookieName string `yaml:"cookie_name"`
// Domain of the CSRF cookie. // Domain of the CSRF cookie.
// Optional. Default value none. // Optional. Default value none.
CookieDomain string `yaml:"cookie_domain"` CookieDomain string `yaml:"cookie_domain"`
// Path of the CSRF cookie. // Path of the CSRF cookie.
// Optional. Default value none. // Optional. Default value none.
CookiePath string `yaml:"cookie_path"` CookiePath string `yaml:"cookie_path"`
// Max age (in seconds) of the CSRF cookie. // Max age (in seconds) of the CSRF cookie.
// Optional. Default value 86400 (24hr). // Optional. Default value 86400 (24hr).
CookieMaxAge int `yaml:"cookie_max_age"` CookieMaxAge int `yaml:"cookie_max_age"`
// Indicates if CSRF cookie is secure. // Indicates if CSRF cookie is secure.
// Optional. Default value false. // Optional. Default value false.
CookieSecure bool `yaml:"cookie_secure"` CookieSecure bool `yaml:"cookie_secure"`
// Indicates if CSRF cookie is HTTP only. // Indicates if CSRF cookie is HTTP only.
// Optional. Default value false. // Optional. Default value false.
CookieHTTPOnly bool `yaml:"cookie_http_only"` CookieHTTPOnly bool `yaml:"cookie_http_only"`
// Indicates SameSite mode of the CSRF cookie. // Indicates SameSite mode of the CSRF cookie.
// Optional. Default value SameSiteDefaultMode. // Optional. Default value SameSiteDefaultMode.
CookieSameSite http.SameSite `yaml:"cookie_same_site"` CookieSameSite http.SameSite `yaml:"cookie_same_site"`
// ErrorHandler defines a function which is executed for returning custom errors. // ErrorHandler defines a function which is executed for returning custom errors.
ErrorHandler CSRFErrorHandler ErrorHandler CSRFErrorHandler
} }
// CSRFErrorHandler is a function which is executed for creating custom errors. // CSRFErrorHandler is a function which is executed for creating custom errors.
CSRFErrorHandler func(err error, c echo.Context) error type CSRFErrorHandler func(err error, c echo.Context) error
)
// ErrCSRFInvalid is returned when CSRF check fails // ErrCSRFInvalid is returned when CSRF check fails
var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token") var ErrCSRFInvalid = echo.NewHTTPError(http.StatusForbidden, "invalid csrf token")
var ( // DefaultCSRFConfig is the default CSRF middleware config.
// DefaultCSRFConfig is the default CSRF middleware config. var DefaultCSRFConfig = CSRFConfig{
DefaultCSRFConfig = CSRFConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, TokenLength: 32,
TokenLength: 32, TokenLookup: "header:" + echo.HeaderXCSRFToken,
TokenLookup: "header:" + echo.HeaderXCSRFToken, ContextKey: "csrf",
ContextKey: "csrf", CookieName: "_csrf",
CookieName: "_csrf", CookieMaxAge: 86400,
CookieMaxAge: 86400, CookieSameSite: http.SameSiteDefaultMode,
CookieSameSite: http.SameSiteDefaultMode, }
}
)
// CSRF returns a Cross-Site Request Forgery (CSRF) middleware. // CSRF returns a Cross-Site Request Forgery (CSRF) middleware.
// See: https://en.wikipedia.org/wiki/Cross-site_request_forgery // See: https://en.wikipedia.org/wiki/Cross-site_request_forgery

View File

@ -12,16 +12,14 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // DecompressConfig defines the config for Decompress middleware.
// DecompressConfig defines the config for Decompress middleware. type DecompressConfig struct {
DecompressConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers // GzipDecompressPool defines an interface to provide the sync.Pool used to create/store Gzip readers
GzipDecompressPool Decompressor GzipDecompressPool Decompressor
} }
)
// GZIPEncoding content-encoding header if set to "gzip", decompress body contents. // GZIPEncoding content-encoding header if set to "gzip", decompress body contents.
const GZIPEncoding string = "gzip" const GZIPEncoding string = "gzip"
@ -31,13 +29,11 @@ type Decompressor interface {
gzipDecompressPool() sync.Pool gzipDecompressPool() sync.Pool
} }
var ( // DefaultDecompressConfig defines the config for decompress middleware
//DefaultDecompressConfig defines the config for decompress middleware var DefaultDecompressConfig = DecompressConfig{
DefaultDecompressConfig = DecompressConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, GzipDecompressPool: &DefaultGzipDecompressPool{},
GzipDecompressPool: &DefaultGzipDecompressPool{}, }
}
)
// DefaultGzipDecompressPool is the default implementation of Decompressor interface // DefaultGzipDecompressPool is the default implementation of Decompressor interface
type DefaultGzipDecompressPool struct { type DefaultGzipDecompressPool struct {

View File

@ -15,139 +15,135 @@ import (
"reflect" "reflect"
) )
type ( // JWTConfig defines the config for JWT middleware.
// JWTConfig defines the config for JWT middleware. type JWTConfig struct {
JWTConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// BeforeFunc defines a function which is executed just before the middleware. // BeforeFunc defines a function which is executed just before the middleware.
BeforeFunc BeforeFunc BeforeFunc BeforeFunc
// SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next // SuccessHandler defines a function which is executed for a valid token before middleware chain continues with next
// middleware or handler. // middleware or handler.
SuccessHandler JWTSuccessHandler SuccessHandler JWTSuccessHandler
// ErrorHandler defines a function which is executed for an invalid token. // ErrorHandler defines a function which is executed for an invalid token.
// It may be used to define a custom JWT error. // It may be used to define a custom JWT error.
ErrorHandler JWTErrorHandler ErrorHandler JWTErrorHandler
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context. // ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
ErrorHandlerWithContext JWTErrorHandlerWithContext ErrorHandlerWithContext JWTErrorHandlerWithContext
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to // ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandlerWithContext decides to
// ignore the error (by returning `nil`). // ignore the error (by returning `nil`).
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality. // This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
// In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context // In that case you can use ErrorHandlerWithContext to set a default public JWT token value in the request context
// and continue. Some logic down the remaining execution chain needs to check that (public) token value then. // and continue. Some logic down the remaining execution chain needs to check that (public) token value then.
ContinueOnIgnoredError bool ContinueOnIgnoredError bool
// Signing key to validate token. // Signing key to validate token.
// This is one of the three options to provide a token validation key. // This is one of the three options to provide a token validation key.
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
// Required if neither user-defined KeyFunc nor SigningKeys is provided. // Required if neither user-defined KeyFunc nor SigningKeys is provided.
SigningKey interface{} SigningKey interface{}
// Map of signing keys to validate token with kid field usage. // Map of signing keys to validate token with kid field usage.
// This is one of the three options to provide a token validation key. // This is one of the three options to provide a token validation key.
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
// Required if neither user-defined KeyFunc nor SigningKey is provided. // Required if neither user-defined KeyFunc nor SigningKey is provided.
SigningKeys map[string]interface{} SigningKeys map[string]interface{}
// Signing method used to check the token's signing algorithm. // Signing method used to check the token's signing algorithm.
// Optional. Default value HS256. // Optional. Default value HS256.
SigningMethod string SigningMethod string
// Context key to store user information from the token into context. // Context key to store user information from the token into context.
// Optional. Default value "user". // Optional. Default value "user".
ContextKey string ContextKey string
// Claims are extendable claims data defining token content. Used by default ParseTokenFunc implementation. // Claims are extendable claims data defining token content. Used by default ParseTokenFunc implementation.
// Not used if custom ParseTokenFunc is set. // Not used if custom ParseTokenFunc is set.
// Optional. Default value jwt.MapClaims // Optional. Default value jwt.MapClaims
Claims jwt.Claims Claims jwt.Claims
// TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used // TokenLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
// to extract token from the request. // to extract token from the request.
// Optional. Default value "header:Authorization". // Optional. Default value "header:Authorization".
// Possible values: // Possible values:
// - "header:<name>" or "header:<name>:<cut-prefix>" // - "header:<name>" or "header:<name>:<cut-prefix>"
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header // `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we // value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
// want to cut is `<auth-scheme> ` note the space at the end. // want to cut is `<auth-scheme> ` note the space at the end.
// In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `. // In case of JWT tokens `Authorization: Bearer <token>` prefix we cut is `Bearer `.
// If prefix is left empty the whole value is returned. // If prefix is left empty the whole value is returned.
// - "query:<name>" // - "query:<name>"
// - "param:<name>" // - "param:<name>"
// - "cookie:<name>" // - "cookie:<name>"
// - "form:<name>" // - "form:<name>"
// Multiple sources example: // Multiple sources example:
// - "header:Authorization,cookie:myowncookie" // - "header:Authorization,cookie:myowncookie"
TokenLookup string TokenLookup string
// TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context. // TokenLookupFuncs defines a list of user-defined functions that extract JWT token from the given context.
// This is one of the two options to provide a token extractor. // This is one of the two options to provide a token extractor.
// The order of precedence is user-defined TokenLookupFuncs, and TokenLookup. // The order of precedence is user-defined TokenLookupFuncs, and TokenLookup.
// You can also provide both if you want. // You can also provide both if you want.
TokenLookupFuncs []ValuesExtractor TokenLookupFuncs []ValuesExtractor
// AuthScheme to be used in the Authorization header. // AuthScheme to be used in the Authorization header.
// Optional. Default value "Bearer". // Optional. Default value "Bearer".
AuthScheme string AuthScheme string
// KeyFunc defines a user-defined function that supplies the public key for a token validation. // KeyFunc defines a user-defined function that supplies the public key for a token validation.
// The function shall take care of verifying the signing algorithm and selecting the proper key. // The function shall take care of verifying the signing algorithm and selecting the proper key.
// A user-defined KeyFunc can be useful if tokens are issued by an external party. // A user-defined KeyFunc can be useful if tokens are issued by an external party.
// Used by default ParseTokenFunc implementation. // Used by default ParseTokenFunc implementation.
// //
// When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored. // When a user-defined KeyFunc is provided, SigningKey, SigningKeys, and SigningMethod are ignored.
// This is one of the three options to provide a token validation key. // This is one of the three options to provide a token validation key.
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey. // The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
// Required if neither SigningKeys nor SigningKey is provided. // Required if neither SigningKeys nor SigningKey is provided.
// Not used if custom ParseTokenFunc is set. // Not used if custom ParseTokenFunc is set.
// Default to an internal implementation verifying the signing algorithm and selecting the proper key. // Default to an internal implementation verifying the signing algorithm and selecting the proper key.
KeyFunc jwt.Keyfunc KeyFunc jwt.Keyfunc
// ParseTokenFunc defines a user-defined function that parses token from given auth. Returns an error when token // ParseTokenFunc defines a user-defined function that parses token from given auth. Returns an error when token
// parsing fails or parsed token is invalid. // parsing fails or parsed token is invalid.
// Defaults to implementation using `github.com/golang-jwt/jwt` as JWT implementation library // Defaults to implementation using `github.com/golang-jwt/jwt` as JWT implementation library
ParseTokenFunc func(auth string, c echo.Context) (interface{}, error) ParseTokenFunc func(auth string, c echo.Context) (interface{}, error)
} }
// JWTSuccessHandler defines a function which is executed for a valid token. // JWTSuccessHandler defines a function which is executed for a valid token.
JWTSuccessHandler func(c echo.Context) type JWTSuccessHandler func(c echo.Context)
// JWTErrorHandler defines a function which is executed for an invalid token. // JWTErrorHandler defines a function which is executed for an invalid token.
JWTErrorHandler func(err error) error type JWTErrorHandler func(err error) error
// JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context. // JWTErrorHandlerWithContext is almost identical to JWTErrorHandler, but it's passed the current context.
JWTErrorHandlerWithContext func(err error, c echo.Context) error type JWTErrorHandlerWithContext func(err error, c echo.Context) error
)
// Algorithms // Algorithms
const ( const (
AlgorithmHS256 = "HS256" AlgorithmHS256 = "HS256"
) )
// Errors // ErrJWTMissing is error that is returned when no JWToken was extracted from the request.
var ( var ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt")
ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
)
var ( // ErrJWTInvalid is error that is returned when middleware could not parse JWT correctly.
// DefaultJWTConfig is the default JWT auth middleware config. var ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt")
DefaultJWTConfig = JWTConfig{
Skipper: DefaultSkipper, // DefaultJWTConfig is the default JWT auth middleware config.
SigningMethod: AlgorithmHS256, var DefaultJWTConfig = JWTConfig{
ContextKey: "user", Skipper: DefaultSkipper,
TokenLookup: "header:" + echo.HeaderAuthorization, SigningMethod: AlgorithmHS256,
TokenLookupFuncs: nil, ContextKey: "user",
AuthScheme: "Bearer", TokenLookup: "header:" + echo.HeaderAuthorization,
Claims: jwt.MapClaims{}, TokenLookupFuncs: nil,
KeyFunc: nil, AuthScheme: "Bearer",
} Claims: jwt.MapClaims{},
) KeyFunc: nil,
}
// JWT returns a JSON Web Token (JWT) auth middleware. // JWT returns a JSON Web Token (JWT) auth middleware.
// //

View File

@ -9,69 +9,65 @@ import (
"net/http" "net/http"
) )
type ( // KeyAuthConfig defines the config for KeyAuth middleware.
// KeyAuthConfig defines the config for KeyAuth middleware. type KeyAuthConfig struct {
KeyAuthConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// KeyLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used // KeyLookup is a string in the form of "<source>:<name>" or "<source>:<name>,<source>:<name>" that is used
// to extract key from the request. // to extract key from the request.
// Optional. Default value "header:Authorization". // Optional. Default value "header:Authorization".
// Possible values: // Possible values:
// - "header:<name>" or "header:<name>:<cut-prefix>" // - "header:<name>" or "header:<name>:<cut-prefix>"
// `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header // `<cut-prefix>` is argument value to cut/trim prefix of the extracted value. This is useful if header
// value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we // value has static prefix like `Authorization: <auth-scheme> <authorisation-parameters>` where part that we
// want to cut is `<auth-scheme> ` note the space at the end. // want to cut is `<auth-scheme> ` note the space at the end.
// In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `. // In case of basic authentication `Authorization: Basic <credentials>` prefix we want to remove is `Basic `.
// - "query:<name>" // - "query:<name>"
// - "form:<name>" // - "form:<name>"
// - "cookie:<name>" // - "cookie:<name>"
// Multiple sources example: // Multiple sources example:
// - "header:Authorization,header:X-Api-Key" // - "header:Authorization,header:X-Api-Key"
KeyLookup string KeyLookup string
// AuthScheme to be used in the Authorization header. // AuthScheme to be used in the Authorization header.
// Optional. Default value "Bearer". // Optional. Default value "Bearer".
AuthScheme string AuthScheme string
// Validator is a function to validate key. // Validator is a function to validate key.
// Required. // Required.
Validator KeyAuthValidator Validator KeyAuthValidator
// ErrorHandler defines a function which is executed for an invalid key. // ErrorHandler defines a function which is executed for an invalid key.
// It may be used to define a custom error. // It may be used to define a custom error.
ErrorHandler KeyAuthErrorHandler ErrorHandler KeyAuthErrorHandler
// ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to // ContinueOnIgnoredError allows the next middleware/handler to be called when ErrorHandler decides to
// ignore the error (by returning `nil`). // ignore the error (by returning `nil`).
// This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality. // This is useful when parts of your site/api allow public access and some authorized routes provide extra functionality.
// In that case you can use ErrorHandler to set a default public key auth value in the request context // In that case you can use ErrorHandler to set a default public key auth value in the request context
// and continue. Some logic down the remaining execution chain needs to check that (public) key auth value then. // and continue. Some logic down the remaining execution chain needs to check that (public) key auth value then.
ContinueOnIgnoredError bool ContinueOnIgnoredError bool
} }
// KeyAuthValidator defines a function to validate KeyAuth credentials. // KeyAuthValidator defines a function to validate KeyAuth credentials.
KeyAuthValidator func(auth string, c echo.Context) (bool, error) type KeyAuthValidator func(auth string, c echo.Context) (bool, error)
// KeyAuthErrorHandler defines a function which is executed for an invalid key. // KeyAuthErrorHandler defines a function which is executed for an invalid key.
KeyAuthErrorHandler func(err error, c echo.Context) error type KeyAuthErrorHandler func(err error, c echo.Context) error
)
var (
// DefaultKeyAuthConfig is the default KeyAuth middleware config.
DefaultKeyAuthConfig = KeyAuthConfig{
Skipper: DefaultSkipper,
KeyLookup: "header:" + echo.HeaderAuthorization,
AuthScheme: "Bearer",
}
)
// ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups // ErrKeyAuthMissing is error type when KeyAuth middleware is unable to extract value from lookups
type ErrKeyAuthMissing struct { type ErrKeyAuthMissing struct {
Err error Err error
} }
// DefaultKeyAuthConfig is the default KeyAuth middleware config.
var DefaultKeyAuthConfig = KeyAuthConfig{
Skipper: DefaultSkipper,
KeyLookup: "header:" + echo.HeaderAuthorization,
AuthScheme: "Bearer",
}
// Error returns errors text // Error returns errors text
func (e *ErrKeyAuthMissing) Error() string { func (e *ErrKeyAuthMissing) Error() string {
return e.Err.Error() return e.Err.Error()

View File

@ -17,77 +17,73 @@ import (
"github.com/valyala/fasttemplate" "github.com/valyala/fasttemplate"
) )
type ( // LoggerConfig defines the config for Logger middleware.
// LoggerConfig defines the config for Logger middleware. type LoggerConfig struct {
LoggerConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Tags to construct the logger format. // Tags to construct the logger format.
// //
// - time_unix // - time_unix
// - time_unix_milli // - time_unix_milli
// - time_unix_micro // - time_unix_micro
// - time_unix_nano // - time_unix_nano
// - time_rfc3339 // - time_rfc3339
// - time_rfc3339_nano // - time_rfc3339_nano
// - time_custom // - time_custom
// - id (Request ID) // - id (Request ID)
// - remote_ip // - remote_ip
// - uri // - uri
// - host // - host
// - method // - method
// - path // - path
// - route // - route
// - protocol // - protocol
// - referer // - referer
// - user_agent // - user_agent
// - status // - status
// - error // - error
// - latency (In nanoseconds) // - latency (In nanoseconds)
// - latency_human (Human readable) // - latency_human (Human readable)
// - bytes_in (Bytes received) // - bytes_in (Bytes received)
// - bytes_out (Bytes sent) // - bytes_out (Bytes sent)
// - header:<NAME> // - header:<NAME>
// - query:<NAME> // - query:<NAME>
// - form:<NAME> // - form:<NAME>
// - custom (see CustomTagFunc field) // - custom (see CustomTagFunc field)
// //
// Example "${remote_ip} ${status}" // Example "${remote_ip} ${status}"
// //
// Optional. Default value DefaultLoggerConfig.Format. // Optional. Default value DefaultLoggerConfig.Format.
Format string `yaml:"format"` Format string `yaml:"format"`
// Optional. Default value DefaultLoggerConfig.CustomTimeFormat. // Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
CustomTimeFormat string `yaml:"custom_time_format"` CustomTimeFormat string `yaml:"custom_time_format"`
// CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf. // CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf.
// Make sure that outputted text creates valid JSON string with other logged tags. // Make sure that outputted text creates valid JSON string with other logged tags.
// Optional. // Optional.
CustomTagFunc func(c echo.Context, buf *bytes.Buffer) (int, error) CustomTagFunc func(c echo.Context, buf *bytes.Buffer) (int, error)
// Output is a writer where logs in JSON format are written. // Output is a writer where logs in JSON format are written.
// Optional. Default value os.Stdout. // Optional. Default value os.Stdout.
Output io.Writer Output io.Writer
template *fasttemplate.Template template *fasttemplate.Template
colorer *color.Color colorer *color.Color
pool *sync.Pool pool *sync.Pool
} }
)
var ( // DefaultLoggerConfig is the default Logger middleware config.
// DefaultLoggerConfig is the default Logger middleware config. var DefaultLoggerConfig = LoggerConfig{
DefaultLoggerConfig = LoggerConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` +
Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` + `"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` +
`"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` + `"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` +
`"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` + `,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n",
`,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n", CustomTimeFormat: "2006-01-02 15:04:05.00000",
CustomTimeFormat: "2006-01-02 15:04:05.00000", colorer: color.New(),
colorer: color.New(), }
}
)
// Logger returns a middleware that logs HTTP requests. // Logger returns a middleware that logs HTTP requests.
func Logger() echo.MiddlewareFunc { func Logger() echo.MiddlewareFunc {

View File

@ -9,28 +9,24 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // MethodOverrideConfig defines the config for MethodOverride middleware.
// MethodOverrideConfig defines the config for MethodOverride middleware. type MethodOverrideConfig struct {
MethodOverrideConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Getter is a function that gets overridden method from the request. // Getter is a function that gets overridden method from the request.
// Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride). // Optional. Default values MethodFromHeader(echo.HeaderXHTTPMethodOverride).
Getter MethodOverrideGetter Getter MethodOverrideGetter
} }
// MethodOverrideGetter is a function that gets overridden method from the request // MethodOverrideGetter is a function that gets overridden method from the request
MethodOverrideGetter func(echo.Context) string type MethodOverrideGetter func(echo.Context) string
)
var ( // DefaultMethodOverrideConfig is the default MethodOverride middleware config.
// DefaultMethodOverrideConfig is the default MethodOverride middleware config. var DefaultMethodOverrideConfig = MethodOverrideConfig{
DefaultMethodOverrideConfig = MethodOverrideConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride),
Getter: MethodFromHeader(echo.HeaderXHTTPMethodOverride), }
}
)
// MethodOverride returns a MethodOverride middleware. // MethodOverride returns a MethodOverride middleware.
// MethodOverride middleware checks for the overridden method from the request and // MethodOverride middleware checks for the overridden method from the request and

View File

@ -12,14 +12,12 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // Skipper defines a function to skip middleware. Returning true skips processing
// Skipper defines a function to skip middleware. Returning true skips processing // the middleware.
// the middleware. type Skipper func(c echo.Context) bool
Skipper func(c echo.Context) bool
// BeforeFunc defines a function which is executed just before the middleware. // BeforeFunc defines a function which is executed just before the middleware.
BeforeFunc func(c echo.Context) type BeforeFunc func(c echo.Context)
)
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer { func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
groups := pattern.FindAllStringSubmatch(input, -1) groups := pattern.FindAllStringSubmatch(input, -1)
@ -56,7 +54,7 @@ func rewriteURL(rewriteRegex map[*regexp.Regexp]string, req *http.Request) error
return nil return nil
} }
// Depending how HTTP request is sent RequestURI could contain Scheme://Host/path or be just /path. // Depending on how HTTP request is sent RequestURI could contain Scheme://Host/path or be just /path.
// We only want to use path part for rewriting and therefore trim prefix if it exists // We only want to use path part for rewriting and therefore trim prefix if it exists
rawURI := req.RequestURI rawURI := req.RequestURI
if rawURI != "" && rawURI[0] != '/' { if rawURI != "" && rawURI[0] != '/' {

View File

@ -22,117 +22,113 @@ import (
// TODO: Handle TLS proxy // TODO: Handle TLS proxy
type ( // ProxyConfig defines the config for Proxy middleware.
// ProxyConfig defines the config for Proxy middleware. type ProxyConfig struct {
ProxyConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Balancer defines a load balancing technique. // Balancer defines a load balancing technique.
// Required. // Required.
Balancer ProxyBalancer Balancer ProxyBalancer
// RetryCount defines the number of times a failed proxied request should be retried // RetryCount defines the number of times a failed proxied request should be retried
// using the next available ProxyTarget. Defaults to 0, meaning requests are never retried. // using the next available ProxyTarget. Defaults to 0, meaning requests are never retried.
RetryCount int RetryCount int
// RetryFilter defines a function used to determine if a failed request to a // RetryFilter defines a function used to determine if a failed request to a
// ProxyTarget should be retried. The RetryFilter will only be called when the number // ProxyTarget should be retried. The RetryFilter will only be called when the number
// of previous retries is less than RetryCount. If the function returns true, the // of previous retries is less than RetryCount. If the function returns true, the
// request will be retried. The provided error indicates the reason for the request // request will be retried. The provided error indicates the reason for the request
// failure. When the ProxyTarget is unavailable, the error will be an instance of // failure. When the ProxyTarget is unavailable, the error will be an instance of
// echo.HTTPError with a Code of http.StatusBadGateway. In all other cases, the error // echo.HTTPError with a Code of http.StatusBadGateway. In all other cases, the error
// will indicate an internal error in the Proxy middleware. When a RetryFilter is not // will indicate an internal error in the Proxy middleware. When a RetryFilter is not
// specified, all requests that fail with http.StatusBadGateway will be retried. A custom // specified, all requests that fail with http.StatusBadGateway will be retried. A custom
// RetryFilter can be provided to only retry specific requests. Note that RetryFilter is // RetryFilter can be provided to only retry specific requests. Note that RetryFilter is
// only called when the request to the target fails, or an internal error in the Proxy // only called when the request to the target fails, or an internal error in the Proxy
// middleware has occurred. Successful requests that return a non-200 response code cannot // middleware has occurred. Successful requests that return a non-200 response code cannot
// be retried. // be retried.
RetryFilter func(c echo.Context, e error) bool RetryFilter func(c echo.Context, e error) bool
// ErrorHandler defines a function which can be used to return custom errors from // ErrorHandler defines a function which can be used to return custom errors from
// the Proxy middleware. ErrorHandler is only invoked when there has been // the Proxy middleware. ErrorHandler is only invoked when there has been
// either an internal error in the Proxy middleware or the ProxyTarget is // either an internal error in the Proxy middleware or the ProxyTarget is
// unavailable. Due to the way requests are proxied, ErrorHandler is not invoked // unavailable. Due to the way requests are proxied, ErrorHandler is not invoked
// when a ProxyTarget returns a non-200 response. In these cases, the response // when a ProxyTarget returns a non-200 response. In these cases, the response
// is already written so errors cannot be modified. ErrorHandler is only // is already written so errors cannot be modified. ErrorHandler is only
// invoked after all retry attempts have been exhausted. // invoked after all retry attempts have been exhausted.
ErrorHandler func(c echo.Context, err error) error ErrorHandler func(c echo.Context, err error) error
// Rewrite defines URL path rewrite rules. The values captured in asterisk can be // Rewrite defines URL path rewrite rules. The values captured in asterisk can be
// retrieved by index e.g. $1, $2 and so on. // retrieved by index e.g. $1, $2 and so on.
// Examples: // Examples:
// "/old": "/new", // "/old": "/new",
// "/api/*": "/$1", // "/api/*": "/$1",
// "/js/*": "/public/javascripts/$1", // "/js/*": "/public/javascripts/$1",
// "/users/*/orders/*": "/user/$1/order/$2", // "/users/*/orders/*": "/user/$1/order/$2",
Rewrite map[string]string Rewrite map[string]string
// RegexRewrite defines rewrite rules using regexp.Rexexp with captures // RegexRewrite defines rewrite rules using regexp.Rexexp with captures
// Every capture group in the values can be retrieved by index e.g. $1, $2 and so on. // Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
// Example: // Example:
// "^/old/[0.9]+/": "/new", // "^/old/[0.9]+/": "/new",
// "^/api/.+?/(.*)": "/v2/$1", // "^/api/.+?/(.*)": "/v2/$1",
RegexRewrite map[*regexp.Regexp]string RegexRewrite map[*regexp.Regexp]string
// Context key to store selected ProxyTarget into context. // Context key to store selected ProxyTarget into context.
// Optional. Default value "target". // Optional. Default value "target".
ContextKey string ContextKey string
// To customize the transport to remote. // To customize the transport to remote.
// Examples: If custom TLS certificates are required. // Examples: If custom TLS certificates are required.
Transport http.RoundTripper Transport http.RoundTripper
// ModifyResponse defines function to modify response from ProxyTarget. // ModifyResponse defines function to modify response from ProxyTarget.
ModifyResponse func(*http.Response) error ModifyResponse func(*http.Response) error
} }
// ProxyTarget defines the upstream target. // ProxyTarget defines the upstream target.
ProxyTarget struct { type ProxyTarget struct {
Name string Name string
URL *url.URL URL *url.URL
Meta echo.Map Meta echo.Map
} }
// ProxyBalancer defines an interface to implement a load balancing technique. // ProxyBalancer defines an interface to implement a load balancing technique.
ProxyBalancer interface { type ProxyBalancer interface {
AddTarget(*ProxyTarget) bool AddTarget(*ProxyTarget) bool
RemoveTarget(string) bool RemoveTarget(string) bool
Next(echo.Context) *ProxyTarget Next(echo.Context) *ProxyTarget
} }
// TargetProvider defines an interface that gives the opportunity for balancer // TargetProvider defines an interface that gives the opportunity for balancer
// to return custom errors when selecting target. // to return custom errors when selecting target.
TargetProvider interface { type TargetProvider interface {
NextTarget(echo.Context) (*ProxyTarget, error) NextTarget(echo.Context) (*ProxyTarget, error)
} }
commonBalancer struct { type commonBalancer struct {
targets []*ProxyTarget targets []*ProxyTarget
mutex sync.Mutex mutex sync.Mutex
} }
// RandomBalancer implements a random load balancing technique. // RandomBalancer implements a random load balancing technique.
randomBalancer struct { type randomBalancer struct {
commonBalancer commonBalancer
random *rand.Rand random *rand.Rand
} }
// RoundRobinBalancer implements a round-robin load balancing technique. // RoundRobinBalancer implements a round-robin load balancing technique.
roundRobinBalancer struct { type roundRobinBalancer struct {
commonBalancer commonBalancer
// tracking the index on `targets` slice for the next `*ProxyTarget` to be used // tracking the index on `targets` slice for the next `*ProxyTarget` to be used
i int i int
} }
)
var ( // DefaultProxyConfig is the default Proxy middleware config.
// DefaultProxyConfig is the default Proxy middleware config. var DefaultProxyConfig = ProxyConfig{
DefaultProxyConfig = ProxyConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, ContextKey: "target",
ContextKey: "target", }
}
)
func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler { func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@ -12,39 +12,34 @@ import (
"golang.org/x/time/rate" "golang.org/x/time/rate"
) )
type ( // RateLimiterStore is the interface to be implemented by custom stores.
// RateLimiterStore is the interface to be implemented by custom stores. type RateLimiterStore interface {
RateLimiterStore interface { // Stores for the rate limiter have to implement the Allow method
// Stores for the rate limiter have to implement the Allow method Allow(identifier string) (bool, error)
Allow(identifier string) (bool, error) }
}
)
type ( // RateLimiterConfig defines the configuration for the rate limiter
// RateLimiterConfig defines the configuration for the rate limiter type RateLimiterConfig struct {
RateLimiterConfig struct { Skipper Skipper
Skipper Skipper BeforeFunc BeforeFunc
BeforeFunc BeforeFunc // IdentifierExtractor uses echo.Context to extract the identifier for a visitor
// IdentifierExtractor uses echo.Context to extract the identifier for a visitor IdentifierExtractor Extractor
IdentifierExtractor Extractor // Store defines a store for the rate limiter
// Store defines a store for the rate limiter Store RateLimiterStore
Store RateLimiterStore // ErrorHandler provides a handler to be called when IdentifierExtractor returns an error
// ErrorHandler provides a handler to be called when IdentifierExtractor returns an error ErrorHandler func(context echo.Context, err error) error
ErrorHandler func(context echo.Context, err error) error // DenyHandler provides a handler to be called when RateLimiter denies access
// DenyHandler provides a handler to be called when RateLimiter denies access DenyHandler func(context echo.Context, identifier string, err error) error
DenyHandler func(context echo.Context, identifier string, err error) error }
}
// Extractor is used to extract data from echo.Context
Extractor func(context echo.Context) (string, error)
)
// errors // Extractor is used to extract data from echo.Context
var ( type Extractor func(context echo.Context) (string, error)
// ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded") // ErrRateLimitExceeded denotes an error raised when rate limit is exceeded
// ErrExtractorError denotes an error raised when extractor function is unsuccessful var ErrRateLimitExceeded = echo.NewHTTPError(http.StatusTooManyRequests, "rate limit exceeded")
ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
) // ErrExtractorError denotes an error raised when extractor function is unsuccessful
var ErrExtractorError = echo.NewHTTPError(http.StatusForbidden, "error while extracting identifier")
// DefaultRateLimiterConfig defines default values for RateLimiterConfig // DefaultRateLimiterConfig defines default values for RateLimiterConfig
var DefaultRateLimiterConfig = RateLimiterConfig{ var DefaultRateLimiterConfig = RateLimiterConfig{
@ -153,25 +148,24 @@ func RateLimiterWithConfig(config RateLimiterConfig) echo.MiddlewareFunc {
} }
} }
type ( // RateLimiterMemoryStore is the built-in store implementation for RateLimiter
// RateLimiterMemoryStore is the built-in store implementation for RateLimiter type RateLimiterMemoryStore struct {
RateLimiterMemoryStore struct { visitors map[string]*Visitor
visitors map[string]*Visitor mutex sync.Mutex
mutex sync.Mutex rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
rate rate.Limit // for more info check out Limiter docs - https://pkg.go.dev/golang.org/x/time/rate#Limit.
burst int burst int
expiresIn time.Duration expiresIn time.Duration
lastCleanup time.Time lastCleanup time.Time
timeNow func() time.Time timeNow func() time.Time
} }
// Visitor signifies a unique user's limiter details
Visitor struct { // Visitor signifies a unique user's limiter details
*rate.Limiter type Visitor struct {
lastSeen time.Time *rate.Limiter
} lastSeen time.Time
) }
/* /*
NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with NewRateLimiterMemoryStore returns an instance of RateLimiterMemoryStore with

View File

@ -12,56 +12,52 @@ import (
"github.com/labstack/gommon/log" "github.com/labstack/gommon/log"
) )
type ( // LogErrorFunc defines a function for custom logging in the middleware.
type LogErrorFunc func(c echo.Context, err error, stack []byte) error
// RecoverConfig defines the config for Recover middleware.
type RecoverConfig struct {
// Skipper defines a function to skip middleware.
Skipper Skipper
// Size of the stack to be printed.
// Optional. Default value 4KB.
StackSize int `yaml:"stack_size"`
// DisableStackAll disables formatting stack traces of all other goroutines
// into buffer after the trace for the current goroutine.
// Optional. Default value false.
DisableStackAll bool `yaml:"disable_stack_all"`
// DisablePrintStack disables printing stack trace.
// Optional. Default value as false.
DisablePrintStack bool `yaml:"disable_print_stack"`
// LogLevel is log level to printing stack trace.
// Optional. Default value 0 (Print).
LogLevel log.Lvl
// LogErrorFunc defines a function for custom logging in the middleware. // LogErrorFunc defines a function for custom logging in the middleware.
LogErrorFunc func(c echo.Context, err error, stack []byte) error // If it's set you don't need to provide LogLevel for config.
// If this function returns nil, the centralized HTTPErrorHandler will not be called.
LogErrorFunc LogErrorFunc
// RecoverConfig defines the config for Recover middleware. // DisableErrorHandler disables the call to centralized HTTPErrorHandler.
RecoverConfig struct { // The recovered error is then passed back to upstream middleware, instead of swallowing the error.
// Skipper defines a function to skip middleware. // Optional. Default value false.
Skipper Skipper DisableErrorHandler bool `yaml:"disable_error_handler"`
}
// Size of the stack to be printed. // DefaultRecoverConfig is the default Recover middleware config.
// Optional. Default value 4KB. var DefaultRecoverConfig = RecoverConfig{
StackSize int `yaml:"stack_size"` Skipper: DefaultSkipper,
StackSize: 4 << 10, // 4 KB
// DisableStackAll disables formatting stack traces of all other goroutines DisableStackAll: false,
// into buffer after the trace for the current goroutine. DisablePrintStack: false,
// Optional. Default value false. LogLevel: 0,
DisableStackAll bool `yaml:"disable_stack_all"` LogErrorFunc: nil,
DisableErrorHandler: false,
// DisablePrintStack disables printing stack trace. }
// Optional. Default value as false.
DisablePrintStack bool `yaml:"disable_print_stack"`
// LogLevel is log level to printing stack trace.
// Optional. Default value 0 (Print).
LogLevel log.Lvl
// LogErrorFunc defines a function for custom logging in the middleware.
// If it's set you don't need to provide LogLevel for config.
// If this function returns nil, the centralized HTTPErrorHandler will not be called.
LogErrorFunc LogErrorFunc
// DisableErrorHandler disables the call to centralized HTTPErrorHandler.
// The recovered error is then passed back to upstream middleware, instead of swallowing the error.
// Optional. Default value false.
DisableErrorHandler bool `yaml:"disable_error_handler"`
}
)
var (
// DefaultRecoverConfig is the default Recover middleware config.
DefaultRecoverConfig = RecoverConfig{
Skipper: DefaultSkipper,
StackSize: 4 << 10, // 4 KB
DisableStackAll: false,
DisablePrintStack: false,
LogLevel: 0,
LogErrorFunc: nil,
DisableErrorHandler: false,
}
)
// Recover returns a middleware which recovers from panics anywhere in the chain // Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler. // and handles the control to the centralized HTTPErrorHandler.

View File

@ -7,32 +7,28 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // RequestIDConfig defines the config for RequestID middleware.
// RequestIDConfig defines the config for RequestID middleware. type RequestIDConfig struct {
RequestIDConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Generator defines a function to generate an ID. // Generator defines a function to generate an ID.
// Optional. Defaults to generator for random string of length 32. // Optional. Defaults to generator for random string of length 32.
Generator func() string Generator func() string
// RequestIDHandler defines a function which is executed for a request id. // RequestIDHandler defines a function which is executed for a request id.
RequestIDHandler func(echo.Context, string) RequestIDHandler func(echo.Context, string)
// TargetHeader defines what header to look for to populate the id // TargetHeader defines what header to look for to populate the id
TargetHeader string TargetHeader string
} }
)
var ( // DefaultRequestIDConfig is the default RequestID middleware config.
// DefaultRequestIDConfig is the default RequestID middleware config. var DefaultRequestIDConfig = RequestIDConfig{
DefaultRequestIDConfig = RequestIDConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Generator: generator,
Generator: generator, TargetHeader: echo.HeaderXRequestID,
TargetHeader: echo.HeaderXRequestID, }
}
)
// RequestID returns a X-Request-ID middleware. // RequestID returns a X-Request-ID middleware.
func RequestID() echo.MiddlewareFunc { func RequestID() echo.MiddlewareFunc {

View File

@ -9,37 +9,33 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // RewriteConfig defines the config for Rewrite middleware.
// RewriteConfig defines the config for Rewrite middleware. type RewriteConfig struct {
RewriteConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Rules defines the URL path rewrite rules. The values captured in asterisk can be // Rules defines the URL path rewrite rules. The values captured in asterisk can be
// retrieved by index e.g. $1, $2 and so on. // retrieved by index e.g. $1, $2 and so on.
// Example: // Example:
// "/old": "/new", // "/old": "/new",
// "/api/*": "/$1", // "/api/*": "/$1",
// "/js/*": "/public/javascripts/$1", // "/js/*": "/public/javascripts/$1",
// "/users/*/orders/*": "/user/$1/order/$2", // "/users/*/orders/*": "/user/$1/order/$2",
// Required. // Required.
Rules map[string]string `yaml:"rules"` Rules map[string]string `yaml:"rules"`
// RegexRules defines the URL path rewrite rules using regexp.Rexexp with captures // RegexRules defines the URL path rewrite rules using regexp.Rexexp with captures
// Every capture group in the values can be retrieved by index e.g. $1, $2 and so on. // Every capture group in the values can be retrieved by index e.g. $1, $2 and so on.
// Example: // Example:
// "^/old/[0.9]+/": "/new", // "^/old/[0.9]+/": "/new",
// "^/api/.+?/(.*)": "/v2/$1", // "^/api/.+?/(.*)": "/v2/$1",
RegexRules map[*regexp.Regexp]string `yaml:"-"` RegexRules map[*regexp.Regexp]string `yaml:"-"`
} }
)
var ( // DefaultRewriteConfig is the default Rewrite middleware config.
// DefaultRewriteConfig is the default Rewrite middleware config. var DefaultRewriteConfig = RewriteConfig{
DefaultRewriteConfig = RewriteConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, }
}
)
// Rewrite returns a Rewrite middleware. // Rewrite returns a Rewrite middleware.
// //

View File

@ -9,84 +9,80 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // SecureConfig defines the config for Secure middleware.
// SecureConfig defines the config for Secure middleware. type SecureConfig struct {
SecureConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// XSSProtection provides protection against cross-site scripting attack (XSS) // XSSProtection provides protection against cross-site scripting attack (XSS)
// by setting the `X-XSS-Protection` header. // by setting the `X-XSS-Protection` header.
// Optional. Default value "1; mode=block". // Optional. Default value "1; mode=block".
XSSProtection string `yaml:"xss_protection"` XSSProtection string `yaml:"xss_protection"`
// ContentTypeNosniff provides protection against overriding Content-Type // ContentTypeNosniff provides protection against overriding Content-Type
// header by setting the `X-Content-Type-Options` header. // header by setting the `X-Content-Type-Options` header.
// Optional. Default value "nosniff". // Optional. Default value "nosniff".
ContentTypeNosniff string `yaml:"content_type_nosniff"` ContentTypeNosniff string `yaml:"content_type_nosniff"`
// XFrameOptions can be used to indicate whether or not a browser should // XFrameOptions can be used to indicate whether or not a browser should
// be allowed to render a page in a <frame>, <iframe> or <object> . // be allowed to render a page in a <frame>, <iframe> or <object> .
// Sites can use this to avoid clickjacking attacks, by ensuring that their // Sites can use this to avoid clickjacking attacks, by ensuring that their
// content is not embedded into other sites.provides protection against // content is not embedded into other sites.provides protection against
// clickjacking. // clickjacking.
// Optional. Default value "SAMEORIGIN". // Optional. Default value "SAMEORIGIN".
// Possible values: // Possible values:
// - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself. // - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself.
// - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so. // - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so.
// - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin. // - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin.
XFrameOptions string `yaml:"x_frame_options"` XFrameOptions string `yaml:"x_frame_options"`
// HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how // HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
// long (in seconds) browsers should remember that this site is only to // long (in seconds) browsers should remember that this site is only to
// be accessed using HTTPS. This reduces your exposure to some SSL-stripping // be accessed using HTTPS. This reduces your exposure to some SSL-stripping
// man-in-the-middle (MITM) attacks. // man-in-the-middle (MITM) attacks.
// Optional. Default value 0. // Optional. Default value 0.
HSTSMaxAge int `yaml:"hsts_max_age"` HSTSMaxAge int `yaml:"hsts_max_age"`
// HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security` // HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
// header, excluding all subdomains from security policy. It has no effect // header, excluding all subdomains from security policy. It has no effect
// unless HSTSMaxAge is set to a non-zero value. // unless HSTSMaxAge is set to a non-zero value.
// Optional. Default value false. // Optional. Default value false.
HSTSExcludeSubdomains bool `yaml:"hsts_exclude_subdomains"` HSTSExcludeSubdomains bool `yaml:"hsts_exclude_subdomains"`
// ContentSecurityPolicy sets the `Content-Security-Policy` header providing // ContentSecurityPolicy sets the `Content-Security-Policy` header providing
// security against cross-site scripting (XSS), clickjacking and other code // security against cross-site scripting (XSS), clickjacking and other code
// injection attacks resulting from execution of malicious content in the // injection attacks resulting from execution of malicious content in the
// trusted web page context. // trusted web page context.
// Optional. Default value "". // Optional. Default value "".
ContentSecurityPolicy string `yaml:"content_security_policy"` ContentSecurityPolicy string `yaml:"content_security_policy"`
// CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead // CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead
// of the `Content-Security-Policy` header. This allows iterative updates of the // of the `Content-Security-Policy` header. This allows iterative updates of the
// content security policy by only reporting the violations that would // content security policy by only reporting the violations that would
// have occurred instead of blocking the resource. // have occurred instead of blocking the resource.
// Optional. Default value false. // Optional. Default value false.
CSPReportOnly bool `yaml:"csp_report_only"` CSPReportOnly bool `yaml:"csp_report_only"`
// HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security` // HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security`
// header, which enables the domain to be included in the HSTS preload list // 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/ // maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
// Optional. Default value false. // Optional. Default value false.
HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"` HSTSPreloadEnabled bool `yaml:"hsts_preload_enabled"`
// ReferrerPolicy sets the `Referrer-Policy` header providing security against // ReferrerPolicy sets the `Referrer-Policy` header providing security against
// leaking potentially sensitive request paths to third parties. // leaking potentially sensitive request paths to third parties.
// Optional. Default value "". // Optional. Default value "".
ReferrerPolicy string `yaml:"referrer_policy"` ReferrerPolicy string `yaml:"referrer_policy"`
} }
)
var ( // DefaultSecureConfig is the default Secure middleware config.
// DefaultSecureConfig is the default Secure middleware config. var DefaultSecureConfig = SecureConfig{
DefaultSecureConfig = SecureConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, XSSProtection: "1; mode=block",
XSSProtection: "1; mode=block", ContentTypeNosniff: "nosniff",
ContentTypeNosniff: "nosniff", XFrameOptions: "SAMEORIGIN",
XFrameOptions: "SAMEORIGIN", HSTSPreloadEnabled: false,
HSTSPreloadEnabled: false, }
}
)
// Secure returns a Secure middleware. // Secure returns a Secure middleware.
// Secure middleware provides protection against cross-site scripting (XSS) attack, // Secure middleware provides protection against cross-site scripting (XSS) attack,

View File

@ -9,24 +9,20 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
type ( // TrailingSlashConfig defines the config for TrailingSlash middleware.
// TrailingSlashConfig defines the config for TrailingSlash middleware. type TrailingSlashConfig struct {
TrailingSlashConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Status code to be used when redirecting the request. // Status code to be used when redirecting the request.
// Optional, but when provided the request is redirected using this code. // Optional, but when provided the request is redirected using this code.
RedirectCode int `yaml:"redirect_code"` RedirectCode int `yaml:"redirect_code"`
} }
)
var ( // DefaultTrailingSlashConfig is the default TrailingSlash middleware config.
// DefaultTrailingSlashConfig is the default TrailingSlash middleware config. var DefaultTrailingSlashConfig = TrailingSlashConfig{
DefaultTrailingSlashConfig = TrailingSlashConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, }
}
)
// AddTrailingSlash returns a root level (before router) middleware which adds a // AddTrailingSlash returns a root level (before router) middleware which adds a
// trailing slash to the request `URL#Path`. // trailing slash to the request `URL#Path`.

View File

@ -17,40 +17,38 @@ import (
"github.com/labstack/gommon/bytes" "github.com/labstack/gommon/bytes"
) )
type ( // StaticConfig defines the config for Static middleware.
// StaticConfig defines the config for Static middleware. type StaticConfig struct {
StaticConfig struct { // Skipper defines a function to skip middleware.
// Skipper defines a function to skip middleware. Skipper Skipper
Skipper Skipper
// Root directory from where the static content is served. // Root directory from where the static content is served.
// Required. // Required.
Root string `yaml:"root"` Root string `yaml:"root"`
// Index file for serving a directory. // Index file for serving a directory.
// Optional. Default value "index.html". // Optional. Default value "index.html".
Index string `yaml:"index"` Index string `yaml:"index"`
// Enable HTML5 mode by forwarding all not-found requests to root so that // Enable HTML5 mode by forwarding all not-found requests to root so that
// SPA (single-page application) can handle the routing. // SPA (single-page application) can handle the routing.
// Optional. Default value false. // Optional. Default value false.
HTML5 bool `yaml:"html5"` HTML5 bool `yaml:"html5"`
// Enable directory browsing. // Enable directory browsing.
// Optional. Default value false. // Optional. Default value false.
Browse bool `yaml:"browse"` Browse bool `yaml:"browse"`
// Enable ignoring of the base of the URL path. // Enable ignoring of the base of the URL path.
// Example: when assigning a static middleware to a non root path group, // Example: when assigning a static middleware to a non root path group,
// the filesystem path is not doubled // the filesystem path is not doubled
// Optional. Default value false. // Optional. Default value false.
IgnoreBase bool `yaml:"ignoreBase"` IgnoreBase bool `yaml:"ignoreBase"`
// Filesystem provides access to the static content. // Filesystem provides access to the static content.
// Optional. Defaults to http.Dir(config.Root) // Optional. Defaults to http.Dir(config.Root)
Filesystem http.FileSystem `yaml:"-"` Filesystem http.FileSystem `yaml:"-"`
} }
)
const html = ` const html = `
<!DOCTYPE html> <!DOCTYPE html>
@ -124,13 +122,11 @@ const html = `
</html> </html>
` `
var ( // DefaultStaticConfig is the default Static middleware config.
// DefaultStaticConfig is the default Static middleware config. var DefaultStaticConfig = StaticConfig{
DefaultStaticConfig = StaticConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Index: "index.html",
Index: "index.html", }
}
)
// Static returns a Static middleware to serves static content from the provided // Static returns a Static middleware to serves static content from the provided
// root directory. // root directory.

View File

@ -80,14 +80,12 @@ type TimeoutConfig struct {
Timeout time.Duration Timeout time.Duration
} }
var ( // DefaultTimeoutConfig is the default Timeout middleware config.
// DefaultTimeoutConfig is the default Timeout middleware config. var DefaultTimeoutConfig = TimeoutConfig{
DefaultTimeoutConfig = TimeoutConfig{ Skipper: DefaultSkipper,
Skipper: DefaultSkipper, Timeout: 0,
Timeout: 0, ErrorMessage: "",
ErrorMessage: "", }
}
)
// Timeout returns a middleware which returns error (503 Service Unavailable error) to client immediately when handler // Timeout returns a middleware which returns error (503 Service Unavailable error) to client immediately when handler
// call runs for longer than its time limit. NB: timeout does not stop handler execution. // call runs for longer than its time limit. NB: timeout does not stop handler execution.

View File

@ -10,20 +10,18 @@ import (
"net/http" "net/http"
) )
type ( // Response wraps an http.ResponseWriter and implements its interface to be used
// Response wraps an http.ResponseWriter and implements its interface to be used // by an HTTP handler to construct an HTTP response.
// by an HTTP handler to construct an HTTP response. // See: https://golang.org/pkg/net/http/#ResponseWriter
// See: https://golang.org/pkg/net/http/#ResponseWriter type Response struct {
Response struct { echo *Echo
echo *Echo beforeFuncs []func()
beforeFuncs []func() afterFuncs []func()
afterFuncs []func() Writer http.ResponseWriter
Writer http.ResponseWriter Status int
Status int Size int64
Size int64 Committed bool
Committed bool }
}
)
// NewResponse creates a new instance of Response. // NewResponse creates a new instance of Response.
func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) { func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) {

100
router.go
View File

@ -9,56 +9,58 @@ import (
"net/http" "net/http"
) )
type ( // Router is the registry of all registered routes for an `Echo` instance for
// Router is the registry of all registered routes for an `Echo` instance for // request matching and URL path parameter parsing.
// request matching and URL path parameter parsing. type Router struct {
Router struct { tree *node
tree *node routes map[string]*Route
routes map[string]*Route echo *Echo
echo *Echo }
}
node struct {
kind kind
label byte
prefix string
parent *node
staticChildren children
originalPath string
methods *routeMethods
paramChild *node
anyChild *node
paramsCount int
// isLeaf indicates that node does not have child routes
isLeaf bool
// isHandler indicates that node has at least one handler registered to it
isHandler bool
// notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases type node struct {
notFoundHandler *routeMethod kind kind
} label byte
kind uint8 prefix string
children []*node parent *node
routeMethod struct { staticChildren children
ppath string originalPath string
pnames []string methods *routeMethods
handler HandlerFunc paramChild *node
} anyChild *node
routeMethods struct { paramsCount int
connect *routeMethod // isLeaf indicates that node does not have child routes
delete *routeMethod isLeaf bool
get *routeMethod // isHandler indicates that node has at least one handler registered to it
head *routeMethod isHandler bool
options *routeMethod
patch *routeMethod // notFoundHandler is handler registered with RouteNotFound method and is executed for 404 cases
post *routeMethod notFoundHandler *routeMethod
propfind *routeMethod }
put *routeMethod
trace *routeMethod type kind uint8
report *routeMethod type children []*node
anyOther map[string]*routeMethod
allowHeader string type routeMethod struct {
} ppath string
) pnames []string
handler HandlerFunc
}
type routeMethods struct {
connect *routeMethod
delete *routeMethod
get *routeMethod
head *routeMethod
options *routeMethod
patch *routeMethod
post *routeMethod
propfind *routeMethod
put *routeMethod
trace *routeMethod
report *routeMethod
anyOther map[string]*routeMethod
allowHeader string
}
const ( const (
staticKind kind = iota staticKind kind = iota