diff options
| author | Jack Baron <jackmbaron@gmail.com> | 2020-12-09 18:28:14 +0000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-09 11:28:14 -0700 | 
| commit | c898a37f4080fe3013974bee9a44ce98bd900cc3 (patch) | |
| tree | 14f9bf7d2259f83040031bda93d548badfd54449 | |
| parent | 31fbcd74016f35c4edf89b5de9c8a519663d588b (diff) | |
httpcaddyfile: support matching headers that do not exist (#3909)
* add integration test for null header matcher
* implement null header matcher syntax
* avoid repeating magic !
* check for field following ! character
| -rw-r--r-- | caddytest/integration/caddyfile_adapt/matcher_syntax.txt | 24 | ||||
| -rw-r--r-- | modules/caddyhttp/matchers.go | 29 | 
2 files changed, 48 insertions, 5 deletions
| diff --git a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt b/caddytest/integration/caddyfile_adapt/matcher_syntax.txt index c5c2760..019ce14 100644 --- a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt +++ b/caddytest/integration/caddyfile_adapt/matcher_syntax.txt @@ -31,6 +31,12 @@  		query bar=baz  	}  	respond @matcher8 "query matcher merging pairs with the same keys" + +	@matcher9 { +		header !Foo +		header Bar foo +	} +	respond @matcher9 "header matcher with null field matcher"  }  ----------  { @@ -183,6 +189,24 @@  									"handler": "static_response"  								}  							] +						}, +						{ +							"match": [ +								{ +									"header": { +										"Bar": [ +											"foo" +										], +										"Foo": null +									} +								} +							], +							"handle": [ +								{ +									"body": "header matcher with null field matcher", +									"handler": "static_response" +								} +							]  						}  					]  				} diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index c5cf21d..4886ba6 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -470,13 +470,32 @@ func (m *MatchHeader) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {  	}  	for d.Next() {  		var field, val string -		if !d.Args(&field, &val) { -			return d.Errf("malformed header matcher: expected both field and value") +		if !d.Args(&field) { +			return d.Errf("malformed header matcher: expected field")  		} -		// If multiple header matchers with the same header field are defined, -		// we want to add the existing to the list of headers (will be OR'ed) -		http.Header(*m).Add(field, val) +		if strings.HasPrefix(field, "!") { +			if len(field) == 1 { +				return d.Errf("malformed header matcher: must have field name following ! character") +			} + +			field = field[1:] +			headers := *m +			headers[field] = nil +			m = &headers +			if d.NextArg() { +				return d.Errf("malformed header matcher: null matching headers cannot have a field value") +			} +		} else { +			if !d.NextArg() { +				return d.Errf("malformed header matcher: expected both field and value") +			} + +			// If multiple header matchers with the same header field are defined, +			// we want to add the existing to the list of headers (will be OR'ed) +			val = d.Val() +			http.Header(*m).Add(field, val) +		}  		if d.NextBlock(0) {  			return d.Err("malformed header matcher: blocks are not supported") | 
