@marcel91200 / caddy Mirror · read-only / commits / ea8df6ff
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 13, 16:45 UTC

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.

Matthew Holt committed Jul 28, 2022 at 14:50 UTC ea8df6ff114299058593530d24fe244201525b9a
4 files changed +43 -109
go.mod
+1 -1
@@ -33,7 +33,6 @@ require (
33 golang.org/x/net v0.0.0-20220630215102-69896b714898
34 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
35 google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21
36 - google.golang.org/protobuf v1.28.0
36 gopkg.in/natefinch/lumberjack.v2 v2.0.0
37 gopkg.in/yaml.v3 v3.0.1
38 )
@@ -127,6 +126,7 @@ require (
126 golang.org/x/tools v0.1.7 // indirect
127 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
128 google.golang.org/grpc v1.46.0 // indirect
129 + google.golang.org/protobuf v1.28.0 // indirect
130 gopkg.in/square/go-jose.v2 v2.6.0 // indirect
131 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
132 howett.net/plist v1.0.0 // indirect
modules/caddyhttp/celmatcher.go
+29 -85
@@ -28,7 +28,6 @@ import (
28 "github.com/caddyserver/caddy/v2"
29 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
30 "github.com/google/cel-go/cel"
31 - "github.com/google/cel-go/checker/decls"
31 "github.com/google/cel-go/common"
32 "github.com/google/cel-go/common/operators"
33 "github.com/google/cel-go/common/types"
@@ -40,7 +39,6 @@ import (
39 "github.com/google/cel-go/parser"
40 "go.uber.org/zap"
41 exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
43 - "google.golang.org/protobuf/proto"
42 )
43
44 func init() {
@@ -126,13 +124,12 @@ func (m *MatchExpression) Provision(ctx caddy.Context) error {
124
125 // create the CEL environment
126 env, err := cel.NewEnv(
129 - cel.Declarations(
130 - decls.NewVar("request", httpRequestObjectType),
131 - decls.NewFunction(placeholderFuncName,
132 - decls.NewOverload(placeholderFuncName+"_httpRequest_string",
133 - []*exprpb.Type{httpRequestObjectType, decls.String},
134 - decls.Any)),
135 - ),
127 + cel.Function(placeholderFuncName, cel.SingletonBinaryImpl(m.caddyPlaceholderFunc), cel.Overload(
128 + placeholderFuncName+"_httpRequest_string",
129 + []*cel.Type{httpRequestObjectType, cel.StringType},
130 + cel.AnyType,
131 + )),
132 + cel.Variable("request", httpRequestObjectType),
133 cel.CustomTypeAdapter(m.ta),
134 ext.Strings(),
135 matcherLib,
@@ -149,20 +146,12 @@ func (m *MatchExpression) Provision(ctx caddy.Context) error {
146
147 // request matching is a boolean operation, so we don't really know
148 // what to do if the expression returns a non-boolean type
152 - if !proto.Equal(checked.ResultType(), decls.Bool) {
153 - return fmt.Errorf("CEL request matcher expects return type of bool, not %s", checked.ResultType())
149 + if checked.OutputType() != cel.BoolType {
150 + return fmt.Errorf("CEL request matcher expects return type of bool, not %s", checked.OutputType())
151 }
152
153 // compile the "program"
157 - m.prg, err = env.Program(checked,
158 - cel.EvalOptions(cel.OptOptimize),
159 - cel.Functions(
160 - &functions.Overload{
161 - Operator: placeholderFuncName,
162 - Binary: m.caddyPlaceholderFunc,
163 - },
164 - ),
165 - )
154 + m.prg, err = env.Program(checked, cel.EvalOptions(cel.OptOptimize))
155 if err != nil {
156 return fmt.Errorf("compiling CEL program: %s", err)
157 }
@@ -321,62 +310,46 @@ type CELLibraryProducer interface {
310 // limited set of function signatures. For strong type validation you may need
311 // to provide a custom macro which does a more detailed analysis of the CEL
312 // literal provided to the macro as an argument.
324 -func CELMatcherImpl(macroName, funcName string, matcherDataTypes []*exprpb.Type, fac CELMatcherFactory) (cel.Library, error) {
325 - requestType := decls.NewObjectType("http.Request")
313 +func CELMatcherImpl(macroName, funcName string, matcherDataTypes []*cel.Type, fac CELMatcherFactory) (cel.Library, error) {
314 + requestType := cel.ObjectType("http.Request")
315 var macro parser.Macro
316 switch len(matcherDataTypes) {
317 case 1:
318 matcherDataType := matcherDataTypes[0]
330 - if isCELStringListType(matcherDataType) {
319 + switch matcherDataType.String() {
320 + case "list(string)":
321 macro = parser.NewGlobalVarArgMacro(macroName, celMatcherStringListMacroExpander(funcName))
332 - } else if isCELStringType(matcherDataType) {
322 + case cel.StringType.String():
323 macro = parser.NewGlobalMacro(macroName, 1, celMatcherStringMacroExpander(funcName))
334 - } else if isCELJSONType(matcherDataType) {
324 + case CELTypeJSON.String():
325 macro = parser.NewGlobalMacro(macroName, 1, celMatcherJSONMacroExpander(funcName))
336 - } else {
337 - return nil, fmt.Errorf("unsupported matcher data type: %s", cel.FormatType(matcherDataType))
326 + default:
327 + return nil, fmt.Errorf("unsupported matcher data type: %s", matcherDataType)
328 }
329 case 2:
340 - if isCELStringType(matcherDataTypes[0]) && isCELStringType(matcherDataTypes[1]) {
330 + if matcherDataTypes[0] == cel.StringType && matcherDataTypes[1] == cel.StringType {
331 macro = parser.NewGlobalMacro(macroName, 2, celMatcherStringListMacroExpander(funcName))
342 - matcherDataTypes = []*exprpb.Type{CelTypeListString}
332 + matcherDataTypes = []*cel.Type{cel.ListType(cel.StringType)}
333 } else {
344 - return nil, fmt.Errorf(
345 - "unsupported matcher data type: %s, %s",
346 - cel.FormatType(matcherDataTypes[0]), cel.FormatType(matcherDataTypes[1]),
347 - )
334 + return nil, fmt.Errorf("unsupported matcher data type: %s, %s", matcherDataTypes[0], matcherDataTypes[1])
335 }
336 case 3:
350 - if isCELStringType(matcherDataTypes[0]) && isCELStringType(matcherDataTypes[1]) && isCELStringType(matcherDataTypes[2]) {
337 + if matcherDataTypes[0] == cel.StringType && matcherDataTypes[1] == cel.StringType && matcherDataTypes[2] == cel.StringType {
338 macro = parser.NewGlobalMacro(macroName, 3, celMatcherStringListMacroExpander(funcName))
352 - matcherDataTypes = []*exprpb.Type{CelTypeListString}
339 + matcherDataTypes = []*cel.Type{cel.ListType(cel.StringType)}
340 } else {
354 - return nil, fmt.Errorf(
355 - "unsupported matcher data type: %s, %s, %s",
356 - cel.FormatType(matcherDataTypes[0]), cel.FormatType(matcherDataTypes[1]), cel.FormatType(matcherDataTypes[2]),
357 - )
341 + return nil, fmt.Errorf("unsupported matcher data type: %s, %s, %s", matcherDataTypes[0], matcherDataTypes[1], matcherDataTypes[2])
342 }
343 }
344 envOptions := []cel.EnvOption{
345 cel.Macros(macro),
362 - cel.Declarations(
363 - decls.NewFunction(funcName,
364 - decls.NewOverload(
365 - funcName,
366 - append([]*exprpb.Type{requestType}, matcherDataTypes...),
367 - decls.Bool,
368 - ),
369 - ),
370 - ),
346 + cel.Function(funcName,
347 + cel.Overload(funcName, append([]*cel.Type{requestType}, matcherDataTypes...), cel.BoolType),
348 +
349 + cel.SingletonBinaryImpl(CELMatcherRuntimeFunction(funcName, fac))),
350 }
351 programOptions := []cel.ProgramOption{
352 cel.CustomDecorator(CELMatcherDecorator(funcName, fac)),
374 - cel.Functions(
375 - &functions.Overload{
376 - Operator: funcName,
377 - Binary: CELMatcherRuntimeFunction(funcName, fac),
378 - },
379 - ),
353 }
354 return NewMatcherCELLibrary(envOptions, programOptions), nil
355 }
@@ -610,25 +583,6 @@ func CELValueToMapStrList(data ref.Val) (map[string][]string, error) {
583 return mapStrListStr, nil
584 }
585
613 -// isCELJSONType returns whether the type corresponds to JSON input.
614 -func isCELJSONType(t *exprpb.Type) bool {
615 - switch t.GetTypeKind().(type) {
616 - case *exprpb.Type_MapType_:
617 - mapType := t.GetMapType()
618 - return isCELStringType(mapType.GetKeyType()) && mapType.GetValueType().GetDyn() != nil
619 - }
620 - return false
621 -}
622 -
623 -// isCELStringType returns whether the type corresponds to a string.
624 -func isCELStringType(t *exprpb.Type) bool {
625 - switch t.GetTypeKind().(type) {
626 - case *exprpb.Type_Primitive:
627 - return t.GetPrimitive() == exprpb.Type_STRING
628 - }
629 - return false
630 -}
631 -
586 // isCELStringExpr indicates whether the expression is a supported string expression
587 func isCELStringExpr(e *exprpb.Expr) bool {
588 return isCELStringLiteral(e) || isCELCaddyPlaceholderCall(e) || isCELConcatCall(e)
@@ -681,15 +635,6 @@ func isCELConcatCall(e *exprpb.Expr) bool {
635 return false
636 }
637
684 -// isCELStringListType returns whether the type corresponds to a list of strings.
685 -func isCELStringListType(t *exprpb.Type) bool {
686 - switch t.GetTypeKind().(type) {
687 - case *exprpb.Type_ListType_:
688 - return isCELStringType(t.GetListType().GetElemType())
689 - }
690 - return false
691 -}
692 -
638 // isCELStringListLiteral returns whether the expression resolves to a list literal
639 // containing only string constants or a placeholder call.
640 func isCELStringListLiteral(e *exprpb.Expr) bool {
@@ -713,11 +658,10 @@ var (
658 placeholderRegexp = regexp.MustCompile(`{([a-zA-Z][\w.-]+)}`)
659 placeholderExpansion = `caddyPlaceholder(request, "${1}")`
660
716 - CelTypeListString = decls.NewListType(decls.String)
717 - CelTypeJson = decls.NewMapType(decls.String, decls.Dyn)
661 + CELTypeJSON = cel.MapType(cel.StringType, cel.DynType)
662 )
663
720 -var httpRequestObjectType = decls.NewObjectType("http.Request")
664 +var httpRequestObjectType = cel.ObjectType("http.Request")
665
666 // The name of the CEL function which accesses Replacer values.
667 const placeholderFuncName = "caddyPlaceholder"
modules/caddyhttp/fileserver/matcher.go
+2 -10
@@ -27,7 +27,6 @@ import (
27 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
28 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
29 "github.com/google/cel-go/cel"
30 - "github.com/google/cel-go/checker/decls"
30 "github.com/google/cel-go/common"
31 "github.com/google/cel-go/common/operators"
32 "github.com/google/cel-go/common/types/ref"
@@ -153,17 +152,10 @@ func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
152 // Example:
153 // expression file({'root': '/srv', 'try_files': [{http.request.uri.path}, '/index.php'], 'try_policy': 'first_exist', 'split_path': ['.php']})
154 func (MatchFile) CELLibrary(ctx caddy.Context) (cel.Library, error) {
156 - requestType := decls.NewObjectType("http.Request")
155 + requestType := cel.ObjectType("http.Request")
156 envOptions := []cel.EnvOption{
157 cel.Macros(parser.NewGlobalVarArgMacro("file", celFileMatcherMacroExpander())),
159 - cel.Declarations(
160 - decls.NewFunction("file",
161 - decls.NewOverload("file_request_map",
162 - []*exprpb.Type{requestType, caddyhttp.CelTypeJson},
163 - decls.Bool,
164 - ),
165 - ),
166 - ),
158 + cel.Function("file", cel.Overload("file_request_map", []*cel.Type{requestType, caddyhttp.CELTypeJSON}, cel.BoolType)),
159 }
160
161 matcherFactory := func(data ref.Val) (caddyhttp.RequestMatcher, error) {
modules/caddyhttp/matchers.go
+11 -13
@@ -33,11 +33,9 @@ import (
33 "github.com/caddyserver/caddy/v2"
34 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
35 "github.com/google/cel-go/cel"
36 - "github.com/google/cel-go/checker/decls"
36 "github.com/google/cel-go/common/types"
37 "github.com/google/cel-go/common/types/ref"
38 "go.uber.org/zap"
40 - exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
39 )
40
41 type (
@@ -310,7 +308,7 @@ func (MatchHost) CELLibrary(ctx caddy.Context) (cel.Library, error) {
308 return CELMatcherImpl(
309 "host",
310 "host_match_request_list",
313 - []*exprpb.Type{CelTypeListString},
311 + []*cel.Type{cel.ListType(cel.StringType)},
312 func(data ref.Val) (RequestMatcher, error) {
313 refStringList := reflect.TypeOf([]string{})
314 strList, err := data.ConvertToNative(refStringList)
@@ -441,7 +439,7 @@ func (MatchPath) CELLibrary(ctx caddy.Context) (cel.Library, error) {
439 // name of the function that the macro will be rewritten to call.
440 "path_match_request_list",
441 // internal data type of the MatchPath value.
444 - []*exprpb.Type{CelTypeListString},
442 + []*cel.Type{cel.ListType(cel.StringType)},
443 // function to convert a constant list of strings to a MatchPath instance.
444 func(data ref.Val) (RequestMatcher, error) {
445 refStringList := reflect.TypeOf([]string{})
@@ -509,7 +507,7 @@ func (MatchPathRE) CELLibrary(ctx caddy.Context) (cel.Library, error) {
507 unnamedPattern, err := CELMatcherImpl(
508 "path_regexp",
509 "path_regexp_request_string",
512 - []*exprpb.Type{decls.String},
510 + []*cel.Type{cel.StringType},
511 func(data ref.Val) (RequestMatcher, error) {
512 pattern := data.(types.String)
513 matcher := MatchPathRE{MatchRegexp{Pattern: string(pattern)}}
@@ -523,7 +521,7 @@ func (MatchPathRE) CELLibrary(ctx caddy.Context) (cel.Library, error) {
521 namedPattern, err := CELMatcherImpl(
522 "path_regexp",
523 "path_regexp_request_string_string",
526 - []*exprpb.Type{decls.String, decls.String},
524 + []*cel.Type{cel.StringType, cel.StringType},
525 func(data ref.Val) (RequestMatcher, error) {
526 refStringList := reflect.TypeOf([]string{})
527 params, err := data.ConvertToNative(refStringList)
@@ -582,7 +580,7 @@ func (MatchMethod) CELLibrary(_ caddy.Context) (cel.Library, error) {
580 return CELMatcherImpl(
581 "method",
582 "method_request_list",
585 - []*exprpb.Type{CelTypeListString},
583 + []*cel.Type{cel.ListType(cel.StringType)},
584 func(data ref.Val) (RequestMatcher, error) {
585 refStringList := reflect.TypeOf([]string{})
586 strList, err := data.ConvertToNative(refStringList)
@@ -668,7 +666,7 @@ func (MatchQuery) CELLibrary(_ caddy.Context) (cel.Library, error) {
666 return CELMatcherImpl(
667 "query",
668 "query_matcher_request_map",
671 - []*exprpb.Type{CelTypeJson},
669 + []*cel.Type{CELTypeJSON},
670 func(data ref.Val) (RequestMatcher, error) {
671 mapStrListStr, err := CELValueToMapStrList(data)
672 if err != nil {
@@ -744,7 +742,7 @@ func (MatchHeader) CELLibrary(_ caddy.Context) (cel.Library, error) {
742 return CELMatcherImpl(
743 "header",
744 "header_matcher_request_map",
747 - []*exprpb.Type{CelTypeJson},
745 + []*cel.Type{CELTypeJSON},
746 func(data ref.Val) (RequestMatcher, error) {
747 mapStrListStr, err := CELValueToMapStrList(data)
748 if err != nil {
@@ -901,7 +899,7 @@ func (MatchHeaderRE) CELLibrary(ctx caddy.Context) (cel.Library, error) {
899 unnamedPattern, err := CELMatcherImpl(
900 "header_regexp",
901 "header_regexp_request_string_string",
904 - []*exprpb.Type{decls.String, decls.String},
902 + []*cel.Type{cel.StringType, cel.StringType},
903 func(data ref.Val) (RequestMatcher, error) {
904 refStringList := reflect.TypeOf([]string{})
905 params, err := data.ConvertToNative(refStringList)
@@ -921,7 +919,7 @@ func (MatchHeaderRE) CELLibrary(ctx caddy.Context) (cel.Library, error) {
919 namedPattern, err := CELMatcherImpl(
920 "header_regexp",
921 "header_regexp_request_string_string_string",
924 - []*exprpb.Type{decls.String, decls.String, decls.String},
922 + []*cel.Type{cel.StringType, cel.StringType, cel.StringType},
923 func(data ref.Val) (RequestMatcher, error) {
924 refStringList := reflect.TypeOf([]string{})
925 params, err := data.ConvertToNative(refStringList)
@@ -985,7 +983,7 @@ func (MatchProtocol) CELLibrary(_ caddy.Context) (cel.Library, error) {
983 return CELMatcherImpl(
984 "protocol",
985 "protocol_request_string",
988 - []*exprpb.Type{decls.String},
986 + []*cel.Type{cel.StringType},
987 func(data ref.Val) (RequestMatcher, error) {
988 protocolStr, ok := data.(types.String)
989 if !ok {
@@ -1107,7 +1105,7 @@ func (MatchRemoteIP) CELLibrary(ctx caddy.Context) (cel.Library, error) {
1105 // name of the function that the macro will be rewritten to call.
1106 "remote_ip_match_request_list",
1107 // internal data type of the MatchPath value.
1110 - []*exprpb.Type{CelTypeListString},
1108 + []*cel.Type{cel.ListType(cel.StringType)},
1109 // function to convert a constant list of strings to a MatchPath instance.
1110 func(data ref.Val) (RequestMatcher, error) {
1111 refStringList := reflect.TypeOf([]string{})