package http import ( "context" "fmt" "strconv" "strings" "time" "forge.cadoles.com/Cadoles/go-proxy/wildcard" "forge.cadoles.com/cadoles/bouncer/internal/rule" "github.com/expr-lang/expr" "github.com/pkg/errors" ) func addResponseHeaderFunc() expr.Option { return expr.Function( "add_header", func(params ...any) (any, error) { ctx, err := rule.Assert[context.Context](params[0]) if err != nil { return nil, errors.WithStack(err) } name, err := rule.Assert[string](params[1]) if err != nil { return nil, errors.WithStack(err) } rawValue := params[2] var value string switch v := rawValue.(type) { case []string: value = strings.Join(v, ",") case time.Time: value = strconv.FormatInt(v.UTC().Unix(), 10) case time.Duration: value = strconv.FormatInt(int64(v.Seconds()), 10) default: value = fmt.Sprintf("%v", rawValue) } r, ok := ctxResponse(ctx) if !ok { return nil, errors.New("could not find http response in context") } r.Header.Add(name, value) return true, nil }, new(func(context.Context, string, string) bool), ) } func setResponseHeaderFunc() expr.Option { return expr.Function( "set_header", func(params ...any) (any, error) { ctx, err := rule.Assert[context.Context](params[0]) if err != nil { return nil, errors.WithStack(err) } name, err := rule.Assert[string](params[1]) if err != nil { return nil, errors.WithStack(err) } rawValue := params[2] var value string switch v := rawValue.(type) { case []string: value = strings.Join(v, ",") case time.Time: value = strconv.FormatInt(v.UTC().Unix(), 10) case time.Duration: value = strconv.FormatInt(int64(v.Seconds()), 10) default: value = fmt.Sprintf("%v", rawValue) } r, ok := ctxResponse(ctx) if !ok { return nil, errors.New("could not find http response in context") } r.Header.Set(name, value) return true, nil }, new(func(context.Context, string, string) bool), ) } func delResponseHeadersFunc() expr.Option { return expr.Function( "del_headers", func(params ...any) (any, error) { ctx, err := rule.Assert[context.Context](params[0]) if err != nil { return nil, errors.WithStack(err) } pattern, err := rule.Assert[string](params[1]) if err != nil { return nil, errors.WithStack(err) } r, ok := ctxResponse(ctx) if !ok { return nil, errors.New("could not find http response in context") } deleted := false for key := range r.Header { if !wildcard.Match(key, pattern) { continue } r.Header.Del(key) deleted = true } return deleted, nil }, new(func(context.Context, string) bool), ) }