80 lines
1.5 KiB
Go
80 lines
1.5 KiB
Go
|
package rewriter
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
|
||
|
"forge.cadoles.com/cadoles/bouncer/internal/rule"
|
||
|
"github.com/expr-lang/expr"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type errRedirect struct {
|
||
|
statusCode int
|
||
|
url string
|
||
|
}
|
||
|
|
||
|
func (e *errRedirect) StatusCode() int {
|
||
|
return e.statusCode
|
||
|
}
|
||
|
|
||
|
func (e *errRedirect) URL() string {
|
||
|
return e.url
|
||
|
}
|
||
|
|
||
|
func (e *errRedirect) Error() string {
|
||
|
return fmt.Sprintf("redirect %d %s", e.statusCode, e.url)
|
||
|
}
|
||
|
|
||
|
func newErrRedirect(statusCode int, url string) *errRedirect {
|
||
|
return &errRedirect{
|
||
|
url: url,
|
||
|
statusCode: statusCode,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var _ error = &errRedirect{}
|
||
|
|
||
|
func redirectFunc() expr.Option {
|
||
|
return expr.Function(
|
||
|
"redirect",
|
||
|
func(params ...any) (any, error) {
|
||
|
_, err := rule.Assert[context.Context](params[0])
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
statusCode, err := rule.Assert[int](params[1])
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
if statusCode < 300 || statusCode >= 400 {
|
||
|
return nil, errors.Errorf("unexpected redirect status code '%d'", statusCode)
|
||
|
}
|
||
|
|
||
|
url, err := rule.Assert[string](params[2])
|
||
|
if err != nil {
|
||
|
return nil, errors.WithStack(err)
|
||
|
}
|
||
|
|
||
|
return nil, newErrRedirect(statusCode, url)
|
||
|
},
|
||
|
new(func(context.Context, int, string) bool),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func WithRewriterFuncs() rule.OptionFunc {
|
||
|
return func(opts *rule.Options) {
|
||
|
funcs := []expr.Option{
|
||
|
redirectFunc(),
|
||
|
}
|
||
|
|
||
|
if len(opts.Expr) == 0 {
|
||
|
opts.Expr = make([]expr.Option, 0)
|
||
|
}
|
||
|
|
||
|
opts.Expr = append(opts.Expr, funcs...)
|
||
|
}
|
||
|
}
|