@@ -202,17 +202,25 @@ func (m *MatchExpression) Provision(ctx caddy.Context) error {
202
202
203
203
// Match returns true if r matches m.
204
204
func (m MatchExpression ) Match (r * http.Request ) bool {
205
+ match , err := m .MatchWithError (r )
206
+ if err != nil {
207
+ SetVar (r .Context (), MatcherErrorVarKey , err )
208
+ }
209
+ return match
210
+ }
211
+
212
+ // MatchWithError returns true if r matches m.
213
+ func (m MatchExpression ) MatchWithError (r * http.Request ) (bool , error ) {
205
214
celReq := celHTTPRequest {r }
206
215
out , _ , err := m .prg .Eval (celReq )
207
216
if err != nil {
208
217
m .log .Error ("evaluating expression" , zap .Error (err ))
209
- SetVar (r .Context (), MatcherErrorVarKey , err )
210
- return false
218
+ return false , err
211
219
}
212
220
if outBool , ok := out .Value ().(bool ); ok {
213
- return outBool
221
+ return outBool , nil
214
222
}
215
- return false
223
+ return false , nil
216
224
}
217
225
218
226
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
@@ -380,7 +388,7 @@ type CELLibraryProducer interface {
380
388
// limited set of function signatures. For strong type validation you may need
381
389
// to provide a custom macro which does a more detailed analysis of the CEL
382
390
// literal provided to the macro as an argument.
383
- func CELMatcherImpl (macroName , funcName string , matcherDataTypes []* cel.Type , fac CELMatcherFactory ) (cel.Library , error ) {
391
+ func CELMatcherImpl (macroName , funcName string , matcherDataTypes []* cel.Type , fac any ) (cel.Library , error ) {
384
392
requestType := cel .ObjectType ("http.Request" )
385
393
var macro parser.Macro
386
394
switch len (matcherDataTypes ) {
@@ -424,7 +432,11 @@ func CELMatcherImpl(macroName, funcName string, matcherDataTypes []*cel.Type, fa
424
432
}
425
433
426
434
// CELMatcherFactory converts a constant CEL value into a RequestMatcher.
427
- type CELMatcherFactory func (data ref.Val ) (RequestMatcher , error )
435
+ // Deprecated: Use CELMatcherWithErrorFactory instead.
436
+ type CELMatcherFactory = func (data ref.Val ) (RequestMatcher , error )
437
+
438
+ // CELMatcherWithErrorFactory converts a constant CEL value into a RequestMatcherWithError.
439
+ type CELMatcherWithErrorFactory = func (data ref.Val ) (RequestMatcherWithError , error )
428
440
429
441
// matcherCELLibrary is a simplistic configurable cel.Library implementation.
430
442
type matcherCELLibrary struct {
@@ -452,7 +464,7 @@ func (lib *matcherCELLibrary) ProgramOptions() []cel.ProgramOption {
452
464
// that takes a single argument, and optimizes the implementation to precompile
453
465
// the matcher and return a function that references the precompiled and
454
466
// provisioned matcher.
455
- func CELMatcherDecorator (funcName string , fac CELMatcherFactory ) interpreter.InterpretableDecorator {
467
+ func CELMatcherDecorator (funcName string , fac any ) interpreter.InterpretableDecorator {
456
468
return func (i interpreter.Interpretable ) (interpreter.Interpretable , error ) {
457
469
call , ok := i .(interpreter.InterpretableCall )
458
470
if ! ok {
@@ -481,35 +493,92 @@ func CELMatcherDecorator(funcName string, fac CELMatcherFactory) interpreter.Int
481
493
// and matcher provisioning should be handled at dynamically.
482
494
return i , nil
483
495
}
484
- matcher , err := fac (matcherData .Value ())
485
- if err != nil {
486
- return nil , err
496
+
497
+ if factory , ok := fac .(CELMatcherWithErrorFactory ); ok {
498
+ matcher , err := factory (matcherData .Value ())
499
+ if err != nil {
500
+ return nil , err
501
+ }
502
+ return interpreter .NewCall (
503
+ i .ID (), funcName , funcName + "_opt" ,
504
+ []interpreter.Interpretable {reqAttr },
505
+ func (args ... ref.Val ) ref.Val {
506
+ // The request value, guaranteed to be of type celHTTPRequest
507
+ celReq := args [0 ]
508
+ // If needed this call could be changed to convert the value
509
+ // to a *http.Request using CEL's ConvertToNative method.
510
+ httpReq := celReq .Value ().(celHTTPRequest )
511
+ match , err := matcher .MatchWithError (httpReq .Request )
512
+ if err != nil {
513
+ return types .WrapErr (err )
514
+ }
515
+ return types .Bool (match )
516
+ },
517
+ ), nil
487
518
}
488
- return interpreter .NewCall (
489
- i .ID (), funcName , funcName + "_opt" ,
490
- []interpreter.Interpretable {reqAttr },
491
- func (args ... ref.Val ) ref.Val {
492
- // The request value, guaranteed to be of type celHTTPRequest
493
- celReq := args [0 ]
494
- // If needed this call could be changed to convert the value
495
- // to a *http.Request using CEL's ConvertToNative method.
496
- httpReq := celReq .Value ().(celHTTPRequest )
497
- return types .Bool (matcher .Match (httpReq .Request ))
498
- },
499
- ), nil
519
+
520
+ if factory , ok := fac .(CELMatcherFactory ); ok {
521
+ matcher , err := factory (matcherData .Value ())
522
+ if err != nil {
523
+ return nil , err
524
+ }
525
+ return interpreter .NewCall (
526
+ i .ID (), funcName , funcName + "_opt" ,
527
+ []interpreter.Interpretable {reqAttr },
528
+ func (args ... ref.Val ) ref.Val {
529
+ // The request value, guaranteed to be of type celHTTPRequest
530
+ celReq := args [0 ]
531
+ // If needed this call could be changed to convert the value
532
+ // to a *http.Request using CEL's ConvertToNative method.
533
+ httpReq := celReq .Value ().(celHTTPRequest )
534
+ if m , ok := matcher .(RequestMatcherWithError ); ok {
535
+ match , err := m .MatchWithError (httpReq .Request )
536
+ if err != nil {
537
+ return types .WrapErr (err )
538
+ }
539
+ return types .Bool (match )
540
+ }
541
+ return types .Bool (matcher .Match (httpReq .Request ))
542
+ },
543
+ ), nil
544
+ }
545
+
546
+ return nil , fmt .Errorf ("invalid matcher factory, must be CELMatcherFactory or CELMatcherWithErrorFactory: %T" , fac )
500
547
}
501
548
}
502
549
503
550
// CELMatcherRuntimeFunction creates a function binding for when the input to the matcher
504
551
// is dynamically resolved rather than a set of static constant values.
505
- func CELMatcherRuntimeFunction (funcName string , fac CELMatcherFactory ) functions.BinaryOp {
552
+ func CELMatcherRuntimeFunction (funcName string , fac any ) functions.BinaryOp {
506
553
return func (celReq , matcherData ref.Val ) ref.Val {
507
- matcher , err := fac (matcherData )
508
- if err != nil {
509
- return types .WrapErr (err )
554
+ if factory , ok := fac .(CELMatcherWithErrorFactory ); ok {
555
+ matcher , err := factory (matcherData )
556
+ if err != nil {
557
+ return types .WrapErr (err )
558
+ }
559
+ httpReq := celReq .Value ().(celHTTPRequest )
560
+ match , err := matcher .MatchWithError (httpReq .Request )
561
+ if err != nil {
562
+ return types .WrapErr (err )
563
+ }
564
+ return types .Bool (match )
565
+ }
566
+ if factory , ok := fac .(CELMatcherFactory ); ok {
567
+ matcher , err := factory (matcherData )
568
+ if err != nil {
569
+ return types .WrapErr (err )
570
+ }
571
+ httpReq := celReq .Value ().(celHTTPRequest )
572
+ if m , ok := matcher .(RequestMatcherWithError ); ok {
573
+ match , err := m .MatchWithError (httpReq .Request )
574
+ if err != nil {
575
+ return types .WrapErr (err )
576
+ }
577
+ return types .Bool (match )
578
+ }
579
+ return types .Bool (matcher .Match (httpReq .Request ))
510
580
}
511
- httpReq := celReq .Value ().(celHTTPRequest )
512
- return types .Bool (matcher .Match (httpReq .Request ))
581
+ return types .NewErr ("CELMatcherRuntimeFunction invalid matcher factory: %T" , fac )
513
582
}
514
583
}
515
584
@@ -733,9 +802,9 @@ const MatcherNameCtxKey = "matcher_name"
733
802
734
803
// Interface guards
735
804
var (
736
- _ caddy.Provisioner = (* MatchExpression )(nil )
737
- _ RequestMatcher = (* MatchExpression )(nil )
738
- _ caddyfile.Unmarshaler = (* MatchExpression )(nil )
739
- _ json.Marshaler = (* MatchExpression )(nil )
740
- _ json.Unmarshaler = (* MatchExpression )(nil )
805
+ _ caddy.Provisioner = (* MatchExpression )(nil )
806
+ _ RequestMatcherWithError = (* MatchExpression )(nil )
807
+ _ caddyfile.Unmarshaler = (* MatchExpression )(nil )
808
+ _ json.Marshaler = (* MatchExpression )(nil )
809
+ _ json.Unmarshaler = (* MatchExpression )(nil )
741
810
)
0 commit comments