mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-02 06:07:21 +01:00
httpcaddyfile: Add shortcut for expression matchers (#4976)
This commit is contained in:
parent
7c35bfa57c
commit
7d5108d132
3 changed files with 65 additions and 18 deletions
|
@ -191,3 +191,7 @@ func Tokenize(input []byte, filename string) ([]Token, error) {
|
||||||
}
|
}
|
||||||
return tokens, nil
|
return tokens, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Token) Quoted() bool {
|
||||||
|
return t.wasQuoted > 0
|
||||||
|
}
|
||||||
|
|
|
@ -1201,6 +1201,7 @@ func (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.Mod
|
||||||
|
|
||||||
func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.ModuleMap) error {
|
func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.ModuleMap) error {
|
||||||
for d.Next() {
|
for d.Next() {
|
||||||
|
// this is the "name" for "named matchers"
|
||||||
definitionName := d.Val()
|
definitionName := d.Val()
|
||||||
|
|
||||||
if _, ok := matchers[definitionName]; ok {
|
if _, ok := matchers[definitionName]; ok {
|
||||||
|
@ -1208,16 +1209,9 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
|
||||||
}
|
}
|
||||||
matchers[definitionName] = make(caddy.ModuleMap)
|
matchers[definitionName] = make(caddy.ModuleMap)
|
||||||
|
|
||||||
// in case there are multiple instances of the same matcher, concatenate
|
// given a matcher name and the tokens following it, parse
|
||||||
// their tokens (we expect that UnmarshalCaddyfile should be able to
|
// the tokens as a matcher module and record it
|
||||||
// handle more than one segment); otherwise, we'd overwrite other
|
makeMatcher := func(matcherName string, tokens []caddyfile.Token) error {
|
||||||
// instances of the matcher in this set
|
|
||||||
tokensByMatcherName := make(map[string][]caddyfile.Token)
|
|
||||||
for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
|
|
||||||
matcherName := d.Val()
|
|
||||||
tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
|
|
||||||
}
|
|
||||||
for matcherName, tokens := range tokensByMatcherName {
|
|
||||||
mod, err := caddy.GetModule("http.matchers." + matcherName)
|
mod, err := caddy.GetModule("http.matchers." + matcherName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
|
return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
|
||||||
|
@ -1235,6 +1229,39 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
|
||||||
return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
|
return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
|
||||||
}
|
}
|
||||||
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
|
matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the next token is quoted, we can assume it's not a matcher name
|
||||||
|
// and that it's probably an 'expression' matcher
|
||||||
|
if d.NextArg() {
|
||||||
|
if d.Token().Quoted() {
|
||||||
|
err := makeMatcher("expression", []caddyfile.Token{d.Token()})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it wasn't quoted, then we need to rewind after calling
|
||||||
|
// d.NextArg() so the below properly grabs the matcher name
|
||||||
|
d.Prev()
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case there are multiple instances of the same matcher, concatenate
|
||||||
|
// their tokens (we expect that UnmarshalCaddyfile should be able to
|
||||||
|
// handle more than one segment); otherwise, we'd overwrite other
|
||||||
|
// instances of the matcher in this set
|
||||||
|
tokensByMatcherName := make(map[string][]caddyfile.Token)
|
||||||
|
for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
|
||||||
|
matcherName := d.Val()
|
||||||
|
tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
|
||||||
|
}
|
||||||
|
for matcherName, tokens := range tokensByMatcherName {
|
||||||
|
err := makeMatcher(matcherName, tokens)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -19,27 +19,30 @@
|
||||||
@matcher6 vars_regexp "{http.request.uri}" `\.([a-f0-9]{6})\.(css|js)$`
|
@matcher6 vars_regexp "{http.request.uri}" `\.([a-f0-9]{6})\.(css|js)$`
|
||||||
respond @matcher6 "from vars_regexp matcher without name"
|
respond @matcher6 "from vars_regexp matcher without name"
|
||||||
|
|
||||||
@matcher7 {
|
@matcher7 `path('/foo*') && method('GET')`
|
||||||
|
respond @matcher7 "inline expression matcher shortcut"
|
||||||
|
|
||||||
|
@matcher8 {
|
||||||
header Foo bar
|
header Foo bar
|
||||||
header Foo foobar
|
header Foo foobar
|
||||||
header Bar foo
|
header Bar foo
|
||||||
}
|
}
|
||||||
respond @matcher7 "header matcher merging values of the same field"
|
respond @matcher8 "header matcher merging values of the same field"
|
||||||
|
|
||||||
@matcher8 {
|
@matcher9 {
|
||||||
query foo=bar foo=baz bar=foo
|
query foo=bar foo=baz bar=foo
|
||||||
query bar=baz
|
query bar=baz
|
||||||
}
|
}
|
||||||
respond @matcher8 "query matcher merging pairs with the same keys"
|
respond @matcher9 "query matcher merging pairs with the same keys"
|
||||||
|
|
||||||
@matcher9 {
|
@matcher10 {
|
||||||
header !Foo
|
header !Foo
|
||||||
header Bar foo
|
header Bar foo
|
||||||
}
|
}
|
||||||
respond @matcher9 "header matcher with null field matcher"
|
respond @matcher10 "header matcher with null field matcher"
|
||||||
|
|
||||||
@matcher10 remote_ip private_ranges
|
@matcher11 remote_ip private_ranges
|
||||||
respond @matcher10 "remote_ip matcher with private ranges"
|
respond @matcher11 "remote_ip matcher with private ranges"
|
||||||
}
|
}
|
||||||
----------
|
----------
|
||||||
{
|
{
|
||||||
|
@ -152,6 +155,19 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"expression": "path('/foo*') \u0026\u0026 method('GET')"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"handle": [
|
||||||
|
{
|
||||||
|
"body": "inline expression matcher shortcut",
|
||||||
|
"handler": "static_response"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"match": [
|
"match": [
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue