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:
parent
5f7bedfb86
commit
3598f295f9
28
bind.go
28
bind.go
@ -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 {
|
||||||
|
170
bind_test.go
170
bind_test.go
@ -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)
|
||||||
|
284
context.go
284
context.go
@ -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.
|
||||||
|
@ -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
211
echo.go
@ -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) {
|
||||||
|
10
echo_test.go
10
echo_test.go
@ -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"}`
|
||||||
|
22
group.go
22
group.go
@ -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
67
log.go
@ -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{})
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
@ -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.
|
||||||
//
|
//
|
||||||
|
@ -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.
|
||||||
//
|
//
|
||||||
|
@ -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.
|
||||||
//
|
//
|
||||||
|
@ -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.
|
||||||
|
@ -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)].
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
//
|
//
|
||||||
|
@ -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()
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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] != '/' {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
//
|
//
|
||||||
|
@ -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,
|
||||||
|
@ -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`.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
26
response.go
26
response.go
@ -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
100
router.go
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user