From ea8df6ff114299058593530d24fe244201525b9a Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Thu, 28 Jul 2022 14:50:28 -0600 Subject: caddyhttp: Use new CEL APIs (fix #4915) Hahaha this is the ultimate "I have no idea what I'm doing" commit but it compiles and the tests pass and I declare victory! ... probably broke something, should be tested more. It is nice that the protobuf dependency becomes indirect now. --- modules/caddyhttp/celmatcher.go | 114 ++++++++------------------------ modules/caddyhttp/fileserver/matcher.go | 12 +--- modules/caddyhttp/matchers.go | 24 +++---- 3 files changed, 42 insertions(+), 108 deletions(-) (limited to 'modules') diff --git a/modules/caddyhttp/celmatcher.go b/modules/caddyhttp/celmatcher.go index 4938cd5..7b1e89d 100644 --- a/modules/caddyhttp/celmatcher.go +++ b/modules/caddyhttp/celmatcher.go @@ -28,7 +28,6 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/google/cel-go/cel" - "github.com/google/cel-go/checker/decls" "github.com/google/cel-go/common" "github.com/google/cel-go/common/operators" "github.com/google/cel-go/common/types" @@ -40,7 +39,6 @@ import ( "github.com/google/cel-go/parser" "go.uber.org/zap" exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" - "google.golang.org/protobuf/proto" ) func init() { @@ -126,13 +124,12 @@ func (m *MatchExpression) Provision(ctx caddy.Context) error { // create the CEL environment env, err := cel.NewEnv( - cel.Declarations( - decls.NewVar("request", httpRequestObjectType), - decls.NewFunction(placeholderFuncName, - decls.NewOverload(placeholderFuncName+"_httpRequest_string", - []*exprpb.Type{httpRequestObjectType, decls.String}, - decls.Any)), - ), + cel.Function(placeholderFuncName, cel.SingletonBinaryImpl(m.caddyPlaceholderFunc), cel.Overload( + placeholderFuncName+"_httpRequest_string", + []*cel.Type{httpRequestObjectType, cel.StringType}, + cel.AnyType, + )), + cel.Variable("request", httpRequestObjectType), cel.CustomTypeAdapter(m.ta), ext.Strings(), matcherLib, @@ -149,20 +146,12 @@ func (m *MatchExpression) Provision(ctx caddy.Context) error { // request matching is a boolean operation, so we don't really know // what to do if the expression returns a non-boolean type - if !proto.Equal(checked.ResultType(), decls.Bool) { - return fmt.Errorf("CEL request matcher expects return type of bool, not %s", checked.ResultType()) + if checked.OutputType() != cel.BoolType { + return fmt.Errorf("CEL request matcher expects return type of bool, not %s", checked.OutputType()) } // compile the "program" - m.prg, err = env.Program(checked, - cel.EvalOptions(cel.OptOptimize), - cel.Functions( - &functions.Overload{ - Operator: placeholderFuncName, - Binary: m.caddyPlaceholderFunc, - }, - ), - ) + m.prg, err = env.Program(checked, cel.EvalOptions(cel.OptOptimize)) if err != nil { return fmt.Errorf("compiling CEL program: %s", err) } @@ -321,62 +310,46 @@ type CELLibraryProducer interface { // limited set of function signatures. For strong type validation you may need // to provide a custom macro which does a more detailed analysis of the CEL // literal provided to the macro as an argument. -func CELMatcherImpl(macroName, funcName string, matcherDataTypes []*exprpb.Type, fac CELMatcherFactory) (cel.Library, error) { - requestType := decls.NewObjectType("http.Request") +func CELMatcherImpl(macroName, funcName string, matcherDataTypes []*cel.Type, fac CELMatcherFactory) (cel.Library, error) { + requestType := cel.ObjectType("http.Request") var macro parser.Macro switch len(matcherDataTypes) { case 1: matcherDataType := matcherDataTypes[0] - if isCELStringListType(matcherDataType) { + switch matcherDataType.String() { + case "list(string)": macro = parser.NewGlobalVarArgMacro(macroName, celMatcherStringListMacroExpander(funcName)) - } else if isCELStringType(matcherDataType) { + case cel.StringType.String(): macro = parser.NewGlobalMacro(macroName, 1, celMatcherStringMacroExpander(funcName)) - } else if isCELJSONType(matcherDataType) { + case CELTypeJSON.String(): macro = parser.NewGlobalMacro(macroName, 1, celMatcherJSONMacroExpander(funcName)) - } else { - return nil, fmt.Errorf("unsupported matcher data type: %s", cel.FormatType(matcherDataType)) + default: + return nil, fmt.Errorf("unsupported matcher data type: %s", matcherDataType) } case 2: - if isCELStringType(matcherDataTypes[0]) && isCELStringType(matcherDataTypes[1]) { + if matcherDataTypes[0] == cel.StringType && matcherDataTypes[1] == cel.StringType { macro = parser.NewGlobalMacro(macroName, 2, celMatcherStringListMacroExpander(funcName)) - matcherDataTypes = []*exprpb.Type{CelTypeListString} + matcherDataTypes = []*cel.Type{cel.ListType(cel.StringType)} } else { - return nil, fmt.Errorf( - "unsupported matcher data type: %s, %s", - cel.FormatType(matcherDataTypes[0]), cel.FormatType(matcherDataTypes[1]), - ) + return nil, fmt.Errorf("unsupported matcher data type: %s, %s", matcherDataTypes[0], matcherDataTypes[1]) } case 3: - if isCELStringType(matcherDataTypes[0]) && isCELStringType(matcherDataTypes[1]) && isCELStringType(matcherDataTypes[2]) { + if matcherDataTypes[0] == cel.StringType && matcherDataTypes[1] == cel.StringType && matcherDataTypes[2] == cel.StringType { macro = parser.NewGlobalMacro(macroName, 3, celMatcherStringListMacroExpander(funcName)) - matcherDataTypes = []*exprpb.Type{CelTypeListString} + matcherDataTypes = []*cel.Type{cel.ListType(cel.StringType)} } else { - return nil, fmt.Errorf( - "unsupported matcher data type: %s, %s, %s", - cel.FormatType(matcherDataTypes[0]), cel.FormatType(matcherDataTypes[1]), cel.FormatType(matcherDataTypes[2]), - ) + return nil, fmt.Errorf("unsupported matcher data type: %s, %s, %s", matcherDataTypes[0], matcherDataTypes[1], matcherDataTypes[2]) } } envOptions := []cel.EnvOption{ cel.Macros(macro), - cel.Declarations( - decls.NewFunction(funcName, - decls.NewOverload( - funcName, - append([]*exprpb.Type{requestType}, matcherDataTypes...), - decls.Bool, - ), - ), - ), + cel.Function(funcName, + cel.Overload(funcName, append([]*cel.Type{requestType}, matcherDataTypes...), cel.BoolType), + + cel.SingletonBinaryImpl(CELMatcherRuntimeFunction(funcName, fac))), } programOptions := []cel.ProgramOption{ cel.CustomDecorator(CELMatcherDecorator(funcName, fac)), - cel.Functions( - &functions.Overload{ - Operator: funcName, - Binary: CELMatcherRuntimeFunction(funcName, fac), - }, - ), } return NewMatcherCELLibrary(envOptions, programOptions), nil } @@ -610,25 +583,6 @@ func CELValueToMapStrList(data ref.Val) (map[string][]string, error) { return mapStrListStr, nil } -// isCELJSONType returns whether the type corresponds to JSON input. -func isCELJSONType(t *exprpb.Type) bool { - switch t.GetTypeKind().(type) { - case *exprpb.Type_MapType_: - mapType := t.GetMapType() - return isCELStringType(mapType.GetKeyType()) && mapType.GetValueType().GetDyn() != nil - } - return false -} - -// isCELStringType returns whether the type corresponds to a string. -func isCELStringType(t *exprpb.Type) bool { - switch t.GetTypeKind().(type) { - case *exprpb.Type_Primitive: - return t.GetPrimitive() == exprpb.Type_STRING - } - return false -} - // isCELStringExpr indicates whether the expression is a supported string expression func isCELStringExpr(e *exprpb.Expr) bool { return isCELStringLiteral(e) || isCELCaddyPlaceholderCall(e) || isCELConcatCall(e) @@ -681,15 +635,6 @@ func isCELConcatCall(e *exprpb.Expr) bool { return false } -// isCELStringListType returns whether the type corresponds to a list of strings. -func isCELStringListType(t *exprpb.Type) bool { - switch t.GetTypeKind().(type) { - case *exprpb.Type_ListType_: - return isCELStringType(t.GetListType().GetElemType()) - } - return false -} - // isCELStringListLiteral returns whether the expression resolves to a list literal // containing only string constants or a placeholder call. func isCELStringListLiteral(e *exprpb.Expr) bool { @@ -713,11 +658,10 @@ var ( placeholderRegexp = regexp.MustCompile(`{([a-zA-Z][\w.-]+)}`) placeholderExpansion = `caddyPlaceholder(request, "${1}")` - CelTypeListString = decls.NewListType(decls.String) - CelTypeJson = decls.NewMapType(decls.String, decls.Dyn) + CELTypeJSON = cel.MapType(cel.StringType, cel.DynType) ) -var httpRequestObjectType = decls.NewObjectType("http.Request") +var httpRequestObjectType = cel.ObjectType("http.Request") // The name of the CEL function which accesses Replacer values. const placeholderFuncName = "caddyPlaceholder" diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go index 4f3ffef..7ed9343 100644 --- a/modules/caddyhttp/fileserver/matcher.go +++ b/modules/caddyhttp/fileserver/matcher.go @@ -27,7 +27,6 @@ import ( "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddyhttp" "github.com/google/cel-go/cel" - "github.com/google/cel-go/checker/decls" "github.com/google/cel-go/common" "github.com/google/cel-go/common/operators" "github.com/google/cel-go/common/types/ref" @@ -153,17 +152,10 @@ func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // Example: // expression file({'root': '/srv', 'try_files': [{http.request.uri.path}, '/index.php'], 'try_policy': 'first_exist', 'split_path': ['.php']}) func (MatchFile) CELLibrary(ctx caddy.Context) (cel.Library, error) { - requestType := decls.NewObjectType("http.Request") + requestType := cel.ObjectType("http.Request") envOptions := []cel.EnvOption{ cel.Macros(parser.NewGlobalVarArgMacro("file", celFileMatcherMacroExpander())), - cel.Declarations( - decls.NewFunction("file", - decls.NewOverload("file_request_map", - []*exprpb.Type{requestType, caddyhttp.CelTypeJson}, - decls.Bool, - ), - ), - ), + cel.Function("file", cel.Overload("file_request_map", []*cel.Type{requestType, caddyhttp.CELTypeJSON}, cel.BoolType)), } matcherFactory := func(data ref.Val) (caddyhttp.RequestMatcher, error) { diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index c8db22f..82972e5 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -33,11 +33,9 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/google/cel-go/cel" - "github.com/google/cel-go/checker/decls" "github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types/ref" "go.uber.org/zap" - exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" ) type ( @@ -310,7 +308,7 @@ func (MatchHost) CELLibrary(ctx caddy.Context) (cel.Library, error) { return CELMatcherImpl( "host", "host_match_request_list", - []*exprpb.Type{CelTypeListString}, + []*cel.Type{cel.ListType(cel.StringType)}, func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) strList, err := data.ConvertToNative(refStringList) @@ -441,7 +439,7 @@ func (MatchPath) CELLibrary(ctx caddy.Context) (cel.Library, error) { // name of the function that the macro will be rewritten to call. "path_match_request_list", // internal data type of the MatchPath value. - []*exprpb.Type{CelTypeListString}, + []*cel.Type{cel.ListType(cel.StringType)}, // function to convert a constant list of strings to a MatchPath instance. func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) @@ -509,7 +507,7 @@ func (MatchPathRE) CELLibrary(ctx caddy.Context) (cel.Library, error) { unnamedPattern, err := CELMatcherImpl( "path_regexp", "path_regexp_request_string", - []*exprpb.Type{decls.String}, + []*cel.Type{cel.StringType}, func(data ref.Val) (RequestMatcher, error) { pattern := data.(types.String) matcher := MatchPathRE{MatchRegexp{Pattern: string(pattern)}} @@ -523,7 +521,7 @@ func (MatchPathRE) CELLibrary(ctx caddy.Context) (cel.Library, error) { namedPattern, err := CELMatcherImpl( "path_regexp", "path_regexp_request_string_string", - []*exprpb.Type{decls.String, decls.String}, + []*cel.Type{cel.StringType, cel.StringType}, func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) params, err := data.ConvertToNative(refStringList) @@ -582,7 +580,7 @@ func (MatchMethod) CELLibrary(_ caddy.Context) (cel.Library, error) { return CELMatcherImpl( "method", "method_request_list", - []*exprpb.Type{CelTypeListString}, + []*cel.Type{cel.ListType(cel.StringType)}, func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) strList, err := data.ConvertToNative(refStringList) @@ -668,7 +666,7 @@ func (MatchQuery) CELLibrary(_ caddy.Context) (cel.Library, error) { return CELMatcherImpl( "query", "query_matcher_request_map", - []*exprpb.Type{CelTypeJson}, + []*cel.Type{CELTypeJSON}, func(data ref.Val) (RequestMatcher, error) { mapStrListStr, err := CELValueToMapStrList(data) if err != nil { @@ -744,7 +742,7 @@ func (MatchHeader) CELLibrary(_ caddy.Context) (cel.Library, error) { return CELMatcherImpl( "header", "header_matcher_request_map", - []*exprpb.Type{CelTypeJson}, + []*cel.Type{CELTypeJSON}, func(data ref.Val) (RequestMatcher, error) { mapStrListStr, err := CELValueToMapStrList(data) if err != nil { @@ -901,7 +899,7 @@ func (MatchHeaderRE) CELLibrary(ctx caddy.Context) (cel.Library, error) { unnamedPattern, err := CELMatcherImpl( "header_regexp", "header_regexp_request_string_string", - []*exprpb.Type{decls.String, decls.String}, + []*cel.Type{cel.StringType, cel.StringType}, func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) params, err := data.ConvertToNative(refStringList) @@ -921,7 +919,7 @@ func (MatchHeaderRE) CELLibrary(ctx caddy.Context) (cel.Library, error) { namedPattern, err := CELMatcherImpl( "header_regexp", "header_regexp_request_string_string_string", - []*exprpb.Type{decls.String, decls.String, decls.String}, + []*cel.Type{cel.StringType, cel.StringType, cel.StringType}, func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) params, err := data.ConvertToNative(refStringList) @@ -985,7 +983,7 @@ func (MatchProtocol) CELLibrary(_ caddy.Context) (cel.Library, error) { return CELMatcherImpl( "protocol", "protocol_request_string", - []*exprpb.Type{decls.String}, + []*cel.Type{cel.StringType}, func(data ref.Val) (RequestMatcher, error) { protocolStr, ok := data.(types.String) if !ok { @@ -1107,7 +1105,7 @@ func (MatchRemoteIP) CELLibrary(ctx caddy.Context) (cel.Library, error) { // name of the function that the macro will be rewritten to call. "remote_ip_match_request_list", // internal data type of the MatchPath value. - []*exprpb.Type{CelTypeListString}, + []*cel.Type{cel.ListType(cel.StringType)}, // function to convert a constant list of strings to a MatchPath instance. func(data ref.Val) (RequestMatcher, error) { refStringList := reflect.TypeOf([]string{}) -- cgit v1.2.3