feat: pass through service name

This commit is contained in:
franklin 2021-09-10 12:02:03 +02:00
parent 0532e5a781
commit dcc26e5101
21 changed files with 183 additions and 132 deletions

View File

@ -47,7 +47,7 @@ func BasicAuth(username string, passwordHash []byte, opts ...BasicAuthOption) Mi
// BasicAuthWithOptions middleware
func BasicAuthWithOptions(username string, passwordHash []byte, opts BasicAuthOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// basic auth from request header
u, p, ok := r.BasicAuth()

View File

@ -0,0 +1,35 @@
package middleware
import (
"net/http"
"github.com/pkg/errors"
)
type (
CookieTokenProviderOptions struct{}
CookieTokenProviderOption func(*CookieTokenProviderOptions)
)
// GetDefaultCookieTokenOptions returns the default options
func GetDefaultCookieTokenOptions() CookieTokenProviderOptions {
return CookieTokenProviderOptions{}
}
func CookieTokenProvider(cookieName string, opts ...CookieTokenProviderOption) TokenProvider {
options := GetDefaultCookieTokenOptions()
for _, opt := range opts {
if opt != nil {
opt(&options)
}
}
return func(r *http.Request) (string, error) {
if cookie, err := r.Cookie(cookieName); errors.Is(err, http.ErrNoCookie) {
return "", nil
} else if err != nil {
return "", errors.New("failed to retrieve cookie")
} else {
return cookie.Value, nil
}
}
}

View File

@ -100,7 +100,7 @@ func CORSWithOptions(opts CORSOptions) Middleware {
exposeHeaders := strings.Join(opts.ExposeHeaders, ",")
maxAge := strconv.Itoa(opts.MaxAge)
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get(keelhttp.HeaderOrigin)
allowOrigin := ""

View File

@ -0,0 +1,58 @@
package middleware
import (
"net/http"
"strings"
"github.com/pkg/errors"
keelhttp "github.com/foomo/keel/net/http"
)
type (
HeaderTokenProviderOptions struct {
Prefix string
Header string
}
HeaderTokenProviderOption func(*HeaderTokenProviderOptions)
)
// GetDefaultHeaderTokenOptions returns the default options
func GetDefaultHeaderTokenOptions() HeaderTokenProviderOptions {
return HeaderTokenProviderOptions{
Prefix: keelhttp.HeaderValueAuthorizationPrefix,
Header: keelhttp.HeaderAuthorization,
}
}
// HeaderTokenProviderWithPrefix middleware option
func HeaderTokenProviderWithPrefix(v string) HeaderTokenProviderOption {
return func(o *HeaderTokenProviderOptions) {
o.Prefix = v
}
}
// HeaderTokenProviderWithHeader middleware option
func HeaderTokenProviderWithHeader(v string) HeaderTokenProviderOption {
return func(o *HeaderTokenProviderOptions) {
o.Header = v
}
}
func HeaderTokenProvider(opts ...HeaderTokenProviderOption) TokenProvider {
options := GetDefaultHeaderTokenOptions()
for _, opt := range opts {
if opt != nil {
opt(&options)
}
}
return func(r *http.Request) (string, error) {
if value := r.Header.Get(options.Header); value == "" {
return "", nil
} else if !strings.HasPrefix(value, options.Prefix) {
return "", errors.New("malformed bearer token")
} else {
return strings.TrimPrefix(value, options.Prefix), nil
}
}
}

View File

@ -122,7 +122,7 @@ func JWT(jwt *jwt.JWT, contextKey interface{}, opts ...JWTOption) Middleware {
// JWTWithOptions middleware
func JWTWithOptions(jwt *jwt.JWT, contextKey interface{}, opts JWTOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
claims := opts.ClaimsProvider()
if value := r.Context().Value(contextKey); value != nil {

View File

@ -34,6 +34,7 @@ func Logger(opts ...LoggerOption) Middleware {
return LoggerWithOptions(options)
}
// LoggerWithMessage middleware option
func LoggerWithMessage(v string) LoggerOption {
return func(o *LoggerOptions) {
o.Message = v
@ -42,7 +43,7 @@ func LoggerWithMessage(v string) LoggerOption {
// LoggerWithOptions middleware
func LoggerWithOptions(opts LoggerOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()

View File

@ -7,14 +7,14 @@ import (
)
// Middleware your way to handle requests
type Middleware func(*zap.Logger, http.Handler) http.Handler
type Middleware func(*zap.Logger, string, http.Handler) http.Handler
func Compose(l *zap.Logger, handler http.Handler, middlewares ...Middleware) http.Handler {
composed := func(l *zap.Logger, next http.Handler) http.Handler {
func Compose(l *zap.Logger, name string, handler http.Handler, middlewares ...Middleware) http.Handler {
composed := func(l *zap.Logger, name string, next http.Handler) http.Handler {
for _, middleware := range middlewares {
next = middleware(l, next)
next = middleware(l, name, next)
}
return next
}
return composed(l, handler)
return composed(l, name, handler)
}

View File

@ -10,7 +10,7 @@ import (
type (
PoweredByHeaderOptions struct {
Header string
Header string
Message string
}
PoweredByHeaderOption func(*PoweredByHeaderOptions)
@ -19,7 +19,7 @@ type (
// GetDefaultPoweredByHeaderOptions returns the default options
func GetDefaultPoweredByHeaderOptions() PoweredByHeaderOptions {
return PoweredByHeaderOptions{
Header: httputils.HeaderXPoweredBy,
Header: httputils.HeaderXPoweredBy,
Message: "a lot of LOVE",
}
}

View File

@ -45,7 +45,7 @@ func Recover(opts ...RecoverOption) Middleware {
// RecoverWithOptions middleware
func RecoverWithOptions(opts RecoverOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if e := recover(); e != nil {

View File

@ -67,7 +67,7 @@ func RequestID(opts ...RequestIDOption) Middleware {
// RequestIDWithOptions middleware
func RequestIDWithOptions(opts RequestIDOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestID := r.Header.Get(opts.ResponseHeader)
if requestID == "" {

View File

@ -0,0 +1,19 @@
package middleware
import (
"net/http"
)
// RequestURIBlacklistSkipper returns a HTTPMiddlewareConfig.Skipper which skips the given uris
func RequestURIBlacklistSkipper(uris ...string) Skipper {
urisMap := make(map[string]bool, len(uris))
for _, uri := range uris {
urisMap[uri] = true
}
return func(r *http.Request) bool {
if _, ok := urisMap[r.RequestURI]; ok {
return false
}
return true
}
}

View File

@ -0,0 +1,19 @@
package middleware
import (
"net/http"
)
// RequestURIWhitelistSkipper returns a HTTPMiddlewareConfig.Skipper which skips all but the given uris
func RequestURIWhitelistSkipper(uris ...string) Skipper {
urisMap := make(map[string]bool, len(uris))
for _, uri := range uris {
urisMap[uri] = true
}
return func(r *http.Request) bool {
if _, ok := urisMap[r.RequestURI]; ok {
return true
}
return false
}
}

View File

@ -60,7 +60,7 @@ func ResponseTime(opts ...ResponseTimeOption) Middleware {
// ResponseTimeWithOptions middleware
func ResponseTimeWithOptions(opts ResponseTimeOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
rw := WrapResponseWriter(w)

View File

@ -11,6 +11,7 @@ import (
type (
ServerHeaderOptions struct {
Header string
Name string
}
ServerHeaderOption func(*ServerHeaderOptions)
)
@ -33,6 +34,13 @@ func ServerHeader(opts ...ServerHeaderOption) Middleware {
return ServerHeaderWithOptions(options)
}
// ServerHeaderWithName middleware option
func ServerHeaderWithName(v string) ServerHeaderOption {
return func(o *ServerHeaderOptions) {
o.Name = v
}
}
// ServerHeaderWithHeader middleware option
func ServerHeaderWithHeader(v string) ServerHeaderOption {
return func(o *ServerHeaderOptions) {
@ -43,6 +51,9 @@ func ServerHeaderWithHeader(v string) ServerHeaderOption {
// ServerHeaderWithOptions middleware
func ServerHeaderWithOptions(opts ServerHeaderOptions) Middleware {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
if opts.Name != "" {
name = opts.Name
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add(opts.Header, name)
next.ServeHTTP(w, r)

View File

@ -110,7 +110,7 @@ func SessionID(opts ...SessionIDOption) Middleware {
// SessionIDWithOptions middleware
func SessionIDWithOptions(opts SessionIDOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var sessionID string
if value := r.Header.Get(opts.Header); value != "" {

View File

@ -7,8 +7,8 @@ import (
)
func Skip(mw Middleware, skippers ...Skipper) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
wrapped := mw(l, next)
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
wrapped := mw(l, name, next)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for _, skipper := range skippers {
if skipper(r) {

View File

@ -5,31 +5,3 @@ import (
)
type Skipper func(*http.Request) bool
// RequestURIWhitelistSkipper returns a HTTPMiddlewareConfig.Skipper which skips all but the given uris
func RequestURIWhitelistSkipper(uris ...string) Skipper {
urisMap := make(map[string]bool, len(uris))
for _, uri := range uris {
urisMap[uri] = true
}
return func(r *http.Request) bool {
if _, ok := urisMap[r.RequestURI]; ok {
return true
}
return false
}
}
// RequestURIBlacklistSkipper returns a HTTPMiddlewareConfig.Skipper which skips the given uris
func RequestURIBlacklistSkipper(uris ...string) Skipper {
urisMap := make(map[string]bool, len(uris))
for _, uri := range uris {
urisMap[uri] = true
}
return func(r *http.Request) bool {
if _, ok := urisMap[r.RequestURI]; ok {
return false
}
return true
}
}

View File

@ -9,6 +9,7 @@ import (
type (
TelemetryOptions struct {
Name string
OtelOpts []otelhttp.Option
}
TelemetryOption func(*TelemetryOptions)
@ -22,19 +23,35 @@ func GetDefaultTelemetryOptions() TelemetryOptions {
}
// Telemetry middleware
func Telemetry(name string, opts ...TelemetryOption) Middleware {
func Telemetry(opts ...TelemetryOption) Middleware {
options := GetDefaultTelemetryOptions()
for _, opt := range opts {
if opt != nil {
opt(&options)
}
}
return TelemetryWithOptions(name, options)
return TelemetryWithOptions(options)
}
func TelemetryWithName(v string) TelemetryOption {
return func(o *TelemetryOptions) {
o.Name = v
}
}
// TelemetryWithOtelOpts middleware options
func TelemetryWithOtelOpts(v ...otelhttp.Option) TelemetryOption {
return func(o *TelemetryOptions) {
o.OtelOpts = v
}
}
// TelemetryWithOptions middleware
func TelemetryWithOptions(name string, opts TelemetryOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
func TelemetryWithOptions(opts TelemetryOptions) Middleware {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
if opts.Name != "" {
name = opts.Name
}
return otelhttp.NewHandler(next, name, opts.OtelOpts...)
}
}

View File

@ -45,7 +45,7 @@ func TokenAuth(token string, opts ...TokenAuthOption) Middleware {
// TokenAuthWithOptions middleware
func TokenAuthWithOptions(token string, opts TokenAuthOptions) Middleware {
return func(l *zap.Logger, next http.Handler) http.Handler {
return func(l *zap.Logger, name string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if value, err := opts.TokenProvider(r); err != nil {
httputils.UnauthorizedServerError(l, w, r, errors.Wrap(err, "failed to retrieve token"))

View File

@ -2,87 +2,6 @@ package middleware
import (
"net/http"
"strings"
"github.com/pkg/errors"
keelhttp "github.com/foomo/keel/net/http"
)
type TokenProvider func(r *http.Request) (string, error)
type (
HeaderTokenProviderOptions struct {
Prefix string
Header string
}
HeaderTokenProviderOption func(*HeaderTokenProviderOptions)
)
// GetDefaultHeaderTokenOptions returns the default options
func GetDefaultHeaderTokenOptions() HeaderTokenProviderOptions {
return HeaderTokenProviderOptions{
Prefix: keelhttp.HeaderValueAuthorizationPrefix,
Header: keelhttp.HeaderAuthorization,
}
}
// HeaderTokenProviderWithPrefix middleware option
func HeaderTokenProviderWithPrefix(v string) HeaderTokenProviderOption {
return func(o *HeaderTokenProviderOptions) {
o.Prefix = v
}
}
// HeaderTokenProviderWithHeader middleware option
func HeaderTokenProviderWithHeader(v string) HeaderTokenProviderOption {
return func(o *HeaderTokenProviderOptions) {
o.Header = v
}
}
func HeaderTokenProvider(opts ...HeaderTokenProviderOption) TokenProvider {
options := GetDefaultHeaderTokenOptions()
for _, opt := range opts {
if opt != nil {
opt(&options)
}
}
return func(r *http.Request) (string, error) {
if value := r.Header.Get(options.Header); value == "" {
return "", nil
} else if !strings.HasPrefix(value, options.Prefix) {
return "", errors.New("malformed bearer token")
} else {
return strings.TrimPrefix(value, options.Prefix), nil
}
}
}
type (
CookieTokenProviderOptions struct{}
CookieTokenProviderOption func(*CookieTokenProviderOptions)
)
// GetDefaultCookieTokenOptions returns the default options
func GetDefaultCookieTokenOptions() CookieTokenProviderOptions {
return CookieTokenProviderOptions{}
}
func CookieTokenProvider(cookieName string, opts ...CookieTokenProviderOption) TokenProvider {
options := GetDefaultCookieTokenOptions()
for _, opt := range opts {
if opt != nil {
opt(&options)
}
}
return func(r *http.Request) (string, error) {
if cookie, err := r.Cookie(cookieName); errors.Is(err, http.ErrNoCookie) {
return "", nil
} else if err != nil {
return "", errors.New("failed to retrieve cookie")
} else {
return cookie.Value, nil
}
}
}

View File

@ -32,7 +32,7 @@ func NewServiceHTTP(l *zap.Logger, name, addr string, handler http.Handler, midd
server: &http.Server{
Addr: addr,
ErrorLog: errorLog,
Handler: middleware.Compose(l, handler, middlewares...),
Handler: middleware.Compose(l, name, handler, middlewares...),
},
l: l,
}