bouncer/internal/proxy/director/context.go
William Petit d4c28b80d7
Some checks are pending
Cadoles/bouncer/pipeline/pr-develop Build started...
feat: global error handler with template rendering
2024-09-27 15:02:49 +02:00

85 lines
2.0 KiB
Go

package director
import (
"context"
"net/http"
"net/url"
"forge.cadoles.com/cadoles/bouncer/internal/store"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type contextKey string
const (
contextKeyProxy contextKey = "proxy"
contextKeyLayers contextKey = "layers"
contextKeyOriginalURL contextKey = "originalURL"
contextKeyHandleError contextKey = "handleError"
)
var (
errContextKeyNotFound = errors.New("context key not found")
errUnexpectedContextValue = errors.New("unexpected context value")
)
func withOriginalURL(ctx context.Context, url *url.URL) context.Context {
return context.WithValue(ctx, contextKeyOriginalURL, url)
}
func OriginalURL(ctx context.Context) (*url.URL, error) {
url, err := ctxValue[*url.URL](ctx, contextKeyOriginalURL)
if err != nil {
return nil, errors.WithStack(err)
}
return url, nil
}
func withLayers(ctx context.Context, layers []*store.Layer) context.Context {
return context.WithValue(ctx, contextKeyLayers, layers)
}
func ctxLayers(ctx context.Context) ([]*store.Layer, error) {
layers, err := ctxValue[[]*store.Layer](ctx, contextKeyLayers)
if err != nil {
return nil, errors.WithStack(err)
}
return layers, nil
}
func ctxValue[T any](ctx context.Context, key contextKey) (T, error) {
raw := ctx.Value(key)
if raw == nil {
return *new(T), errors.WithStack(errContextKeyNotFound)
}
value, ok := raw.(T)
if !ok {
return *new(T), errors.WithStack(errUnexpectedContextValue)
}
return value, nil
}
type HandleErrorFunc func(w http.ResponseWriter, r *http.Request, status int, err error)
func withHandleError(ctx context.Context, fn HandleErrorFunc) context.Context {
return context.WithValue(ctx, contextKeyHandleError, fn)
}
func HandleError(ctx context.Context, w http.ResponseWriter, r *http.Request, status int, err error) {
err = errors.WithStack(err)
fn, ok := ctx.Value(contextKeyHandleError).(HandleErrorFunc)
if !ok {
logger.Error(ctx, err.Error(), logger.CapturedE(err))
http.Error(w, http.StatusText(status), status)
return
}
fn(w, r, status, err)
}