@@ -118,6 +118,11 @@ func parseHostPattern(input string) (host []labelPattern, rest string, err error
118
118
host = append (host , label )
119
119
}
120
120
121
+ // Validate: host patterns cannot end with asterisk
122
+ if len (host ) > 0 && host [len (host )- 1 ] == "*" {
123
+ return nil , "" , errors .New ("host patterns cannot end with asterisk" )
124
+ }
125
+
121
126
return host , rest , nil
122
127
}
123
128
@@ -319,17 +324,31 @@ func parseAllowRule(ruleStr string) (Rule, error) {
319
324
// Parse the value based on the key type
320
325
switch key {
321
326
case "method" :
322
- token , remaining , err := parseMethodPattern (valueRest )
323
- if err != nil {
324
- return Rule {}, fmt .Errorf ("failed to parse method: %v" , err )
325
- }
327
+ // Handle comma-separated methods
328
+ methodsRest := valueRest
326
329
327
330
// Initialize Methods map if needed
328
331
if rule .MethodPatterns == nil {
329
332
rule .MethodPatterns = make (map [methodPattern ]struct {})
330
333
}
331
- rule .MethodPatterns [token ] = struct {}{}
332
- rest = remaining
334
+
335
+ for {
336
+ token , remaining , err := parseMethodPattern (methodsRest )
337
+ if err != nil {
338
+ return Rule {}, fmt .Errorf ("failed to parse method: %v" , err )
339
+ }
340
+
341
+ rule .MethodPatterns [token ] = struct {}{}
342
+
343
+ // Check if there's a comma for more methods
344
+ if remaining != "" && remaining [0 ] == ',' {
345
+ methodsRest = remaining [1 :] // Skip the comma
346
+ continue
347
+ }
348
+
349
+ rest = remaining
350
+ break
351
+ }
333
352
334
353
case "domain" :
335
354
hostLabels , remaining , err := parseHostPattern (valueRest )
@@ -429,14 +448,14 @@ func (re *Engine) matches(r Rule, method, url string) bool {
429
448
}
430
449
}
431
450
if ! methodMatches {
432
- re .logger .Info ("rule does not match" , "reason" , "method pattern mismatch" , "rule" , r .Raw , "method" , method , "url" , url )
451
+ re .logger .Debug ("rule does not match" , "reason" , "method pattern mismatch" , "rule" , r .Raw , "method" , method , "url" , url )
433
452
return false
434
453
}
435
454
}
436
455
437
456
parsedUrl , err := neturl .Parse (url )
438
457
if err != nil {
439
- re .logger .Info ("rule does not match" , "reason" , "invalid URL" , "rule" , r .Raw , "method" , method , "url" , url , "error" , err )
458
+ re .logger .Debug ("rule does not match" , "reason" , "invalid URL" , "rule" , r .Raw , "method" , method , "url" , url , "error" , err )
440
459
return false
441
460
}
442
461
@@ -450,15 +469,16 @@ func (re *Engine) matches(r Rule, method, url string) bool {
450
469
451
470
// If the host pattern is longer than the actual host, it's definitely not a match
452
471
if len (r .HostPattern ) > len (labels ) {
453
- re .logger .Info ("rule does not match" , "reason" , "host pattern too long" , "rule" , r .Raw , "method" , method , "url" , url , "pattern_length" , len (r .HostPattern ), "hostname_labels" , len (labels ))
472
+ re .logger .Debug ("rule does not match" , "reason" , "host pattern too long" , "rule" , r .Raw , "method" , method , "url" , url , "pattern_length" , len (r .HostPattern ), "hostname_labels" , len (labels ))
454
473
return false
455
474
}
456
475
457
- // Compare pattern with the end of labels (allowing subdomains)
476
+ // Since host patterns cannot end with asterisk, we only need to handle:
477
+ // "example.com" or "*.example.com" - match from the end (allowing subdomains)
458
478
for i , lp := range r .HostPattern {
459
479
labelIndex := len (labels ) - len (r .HostPattern ) + i
460
480
if string (lp ) != labels [labelIndex ] && lp != "*" {
461
- re .logger .Info ("rule does not match" , "reason" , "host pattern label mismatch" , "rule" , r .Raw , "method" , method , "url" , url , "expected" , string (lp ), "actual" , labels [labelIndex ])
481
+ re .logger .Debug ("rule does not match" , "reason" , "host pattern label mismatch" , "rule" , r .Raw , "method" , method , "url" , url , "expected" , string (lp ), "actual" , labels [labelIndex ])
462
482
return false
463
483
}
464
484
}
@@ -467,21 +487,26 @@ func (re *Engine) matches(r Rule, method, url string) bool {
467
487
if r .PathPattern != nil {
468
488
segments := strings .Split (parsedUrl .Path , "/" )
469
489
490
+ // Skip the first empty segment if the path starts with "/"
491
+ if len (segments ) > 0 && segments [0 ] == "" {
492
+ segments = segments [1 :]
493
+ }
494
+
470
495
// If the path pattern is longer than the actual path, definitely not a match
471
496
if len (r .PathPattern ) > len (segments ) {
472
- re .logger .Info ("rule does not match" , "reason" , "path pattern too long" , "rule" , r .Raw , "method" , method , "url" , url , "pattern_length" , len (r .PathPattern ), "path_segments" , len (segments ))
497
+ re .logger .Debug ("rule does not match" , "reason" , "path pattern too long" , "rule" , r .Raw , "method" , method , "url" , url , "pattern_length" , len (r .PathPattern ), "path_segments" , len (segments ))
473
498
return false
474
499
}
475
500
476
501
// Each segment in the pattern must be either as asterisk or match the actual path segment
477
502
for i , sp := range r .PathPattern {
478
503
if string (sp ) != segments [i ] && sp != "*" {
479
- re .logger .Info ("rule does not match" , "reason" , "path pattern segment mismatch" , "rule" , r .Raw , "method" , method , "url" , url , "expected" , string (sp ), "actual" , segments [i ])
504
+ re .logger .Debug ("rule does not match" , "reason" , "path pattern segment mismatch" , "rule" , r .Raw , "method" , method , "url" , url , "expected" , string (sp ), "actual" , segments [i ])
480
505
return false
481
506
}
482
507
}
483
508
}
484
509
485
- re .logger .Info ("rule matches" , "reason" , "all patterns matched" , "rule" , r .Raw , "method" , method , "url" , url )
510
+ re .logger .Debug ("rule matches" , "reason" , "all patterns matched" , "rule" , r .Raw , "method" , method , "url" , url )
486
511
return true
487
512
}
0 commit comments