map: Bug fixes; null literal with hyphen in Caddyfile

This commit is contained in:
Matthew Holt 2020-10-02 16:08:28 -06:00
parent 0fc47e8357
commit ef8a372a1c
No known key found for this signature in database
GPG Key ID: 2A349DD577D586A5
2 changed files with 26 additions and 12 deletions

View File

@ -35,6 +35,9 @@ func init() {
// If the input value is prefixed with a tilde (~), then the input will be parsed as a // If the input value is prefixed with a tilde (~), then the input will be parsed as a
// regular expression. // regular expression.
// //
// The Caddyfile adapter treats outputs that are a literal hyphen (-) as a null/nil
// value. This is useful if you want to fall back to default for that particular output.
//
// The number of outputs for each mapping must not be more than the number of destinations. // The number of outputs for each mapping must not be more than the number of destinations.
// However, for convenience, there may be fewer outputs than destinations and any missing // However, for convenience, there may be fewer outputs than destinations and any missing
// outputs will be filled in implicitly. // outputs will be filled in implicitly.
@ -72,8 +75,12 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
in := h.Val() in := h.Val()
var outs []interface{} var outs []interface{}
for _, out := range h.RemainingArgs() { for _, out := range h.RemainingArgs() {
if out == "-" {
outs = append(outs, nil)
} else {
outs = append(outs, out) outs = append(outs, out)
} }
}
// cannot have more outputs than destinations // cannot have more outputs than destinations
if len(outs) > len(handler.Destinations) { if len(outs) > len(handler.Destinations) {

View File

@ -43,7 +43,7 @@ type Handler struct {
Destinations []string `json:"destinations,omitempty"` Destinations []string `json:"destinations,omitempty"`
// Mappings from source values (inputs) to destination values (outputs). // Mappings from source values (inputs) to destination values (outputs).
// The first matching mapping will be applied. // The first matching, non-nil mapping will be applied.
Mappings []Mapping `json:"mappings,omitempty"` Mappings []Mapping `json:"mappings,omitempty"`
// If no mappings match or if the mapped output is null/nil, the associated // If no mappings match or if the mapped output is null/nil, the associated
@ -69,9 +69,6 @@ func (h *Handler) Provision(_ caddy.Context) error {
if m.InputRegexp == "" { if m.InputRegexp == "" {
continue continue
} }
if m.Input != "" {
return fmt.Errorf("mapping %d has both input and input_regexp fields specified, which is confusing", i)
}
var err error var err error
h.Mappings[i].re, err = regexp.Compile(m.InputRegexp) h.Mappings[i].re, err = regexp.Compile(m.InputRegexp)
if err != nil { if err != nil {
@ -94,11 +91,20 @@ func (h *Handler) Validate() error {
seen := make(map[string]int) seen := make(map[string]int)
for i, m := range h.Mappings { for i, m := range h.Mappings {
// prevent duplicate mappings // prevent confusing/ambiguous mappings
if prev, ok := seen[m.Input]; ok { if m.Input != "" && m.InputRegexp != "" {
return fmt.Errorf("mapping %d has a duplicate input '%s' previously used with mapping %d", i, m.Input, prev) return fmt.Errorf("mapping %d has both input and input_regexp fields specified, which is confusing", i)
} }
seen[m.Input] = i
// prevent duplicate mappings
input := m.Input
if m.InputRegexp != "" {
input = m.InputRegexp
}
if prev, ok := seen[input]; ok {
return fmt.Errorf("mapping %d has a duplicate input '%s' previously used with mapping %d", i, input, prev)
}
seen[input] = i
// ensure mappings have 1:1 output-to-destination correspondence // ensure mappings have 1:1 output-to-destination correspondence
nOut := len(m.Outputs) nOut := len(m.Outputs)
@ -128,7 +134,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt
if m.re != nil { if m.re != nil {
if m.re.MatchString(input) { if m.re.MatchString(input) {
if output := m.Outputs[destIdx]; output == nil { if output := m.Outputs[destIdx]; output == nil {
break continue
} else { } else {
return output, true return output, true
} }
@ -137,7 +143,7 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt
} }
if input == m.Input { if input == m.Input {
if output := m.Outputs[destIdx]; output == nil { if output := m.Outputs[destIdx]; output == nil {
break continue
} else { } else {
return output, true return output, true
} }
@ -176,7 +182,8 @@ type Mapping struct {
InputRegexp string `json:"input_regexp,omitempty"` InputRegexp string `json:"input_regexp,omitempty"`
// Upon a match with the input, each output is positionally correlated // Upon a match with the input, each output is positionally correlated
// with each destination of the parent handler. // with each destination of the parent handler. An output that is null
// (nil) will be treated as if it was not mapped at all.
Outputs []interface{} `json:"outputs,omitempty"` Outputs []interface{} `json:"outputs,omitempty"`
re *regexp.Regexp re *regexp.Regexp