caddyfile: Normalize & flatten all unmarshalers (#6037)

This commit is contained in:
Francis Lavoie 2024-01-23 19:36:59 -05:00 committed by GitHub
parent 54823f52bc
commit 750d0b8331
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 3026 additions and 3013 deletions

View file

@ -92,30 +92,26 @@ func FormattingDifference(filename string, body []byte) (caddyconfig.Warning, bo
}, true }, true
} }
// Unmarshaler is a type that can unmarshal // Unmarshaler is a type that can unmarshal Caddyfile tokens to
// Caddyfile tokens to set itself up for a // set itself up for a JSON encoding. The goal of an unmarshaler
// JSON encoding. The goal of an unmarshaler // is not to set itself up for actual use, but to set itself up for
// is not to set itself up for actual use, // being marshaled into JSON. Caddyfile-unmarshaled values will not
// but to set itself up for being marshaled // be used directly; they will be encoded as JSON and then used from
// into JSON. Caddyfile-unmarshaled values // that. Implementations _may_ be able to support multiple segments
// will not be used directly; they will be // (instances of their directive or batch of tokens); typically this
// encoded as JSON and then used from that. // means wrapping parsing logic in a loop: `for d.Next() { ... }`.
// Implementations must be able to support // More commonly, only a single segment is supported, so a simple
// multiple segments (instances of their // `d.Next()` at the start should be used to consume the module
// directive or batch of tokens); typically // identifier token (directive name, etc).
// this means wrapping all token logic in
// a loop: `for d.Next() { ... }`.
type Unmarshaler interface { type Unmarshaler interface {
UnmarshalCaddyfile(d *Dispenser) error UnmarshalCaddyfile(d *Dispenser) error
} }
// ServerType is a type that can evaluate a Caddyfile and set up a caddy config. // ServerType is a type that can evaluate a Caddyfile and set up a caddy config.
type ServerType interface { type ServerType interface {
// Setup takes the server blocks which // Setup takes the server blocks which contain tokens,
// contain tokens, as well as options // as well as options (e.g. CLI flags) and creates a
// (e.g. CLI flags) and creates a Caddy // Caddy config, along with any warnings or an error.
// config, along with any warnings or
// an error.
Setup([]ServerBlock, map[string]any) (*caddy.Config, []caddyconfig.Warning, error) Setup([]ServerBlock, map[string]any) (*caddy.Config, []caddyconfig.Warning, error)
} }

View file

@ -59,11 +59,8 @@ func init() {
// //
// bind <addresses...> // bind <addresses...>
func parseBind(h Helper) ([]ConfigValue, error) { func parseBind(h Helper) ([]ConfigValue, error) {
var lnHosts []string h.Next() // consume directive name
for h.Next() { return []ConfigValue{{Class: "bind", Value: h.RemainingArgs()}}, nil
lnHosts = append(lnHosts, h.RemainingArgs()...)
}
return h.NewBindAddresses(lnHosts), nil
} }
// parseTLS parses the tls directive. Syntax: // parseTLS parses the tls directive. Syntax:
@ -98,6 +95,8 @@ func parseBind(h Helper) ([]ConfigValue, error) {
// insecure_secrets_log <log_file> // insecure_secrets_log <log_file>
// } // }
func parseTLS(h Helper) ([]ConfigValue, error) { func parseTLS(h Helper) ([]ConfigValue, error) {
h.Next() // consume directive name
cp := new(caddytls.ConnectionPolicy) cp := new(caddytls.ConnectionPolicy)
var fileLoader caddytls.FileLoader var fileLoader caddytls.FileLoader
var folderLoader caddytls.FolderLoader var folderLoader caddytls.FolderLoader
@ -110,7 +109,6 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
var onDemand bool var onDemand bool
var reusePrivateKeys bool var reusePrivateKeys bool
for h.Next() {
// file certificate loader // file certificate loader
firstLine := h.RemainingArgs() firstLine := h.RemainingArgs()
switch len(firstLine) { switch len(firstLine) {
@ -177,7 +175,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
} }
var hasBlock bool var hasBlock bool
for nesting := h.Nesting(); h.NextBlock(nesting); { for h.NextBlock(0) {
hasBlock = true hasBlock = true
switch h.Val() { switch h.Val() {
@ -525,7 +523,6 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
if len(firstLine) == 0 && !hasBlock { if len(firstLine) == 0 && !hasBlock {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
}
// begin building the final config values // begin building the final config values
configVals := []ConfigValue{} configVals := []ConfigValue{}
@ -646,10 +643,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
// //
// root [<matcher>] <path> // root [<matcher>] <path>
func parseRoot(h Helper) ([]ConfigValue, error) { func parseRoot(h Helper) ([]ConfigValue, error) {
// consume directive name h.Next() // consume directive name
if !h.NextArg() {
return nil, h.ArgErr()
}
// count the tokens to determine what to do // count the tokens to determine what to do
argsCount := h.CountRemainingArgs() argsCount := h.CountRemainingArgs()
@ -673,11 +667,8 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
h.Next() // consume directive name again, matcher parsing does a reset
// consume directive name, again, because extracting matcher does a reset
if !h.NextArg() {
return nil, h.ArgErr()
}
// advance to the root path // advance to the root path
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
@ -690,17 +681,14 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
// //
// fs <filesystem> // fs <filesystem>
func parseFilesystem(h Helper) (caddyhttp.MiddlewareHandler, error) { func parseFilesystem(h Helper) (caddyhttp.MiddlewareHandler, error) {
var name string h.Next() // consume directive name
for h.Next() {
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
name = h.Val()
if h.NextArg() { if h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
} return caddyhttp.VarsMiddleware{"fs": h.Val()}, nil
return caddyhttp.VarsMiddleware{"fs": name}, nil
} }
// parseVars parses the vars directive. See its UnmarshalCaddyfile method for syntax. // parseVars parses the vars directive. See its UnmarshalCaddyfile method for syntax.
@ -720,10 +708,7 @@ func parseVars(h Helper) (caddyhttp.MiddlewareHandler, error) {
// respond with HTTP 200 and no Location header; redirect is performed // respond with HTTP 200 and no Location header; redirect is performed
// with JS and a meta tag). // with JS and a meta tag).
func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) { func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
if !h.Next() { h.Next() // consume directive name
return nil, h.ArgErr()
}
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
@ -739,8 +724,10 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
switch code { switch code {
case "permanent": case "permanent":
code = "301" code = "301"
case "temporary", "": case "temporary", "":
code = "302" code = "302"
case "html": case "html":
// Script tag comes first since that will better imitate a redirect in the browser's // Script tag comes first since that will better imitate a redirect in the browser's
// history, but the meta tag is a fallback for most non-JS clients. // history, but the meta tag is a fallback for most non-JS clients.
@ -758,6 +745,7 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo) body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo)
hdr = http.Header{"Content-Type": []string{"text/html; charset=utf-8"}} hdr = http.Header{"Content-Type": []string{"text/html; charset=utf-8"}}
code = "200" // don't redirect non-browser clients code = "200" // don't redirect non-browser clients
default: default:
// Allow placeholders for the code // Allow placeholders for the code
if strings.HasPrefix(code, "{") { if strings.HasPrefix(code, "{") {
@ -796,10 +784,7 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
func parseRespond(h Helper) (caddyhttp.MiddlewareHandler, error) { func parseRespond(h Helper) (caddyhttp.MiddlewareHandler, error) {
sr := new(caddyhttp.StaticResponse) sr := new(caddyhttp.StaticResponse)
err := sr.UnmarshalCaddyfile(h.Dispenser) err := sr.UnmarshalCaddyfile(h.Dispenser)
if err != nil { return sr, err
return nil, err
}
return sr, nil
} }
// parseAbort parses the abort directive. // parseAbort parses the abort directive.
@ -815,10 +800,7 @@ func parseAbort(h Helper) (caddyhttp.MiddlewareHandler, error) {
func parseError(h Helper) (caddyhttp.MiddlewareHandler, error) { func parseError(h Helper) (caddyhttp.MiddlewareHandler, error) {
se := new(caddyhttp.StaticError) se := new(caddyhttp.StaticError)
err := se.UnmarshalCaddyfile(h.Dispenser) err := se.UnmarshalCaddyfile(h.Dispenser)
if err != nil { return se, err
return nil, err
}
return se, nil
} }
// parseRoute parses the route directive. // parseRoute parses the route directive.
@ -844,11 +826,11 @@ func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
} }
func parseHandleErrors(h Helper) ([]ConfigValue, error) { func parseHandleErrors(h Helper) ([]ConfigValue, error) {
h.Next() h.Next() // consume directive name
args := h.RemainingArgs()
expression := "" expression := ""
args := h.RemainingArgs()
if len(args) > 0 { if len(args) > 0 {
expression = ""
codes := []string{} codes := []string{}
for _, val := range args { for _, val := range args {
if len(val) != 3 { if len(val) != 3 {
@ -951,12 +933,14 @@ func parseLog(h Helper) ([]ConfigValue, error) {
// level. The parseAsGlobalOption parameter is used to distinguish any differing logic // level. The parseAsGlobalOption parameter is used to distinguish any differing logic
// between the two. // between the two.
func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue, error) { func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue, error) {
h.Next() // consume option name
// When the globalLogNames parameter is passed in, we make // When the globalLogNames parameter is passed in, we make
// modifications to the parsing behavior. // modifications to the parsing behavior.
parseAsGlobalOption := globalLogNames != nil parseAsGlobalOption := globalLogNames != nil
var configValues []ConfigValue var configValues []ConfigValue
for h.Next() {
// Logic below expects that a name is always present when a // Logic below expects that a name is always present when a
// global option is being parsed; or an optional override // global option is being parsed; or an optional override
// is supported for access logs. // is supported for access logs.
@ -1128,7 +1112,6 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
Class: "custom_log", Class: "custom_log",
Value: val, Value: val,
}) })
}
return configValues, nil return configValues, nil
} }
@ -1136,10 +1119,9 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
// //
// skip_log [<matcher>] // skip_log [<matcher>]
func parseSkipLog(h Helper) (caddyhttp.MiddlewareHandler, error) { func parseSkipLog(h Helper) (caddyhttp.MiddlewareHandler, error) {
for h.Next() { h.Next() // consume directive name
if h.NextArg() { if h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
}
return caddyhttp.VarsMiddleware{"skip_log": true}, nil return caddyhttp.VarsMiddleware{"skip_log": true}, nil
} }

View file

@ -271,12 +271,6 @@ func (h Helper) GroupRoutes(vals []ConfigValue) {
} }
} }
// NewBindAddresses returns config values relevant to adding
// listener bind addresses to the config.
func (h Helper) NewBindAddresses(addrs []string) []ConfigValue {
return []ConfigValue{{Class: "bind", Value: addrs}}
}
// WithDispenser returns a new instance based on d. All others Helper // WithDispenser returns a new instance based on d. All others Helper
// fields are copied, so typically maps are shared with this new instance. // fields are copied, so typically maps are shared with this new instance.
func (h Helper) WithDispenser(d *caddyfile.Dispenser) Helper { func (h Helper) WithDispenser(d *caddyfile.Dispenser) Helper {

View file

@ -1381,7 +1381,8 @@ 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() { d.Next() // advance to the first token
// this is the "name" for "named matchers" // this is the "name" for "named matchers"
definitionName := d.Val() definitionName := d.Val()
@ -1417,11 +1418,16 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
// and that it's probably an 'expression' matcher // and that it's probably an 'expression' matcher
if d.NextArg() { if d.NextArg() {
if d.Token().Quoted() { if d.Token().Quoted() {
err := makeMatcher("expression", []caddyfile.Token{d.Token()}) // since it was missing the matcher name, we insert a token
// in front of the expression token itself
err := makeMatcher("expression", []caddyfile.Token{
{Text: "expression", File: d.File(), Line: d.Line()},
d.Token(),
})
if err != nil { if err != nil {
return err return err
} }
continue return nil
} }
// if it wasn't quoted, then we need to rewind after calling // if it wasn't quoted, then we need to rewind after calling
@ -1444,7 +1450,6 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
return err return err
} }
} }
}
return nil return nil
} }

View file

@ -62,8 +62,8 @@ func init() {
func parseOptTrue(d *caddyfile.Dispenser, _ any) (any, error) { return true, nil } func parseOptTrue(d *caddyfile.Dispenser, _ any) (any, error) { return true, nil }
func parseOptHTTPPort(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptHTTPPort(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume option name
var httpPort int var httpPort int
for d.Next() {
var httpPortStr string var httpPortStr string
if !d.AllArgs(&httpPortStr) { if !d.AllArgs(&httpPortStr) {
return 0, d.ArgErr() return 0, d.ArgErr()
@ -73,13 +73,12 @@ func parseOptHTTPPort(d *caddyfile.Dispenser, _ any) (any, error) {
if err != nil { if err != nil {
return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err) return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err)
} }
}
return httpPort, nil return httpPort, nil
} }
func parseOptHTTPSPort(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptHTTPSPort(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume option name
var httpsPort int var httpsPort int
for d.Next() {
var httpsPortStr string var httpsPortStr string
if !d.AllArgs(&httpsPortStr) { if !d.AllArgs(&httpsPortStr) {
return 0, d.ArgErr() return 0, d.ArgErr()
@ -89,14 +88,12 @@ func parseOptHTTPSPort(d *caddyfile.Dispenser, _ any) (any, error) {
if err != nil { if err != nil {
return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err) return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err)
} }
}
return httpsPort, nil return httpsPort, nil
} }
func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) {
newOrder := directiveOrder d.Next() // consume option name
for d.Next() {
// get directive name // get directive name
if !d.Next() { if !d.Next() {
return nil, d.ArgErr() return nil, d.ArgErr()
@ -112,6 +109,8 @@ func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) {
} }
pos := d.Val() pos := d.Val()
newOrder := directiveOrder
// if directive exists, first remove it // if directive exists, first remove it
for i, d := range newOrder { for i, d := range newOrder {
if d == dirName { if d == dirName {
@ -162,7 +161,6 @@ func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) {
break break
} }
} }
}
directiveOrder = newOrder directiveOrder = newOrder
@ -223,11 +221,11 @@ func parseOptACMEDNS(d *caddyfile.Dispenser, _ any) (any, error) {
func parseOptACMEEAB(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptACMEEAB(d *caddyfile.Dispenser, _ any) (any, error) {
eab := new(acme.EAB) eab := new(acme.EAB)
for d.Next() { d.Next() // consume option name
if d.NextArg() { if d.NextArg() {
return nil, d.ArgErr() return nil, d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "key_id": case "key_id":
if !d.NextArg() { if !d.NextArg() {
@ -245,17 +243,19 @@ func parseOptACMEEAB(d *caddyfile.Dispenser, _ any) (any, error) {
return nil, d.Errf("unrecognized parameter '%s'", d.Val()) return nil, d.Errf("unrecognized parameter '%s'", d.Val())
} }
} }
}
return eab, nil return eab, nil
} }
func parseOptCertIssuer(d *caddyfile.Dispenser, existing any) (any, error) { func parseOptCertIssuer(d *caddyfile.Dispenser, existing any) (any, error) {
d.Next() // consume option name
var issuers []certmagic.Issuer var issuers []certmagic.Issuer
if existing != nil { if existing != nil {
issuers = existing.([]certmagic.Issuer) issuers = existing.([]certmagic.Issuer)
} }
for d.Next() { // consume option name
if !d.Next() { // get issuer module name // get issuer module name
if !d.Next() {
return nil, d.ArgErr() return nil, d.ArgErr()
} }
modID := "tls.issuance." + d.Val() modID := "tls.issuance." + d.Val()
@ -268,12 +268,11 @@ func parseOptCertIssuer(d *caddyfile.Dispenser, existing any) (any, error) {
return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm) return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
} }
issuers = append(issuers, iss) issuers = append(issuers, iss)
}
return issuers, nil return issuers, nil
} }
func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume parameter name d.Next() // consume option name
if !d.Next() { if !d.Next() {
return "", d.ArgErr() return "", d.ArgErr()
} }
@ -285,7 +284,7 @@ func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {
} }
func parseOptStringList(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptStringList(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume parameter name d.Next() // consume option name
val := d.RemainingArgs() val := d.RemainingArgs()
if len(val) == 0 { if len(val) == 0 {
return "", d.ArgErr() return "", d.ArgErr()
@ -294,8 +293,9 @@ func parseOptStringList(d *caddyfile.Dispenser, _ any) (any, error) {
} }
func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume option name
adminCfg := new(caddy.AdminConfig) adminCfg := new(caddy.AdminConfig)
for d.Next() {
if d.NextArg() { if d.NextArg() {
listenAddress := d.Val() listenAddress := d.Val()
if listenAddress == "off" { if listenAddress == "off" {
@ -310,7 +310,7 @@ func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
} }
} }
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "enforce_origin": case "enforce_origin":
adminCfg.EnforceOrigin = true adminCfg.EnforceOrigin = true
@ -322,7 +322,6 @@ func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
return nil, d.Errf("unrecognized parameter '%s'", d.Val()) return nil, d.Errf("unrecognized parameter '%s'", d.Val())
} }
} }
}
if adminCfg.Listen == "" && !adminCfg.Disabled { if adminCfg.Listen == "" && !adminCfg.Disabled {
adminCfg.Listen = caddy.DefaultAdminListen adminCfg.Listen = caddy.DefaultAdminListen
} }
@ -330,12 +329,13 @@ func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
} }
func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) {
var ond *caddytls.OnDemandConfig d.Next() // consume option name
for d.Next() {
if d.NextArg() { if d.NextArg() {
return nil, d.ArgErr() return nil, d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); {
var ond *caddytls.OnDemandConfig
for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "ask": case "ask":
if !d.NextArg() { if !d.NextArg() {
@ -382,7 +382,6 @@ func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) {
return nil, d.Errf("unrecognized parameter '%s'", d.Val()) return nil, d.Errf("unrecognized parameter '%s'", d.Val())
} }
} }
}
if ond == nil { if ond == nil {
return nil, d.Err("expected at least one config parameter for on_demand_tls") return nil, d.Err("expected at least one config parameter for on_demand_tls")
} }
@ -390,7 +389,7 @@ func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) {
} }
func parseOptPersistConfig(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptPersistConfig(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume parameter name d.Next() // consume option name
if !d.Next() { if !d.Next() {
return "", d.ArgErr() return "", d.ArgErr()
} }
@ -405,7 +404,7 @@ func parseOptPersistConfig(d *caddyfile.Dispenser, _ any) (any, error) {
} }
func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume parameter name d.Next() // consume option name
if !d.Next() { if !d.Next() {
return "", d.ArgErr() return "", d.ArgErr()
} }

View file

@ -48,10 +48,12 @@ func init() {
// //
// When the CA ID is unspecified, 'local' is assumed. // When the CA ID is unspecified, 'local' is assumed.
func parsePKIApp(d *caddyfile.Dispenser, existingVal any) (any, error) { func parsePKIApp(d *caddyfile.Dispenser, existingVal any) (any, error) {
pki := &caddypki.PKI{CAs: make(map[string]*caddypki.CA)} d.Next() // consume app name
for d.Next() { pki := &caddypki.PKI{
for nesting := d.Nesting(); d.NextBlock(nesting); { CAs: make(map[string]*caddypki.CA),
}
for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "ca": case "ca":
pkiCa := new(caddypki.CA) pkiCa := new(caddypki.CA)
@ -164,8 +166,6 @@ func parsePKIApp(d *caddyfile.Dispenser, existingVal any) (any, error) {
return nil, d.Errf("unrecognized pki option '%s'", d.Val()) return nil, d.Errf("unrecognized pki option '%s'", d.Val())
} }
} }
}
return pki, nil return pki, nil
} }

View file

@ -53,15 +53,16 @@ type serverOptions struct {
} }
func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) { func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
d.Next() // consume option name
serverOpts := serverOptions{} serverOpts := serverOptions{}
for d.Next() {
if d.NextArg() { if d.NextArg() {
serverOpts.ListenerAddress = d.Val() serverOpts.ListenerAddress = d.Val()
if d.NextArg() { if d.NextArg() {
return nil, d.ArgErr() return nil, d.ArgErr()
} }
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "name": case "name":
if serverOpts.ListenerAddress == "" { if serverOpts.ListenerAddress == "" {
@ -283,7 +284,6 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
return nil, d.Errf("unrecognized servers option '%s'", d.Val()) return nil, d.Errf("unrecognized servers option '%s'", d.Val())
} }
} }
}
return serverOpts, nil return serverOpts, nil
} }

View file

@ -0,0 +1,78 @@
:80
push * /foo.txt
push {
GET /foo.txt
}
push {
GET /foo.txt
HEAD /foo.txt
}
push {
headers {
Foo bar
}
}
----------
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [
":80"
],
"routes": [
{
"handle": [
{
"handler": "push",
"resources": [
{
"target": "/foo.txt"
}
]
},
{
"handler": "push",
"resources": [
{
"method": "GET",
"target": "/foo.txt"
}
]
},
{
"handler": "push",
"resources": [
{
"method": "GET",
"target": "/foo.txt"
},
{
"method": "HEAD",
"target": "/foo.txt"
}
]
},
{
"handler": "push",
"headers": {
"set": {
"Foo": [
"bar"
]
}
}
}
]
}
]
}
}
}
}
}

View file

@ -40,14 +40,8 @@ func init() {
// //
// If <event> is *, then it will bind to all events. // If <event> is *, then it will bind to all events.
func parseApp(d *caddyfile.Dispenser, _ any) (any, error) { func parseApp(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume option name
app := new(caddyevents.App) app := new(caddyevents.App)
// consume the option name
if !d.Next() {
return nil, d.ArgErr()
}
// handle the block
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "on": case "on":

View file

@ -34,10 +34,11 @@ func init() {
// //
// If no hash algorithm is supplied, bcrypt will be assumed. // If no hash algorithm is supplied, bcrypt will be assumed.
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
h.Next() // consume directive name
var ba HTTPBasicAuth var ba HTTPBasicAuth
ba.HashCache = new(Cache) ba.HashCache = new(Cache)
for h.Next() {
var cmp Comparer var cmp Comparer
args := h.RemainingArgs() args := h.RemainingArgs()
@ -84,7 +85,6 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
Salt: b64Salt, Salt: b64Salt,
}) })
} }
}
return Authentication{ return Authentication{
ProvidersRaw: caddy.ModuleMap{ ProvidersRaw: caddy.ModuleMap{

View file

@ -176,13 +176,27 @@ func (m MatchExpression) Match(r *http.Request) bool {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchExpression) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchExpression) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume matcher name
// if there's multiple args, then we need to keep the raw
// tokens because the user may have used quotes within their
// CEL expression (e.g. strings) and we should retain that
if d.CountRemainingArgs() > 1 { if d.CountRemainingArgs() > 1 {
m.Expr = strings.Join(d.RemainingArgsRaw(), " ") m.Expr = strings.Join(d.RemainingArgsRaw(), " ")
} else { return nil
}
// there should at least be one arg
if !d.NextArg() {
return d.ArgErr()
}
// if there's only one token, then we can safely grab the
// cleaned token (no quotes) and use that as the expression
// because there's no valid CEL expression that is only a
// quoted string; commonly quotes are used in Caddyfile to
// define the expression
m.Expr = d.Val() m.Expr = d.Val()
}
}
return nil return nil
} }

View file

@ -54,11 +54,9 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
// //
// Specifying the formats on the first line will use those formats' defaults. // Specifying the formats on the first line will use those formats' defaults.
func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
var prefer []string d.Next() // consume directive name
responseMatchers := make(map[string]caddyhttp.ResponseMatcher) prefer := []string{}
for d.Next() {
for _, arg := range d.RemainingArgs() { for _, arg := range d.RemainingArgs() {
mod, err := caddy.GetModule("http.encoders." + arg) mod, err := caddy.GetModule("http.encoders." + arg)
if err != nil { if err != nil {
@ -75,6 +73,7 @@ func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
prefer = append(prefer, arg) prefer = append(prefer, arg)
} }
responseMatchers := make(map[string]caddyhttp.ResponseMatcher)
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "minimum_length": case "minimum_length":
@ -111,7 +110,6 @@ func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
prefer = append(prefer, name) prefer = append(prefer, name)
} }
} }
}
// use the order in which the encoders were defined. // use the order in which the encoders were defined.
enc.Prefer = prefer enc.Prefer = prefer

View file

@ -44,9 +44,9 @@ func (Gzip) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the handler from Caddyfile tokens. // UnmarshalCaddyfile sets up the handler from Caddyfile tokens.
func (g *Gzip) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (g *Gzip) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume option name
if !d.NextArg() { if !d.NextArg() {
continue return nil
} }
levelStr := d.Val() levelStr := d.Val()
level, err := strconv.Atoi(levelStr) level, err := strconv.Atoi(levelStr)
@ -54,7 +54,6 @@ func (g *Gzip) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return err return err
} }
g.Level = level g.Level = level
}
return nil return nil
} }

View file

@ -223,7 +223,7 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
// parse out the optional try policy // parse out the optional try policy
var tryPolicy string var tryPolicy string
for nesting := h.Nesting(); h.NextBlock(nesting); { for h.NextBlock(0) {
switch h.Val() { switch h.Val() {
case "policy": case "policy":
if tryPolicy != "" { if tryPolicy != "" {

View file

@ -127,6 +127,7 @@ func (MatchFile) CaddyModule() caddy.ModuleInfo {
// try_policy first_exist|smallest_size|largest_size|most_recently_modified // try_policy first_exist|smallest_size|largest_size|most_recently_modified
// } // }
func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
m.TryFiles = append(m.TryFiles, d.RemainingArgs()...) m.TryFiles = append(m.TryFiles, d.RemainingArgs()...)
for d.NextBlock(0) { for d.NextBlock(0) {

View file

@ -47,14 +47,12 @@ func init() {
// ? conditionally sets a value only if the header field is not already set, // ? conditionally sets a value only if the header field is not already set,
// and > sets a field with defer enabled. // and > sets a field with defer enabled.
func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) { func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
if !h.Next() { h.Next() // consume directive name
return nil, h.ArgErr()
}
matcherSet, err := h.ExtractMatcherSet() matcherSet, err := h.ExtractMatcherSet()
if err != nil { if err != nil {
return nil, err return nil, err
} }
h.Next() // consume the directive name again (matcher parsing resets)
makeHandler := func() Handler { makeHandler := func() Handler {
return Handler{ return Handler{
@ -65,7 +63,6 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
} }
handler, handlerWithRequire := makeHandler(), makeHandler() handler, handlerWithRequire := makeHandler(), makeHandler()
for h.Next() {
// first see if headers are in the initial line // first see if headers are in the initial line
var hasArgs bool var hasArgs bool
if h.NextArg() { if h.NextArg() {
@ -133,7 +130,6 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
return nil, h.Err(err.Error()) return nil, h.Err(err.Error())
} }
} }
}
var configValues []httpcaddyfile.ConfigValue var configValues []httpcaddyfile.ConfigValue
if !reflect.DeepEqual(handler, makeHandler()) { if !reflect.DeepEqual(handler, makeHandler()) {
@ -151,18 +147,15 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
// //
// request_header [<matcher>] [[+|-]<field> [<value|regexp>] [<replacement>]] // request_header [<matcher>] [[+|-]<field> [<value|regexp>] [<replacement>]]
func parseReqHdrCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) { func parseReqHdrCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
if !h.Next() { h.Next() // consume directive name
return nil, h.ArgErr()
}
matcherSet, err := h.ExtractMatcherSet() matcherSet, err := h.ExtractMatcherSet()
if err != nil { if err != nil {
return nil, err return nil, err
} }
h.Next() // consume the directive name again (matcher parsing resets)
configValues := []httpcaddyfile.ConfigValue{} configValues := []httpcaddyfile.ConfigValue{}
for h.Next() {
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
@ -200,7 +193,6 @@ func parseReqHdrCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue,
if h.NextArg() { if h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
}
return configValues, nil return configValues, nil
} }

View file

@ -79,7 +79,7 @@ func (MatchRemoteIP) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume matcher name
for d.NextArg() { for d.NextArg() {
if d.Val() == "forwarded" { if d.Val() == "forwarded" {
if len(m.Ranges) > 0 { if len(m.Ranges) > 0 {
@ -97,7 +97,6 @@ func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if d.NextBlock(0) { if d.NextBlock(0) {
return d.Err("malformed remote_ip matcher: blocks are not supported") return d.Err("malformed remote_ip matcher: blocks are not supported")
} }
}
return nil return nil
} }
@ -189,7 +188,7 @@ func (MatchClientIP) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchClientIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchClientIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume matcher name
for d.NextArg() { for d.NextArg() {
if d.Val() == "private_ranges" { if d.Val() == "private_ranges" {
m.Ranges = append(m.Ranges, PrivateRangesCIDR()...) m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
@ -200,7 +199,6 @@ func (m *MatchClientIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if d.NextBlock(0) { if d.NextBlock(0) {
return d.Err("malformed client_ip matcher: blocks are not supported") return d.Err("malformed client_ip matcher: blocks are not supported")
} }
}
return nil return nil
} }

View file

@ -42,9 +42,10 @@ func init() {
// 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.
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
h.Next() // consume directive name
var handler Handler var handler Handler
for h.Next() {
// source // source
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
@ -109,7 +110,5 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
handler.Mappings = append(handler.Mappings, mapping) handler.Mappings = append(handler.Mappings, mapping)
} }
}
return handler, nil return handler, nil
} }

View file

@ -225,6 +225,7 @@ func (MatchHost) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchHost) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchHost) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
*m = append(*m, d.RemainingArgs()...) *m = append(*m, d.RemainingArgs()...)
if d.NextBlock(0) { if d.NextBlock(0) {
@ -632,6 +633,7 @@ func (MatchPath) CELLibrary(ctx caddy.Context) (cel.Library, error) {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchPath) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchPath) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
*m = append(*m, d.RemainingArgs()...) *m = append(*m, d.RemainingArgs()...)
if d.NextBlock(0) { if d.NextBlock(0) {
@ -716,6 +718,7 @@ func (MatchMethod) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchMethod) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchMethod) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
*m = append(*m, d.RemainingArgs()...) *m = append(*m, d.RemainingArgs()...)
if d.NextBlock(0) { if d.NextBlock(0) {
@ -770,6 +773,7 @@ func (m *MatchQuery) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil { if *m == nil {
*m = make(map[string][]string) *m = make(map[string][]string)
} }
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
for _, query := range d.RemainingArgs() { for _, query := range d.RemainingArgs() {
if query == "" { if query == "" {
@ -868,6 +872,7 @@ func (m *MatchHeader) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil { if *m == nil {
*m = make(map[string][]string) *m = make(map[string][]string)
} }
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
var field, val string var field, val string
if !d.Args(&field) { if !d.Args(&field) {
@ -1002,6 +1007,7 @@ func (m *MatchHeaderRE) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil { if *m == nil {
*m = make(map[string]*MatchRegexp) *m = make(map[string]*MatchRegexp)
} }
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
var first, second, third string var first, second, third string
if !d.Args(&first, &second) { if !d.Args(&first, &second) {
@ -1166,6 +1172,7 @@ func (m MatchProtocol) Match(r *http.Request) bool {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchProtocol) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchProtocol) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
var proto string var proto string
if !d.Args(&proto) { if !d.Args(&proto) {
@ -1207,6 +1214,7 @@ func (MatchNot) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchNot) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *MatchNot) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
matcherSet, err := ParseCaddyfileNestedMatcherSet(d) matcherSet, err := ParseCaddyfileNestedMatcherSet(d)
if err != nil { if err != nil {
@ -1331,6 +1339,7 @@ func (mre *MatchRegexp) Match(input string, repl *caddy.Replacer) bool {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (mre *MatchRegexp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (mre *MatchRegexp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
// If this is the second iteration of the loop // If this is the second iteration of the loop
// then there's more than one path_regexp matcher // then there's more than one path_regexp matcher

View file

@ -39,7 +39,8 @@ func (ListenerWrapper) CaddyModule() caddy.ModuleInfo {
// fallback_policy <policy> // fallback_policy <policy>
// } // }
func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume wrapper name
// No same-line options are supported // No same-line options are supported
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
@ -74,7 +75,6 @@ func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr() return d.ArgErr()
} }
} }
}
return nil return nil
} }

View file

@ -44,21 +44,23 @@ func init() {
// Placeholders are accepted in resource and header field // Placeholders are accepted in resource and header field
// name and value and replacement tokens. // name and value and replacement tokens.
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
h.Next() // consume directive name
handler := new(Handler) handler := new(Handler)
for h.Next() { // inline resources
if h.NextArg() { if h.NextArg() {
handler.Resources = append(handler.Resources, Resource{Target: h.Val()}) handler.Resources = append(handler.Resources, Resource{Target: h.Val()})
} }
// optional block // optional block
for outerNesting := h.Nesting(); h.NextBlock(outerNesting); { for h.NextBlock(0) {
switch h.Val() { switch h.Val() {
case "headers": case "headers":
if h.NextArg() { if h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
for innerNesting := h.Nesting(); h.NextBlock(innerNesting); { for nesting := h.Nesting(); h.NextBlock(nesting); {
var err error var err error
// include current token, which we treat as an argument here // include current token, which we treat as an argument here
@ -100,7 +102,5 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
handler.Resources = append(handler.Resources, Resource{Target: h.Val()}) handler.Resources = append(handler.Resources, Resource{Target: h.Val()})
} }
} }
}
return handler, nil return handler, nil
} }

View file

@ -26,9 +26,10 @@ func init() {
} }
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
h.Next() // consume directive name
rb := new(RequestBody) rb := new(RequestBody)
for h.Next() {
// configuration should be in a block // configuration should be in a block
for h.NextBlock(0) { for h.NextBlock(0) {
switch h.Val() { switch h.Val() {
@ -42,11 +43,11 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
return nil, h.Errf("parsing max_size: %v", err) return nil, h.Errf("parsing max_size: %v", err)
} }
rb.MaxSize = int64(size) rb.MaxSize = int64(size)
default: default:
return nil, h.Errf("unrecognized servers option '%s'", h.Val()) return nil, h.Errf("unrecognized servers option '%s'", h.Val())
} }
} }
}
return rb, nil return rb, nil
} }

View file

@ -67,7 +67,7 @@ func (rm ResponseMatcher) matchStatusCode(statusCode int) bool {
// //
// @name [header <field> [<value>]] | [status <code...>] // @name [header <field> [<value>]] | [status <code...>]
func ParseNamedResponseMatcher(d *caddyfile.Dispenser, matchers map[string]ResponseMatcher) error { func ParseNamedResponseMatcher(d *caddyfile.Dispenser, matchers map[string]ResponseMatcher) error {
for d.Next() { d.Next() // consume matcher name
definitionName := d.Val() definitionName := d.Val()
if _, ok := matchers[definitionName]; ok { if _, ok := matchers[definitionName]; ok {
@ -114,8 +114,6 @@ func ParseNamedResponseMatcher(d *caddyfile.Dispenser, matchers map[string]Respo
return d.Errf("unrecognized response matcher %s", d.Val()) return d.Errf("unrecognized response matcher %s", d.Val())
} }
} }
matchers[definitionName] = matcher matchers[definitionName] = matcher
}
return nil return nil
} }

View file

@ -210,7 +210,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
} }
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
// if the subdirective has an "@" prefix then we // if the subdirective has an "@" prefix then we
// parse it as a response matcher for use with "handle_response" // parse it as a response matcher for use with "handle_response"
if strings.HasPrefix(d.Val(), matcherPrefix) { if strings.HasPrefix(d.Val(), matcherPrefix) {
@ -774,7 +774,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
} }
// make sure there's no block, cause it doesn't make sense // make sure there's no block, cause it doesn't make sense
if d.NextBlock(1) { if nesting := d.Nesting(); d.NextBlock(nesting) {
return d.Errf("cannot define routes for 'replace_status', use 'handle_response' instead.") return d.Errf("cannot define routes for 'replace_status', use 'handle_response' instead.")
} }
@ -930,7 +930,7 @@ func (h *Handler) FinalizeUnmarshalCaddyfile(helper httpcaddyfile.Helper) error
// max_idle_conns_per_host <count> // max_idle_conns_per_host <count>
// } // }
func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume transport name
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "read_buffer": case "read_buffer":
@ -1222,7 +1222,6 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective %s", d.Val()) return d.Errf("unrecognized subdirective %s", d.Val())
} }
} }
}
return nil return nil
} }
@ -1241,12 +1240,13 @@ func parseCopyResponseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHan
// status <status> // status <status>
// } // }
func (h *CopyResponseHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (h *CopyResponseHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume directive name
args := d.RemainingArgs() args := d.RemainingArgs()
if len(args) == 1 { if len(args) == 1 {
if num, err := strconv.Atoi(args[0]); err == nil && num > 0 { if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
h.StatusCode = caddyhttp.WeakString(args[0]) h.StatusCode = caddyhttp.WeakString(args[0])
break return nil
} }
} }
@ -1261,7 +1261,6 @@ func (h *CopyResponseHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective '%s'", d.Val()) return d.Errf("unrecognized subdirective '%s'", d.Val())
} }
} }
}
return nil return nil
} }
@ -1281,7 +1280,8 @@ func parseCopyResponseHeadersCaddyfile(h httpcaddyfile.Helper) (caddyhttp.Middle
// exclude <fields...> // exclude <fields...>
// } // }
func (h *CopyResponseHeadersHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (h *CopyResponseHeadersHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume directive name
args := d.RemainingArgs() args := d.RemainingArgs()
if len(args) > 0 { if len(args) > 0 {
return d.ArgErr() return d.ArgErr()
@ -1299,7 +1299,6 @@ func (h *CopyResponseHeadersHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser)
return d.Errf("unrecognized subdirective '%s'", d.Val()) return d.Errf("unrecognized subdirective '%s'", d.Val())
} }
} }
}
return nil return nil
} }
@ -1315,7 +1314,8 @@ func (h *CopyResponseHeadersHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser)
// dial_fallback_delay <timeout> // dial_fallback_delay <timeout>
// } // }
func (u *SRVUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (u *SRVUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume upstream source name
args := d.RemainingArgs() args := d.RemainingArgs()
if len(args) > 1 { if len(args) > 1 {
return d.ArgErr() return d.ArgErr()
@ -1396,8 +1396,6 @@ func (u *SRVUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized srv option '%s'", d.Val()) return d.Errf("unrecognized srv option '%s'", d.Val())
} }
} }
}
return nil return nil
} }
@ -1413,7 +1411,8 @@ func (u *SRVUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// versions ipv4|ipv6 // versions ipv4|ipv6
// } // }
func (u *AUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (u *AUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume upstream source name
args := d.RemainingArgs() args := d.RemainingArgs()
if len(args) > 2 { if len(args) > 2 {
return d.ArgErr() return d.ArgErr()
@ -1510,8 +1509,6 @@ func (u *AUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized a option '%s'", d.Val()) return d.Errf("unrecognized a option '%s'", d.Val())
} }
} }
}
return nil return nil
} }
@ -1521,12 +1518,13 @@ func (u *AUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// <source> [...] // <source> [...]
// } // }
func (u *MultiUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (u *MultiUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume upstream source name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
dynModule := d.Val() dynModule := d.Val()
modID := "http.reverse_proxy.upstreams." + dynModule modID := "http.reverse_proxy.upstreams." + dynModule
unm, err := caddyfile.UnmarshalModule(d, modID) unm, err := caddyfile.UnmarshalModule(d, modID)
@ -1539,8 +1537,6 @@ func (u *MultiUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
} }
u.SourcesRaw = append(u.SourcesRaw, caddyconfig.JSONModuleObject(source, "source", dynModule, nil)) u.SourcesRaw = append(u.SourcesRaw, caddyconfig.JSONModuleObject(source, "source", dynModule, nil))
} }
}
return nil return nil
} }

View file

@ -46,7 +46,7 @@ func init() {
// capture_stderr // capture_stderr
// } // }
func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume transport name
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "root": case "root":
@ -117,7 +117,6 @@ func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective %s", d.Val()) return d.Errf("unrecognized subdirective %s", d.Val())
} }
} }
}
return nil return nil
} }

View file

@ -68,11 +68,10 @@ func (r RandomSelection) Select(pool UpstreamPool, request *http.Request, _ http
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *RandomSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *RandomSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -98,7 +97,8 @@ func (WeightedRoundRobinSelection) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *WeightedRoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *WeightedRoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
args := d.RemainingArgs() args := d.RemainingArgs()
if len(args) == 0 { if len(args) == 0 {
return d.ArgErr() return d.ArgErr()
@ -114,7 +114,6 @@ func (r *WeightedRoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser)
} }
r.Weights = append(r.Weights, weightInt) r.Weights = append(r.Weights, weightInt)
} }
}
return nil return nil
} }
@ -179,7 +178,8 @@ func (RandomChoiceSelection) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *RandomChoiceSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *RandomChoiceSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
@ -189,7 +189,6 @@ func (r *RandomChoiceSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error
return d.Errf("invalid choice value '%s': %v", chooseStr, err) return d.Errf("invalid choice value '%s': %v", chooseStr, err)
} }
r.Choose = choose r.Choose = choose
}
return nil return nil
} }
@ -280,11 +279,10 @@ func (LeastConnSelection) Select(pool UpstreamPool, _ *http.Request, _ http.Resp
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *LeastConnSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *LeastConnSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -320,11 +318,10 @@ func (r *RoundRobinSelection) Select(pool UpstreamPool, _ *http.Request, _ http.
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *RoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *RoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -352,11 +349,10 @@ func (FirstSelection) Select(pool UpstreamPool, _ *http.Request, _ http.Response
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *FirstSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *FirstSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -383,11 +379,10 @@ func (IPHashSelection) Select(pool UpstreamPool, req *http.Request, _ http.Respo
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *IPHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *IPHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -416,11 +411,10 @@ func (ClientIPHashSelection) Select(pool UpstreamPool, req *http.Request, _ http
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *ClientIPHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *ClientIPHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -443,11 +437,10 @@ func (URIHashSelection) Select(pool UpstreamPool, req *http.Request, _ http.Resp
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (r *URIHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (r *URIHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -504,13 +497,14 @@ func (s QueryHashSelection) Select(pool UpstreamPool, req *http.Request, _ http.
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (s *QueryHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (s *QueryHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
s.Key = d.Val() s.Key = d.Val()
}
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "fallback": case "fallback":
if !d.NextArg() { if !d.NextArg() {
@ -583,13 +577,14 @@ func (s HeaderHashSelection) Select(pool UpstreamPool, req *http.Request, _ http
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (s *HeaderHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (s *HeaderHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume policy name
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
s.Field = d.Val() s.Field = d.Val()
}
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "fallback": case "fallback":
if !d.NextArg() { if !d.NextArg() {
@ -708,7 +703,7 @@ func (s *CookieHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
default: default:
return d.ArgErr() return d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "fallback": case "fallback":
if !d.NextArg() { if !d.NextArg() {

View file

@ -39,10 +39,7 @@ func init() {
// Only URI components which are given in <to> will be set in the resulting URI. // Only URI components which are given in <to> will be set in the resulting URI.
// See the docs for the rewrite handler for more information. // See the docs for the rewrite handler for more information.
func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) { func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
// consume directive name h.Next() // consume directive name
if !h.NextArg() {
return nil, h.ArgErr()
}
// count the tokens to determine what to do // count the tokens to determine what to do
argsCount := h.CountRemainingArgs() argsCount := h.CountRemainingArgs()
@ -66,26 +63,9 @@ func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue,
if err != nil { if err != nil {
return nil, err return nil, err
} }
h.Next() // consume directive name again, matcher parsing does a reset
h.Next() // advance to the rewrite URI
// consume directive name, again, because extracting matcher does a reset
if !h.NextArg() {
return nil, h.ArgErr()
}
// advance to the rewrite URI
if !h.NextArg() {
return nil, h.ArgErr()
}
var rewr Rewrite
for h.Next() {
if !h.NextArg() {
return nil, h.ArgErr()
}
rewr.URI = h.Val()
if h.NextArg() {
return nil, h.ArgErr()
}
}
return h.NewRoute(userMatcherSet, Rewrite{URI: h.Val()}), nil return h.NewRoute(userMatcherSet, Rewrite{URI: h.Val()}), nil
} }
@ -93,17 +73,14 @@ func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue,
// //
// method [<matcher>] <method> // method [<matcher>] <method>
func parseCaddyfileMethod(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfileMethod(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var rewr Rewrite h.Next() // consume directive name
for h.Next() {
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
rewr.Method = h.Val()
if h.NextArg() { if h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
} return Rewrite{Method: h.Val()}, nil
return rewr, nil
} }
// parseCaddyfileURI sets up a handler for manipulating (but not "rewriting") the // parseCaddyfileURI sets up a handler for manipulating (but not "rewriting") the
@ -118,12 +95,15 @@ func parseCaddyfileMethod(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler,
// path_regexp is used, then regular expression replacements will be performed // path_regexp is used, then regular expression replacements will be performed
// on the path portion of the URI (and a limit cannot be set). // on the path portion of the URI (and a limit cannot be set).
func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var rewr Rewrite h.Next() // consume directive name
for h.Next() {
args := h.RemainingArgs() args := h.RemainingArgs()
if len(args) < 2 { if len(args) < 2 {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
var rewr Rewrite
switch args[0] { switch args[0] {
case "strip_prefix": case "strip_prefix":
if len(args) > 2 { if len(args) > 2 {
@ -133,11 +113,13 @@ func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, err
if !strings.HasPrefix(rewr.StripPathPrefix, "/") { if !strings.HasPrefix(rewr.StripPathPrefix, "/") {
rewr.StripPathPrefix = "/" + rewr.StripPathPrefix rewr.StripPathPrefix = "/" + rewr.StripPathPrefix
} }
case "strip_suffix": case "strip_suffix":
if len(args) > 2 { if len(args) > 2 {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
rewr.StripPathSuffix = args[1] rewr.StripPathSuffix = args[1]
case "replace": case "replace":
var find, replace, lim string var find, replace, lim string
switch len(args) { switch len(args) {
@ -165,6 +147,7 @@ func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, err
Replace: replace, Replace: replace,
Limit: limInt, Limit: limInt,
}) })
case "path_regexp": case "path_regexp":
if len(args) != 3 { if len(args) != 3 {
return nil, h.ArgErr() return nil, h.ArgErr()
@ -174,10 +157,10 @@ func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, err
Find: find, Find: find,
Replace: replace, Replace: replace,
}) })
default: default:
return nil, h.Errf("unrecognized URI manipulation '%s'", args[0]) return nil, h.Errf("unrecognized URI manipulation '%s'", args[0])
} }
}
return rewr, nil return rewr, nil
} }
@ -190,9 +173,9 @@ func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, err
// Only path matchers (with a `/` prefix) are supported as this is a shortcut // Only path matchers (with a `/` prefix) are supported as this is a shortcut
// for the handle directive with a strip_prefix rewrite. // for the handle directive with a strip_prefix rewrite.
func parseCaddyfileHandlePath(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) { func parseCaddyfileHandlePath(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
if !h.Next() { h.Next() // consume directive name
return nil, h.ArgErr()
} // there must be a path matcher
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }

View file

@ -60,7 +60,7 @@ func (StaticError) CaddyModule() caddy.ModuleInfo {
// If there is just one argument (other than the matcher), it is considered // If there is just one argument (other than the matcher), it is considered
// to be a status code if it's a valid positive integer of 3 digits. // to be a status code if it's a valid positive integer of 3 digits.
func (e *StaticError) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (e *StaticError) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume directive name
args := d.RemainingArgs() args := d.RemainingArgs()
switch len(args) { switch len(args) {
case 1: case 1:
@ -91,7 +91,6 @@ func (e *StaticError) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective '%s'", d.Val()) return d.Errf("unrecognized subdirective '%s'", d.Val())
} }
} }
}
return nil return nil
} }

View file

@ -138,7 +138,7 @@ func (StaticResponse) CaddyModule() caddy.ModuleInfo {
// If there is just one argument (other than the matcher), it is considered // If there is just one argument (other than the matcher), it is considered
// to be a status code if it's a valid positive integer of 3 digits. // to be a status code if it's a valid positive integer of 3 digits.
func (s *StaticResponse) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (s *StaticResponse) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume directive name
args := d.RemainingArgs() args := d.RemainingArgs()
switch len(args) { switch len(args) {
case 1: case 1:
@ -174,7 +174,6 @@ func (s *StaticResponse) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective '%s'", d.Val()) return d.Errf("unrecognized subdirective '%s'", d.Val())
} }
} }
}
return nil return nil
} }

View file

@ -34,8 +34,8 @@ func init() {
// root <path> // root <path>
// } // }
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
h.Next() // consume directive name
t := new(Templates) t := new(Templates)
for h.Next() {
for h.NextBlock(0) { for h.NextBlock(0) {
switch h.Val() { switch h.Val() {
case "mime": case "mime":
@ -77,6 +77,5 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
} }
} }
} }
}
return t, nil return t, nil
} }

View file

@ -88,9 +88,8 @@ func (ot *Tracing) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
"span": &ot.SpanName, "span": &ot.SpanName,
} }
for d.Next() { d.Next() // consume directive name
args := d.RemainingArgs() if d.NextArg() {
if len(args) > 0 {
return d.ArgErr() return d.ArgErr()
} }
@ -103,7 +102,6 @@ func (ot *Tracing) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr() return d.ArgErr()
} }
} }
}
return nil return nil
} }

View file

@ -68,6 +68,8 @@ func (m VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next H
// ... // ...
// } // }
func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
d.Next() // consume directive name
if *m == nil { if *m == nil {
*m = make(VarsMiddleware) *m = make(VarsMiddleware)
} }
@ -94,16 +96,14 @@ func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return nil return nil
} }
for d.Next() {
if err := nextVar(true); err != nil { if err := nextVar(true); err != nil {
return err return err
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
if err := nextVar(false); err != nil { if err := nextVar(false); err != nil {
return err return err
} }
} }
}
return nil return nil
} }
@ -135,6 +135,7 @@ func (m *VarsMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil { if *m == nil {
*m = make(map[string][]string) *m = make(map[string][]string)
} }
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
var field string var field string
if !d.Args(&field) { if !d.Args(&field) {
@ -216,6 +217,7 @@ func (m *MatchVarsRE) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil { if *m == nil {
*m = make(map[string]*MatchRegexp) *m = make(map[string]*MatchRegexp)
} }
// iterate to merge multiple matchers into one
for d.Next() { for d.Next() {
var first, second, third string var first, second, third string
if !d.Args(&first, &second) { if !d.Args(&first, &second) {

View file

@ -34,22 +34,21 @@ func init() {
// resolvers <addresses...> // resolvers <addresses...>
// } // }
func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) { func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
if !h.Next() { h.Next() // consume directive name
return nil, h.ArgErr()
}
matcherSet, err := h.ExtractMatcherSet() matcherSet, err := h.ExtractMatcherSet()
if err != nil { if err != nil {
return nil, err return nil, err
} }
h.Next() // consume the directive name again (matcher parsing resets)
// no inline args allowed
if h.NextArg() {
return nil, h.ArgErr()
}
var acmeServer Handler var acmeServer Handler
var ca *caddypki.CA var ca *caddypki.CA
for h.Next() {
if h.NextArg() {
return nil, h.ArgErr()
}
for h.NextBlock(0) { for h.NextBlock(0) {
switch h.Val() { switch h.Val() {
case "ca": case "ca":
@ -60,6 +59,7 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
ca = new(caddypki.CA) ca = new(caddypki.CA)
} }
ca.ID = acmeServer.CA ca.ID = acmeServer.CA
case "lifetime": case "lifetime":
if !h.NextArg() { if !h.NextArg() {
return nil, h.ArgErr() return nil, h.ArgErr()
@ -83,7 +83,6 @@ func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
} }
} }
} }
}
configVals := h.NewRoute(matcherSet, acmeServer) configVals := h.NewRoute(matcherSet, acmeServer)

View file

@ -277,14 +277,16 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss }
// } // }
// } // }
func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume issuer name
if d.NextArg() { if d.NextArg() {
iss.CA = d.Val() iss.CA = d.Val()
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
} }
for nesting := d.Nesting(); d.NextBlock(nesting); {
for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "dir": case "dir":
if iss.CA != "" { if iss.CA != "" {
@ -490,7 +492,6 @@ func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized ACME issuer property: %s", d.Val()) return d.Errf("unrecognized ACME issuer property: %s", d.Val())
} }
} }
}
return nil return nil
} }

View file

@ -72,11 +72,10 @@ func (ts Tailscale) canHazCertificate(ctx context.Context, hello *tls.ClientHell
// //
// ... tailscale // ... tailscale
func (Tailscale) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (Tailscale) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume cert manager name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
}
return nil return nil
} }
@ -169,18 +168,19 @@ func (hcg HTTPCertGetter) GetCertificate(ctx context.Context, hello *tls.ClientH
// //
// ... http <url> // ... http <url>
func (hcg *HTTPCertGetter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (hcg *HTTPCertGetter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume cert manager name
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
hcg.URL = d.Val() hcg.URL = d.Val()
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { if d.NextBlock(0) {
return d.Err("block not allowed here") return d.Err("block not allowed here")
} }
}
return nil return nil
} }

View file

@ -155,7 +155,7 @@ func (iss InternalIssuer) Issue(ctx context.Context, csr *x509.CertificateReques
// sign_with_root // sign_with_root
// } // }
func (iss *InternalIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (iss *InternalIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume issuer name
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "ca": case "ca":
@ -181,7 +181,6 @@ func (iss *InternalIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
} }
} }
}
return nil return nil
} }

View file

@ -208,7 +208,7 @@ func (iss *ZeroSSLIssuer) Revoke(ctx context.Context, cert certmagic.Certificate
// //
// Any of the subdirectives for the ACME issuer can be used in the block. // Any of the subdirectives for the ACME issuer can be used in the block.
func (iss *ZeroSSLIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (iss *ZeroSSLIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume issuer name
if d.NextArg() { if d.NextArg() {
iss.APIKey = d.Val() iss.APIKey = d.Val()
if d.NextArg() { if d.NextArg() {
@ -223,7 +223,6 @@ func (iss *ZeroSSLIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if err != nil { if err != nil {
return err return err
} }
}
return nil return nil
} }

View file

@ -55,7 +55,7 @@ func (s *FileStorage) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "root": case "root":
if !d.NextArg() { if !d.NextArg() {

View file

@ -65,7 +65,7 @@ func (ce *ConsoleEncoder) Provision(_ caddy.Context) error {
// See the godoc on the LogEncoderConfig type for the syntax of // See the godoc on the LogEncoderConfig type for the syntax of
// subdirectives that are common to most/all encoders. // subdirectives that are common to most/all encoders.
func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume encoder name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
@ -73,7 +73,6 @@ func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if err != nil { if err != nil {
return err return err
} }
}
return nil return nil
} }
@ -106,7 +105,7 @@ func (je *JSONEncoder) Provision(_ caddy.Context) error {
// See the godoc on the LogEncoderConfig type for the syntax of // See the godoc on the LogEncoderConfig type for the syntax of
// subdirectives that are common to most/all encoders. // subdirectives that are common to most/all encoders.
func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume encoder name
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
@ -114,7 +113,6 @@ func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if err != nil { if err != nil {
return err return err
} }
}
return nil return nil
} }
@ -149,7 +147,7 @@ type LogEncoderConfig struct {
// level_format <format> // level_format <format>
// } // }
func (lec *LogEncoderConfig) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (lec *LogEncoderConfig) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
subdir := d.Val() subdir := d.Val()
switch subdir { switch subdir {
case "time_local": case "time_local":

View file

@ -154,7 +154,7 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
// omitted or set to a zero value, then Caddy's default value for that // omitted or set to a zero value, then Caddy's default value for that
// subdirective is used. // subdirective is used.
func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume writer name
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
@ -222,7 +222,6 @@ func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
fw.RollKeepDays = int(math.Ceil(keepFor.Hours() / 24)) fw.RollKeepDays = int(math.Ceil(keepFor.Hours() / 24))
} }
} }
}
return nil return nil
} }

View file

@ -108,7 +108,7 @@ func (fe *FilterEncoder) Provision(ctx caddy.Context) error {
// } // }
// } // }
func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume encoder name
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "wrap": case "wrap":
@ -128,7 +128,7 @@ func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
fe.WrappedRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, nil) fe.WrappedRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, nil)
case "fields": case "fields":
for d.NextBlock(1) { for nesting := d.Nesting(); d.NextBlock(nesting); {
field := d.Val() field := d.Val()
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
@ -153,7 +153,6 @@ func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective %s", d.Val()) return d.Errf("unrecognized subdirective %s", d.Val())
} }
} }
}
return nil return nil
} }

View file

@ -128,11 +128,10 @@ func (ReplaceFilter) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (f *ReplaceFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (f *ReplaceFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume filter name
if d.NextArg() { if d.NextArg() {
f.Value = d.Val() f.Value = d.Val()
} }
}
return nil return nil
} }
@ -169,7 +168,7 @@ func (IPMaskFilter) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (m *IPMaskFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *IPMaskFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume filter name
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "ipv4": case "ipv4":
@ -196,7 +195,6 @@ func (m *IPMaskFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective %s", d.Val()) return d.Errf("unrecognized subdirective %s", d.Val())
} }
} }
}
return nil return nil
} }
@ -328,7 +326,7 @@ func (QueryFilter) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (m *QueryFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *QueryFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume filter name
for d.NextBlock(0) { for d.NextBlock(0) {
qfa := queryFilterAction{} qfa := queryFilterAction{}
switch d.Val() { switch d.Val() {
@ -367,7 +365,6 @@ func (m *QueryFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
m.Actions = append(m.Actions, qfa) m.Actions = append(m.Actions, qfa)
} }
}
return nil return nil
} }
@ -460,7 +457,7 @@ func (CookieFilter) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (m *CookieFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *CookieFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume filter name
for d.NextBlock(0) { for d.NextBlock(0) {
cfa := cookieFilterAction{} cfa := cookieFilterAction{}
switch d.Val() { switch d.Val() {
@ -499,7 +496,6 @@ func (m *CookieFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
m.Actions = append(m.Actions, cfa) m.Actions = append(m.Actions, cfa)
} }
}
return nil return nil
} }
@ -571,14 +567,13 @@ func (RegexpFilter) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (f *RegexpFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (f *RegexpFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume filter name
if d.NextArg() { if d.NextArg() {
f.RawRegexp = d.Val() f.RawRegexp = d.Val()
} }
if d.NextArg() { if d.NextArg() {
f.Value = d.Val() f.Value = d.Val()
} }
}
return nil return nil
} }
@ -625,11 +620,10 @@ func (RenameFilter) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
func (f *RenameFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (f *RenameFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume filter name
if d.NextArg() { if d.NextArg() {
f.Name = d.Val() f.Name = d.Val()
} }
}
return nil return nil
} }

View file

@ -117,7 +117,7 @@ func (nw NetWriter) OpenWriter() (io.WriteCloser, error) {
// soft_start // soft_start
// } // }
func (nw *NetWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (nw *NetWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume writer name
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
@ -125,7 +125,7 @@ func (nw *NetWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if d.NextArg() { if d.NextArg() {
return d.ArgErr() return d.ArgErr()
} }
for nesting := d.Nesting(); d.NextBlock(nesting); { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "dial_timeout": case "dial_timeout":
if !d.NextArg() { if !d.NextArg() {
@ -147,7 +147,6 @@ func (nw *NetWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
nw.SoftStart = true nw.SoftStart = true
} }
} }
}
return nil return nil
} }

View file

@ -78,7 +78,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
// disable_openmetrics // disable_openmetrics
// } // }
func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() { d.Next() // consume directive name
args := d.RemainingArgs() args := d.RemainingArgs()
if len(args) > 0 { if len(args) > 0 {
return d.ArgErr() return d.ArgErr()
@ -92,7 +92,6 @@ func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("unrecognized subdirective %q", d.Val()) return d.Errf("unrecognized subdirective %q", d.Val())
} }
} }
}
return nil return nil
} }