aboutsummaryrefslogtreecommitdiffhomepage
path: root/caddyconfig
diff options
context:
space:
mode:
authorFrancis Lavoie <[email protected]>2024-01-23 19:36:59 -0500
committerGitHub <[email protected]>2024-01-23 19:36:59 -0500
commit750d0b83319ac0ea6b7f057b8270c19404c3d6fa (patch)
treed0c3fb610cde8ae9d73a0a2caba94542af099770 /caddyconfig
parent54823f52bc9aed66a1a37f820daf6e494181211a (diff)
downloadcaddy-750d0b83319ac0ea6b7f057b8270c19404c3d6fa.tar.gz
caddy-750d0b83319ac0ea6b7f057b8270c19404c3d6fa.zip
caddyfile: Normalize & flatten all unmarshalers (#6037)
Diffstat (limited to 'caddyconfig')
-rw-r--r--caddyconfig/caddyfile/adapter.go32
-rw-r--r--caddyconfig/httpcaddyfile/builtins.go1086
-rw-r--r--caddyconfig/httpcaddyfile/directives.go6
-rw-r--r--caddyconfig/httpcaddyfile/httptype.go109
-rw-r--r--caddyconfig/httpcaddyfile/options.go365
-rw-r--r--caddyconfig/httpcaddyfile/pkiapp.go196
-rw-r--r--caddyconfig/httpcaddyfile/serveroptions.go400
7 files changed, 1085 insertions, 1109 deletions
diff --git a/caddyconfig/caddyfile/adapter.go b/caddyconfig/caddyfile/adapter.go
index d6ef602dc..edd825b88 100644
--- a/caddyconfig/caddyfile/adapter.go
+++ b/caddyconfig/caddyfile/adapter.go
@@ -92,30 +92,26 @@ func FormattingDifference(filename string, body []byte) (caddyconfig.Warning, bo
}, true
}
-// Unmarshaler is a type that can unmarshal
-// Caddyfile tokens to set itself up for a
-// JSON encoding. The goal of an unmarshaler
-// is not to set itself up for actual use,
-// but to set itself up for being marshaled
-// into JSON. Caddyfile-unmarshaled values
-// will not be used directly; they will be
-// encoded as JSON and then used from that.
-// Implementations must be able to support
-// multiple segments (instances of their
-// directive or batch of tokens); typically
-// this means wrapping all token logic in
-// a loop: `for d.Next() { ... }`.
+// Unmarshaler is a type that can unmarshal Caddyfile tokens to
+// set itself up for a JSON encoding. The goal of an unmarshaler
+// is not to set itself up for actual use, but to set itself up for
+// being marshaled into JSON. Caddyfile-unmarshaled values will not
+// be used directly; they will be encoded as JSON and then used from
+// that. Implementations _may_ be able to support multiple segments
+// (instances of their directive or batch of tokens); typically this
+// means wrapping parsing logic in a loop: `for d.Next() { ... }`.
+// More commonly, only a single segment is supported, so a simple
+// `d.Next()` at the start should be used to consume the module
+// identifier token (directive name, etc).
type Unmarshaler interface {
UnmarshalCaddyfile(d *Dispenser) error
}
// ServerType is a type that can evaluate a Caddyfile and set up a caddy config.
type ServerType interface {
- // Setup takes the server blocks which
- // contain tokens, as well as options
- // (e.g. CLI flags) and creates a Caddy
- // config, along with any warnings or
- // an error.
+ // Setup takes the server blocks which contain tokens,
+ // as well as options (e.g. CLI flags) and creates a
+ // Caddy config, along with any warnings or an error.
Setup([]ServerBlock, map[string]any) (*caddy.Config, []caddyconfig.Warning, error)
}
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go
index bf95a3616..11d18caea 100644
--- a/caddyconfig/httpcaddyfile/builtins.go
+++ b/caddyconfig/httpcaddyfile/builtins.go
@@ -59,11 +59,8 @@ func init() {
//
// bind <addresses...>
func parseBind(h Helper) ([]ConfigValue, error) {
- var lnHosts []string
- for h.Next() {
- lnHosts = append(lnHosts, h.RemainingArgs()...)
- }
- return h.NewBindAddresses(lnHosts), nil
+ h.Next() // consume directive name
+ return []ConfigValue{{Class: "bind", Value: h.RemainingArgs()}}, nil
}
// parseTLS parses the tls directive. Syntax:
@@ -98,6 +95,8 @@ func parseBind(h Helper) ([]ConfigValue, error) {
// insecure_secrets_log <log_file>
// }
func parseTLS(h Helper) ([]ConfigValue, error) {
+ h.Next() // consume directive name
+
cp := new(caddytls.ConnectionPolicy)
var fileLoader caddytls.FileLoader
var folderLoader caddytls.FolderLoader
@@ -110,423 +109,421 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
var onDemand bool
var reusePrivateKeys bool
- for h.Next() {
- // file certificate loader
- firstLine := h.RemainingArgs()
- switch len(firstLine) {
- case 0:
- case 1:
- if firstLine[0] == "internal" {
- internalIssuer = new(caddytls.InternalIssuer)
- } else if !strings.Contains(firstLine[0], "@") {
- return nil, h.Err("single argument must either be 'internal' or an email address")
- } else {
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- acmeIssuer.Email = firstLine[0]
- }
-
- case 2:
- certFilename := firstLine[0]
- keyFilename := firstLine[1]
-
- // tag this certificate so if multiple certs match, specifically
- // this one that the user has provided will be used, see #2588:
- // https://github.com/caddyserver/caddy/issues/2588 ... but we
- // must be careful about how we do this; being careless will
- // lead to failed handshakes
- //
- // we need to remember which cert files we've seen, since we
- // must load each cert only once; otherwise, they each get a
- // different tag... since a cert loaded twice has the same
- // bytes, it will overwrite the first one in the cache, and
- // only the last cert (and its tag) will survive, so any conn
- // policy that is looking for any tag other than the last one
- // to be loaded won't find it, and TLS handshakes will fail
- // (see end of issue #3004)
- //
- // tlsCertTags maps certificate filenames to their tag.
- // This is used to remember which tag is used for each
- // certificate files, since we need to avoid loading
- // the same certificate files more than once, overwriting
- // previous tags
- tlsCertTags, ok := h.State["tlsCertTags"].(map[string]string)
- if !ok {
- tlsCertTags = make(map[string]string)
- h.State["tlsCertTags"] = tlsCertTags
+ // file certificate loader
+ firstLine := h.RemainingArgs()
+ switch len(firstLine) {
+ case 0:
+ case 1:
+ if firstLine[0] == "internal" {
+ internalIssuer = new(caddytls.InternalIssuer)
+ } else if !strings.Contains(firstLine[0], "@") {
+ return nil, h.Err("single argument must either be 'internal' or an email address")
+ } else {
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
}
+ acmeIssuer.Email = firstLine[0]
+ }
- tag, ok := tlsCertTags[certFilename]
- if !ok {
- // haven't seen this cert file yet, let's give it a tag
- // and add a loader for it
- tag = fmt.Sprintf("cert%d", len(tlsCertTags))
- fileLoader = append(fileLoader, caddytls.CertKeyFilePair{
- Certificate: certFilename,
- Key: keyFilename,
- Tags: []string{tag},
- })
- // remember this for next time we see this cert file
- tlsCertTags[certFilename] = tag
- }
- certSelector.AnyTag = append(certSelector.AnyTag, tag)
+ case 2:
+ certFilename := firstLine[0]
+ keyFilename := firstLine[1]
+
+ // tag this certificate so if multiple certs match, specifically
+ // this one that the user has provided will be used, see #2588:
+ // https://github.com/caddyserver/caddy/issues/2588 ... but we
+ // must be careful about how we do this; being careless will
+ // lead to failed handshakes
+ //
+ // we need to remember which cert files we've seen, since we
+ // must load each cert only once; otherwise, they each get a
+ // different tag... since a cert loaded twice has the same
+ // bytes, it will overwrite the first one in the cache, and
+ // only the last cert (and its tag) will survive, so any conn
+ // policy that is looking for any tag other than the last one
+ // to be loaded won't find it, and TLS handshakes will fail
+ // (see end of issue #3004)
+ //
+ // tlsCertTags maps certificate filenames to their tag.
+ // This is used to remember which tag is used for each
+ // certificate files, since we need to avoid loading
+ // the same certificate files more than once, overwriting
+ // previous tags
+ tlsCertTags, ok := h.State["tlsCertTags"].(map[string]string)
+ if !ok {
+ tlsCertTags = make(map[string]string)
+ h.State["tlsCertTags"] = tlsCertTags
+ }
- default:
- return nil, h.ArgErr()
+ tag, ok := tlsCertTags[certFilename]
+ if !ok {
+ // haven't seen this cert file yet, let's give it a tag
+ // and add a loader for it
+ tag = fmt.Sprintf("cert%d", len(tlsCertTags))
+ fileLoader = append(fileLoader, caddytls.CertKeyFilePair{
+ Certificate: certFilename,
+ Key: keyFilename,
+ Tags: []string{tag},
+ })
+ // remember this for next time we see this cert file
+ tlsCertTags[certFilename] = tag
}
+ certSelector.AnyTag = append(certSelector.AnyTag, tag)
- var hasBlock bool
- for nesting := h.Nesting(); h.NextBlock(nesting); {
- hasBlock = true
+ default:
+ return nil, h.ArgErr()
+ }
+
+ var hasBlock bool
+ for h.NextBlock(0) {
+ hasBlock = true
- switch h.Val() {
- case "protocols":
- args := h.RemainingArgs()
- if len(args) == 0 {
- return nil, h.Errf("protocols requires one or two arguments")
+ switch h.Val() {
+ case "protocols":
+ args := h.RemainingArgs()
+ if len(args) == 0 {
+ return nil, h.Errf("protocols requires one or two arguments")
+ }
+ if len(args) > 0 {
+ if _, ok := caddytls.SupportedProtocols[args[0]]; !ok {
+ return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[0])
}
- if len(args) > 0 {
- if _, ok := caddytls.SupportedProtocols[args[0]]; !ok {
- return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[0])
- }
- cp.ProtocolMin = args[0]
+ cp.ProtocolMin = args[0]
+ }
+ if len(args) > 1 {
+ if _, ok := caddytls.SupportedProtocols[args[1]]; !ok {
+ return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[1])
}
- if len(args) > 1 {
- if _, ok := caddytls.SupportedProtocols[args[1]]; !ok {
- return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[1])
- }
- cp.ProtocolMax = args[1]
+ cp.ProtocolMax = args[1]
+ }
+
+ case "ciphers":
+ for h.NextArg() {
+ if !caddytls.CipherSuiteNameSupported(h.Val()) {
+ return nil, h.Errf("wrong cipher suite name or cipher suite not supported: '%s'", h.Val())
}
+ cp.CipherSuites = append(cp.CipherSuites, h.Val())
+ }
- case "ciphers":
- for h.NextArg() {
- if !caddytls.CipherSuiteNameSupported(h.Val()) {
- return nil, h.Errf("wrong cipher suite name or cipher suite not supported: '%s'", h.Val())
- }
- cp.CipherSuites = append(cp.CipherSuites, h.Val())
+ case "curves":
+ for h.NextArg() {
+ if _, ok := caddytls.SupportedCurves[h.Val()]; !ok {
+ return nil, h.Errf("Wrong curve name or curve not supported: '%s'", h.Val())
}
+ cp.Curves = append(cp.Curves, h.Val())
+ }
- case "curves":
- for h.NextArg() {
- if _, ok := caddytls.SupportedCurves[h.Val()]; !ok {
- return nil, h.Errf("Wrong curve name or curve not supported: '%s'", h.Val())
+ case "client_auth":
+ cp.ClientAuthentication = &caddytls.ClientAuthentication{}
+ for nesting := h.Nesting(); h.NextBlock(nesting); {
+ subdir := h.Val()
+ switch subdir {
+ case "verifier":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
}
- cp.Curves = append(cp.Curves, h.Val())
- }
- case "client_auth":
- cp.ClientAuthentication = &caddytls.ClientAuthentication{}
- for nesting := h.Nesting(); h.NextBlock(nesting); {
- subdir := h.Val()
- switch subdir {
- case "verifier":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
+ vType := h.Val()
+ modID := "tls.client_auth." + vType
+ unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
+ if err != nil {
+ return nil, err
+ }
- vType := h.Val()
- modID := "tls.client_auth." + vType
- unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
- if err != nil {
- return nil, err
- }
+ _, ok := unm.(caddytls.ClientCertificateVerifier)
+ if !ok {
+ return nil, h.Dispenser.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
+ }
- _, ok := unm.(caddytls.ClientCertificateVerifier)
- if !ok {
- return nil, h.Dispenser.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
- }
+ cp.ClientAuthentication.VerifiersRaw = append(cp.ClientAuthentication.VerifiersRaw, caddyconfig.JSONModuleObject(unm, "verifier", vType, h.warnings))
+ case "mode":
+ if !h.Args(&cp.ClientAuthentication.Mode) {
+ return nil, h.ArgErr()
+ }
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
- cp.ClientAuthentication.VerifiersRaw = append(cp.ClientAuthentication.VerifiersRaw, caddyconfig.JSONModuleObject(unm, "verifier", vType, h.warnings))
- case "mode":
- if !h.Args(&cp.ClientAuthentication.Mode) {
- return nil, h.ArgErr()
- }
- if h.NextArg() {
- return nil, h.ArgErr()
- }
+ case "trusted_ca_cert",
+ "trusted_leaf_cert":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ if subdir == "trusted_ca_cert" {
+ cp.ClientAuthentication.TrustedCACerts = append(cp.ClientAuthentication.TrustedCACerts, h.Val())
+ } else {
+ cp.ClientAuthentication.TrustedLeafCerts = append(cp.ClientAuthentication.TrustedLeafCerts, h.Val())
+ }
- case "trusted_ca_cert",
- "trusted_leaf_cert":
- if !h.NextArg() {
- return nil, h.ArgErr()
+ case "trusted_ca_cert_file",
+ "trusted_leaf_cert_file":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ filename := h.Val()
+ certDataPEM, err := os.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ // while block is not nil, we have more certificates in the file
+ for block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {
+ if block.Type != "CERTIFICATE" {
+ return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
}
- if subdir == "trusted_ca_cert" {
- cp.ClientAuthentication.TrustedCACerts = append(cp.ClientAuthentication.TrustedCACerts, h.Val())
+ if subdir == "trusted_ca_cert_file" {
+ cp.ClientAuthentication.TrustedCACerts = append(
+ cp.ClientAuthentication.TrustedCACerts,
+ base64.StdEncoding.EncodeToString(block.Bytes),
+ )
} else {
- cp.ClientAuthentication.TrustedLeafCerts = append(cp.ClientAuthentication.TrustedLeafCerts, h.Val())
- }
-
- case "trusted_ca_cert_file",
- "trusted_leaf_cert_file":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- filename := h.Val()
- certDataPEM, err := os.ReadFile(filename)
- if err != nil {
- return nil, err
+ cp.ClientAuthentication.TrustedLeafCerts = append(
+ cp.ClientAuthentication.TrustedLeafCerts,
+ base64.StdEncoding.EncodeToString(block.Bytes),
+ )
}
- // while block is not nil, we have more certificates in the file
- for block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {
- if block.Type != "CERTIFICATE" {
- return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
- }
- if subdir == "trusted_ca_cert_file" {
- cp.ClientAuthentication.TrustedCACerts = append(
- cp.ClientAuthentication.TrustedCACerts,
- base64.StdEncoding.EncodeToString(block.Bytes),
- )
- } else {
- cp.ClientAuthentication.TrustedLeafCerts = append(
- cp.ClientAuthentication.TrustedLeafCerts,
- base64.StdEncoding.EncodeToString(block.Bytes),
- )
- }
- }
- // if we decoded nothing, return an error
- if len(cp.ClientAuthentication.TrustedCACerts) == 0 && len(cp.ClientAuthentication.TrustedLeafCerts) == 0 {
- return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
- }
-
- default:
- return nil, h.Errf("unknown subdirective for client_auth: %s", subdir)
}
- }
+ // if we decoded nothing, return an error
+ if len(cp.ClientAuthentication.TrustedCACerts) == 0 && len(cp.ClientAuthentication.TrustedLeafCerts) == 0 {
+ return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
+ }
- case "alpn":
- args := h.RemainingArgs()
- if len(args) == 0 {
- return nil, h.ArgErr()
+ default:
+ return nil, h.Errf("unknown subdirective for client_auth: %s", subdir)
}
- cp.ALPN = args
+ }
- case "load":
- folderLoader = append(folderLoader, h.RemainingArgs()...)
+ case "alpn":
+ args := h.RemainingArgs()
+ if len(args) == 0 {
+ return nil, h.ArgErr()
+ }
+ cp.ALPN = args
- case "ca":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- acmeIssuer.CA = arg[0]
+ case "load":
+ folderLoader = append(folderLoader, h.RemainingArgs()...)
- case "key_type":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- keyType = arg[0]
+ case "ca":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ acmeIssuer.CA = arg[0]
- case "eab":
- arg := h.RemainingArgs()
- if len(arg) != 2 {
- return nil, h.ArgErr()
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- acmeIssuer.ExternalAccount = &acme.EAB{
- KeyID: arg[0],
- MACKey: arg[1],
- }
+ case "key_type":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ keyType = arg[0]
- case "issuer":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- modName := h.Val()
- modID := "tls.issuance." + modName
- unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
- if err != nil {
- return nil, err
- }
- issuer, ok := unm.(certmagic.Issuer)
- if !ok {
- return nil, h.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
- }
- issuers = append(issuers, issuer)
+ case "eab":
+ arg := h.RemainingArgs()
+ if len(arg) != 2 {
+ return nil, h.ArgErr()
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ acmeIssuer.ExternalAccount = &acme.EAB{
+ KeyID: arg[0],
+ MACKey: arg[1],
+ }
- case "get_certificate":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- modName := h.Val()
- modID := "tls.get_certificate." + modName
- unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
- if err != nil {
- return nil, err
- }
- certManager, ok := unm.(certmagic.Manager)
- if !ok {
- return nil, h.Errf("module %s (%T) is not a certmagic.CertificateManager", modID, unm)
- }
- certManagers = append(certManagers, certManager)
+ case "issuer":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ modName := h.Val()
+ modID := "tls.issuance." + modName
+ unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
+ if err != nil {
+ return nil, err
+ }
+ issuer, ok := unm.(certmagic.Issuer)
+ if !ok {
+ return nil, h.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
+ }
+ issuers = append(issuers, issuer)
- case "dns":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- provName := h.Val()
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- if acmeIssuer.Challenges == nil {
- acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
- }
- if acmeIssuer.Challenges.DNS == nil {
- acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
- }
- modID := "dns.providers." + provName
- unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
- if err != nil {
- return nil, err
- }
- acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
+ case "get_certificate":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ modName := h.Val()
+ modID := "tls.get_certificate." + modName
+ unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
+ if err != nil {
+ return nil, err
+ }
+ certManager, ok := unm.(certmagic.Manager)
+ if !ok {
+ return nil, h.Errf("module %s (%T) is not a certmagic.CertificateManager", modID, unm)
+ }
+ certManagers = append(certManagers, certManager)
- case "resolvers":
- args := h.RemainingArgs()
- if len(args) == 0 {
- return nil, h.ArgErr()
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- if acmeIssuer.Challenges == nil {
- acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
- }
- if acmeIssuer.Challenges.DNS == nil {
- acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
- }
- acmeIssuer.Challenges.DNS.Resolvers = args
+ case "dns":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ provName := h.Val()
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ if acmeIssuer.Challenges == nil {
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ }
+ if acmeIssuer.Challenges.DNS == nil {
+ acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
+ }
+ modID := "dns.providers." + provName
+ unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
+ if err != nil {
+ return nil, err
+ }
+ acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
- case "propagation_delay":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- delayStr := arg[0]
- delay, err := caddy.ParseDuration(delayStr)
- if err != nil {
- return nil, h.Errf("invalid propagation_delay duration %s: %v", delayStr, err)
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- if acmeIssuer.Challenges == nil {
- acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
- }
- if acmeIssuer.Challenges.DNS == nil {
- acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
- }
- acmeIssuer.Challenges.DNS.PropagationDelay = caddy.Duration(delay)
+ case "resolvers":
+ args := h.RemainingArgs()
+ if len(args) == 0 {
+ return nil, h.ArgErr()
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ if acmeIssuer.Challenges == nil {
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ }
+ if acmeIssuer.Challenges.DNS == nil {
+ acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
+ }
+ acmeIssuer.Challenges.DNS.Resolvers = args
- case "propagation_timeout":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- timeoutStr := arg[0]
- var timeout time.Duration
- if timeoutStr == "-1" {
- timeout = time.Duration(-1)
- } else {
- var err error
- timeout, err = caddy.ParseDuration(timeoutStr)
- if err != nil {
- return nil, h.Errf("invalid propagation_timeout duration %s: %v", timeoutStr, err)
- }
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- if acmeIssuer.Challenges == nil {
- acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
- }
- if acmeIssuer.Challenges.DNS == nil {
- acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
- }
- acmeIssuer.Challenges.DNS.PropagationTimeout = caddy.Duration(timeout)
+ case "propagation_delay":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ delayStr := arg[0]
+ delay, err := caddy.ParseDuration(delayStr)
+ if err != nil {
+ return nil, h.Errf("invalid propagation_delay duration %s: %v", delayStr, err)
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ if acmeIssuer.Challenges == nil {
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ }
+ if acmeIssuer.Challenges.DNS == nil {
+ acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
+ }
+ acmeIssuer.Challenges.DNS.PropagationDelay = caddy.Duration(delay)
- case "dns_ttl":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- ttlStr := arg[0]
- ttl, err := caddy.ParseDuration(ttlStr)
+ case "propagation_timeout":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ timeoutStr := arg[0]
+ var timeout time.Duration
+ if timeoutStr == "-1" {
+ timeout = time.Duration(-1)
+ } else {
+ var err error
+ timeout, err = caddy.ParseDuration(timeoutStr)
if err != nil {
- return nil, h.Errf("invalid dns_ttl duration %s: %v", ttlStr, err)
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- if acmeIssuer.Challenges == nil {
- acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ return nil, h.Errf("invalid propagation_timeout duration %s: %v", timeoutStr, err)
}
- if acmeIssuer.Challenges.DNS == nil {
- acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
- }
- acmeIssuer.Challenges.DNS.TTL = caddy.Duration(ttl)
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ if acmeIssuer.Challenges == nil {
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ }
+ if acmeIssuer.Challenges.DNS == nil {
+ acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
+ }
+ acmeIssuer.Challenges.DNS.PropagationTimeout = caddy.Duration(timeout)
- case "dns_challenge_override_domain":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- if acmeIssuer.Challenges == nil {
- acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
- }
- if acmeIssuer.Challenges.DNS == nil {
- acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
- }
- acmeIssuer.Challenges.DNS.OverrideDomain = arg[0]
+ case "dns_ttl":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ ttlStr := arg[0]
+ ttl, err := caddy.ParseDuration(ttlStr)
+ if err != nil {
+ return nil, h.Errf("invalid dns_ttl duration %s: %v", ttlStr, err)
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ if acmeIssuer.Challenges == nil {
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ }
+ if acmeIssuer.Challenges.DNS == nil {
+ acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
+ }
+ acmeIssuer.Challenges.DNS.TTL = caddy.Duration(ttl)
- case "ca_root":
- arg := h.RemainingArgs()
- if len(arg) != 1 {
- return nil, h.ArgErr()
- }
- if acmeIssuer == nil {
- acmeIssuer = new(caddytls.ACMEIssuer)
- }
- acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, arg[0])
+ case "dns_challenge_override_domain":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ if acmeIssuer.Challenges == nil {
+ acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
+ }
+ if acmeIssuer.Challenges.DNS == nil {
+ acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
+ }
+ acmeIssuer.Challenges.DNS.OverrideDomain = arg[0]
- case "on_demand":
- if h.NextArg() {
- return nil, h.ArgErr()
- }
- onDemand = true
+ case "ca_root":
+ arg := h.RemainingArgs()
+ if len(arg) != 1 {
+ return nil, h.ArgErr()
+ }
+ if acmeIssuer == nil {
+ acmeIssuer = new(caddytls.ACMEIssuer)
+ }
+ acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, arg[0])
- case "reuse_private_keys":
- if h.NextArg() {
- return nil, h.ArgErr()
- }
- reusePrivateKeys = true
+ case "on_demand":
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ onDemand = true
- case "insecure_secrets_log":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- cp.InsecureSecretsLog = h.Val()
+ case "reuse_private_keys":
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ reusePrivateKeys = true
- default:
- return nil, h.Errf("unknown subdirective: %s", h.Val())
+ case "insecure_secrets_log":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
}
- }
+ cp.InsecureSecretsLog = h.Val()
- // a naked tls directive is not allowed
- if len(firstLine) == 0 && !hasBlock {
- return nil, h.ArgErr()
+ default:
+ return nil, h.Errf("unknown subdirective: %s", h.Val())
}
}
+ // a naked tls directive is not allowed
+ if len(firstLine) == 0 && !hasBlock {
+ return nil, h.ArgErr()
+ }
+
// begin building the final config values
configVals := []ConfigValue{}
@@ -646,10 +643,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
//
// root [<matcher>] <path>
func parseRoot(h Helper) ([]ConfigValue, error) {
- // consume directive name
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
+ h.Next() // consume directive name
// count the tokens to determine what to do
argsCount := h.CountRemainingArgs()
@@ -673,11 +667,8 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
if err != nil {
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
if !h.NextArg() {
return nil, h.ArgErr()
@@ -690,17 +681,14 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
//
// fs <filesystem>
func parseFilesystem(h Helper) (caddyhttp.MiddlewareHandler, error) {
- var name string
- for h.Next() {
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- name = h.Val()
- if h.NextArg() {
- return nil, h.ArgErr()
- }
+ h.Next() // consume directive name
+ if !h.NextArg() {
+ return nil, h.ArgErr()
}
- return caddyhttp.VarsMiddleware{"fs": name}, nil
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ return caddyhttp.VarsMiddleware{"fs": h.Val()}, nil
}
// 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
// with JS and a meta tag).
func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
- if !h.Next() {
- return nil, h.ArgErr()
- }
-
+ h.Next() // consume directive name
if !h.NextArg() {
return nil, h.ArgErr()
}
@@ -739,8 +724,10 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
switch code {
case "permanent":
code = "301"
+
case "temporary", "":
code = "302"
+
case "html":
// 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.
@@ -758,6 +745,7 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo)
hdr = http.Header{"Content-Type": []string{"text/html; charset=utf-8"}}
code = "200" // don't redirect non-browser clients
+
default:
// Allow placeholders for the code
if strings.HasPrefix(code, "{") {
@@ -796,10 +784,7 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
func parseRespond(h Helper) (caddyhttp.MiddlewareHandler, error) {
sr := new(caddyhttp.StaticResponse)
err := sr.UnmarshalCaddyfile(h.Dispenser)
- if err != nil {
- return nil, err
- }
- return sr, nil
+ return sr, err
}
// parseAbort parses the abort directive.
@@ -815,10 +800,7 @@ func parseAbort(h Helper) (caddyhttp.MiddlewareHandler, error) {
func parseError(h Helper) (caddyhttp.MiddlewareHandler, error) {
se := new(caddyhttp.StaticError)
err := se.UnmarshalCaddyfile(h.Dispenser)
- if err != nil {
- return nil, err
- }
- return se, nil
+ return se, err
}
// parseRoute parses the route directive.
@@ -844,11 +826,11 @@ func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
}
func parseHandleErrors(h Helper) ([]ConfigValue, error) {
- h.Next()
- args := h.RemainingArgs()
+ h.Next() // consume directive name
+
expression := ""
+ args := h.RemainingArgs()
if len(args) > 0 {
- expression = ""
codes := []string{}
for _, val := range args {
if len(val) != 3 {
@@ -951,184 +933,185 @@ func parseLog(h Helper) ([]ConfigValue, error) {
// level. The parseAsGlobalOption parameter is used to distinguish any differing logic
// between the two.
func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue, error) {
+ h.Next() // consume option name
+
// When the globalLogNames parameter is passed in, we make
// modifications to the parsing behavior.
parseAsGlobalOption := globalLogNames != nil
var configValues []ConfigValue
- for h.Next() {
- // Logic below expects that a name is always present when a
- // global option is being parsed; or an optional override
- // is supported for access logs.
- var logName string
- if parseAsGlobalOption {
- if h.NextArg() {
- logName = h.Val()
+ // Logic below expects that a name is always present when a
+ // global option is being parsed; or an optional override
+ // is supported for access logs.
+ var logName string
- // Only a single argument is supported.
- if h.NextArg() {
- return nil, h.ArgErr()
- }
- } else {
- // If there is no log name specified, we
- // reference the default logger. See the
- // setupNewDefault function in the logging
- // package for where this is configured.
- logName = caddy.DefaultLoggerName
- }
+ if parseAsGlobalOption {
+ if h.NextArg() {
+ logName = h.Val()
- // Verify this name is unused.
- _, used := globalLogNames[logName]
- if used {
- return nil, h.Err("duplicate global log option for: " + logName)
+ // Only a single argument is supported.
+ if h.NextArg() {
+ return nil, h.ArgErr()
}
- globalLogNames[logName] = struct{}{}
} else {
- // An optional override of the logger name can be provided;
- // otherwise a default will be used, like "log0", "log1", etc.
- if h.NextArg() {
- logName = h.Val()
+ // If there is no log name specified, we
+ // reference the default logger. See the
+ // setupNewDefault function in the logging
+ // package for where this is configured.
+ logName = caddy.DefaultLoggerName
+ }
- // Only a single argument is supported.
- if h.NextArg() {
- return nil, h.ArgErr()
- }
- }
+ // Verify this name is unused.
+ _, used := globalLogNames[logName]
+ if used {
+ return nil, h.Err("duplicate global log option for: " + logName)
}
+ globalLogNames[logName] = struct{}{}
+ } else {
+ // An optional override of the logger name can be provided;
+ // otherwise a default will be used, like "log0", "log1", etc.
+ if h.NextArg() {
+ logName = h.Val()
- cl := new(caddy.CustomLog)
+ // Only a single argument is supported.
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ }
+ }
- // allow overriding the current site block's hostnames for this logger;
- // this is useful for setting up loggers per subdomain in a site block
- // with a wildcard domain
- customHostnames := []string{}
+ cl := new(caddy.CustomLog)
- for h.NextBlock(0) {
- switch h.Val() {
- case "hostnames":
- if parseAsGlobalOption {
- return nil, h.Err("hostnames is not allowed in the log global options")
- }
- args := h.RemainingArgs()
- if len(args) == 0 {
- return nil, h.ArgErr()
- }
- customHostnames = append(customHostnames, args...)
+ // allow overriding the current site block's hostnames for this logger;
+ // this is useful for setting up loggers per subdomain in a site block
+ // with a wildcard domain
+ customHostnames := []string{}
- case "output":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- moduleName := h.Val()
-
- // can't use the usual caddyfile.Unmarshaler flow with the
- // standard writers because they are in the caddy package
- // (because they are the default) and implementing that
- // interface there would unfortunately create circular import
- var wo caddy.WriterOpener
- switch moduleName {
- case "stdout":
- wo = caddy.StdoutWriter{}
- case "stderr":
- wo = caddy.StderrWriter{}
- case "discard":
- wo = caddy.DiscardWriter{}
- default:
- modID := "caddy.logging.writers." + moduleName
- unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
- if err != nil {
- return nil, err
- }
- var ok bool
- wo, ok = unm.(caddy.WriterOpener)
- if !ok {
- return nil, h.Errf("module %s (%T) is not a WriterOpener", modID, unm)
- }
- }
- cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
+ for h.NextBlock(0) {
+ switch h.Val() {
+ case "hostnames":
+ if parseAsGlobalOption {
+ return nil, h.Err("hostnames is not allowed in the log global options")
+ }
+ args := h.RemainingArgs()
+ if len(args) == 0 {
+ return nil, h.ArgErr()
+ }
+ customHostnames = append(customHostnames, args...)
- case "format":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- moduleName := h.Val()
- moduleID := "caddy.logging.encoders." + moduleName
- unm, err := caddyfile.UnmarshalModule(h.Dispenser, moduleID)
+ case "output":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ moduleName := h.Val()
+
+ // can't use the usual caddyfile.Unmarshaler flow with the
+ // standard writers because they are in the caddy package
+ // (because they are the default) and implementing that
+ // interface there would unfortunately create circular import
+ var wo caddy.WriterOpener
+ switch moduleName {
+ case "stdout":
+ wo = caddy.StdoutWriter{}
+ case "stderr":
+ wo = caddy.StderrWriter{}
+ case "discard":
+ wo = caddy.DiscardWriter{}
+ default:
+ modID := "caddy.logging.writers." + moduleName
+ unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
if err != nil {
return nil, err
}
- enc, ok := unm.(zapcore.Encoder)
+ var ok bool
+ wo, ok = unm.(caddy.WriterOpener)
if !ok {
- return nil, h.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
+ return nil, h.Errf("module %s (%T) is not a WriterOpener", modID, unm)
}
- cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings)
+ }
+ cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
- case "level":
- if !h.NextArg() {
- return nil, h.ArgErr()
- }
- cl.Level = h.Val()
- if h.NextArg() {
- return nil, h.ArgErr()
- }
+ case "format":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ moduleName := h.Val()
+ moduleID := "caddy.logging.encoders." + moduleName
+ unm, err := caddyfile.UnmarshalModule(h.Dispenser, moduleID)
+ if err != nil {
+ return nil, err
+ }
+ enc, ok := unm.(zapcore.Encoder)
+ if !ok {
+ return nil, h.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
+ }
+ cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings)
- case "include":
- if !parseAsGlobalOption {
- return nil, h.Err("include is not allowed in the log directive")
- }
- for h.NextArg() {
- cl.Include = append(cl.Include, h.Val())
- }
+ case "level":
+ if !h.NextArg() {
+ return nil, h.ArgErr()
+ }
+ cl.Level = h.Val()
+ if h.NextArg() {
+ return nil, h.ArgErr()
+ }
- case "exclude":
- if !parseAsGlobalOption {
- return nil, h.Err("exclude is not allowed in the log directive")
- }
- for h.NextArg() {
- cl.Exclude = append(cl.Exclude, h.Val())
- }
+ case "include":
+ if !parseAsGlobalOption {
+ return nil, h.Err("include is not allowed in the log directive")
+ }
+ for h.NextArg() {
+ cl.Include = append(cl.Include, h.Val())
+ }
- default:
- return nil, h.Errf("unrecognized subdirective: %s", h.Val())
+ case "exclude":
+ if !parseAsGlobalOption {
+ return nil, h.Err("exclude is not allowed in the log directive")
+ }
+ for h.NextArg() {
+ cl.Exclude = append(cl.Exclude, h.Val())
}
+
+ default:
+ return nil, h.Errf("unrecognized subdirective: %s", h.Val())
}
+ }
- var val namedCustomLog
- val.hostnames = customHostnames
+ var val namedCustomLog
+ val.hostnames = customHostnames
- isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))
+ isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))
- // Skip handling of empty logging configs
+ // Skip handling of empty logging configs
- if parseAsGlobalOption {
- // Use indicated name for global log options
+ if parseAsGlobalOption {
+ // Use indicated name for global log options
+ val.name = logName
+ } else {
+ if logName != "" {
val.name = logName
- } else {
- if logName != "" {
- val.name = logName
- } else if !isEmptyConfig {
- // Construct a log name for server log streams
- logCounter, ok := h.State["logCounter"].(int)
- if !ok {
- logCounter = 0
- }
- val.name = fmt.Sprintf("log%d", logCounter)
- logCounter++
- h.State["logCounter"] = logCounter
- }
- if val.name != "" {
- cl.Include = []string{"http.log.access." + val.name}
+ } else if !isEmptyConfig {
+ // Construct a log name for server log streams
+ logCounter, ok := h.State["logCounter"].(int)
+ if !ok {
+ logCounter = 0
}
+ val.name = fmt.Sprintf("log%d", logCounter)
+ logCounter++
+ h.State["logCounter"] = logCounter
}
- if !isEmptyConfig {
- val.log = cl
+ if val.name != "" {
+ cl.Include = []string{"http.log.access." + val.name}
}
- configValues = append(configValues, ConfigValue{
- Class: "custom_log",
- Value: val,
- })
}
+ if !isEmptyConfig {
+ val.log = cl
+ }
+ configValues = append(configValues, ConfigValue{
+ Class: "custom_log",
+ Value: val,
+ })
return configValues, nil
}
@@ -1136,10 +1119,9 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
//
// skip_log [<matcher>]
func parseSkipLog(h Helper) (caddyhttp.MiddlewareHandler, error) {
- for h.Next() {
- if h.NextArg() {
- return nil, h.ArgErr()
- }
+ h.Next() // consume directive name
+ if h.NextArg() {
+ return nil, h.ArgErr()
}
return caddyhttp.VarsMiddleware{"skip_log": true}, nil
}
diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go
index 58da2bd79..6e5241c7f 100644
--- a/caddyconfig/httpcaddyfile/directives.go
+++ b/caddyconfig/httpcaddyfile/directives.go
@@ -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
// fields are copied, so typically maps are shared with this new instance.
func (h Helper) WithDispenser(d *caddyfile.Dispenser) Helper {
diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go
index 066df3014..54e781119 100644
--- a/caddyconfig/httpcaddyfile/httptype.go
+++ b/caddyconfig/httpcaddyfile/httptype.go
@@ -1381,68 +1381,73 @@ func (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.Mod
}
func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.ModuleMap) error {
- for d.Next() {
- // this is the "name" for "named matchers"
- definitionName := d.Val()
+ d.Next() // advance to the first token
- if _, ok := matchers[definitionName]; ok {
- return fmt.Errorf("matcher is defined more than once: %s", definitionName)
+ // this is the "name" for "named matchers"
+ definitionName := d.Val()
+
+ if _, ok := matchers[definitionName]; ok {
+ return fmt.Errorf("matcher is defined more than once: %s", definitionName)
+ }
+ matchers[definitionName] = make(caddy.ModuleMap)
+
+ // given a matcher name and the tokens following it, parse
+ // the tokens as a matcher module and record it
+ makeMatcher := func(matcherName string, tokens []caddyfile.Token) error {
+ mod, err := caddy.GetModule("http.matchers." + matcherName)
+ if err != nil {
+ return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
}
- matchers[definitionName] = make(caddy.ModuleMap)
+ unm, ok := mod.New().(caddyfile.Unmarshaler)
+ if !ok {
+ return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
+ }
+ err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
+ if err != nil {
+ return err
+ }
+ rm, ok := unm.(caddyhttp.RequestMatcher)
+ if !ok {
+ return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
+ }
+ matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
+ return nil
+ }
- // given a matcher name and the tokens following it, parse
- // the tokens as a matcher module and record it
- makeMatcher := func(matcherName string, tokens []caddyfile.Token) error {
- mod, err := caddy.GetModule("http.matchers." + matcherName)
- if err != nil {
- return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
- }
- unm, ok := mod.New().(caddyfile.Unmarshaler)
- if !ok {
- return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
- }
- err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
+ // 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() {
+ // 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 {
return err
}
- rm, ok := unm.(caddyhttp.RequestMatcher)
- if !ok {
- return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
- }
- 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()
- }
+ // 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
- }
+ // 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
diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go
index ba1896b6b..fa447f8dc 100644
--- a/caddyconfig/httpcaddyfile/options.go
+++ b/caddyconfig/httpcaddyfile/options.go
@@ -62,105 +62,103 @@ func init() {
func parseOptTrue(d *caddyfile.Dispenser, _ any) (any, error) { return true, nil }
func parseOptHTTPPort(d *caddyfile.Dispenser, _ any) (any, error) {
+ d.Next() // consume option name
var httpPort int
- for d.Next() {
- var httpPortStr string
- if !d.AllArgs(&httpPortStr) {
- return 0, d.ArgErr()
- }
- var err error
- httpPort, err = strconv.Atoi(httpPortStr)
- if err != nil {
- return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err)
- }
+ var httpPortStr string
+ if !d.AllArgs(&httpPortStr) {
+ return 0, d.ArgErr()
+ }
+ var err error
+ httpPort, err = strconv.Atoi(httpPortStr)
+ if err != nil {
+ return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err)
}
return httpPort, nil
}
func parseOptHTTPSPort(d *caddyfile.Dispenser, _ any) (any, error) {
+ d.Next() // consume option name
var httpsPort int
- for d.Next() {
- var httpsPortStr string
- if !d.AllArgs(&httpsPortStr) {
- return 0, d.ArgErr()
- }
- var err error
- httpsPort, err = strconv.Atoi(httpsPortStr)
- if err != nil {
- return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err)
- }
+ var httpsPortStr string
+ if !d.AllArgs(&httpsPortStr) {
+ return 0, d.ArgErr()
+ }
+ var err error
+ httpsPort, err = strconv.Atoi(httpsPortStr)
+ if err != nil {
+ return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err)
}
return httpsPort, nil
}
func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) {
- newOrder := directiveOrder
+ d.Next() // consume option name
- for d.Next() {
- // get directive name
- if !d.Next() {
- return nil, d.ArgErr()
- }
- dirName := d.Val()
- if _, ok := registeredDirectives[dirName]; !ok {
- return nil, d.Errf("%s is not a registered directive", dirName)
- }
+ // get directive name
+ if !d.Next() {
+ return nil, d.ArgErr()
+ }
+ dirName := d.Val()
+ if _, ok := registeredDirectives[dirName]; !ok {
+ return nil, d.Errf("%s is not a registered directive", dirName)
+ }
- // get positional token
- if !d.Next() {
- return nil, d.ArgErr()
- }
- pos := d.Val()
+ // get positional token
+ if !d.Next() {
+ return nil, d.ArgErr()
+ }
+ pos := d.Val()
- // if directive exists, first remove it
- for i, d := range newOrder {
- if d == dirName {
- newOrder = append(newOrder[:i], newOrder[i+1:]...)
- break
- }
- }
+ newOrder := directiveOrder
- // act on the positional
- switch pos {
- case "first":
- newOrder = append([]string{dirName}, newOrder...)
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- directiveOrder = newOrder
- return newOrder, nil
- case "last":
- newOrder = append(newOrder, dirName)
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- directiveOrder = newOrder
- return newOrder, nil
- case "before":
- case "after":
- default:
- return nil, d.Errf("unknown positional '%s'", pos)
+ // if directive exists, first remove it
+ for i, d := range newOrder {
+ if d == dirName {
+ newOrder = append(newOrder[:i], newOrder[i+1:]...)
+ break
}
+ }
- // get name of other directive
- if !d.NextArg() {
+ // act on the positional
+ switch pos {
+ case "first":
+ newOrder = append([]string{dirName}, newOrder...)
+ if d.NextArg() {
return nil, d.ArgErr()
}
- otherDir := d.Val()
+ directiveOrder = newOrder
+ return newOrder, nil
+ case "last":
+ newOrder = append(newOrder, dirName)
if d.NextArg() {
return nil, d.ArgErr()
}
+ directiveOrder = newOrder
+ return newOrder, nil
+ case "before":
+ case "after":
+ default:
+ return nil, d.Errf("unknown positional '%s'", pos)
+ }
+
+ // get name of other directive
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ otherDir := d.Val()
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
- // insert directive into proper position
- for i, d := range newOrder {
- if d == otherDir {
- if pos == "before" {
- newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...)
- } else if pos == "after" {
- newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...)
- }
- break
+ // insert directive into proper position
+ for i, d := range newOrder {
+ if d == otherDir {
+ if pos == "before" {
+ newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...)
+ } else if pos == "after" {
+ newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...)
}
+ break
}
}
@@ -223,57 +221,58 @@ func parseOptACMEDNS(d *caddyfile.Dispenser, _ any) (any, error) {
func parseOptACMEEAB(d *caddyfile.Dispenser, _ any) (any, error) {
eab := new(acme.EAB)
- for d.Next() {
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "key_id":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- eab.KeyID = d.Val()
-
- case "mac_key":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- eab.MACKey = d.Val()
-
- default:
- return nil, d.Errf("unrecognized parameter '%s'", d.Val())
+ d.Next() // consume option name
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ for d.NextBlock(0) {
+ switch d.Val() {
+ case "key_id":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ eab.KeyID = d.Val()
+
+ case "mac_key":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
}
+ eab.MACKey = d.Val()
+
+ default:
+ return nil, d.Errf("unrecognized parameter '%s'", d.Val())
}
}
return eab, nil
}
func parseOptCertIssuer(d *caddyfile.Dispenser, existing any) (any, error) {
+ d.Next() // consume option name
+
var issuers []certmagic.Issuer
if existing != nil {
issuers = existing.([]certmagic.Issuer)
}
- for d.Next() { // consume option name
- if !d.Next() { // get issuer module name
- return nil, d.ArgErr()
- }
- modID := "tls.issuance." + d.Val()
- unm, err := caddyfile.UnmarshalModule(d, modID)
- if err != nil {
- return nil, err
- }
- iss, ok := unm.(certmagic.Issuer)
- if !ok {
- return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
- }
- issuers = append(issuers, iss)
+
+ // get issuer module name
+ if !d.Next() {
+ return nil, d.ArgErr()
+ }
+ modID := "tls.issuance." + d.Val()
+ unm, err := caddyfile.UnmarshalModule(d, modID)
+ if err != nil {
+ return nil, err
+ }
+ iss, ok := unm.(certmagic.Issuer)
+ if !ok {
+ return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
}
+ issuers = append(issuers, iss)
return issuers, nil
}
func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {
- d.Next() // consume parameter name
+ d.Next() // consume option name
if !d.Next() {
return "", d.ArgErr()
}
@@ -285,7 +284,7 @@ func parseOptSingleString(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()
if len(val) == 0 {
return "", d.ArgErr()
@@ -294,33 +293,33 @@ func parseOptStringList(d *caddyfile.Dispenser, _ any) (any, error) {
}
func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
+ d.Next() // consume option name
+
adminCfg := new(caddy.AdminConfig)
- for d.Next() {
- if d.NextArg() {
- listenAddress := d.Val()
- if listenAddress == "off" {
- adminCfg.Disabled = true
- if d.Next() { // Do not accept any remaining options including block
- return nil, d.Err("No more option is allowed after turning off admin config")
- }
- } else {
- adminCfg.Listen = listenAddress
- if d.NextArg() { // At most 1 arg is allowed
- return nil, d.ArgErr()
- }
+ if d.NextArg() {
+ listenAddress := d.Val()
+ if listenAddress == "off" {
+ adminCfg.Disabled = true
+ if d.Next() { // Do not accept any remaining options including block
+ return nil, d.Err("No more option is allowed after turning off admin config")
+ }
+ } else {
+ adminCfg.Listen = listenAddress
+ if d.NextArg() { // At most 1 arg is allowed
+ return nil, d.ArgErr()
}
}
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "enforce_origin":
- adminCfg.EnforceOrigin = true
+ }
+ for d.NextBlock(0) {
+ switch d.Val() {
+ case "enforce_origin":
+ adminCfg.EnforceOrigin = true
- case "origins":
- adminCfg.Origins = d.RemainingArgs()
+ case "origins":
+ adminCfg.Origins = d.RemainingArgs()
- default:
- return nil, d.Errf("unrecognized parameter '%s'", d.Val())
- }
+ default:
+ return nil, d.Errf("unrecognized parameter '%s'", d.Val())
}
}
if adminCfg.Listen == "" && !adminCfg.Disabled {
@@ -330,57 +329,57 @@ func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
}
func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) {
+ d.Next() // consume option name
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+
var ond *caddytls.OnDemandConfig
- for d.Next() {
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "ask":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- if ond == nil {
- ond = new(caddytls.OnDemandConfig)
- }
- ond.Ask = d.Val()
-
- case "interval":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, err
- }
- if ond == nil {
- ond = new(caddytls.OnDemandConfig)
- }
- if ond.RateLimit == nil {
- ond.RateLimit = new(caddytls.RateLimit)
- }
- ond.RateLimit.Interval = caddy.Duration(dur)
-
- case "burst":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- burst, err := strconv.Atoi(d.Val())
- if err != nil {
- return nil, err
- }
- if ond == nil {
- ond = new(caddytls.OnDemandConfig)
- }
- if ond.RateLimit == nil {
- ond.RateLimit = new(caddytls.RateLimit)
- }
- ond.RateLimit.Burst = burst
-
- default:
- return nil, d.Errf("unrecognized parameter '%s'", d.Val())
+ for d.NextBlock(0) {
+ switch d.Val() {
+ case "ask":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ if ond == nil {
+ ond = new(caddytls.OnDemandConfig)
+ }
+ ond.Ask = d.Val()
+
+ case "interval":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, err
}
+ if ond == nil {
+ ond = new(caddytls.OnDemandConfig)
+ }
+ if ond.RateLimit == nil {
+ ond.RateLimit = new(caddytls.RateLimit)
+ }
+ ond.RateLimit.Interval = caddy.Duration(dur)
+
+ case "burst":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ burst, err := strconv.Atoi(d.Val())
+ if err != nil {
+ return nil, err
+ }
+ if ond == nil {
+ ond = new(caddytls.OnDemandConfig)
+ }
+ if ond.RateLimit == nil {
+ ond.RateLimit = new(caddytls.RateLimit)
+ }
+ ond.RateLimit.Burst = burst
+
+ default:
+ return nil, d.Errf("unrecognized parameter '%s'", d.Val())
}
}
if ond == nil {
@@ -390,7 +389,7 @@ func parseOptOnDemand(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() {
return "", d.ArgErr()
}
@@ -405,7 +404,7 @@ func parseOptPersistConfig(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() {
return "", d.ArgErr()
}
diff --git a/caddyconfig/httpcaddyfile/pkiapp.go b/caddyconfig/httpcaddyfile/pkiapp.go
index b5c682187..c57263baf 100644
--- a/caddyconfig/httpcaddyfile/pkiapp.go
+++ b/caddyconfig/httpcaddyfile/pkiapp.go
@@ -48,124 +48,124 @@ func init() {
//
// When the CA ID is unspecified, 'local' is assumed.
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() {
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "ca":
- pkiCa := new(caddypki.CA)
+ pki := &caddypki.PKI{
+ CAs: make(map[string]*caddypki.CA),
+ }
+ for d.NextBlock(0) {
+ switch d.Val() {
+ case "ca":
+ pkiCa := new(caddypki.CA)
+ if d.NextArg() {
+ pkiCa.ID = d.Val()
if d.NextArg() {
- pkiCa.ID = d.Val()
- if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ }
+ if pkiCa.ID == "" {
+ pkiCa.ID = caddypki.DefaultCAID
+ }
+
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "name":
+ if !d.NextArg() {
return nil, d.ArgErr()
}
- }
- if pkiCa.ID == "" {
- pkiCa.ID = caddypki.DefaultCAID
- }
+ pkiCa.Name = d.Val()
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "name":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Name = d.Val()
+ case "root_cn":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ pkiCa.RootCommonName = d.Val()
- case "root_cn":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.RootCommonName = d.Val()
+ case "intermediate_cn":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ pkiCa.IntermediateCommonName = d.Val()
- case "intermediate_cn":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.IntermediateCommonName = d.Val()
+ case "intermediate_lifetime":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, err
+ }
+ pkiCa.IntermediateLifetime = caddy.Duration(dur)
- case "intermediate_lifetime":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, err
- }
- pkiCa.IntermediateLifetime = caddy.Duration(dur)
+ case "root":
+ if pkiCa.Root == nil {
+ pkiCa.Root = new(caddypki.KeyPair)
+ }
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "cert":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ pkiCa.Root.Certificate = d.Val()
- case "root":
- if pkiCa.Root == nil {
- pkiCa.Root = new(caddypki.KeyPair)
- }
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "cert":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Root.Certificate = d.Val()
-
- case "key":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Root.PrivateKey = d.Val()
-
- case "format":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Root.Format = d.Val()
-
- default:
- return nil, d.Errf("unrecognized pki ca root option '%s'", d.Val())
+ case "key":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
}
- }
+ pkiCa.Root.PrivateKey = d.Val()
- case "intermediate":
- if pkiCa.Intermediate == nil {
- pkiCa.Intermediate = new(caddypki.KeyPair)
- }
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "cert":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Intermediate.Certificate = d.Val()
-
- case "key":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Intermediate.PrivateKey = d.Val()
-
- case "format":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- pkiCa.Intermediate.Format = d.Val()
-
- default:
- return nil, d.Errf("unrecognized pki ca intermediate option '%s'", d.Val())
+ case "format":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
}
+ pkiCa.Root.Format = d.Val()
+
+ default:
+ return nil, d.Errf("unrecognized pki ca root option '%s'", d.Val())
}
+ }
- default:
- return nil, d.Errf("unrecognized pki ca option '%s'", d.Val())
+ case "intermediate":
+ if pkiCa.Intermediate == nil {
+ pkiCa.Intermediate = new(caddypki.KeyPair)
}
- }
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "cert":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ pkiCa.Intermediate.Certificate = d.Val()
- pki.CAs[pkiCa.ID] = pkiCa
+ case "key":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ pkiCa.Intermediate.PrivateKey = d.Val()
- default:
- return nil, d.Errf("unrecognized pki option '%s'", d.Val())
+ case "format":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ pkiCa.Intermediate.Format = d.Val()
+
+ default:
+ return nil, d.Errf("unrecognized pki ca intermediate option '%s'", d.Val())
+ }
+ }
+
+ default:
+ return nil, d.Errf("unrecognized pki ca option '%s'", d.Val())
+ }
}
+
+ pki.CAs[pkiCa.ID] = pkiCa
+
+ default:
+ return nil, d.Errf("unrecognized pki option '%s'", d.Val())
}
}
-
return pki, nil
}
diff --git a/caddyconfig/httpcaddyfile/serveroptions.go b/caddyconfig/httpcaddyfile/serveroptions.go
index c131a6417..62902b964 100644
--- a/caddyconfig/httpcaddyfile/serveroptions.go
+++ b/caddyconfig/httpcaddyfile/serveroptions.go
@@ -53,235 +53,235 @@ type serverOptions struct {
}
func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
+ d.Next() // consume option name
+
serverOpts := serverOptions{}
- for d.Next() {
+ if d.NextArg() {
+ serverOpts.ListenerAddress = d.Val()
if d.NextArg() {
- serverOpts.ListenerAddress = d.Val()
- if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ }
+ for d.NextBlock(0) {
+ switch d.Val() {
+ case "name":
+ if serverOpts.ListenerAddress == "" {
+ return nil, d.Errf("cannot set a name for a server without a listener address")
+ }
+ if !d.NextArg() {
return nil, d.ArgErr()
}
- }
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "name":
- if serverOpts.ListenerAddress == "" {
- return nil, d.Errf("cannot set a name for a server without a listener address")
+ serverOpts.Name = d.Val()
+
+ case "listener_wrappers":
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ modID := "caddy.listeners." + d.Val()
+ unm, err := caddyfile.UnmarshalModule(d, modID)
+ if err != nil {
+ return nil, err
}
- if !d.NextArg() {
- return nil, d.ArgErr()
+ listenerWrapper, ok := unm.(caddy.ListenerWrapper)
+ if !ok {
+ return nil, fmt.Errorf("module %s (%T) is not a listener wrapper", modID, unm)
}
- serverOpts.Name = d.Val()
+ jsonListenerWrapper := caddyconfig.JSONModuleObject(
+ listenerWrapper,
+ "wrapper",
+ listenerWrapper.(caddy.Module).CaddyModule().ID.Name(),
+ nil,
+ )
+ serverOpts.ListenerWrappersRaw = append(serverOpts.ListenerWrappersRaw, jsonListenerWrapper)
+ }
- case "listener_wrappers":
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- modID := "caddy.listeners." + d.Val()
- unm, err := caddyfile.UnmarshalModule(d, modID)
+ case "timeouts":
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "read_body":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
if err != nil {
- return nil, err
+ return nil, d.Errf("parsing read_body timeout duration: %v", err)
}
- listenerWrapper, ok := unm.(caddy.ListenerWrapper)
- if !ok {
- return nil, fmt.Errorf("module %s (%T) is not a listener wrapper", modID, unm)
+ serverOpts.ReadTimeout = caddy.Duration(dur)
+
+ case "read_header":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
}
- jsonListenerWrapper := caddyconfig.JSONModuleObject(
- listenerWrapper,
- "wrapper",
- listenerWrapper.(caddy.Module).CaddyModule().ID.Name(),
- nil,
- )
- serverOpts.ListenerWrappersRaw = append(serverOpts.ListenerWrappersRaw, jsonListenerWrapper)
- }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing read_header timeout duration: %v", err)
+ }
+ serverOpts.ReadHeaderTimeout = caddy.Duration(dur)
- case "timeouts":
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "read_body":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, d.Errf("parsing read_body timeout duration: %v", err)
- }
- serverOpts.ReadTimeout = caddy.Duration(dur)
-
- case "read_header":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, d.Errf("parsing read_header timeout duration: %v", err)
- }
- serverOpts.ReadHeaderTimeout = caddy.Duration(dur)
-
- case "write":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, d.Errf("parsing write timeout duration: %v", err)
- }
- serverOpts.WriteTimeout = caddy.Duration(dur)
-
- case "idle":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, d.Errf("parsing idle timeout duration: %v", err)
- }
- serverOpts.IdleTimeout = caddy.Duration(dur)
-
- default:
- return nil, d.Errf("unrecognized timeouts option '%s'", d.Val())
+ case "write":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
}
- }
- case "keepalive_interval":
- if !d.NextArg() {
- return nil, d.ArgErr()
- }
- dur, err := caddy.ParseDuration(d.Val())
- if err != nil {
- return nil, d.Errf("parsing keepalive interval duration: %v", err)
- }
- serverOpts.KeepAliveInterval = caddy.Duration(dur)
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing write timeout duration: %v", err)
+ }
+ serverOpts.WriteTimeout = caddy.Duration(dur)
- case "max_header_size":
- var sizeStr string
- if !d.AllArgs(&sizeStr) {
- return nil, d.ArgErr()
- }
- size, err := humanize.ParseBytes(sizeStr)
- if err != nil {
- return nil, d.Errf("parsing max_header_size: %v", err)
- }
- serverOpts.MaxHeaderBytes = int(size)
+ case "idle":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing idle timeout duration: %v", err)
+ }
+ serverOpts.IdleTimeout = caddy.Duration(dur)
- case "enable_full_duplex":
- if d.NextArg() {
- return nil, d.ArgErr()
+ default:
+ return nil, d.Errf("unrecognized timeouts option '%s'", d.Val())
}
- serverOpts.EnableFullDuplex = true
+ }
+ case "keepalive_interval":
+ if !d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ dur, err := caddy.ParseDuration(d.Val())
+ if err != nil {
+ return nil, d.Errf("parsing keepalive interval duration: %v", err)
+ }
+ serverOpts.KeepAliveInterval = caddy.Duration(dur)
- case "log_credentials":
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- serverOpts.ShouldLogCredentials = true
+ case "max_header_size":
+ var sizeStr string
+ if !d.AllArgs(&sizeStr) {
+ return nil, d.ArgErr()
+ }
+ size, err := humanize.ParseBytes(sizeStr)
+ if err != nil {
+ return nil, d.Errf("parsing max_header_size: %v", err)
+ }
+ serverOpts.MaxHeaderBytes = int(size)
- case "protocols":
- protos := d.RemainingArgs()
- for _, proto := range protos {
- if proto != "h1" && proto != "h2" && proto != "h2c" && proto != "h3" {
- return nil, d.Errf("unknown protocol '%s': expected h1, h2, h2c, or h3", proto)
- }
- if sliceContains(serverOpts.Protocols, proto) {
- return nil, d.Errf("protocol %s specified more than once", proto)
- }
- serverOpts.Protocols = append(serverOpts.Protocols, proto)
- }
- if nesting := d.Nesting(); d.NextBlock(nesting) {
- return nil, d.ArgErr()
- }
+ case "enable_full_duplex":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ serverOpts.EnableFullDuplex = true
- case "strict_sni_host":
- if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
- return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
- }
- boolVal := true
- if d.Val() == "insecure_off" {
- boolVal = false
- }
- serverOpts.StrictSNIHost = &boolVal
+ case "log_credentials":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ serverOpts.ShouldLogCredentials = true
- case "trusted_proxies":
- if !d.NextArg() {
- return nil, d.Err("trusted_proxies expects an IP range source module name as its first argument")
- }
- modID := "http.ip_sources." + d.Val()
- unm, err := caddyfile.UnmarshalModule(d, modID)
- if err != nil {
- return nil, err
+ case "protocols":
+ protos := d.RemainingArgs()
+ for _, proto := range protos {
+ if proto != "h1" && proto != "h2" && proto != "h2c" && proto != "h3" {
+ return nil, d.Errf("unknown protocol '%s': expected h1, h2, h2c, or h3", proto)
}
- source, ok := unm.(caddyhttp.IPRangeSource)
- if !ok {
- return nil, fmt.Errorf("module %s (%T) is not an IP range source", modID, unm)
+ if sliceContains(serverOpts.Protocols, proto) {
+ return nil, d.Errf("protocol %s specified more than once", proto)
}
- jsonSource := caddyconfig.JSONModuleObject(
- source,
- "source",
- source.(caddy.Module).CaddyModule().ID.Name(),
- nil,
- )
- serverOpts.TrustedProxiesRaw = jsonSource
+ serverOpts.Protocols = append(serverOpts.Protocols, proto)
+ }
+ if nesting := d.Nesting(); d.NextBlock(nesting) {
+ return nil, d.ArgErr()
+ }
+
+ case "strict_sni_host":
+ if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
+ return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
+ }
+ boolVal := true
+ if d.Val() == "insecure_off" {
+ boolVal = false
+ }
+ serverOpts.StrictSNIHost = &boolVal
+
+ case "trusted_proxies":
+ if !d.NextArg() {
+ return nil, d.Err("trusted_proxies expects an IP range source module name as its first argument")
+ }
+ modID := "http.ip_sources." + d.Val()
+ unm, err := caddyfile.UnmarshalModule(d, modID)
+ if err != nil {
+ return nil, err
+ }
+ source, ok := unm.(caddyhttp.IPRangeSource)
+ if !ok {
+ return nil, fmt.Errorf("module %s (%T) is not an IP range source", modID, unm)
+ }
+ jsonSource := caddyconfig.JSONModuleObject(
+ source,
+ "source",
+ source.(caddy.Module).CaddyModule().ID.Name(),
+ nil,
+ )
+ serverOpts.TrustedProxiesRaw = jsonSource
+
+ case "trusted_proxies_strict":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ serverOpts.TrustedProxiesStrict = 1
- case "trusted_proxies_strict":
- if d.NextArg() {
- return nil, d.ArgErr()
+ case "client_ip_headers":
+ headers := d.RemainingArgs()
+ for _, header := range headers {
+ if sliceContains(serverOpts.ClientIPHeaders, header) {
+ return nil, d.Errf("client IP header %s specified more than once", header)
}
- serverOpts.TrustedProxiesStrict = 1
+ serverOpts.ClientIPHeaders = append(serverOpts.ClientIPHeaders, header)
+ }
+ if nesting := d.Nesting(); d.NextBlock(nesting) {
+ return nil, d.ArgErr()
+ }
+
+ case "metrics":
+ if d.NextArg() {
+ return nil, d.ArgErr()
+ }
+ if nesting := d.Nesting(); d.NextBlock(nesting) {
+ return nil, d.ArgErr()
+ }
+ serverOpts.Metrics = new(caddyhttp.Metrics)
+
+ // TODO: DEPRECATED. (August 2022)
+ case "protocol":
+ caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol sub-option will be removed soon")
- case "client_ip_headers":
- headers := d.RemainingArgs()
- for _, header := range headers {
- if sliceContains(serverOpts.ClientIPHeaders, header) {
- return nil, d.Errf("client IP header %s specified more than once", header)
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ switch d.Val() {
+ case "allow_h2c":
+ caddy.Log().Named("caddyfile").Warn("DEPRECATED: allow_h2c will be removed soon; use protocols option instead")
+
+ if d.NextArg() {
+ return nil, d.ArgErr()
}
- serverOpts.ClientIPHeaders = append(serverOpts.ClientIPHeaders, header)
- }
- if nesting := d.Nesting(); d.NextBlock(nesting) {
- return nil, d.ArgErr()
- }
+ if sliceContains(serverOpts.Protocols, "h2c") {
+ return nil, d.Errf("protocol h2c already specified")
+ }
+ serverOpts.Protocols = append(serverOpts.Protocols, "h2c")
- case "metrics":
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- if nesting := d.Nesting(); d.NextBlock(nesting) {
- return nil, d.ArgErr()
- }
- serverOpts.Metrics = new(caddyhttp.Metrics)
-
- // TODO: DEPRECATED. (August 2022)
- case "protocol":
- caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol sub-option will be removed soon")
-
- for nesting := d.Nesting(); d.NextBlock(nesting); {
- switch d.Val() {
- case "allow_h2c":
- caddy.Log().Named("caddyfile").Warn("DEPRECATED: allow_h2c will be removed soon; use protocols option instead")
-
- if d.NextArg() {
- return nil, d.ArgErr()
- }
- if sliceContains(serverOpts.Protocols, "h2c") {
- return nil, d.Errf("protocol h2c already specified")
- }
- serverOpts.Protocols = append(serverOpts.Protocols, "h2c")
-
- case "strict_sni_host":
- caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol > strict_sni_host in this position will be removed soon; move up to the servers block instead")
-
- if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
- return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
- }
- boolVal := true
- if d.Val() == "insecure_off" {
- boolVal = false
- }
- serverOpts.StrictSNIHost = &boolVal
-
- default:
- return nil, d.Errf("unrecognized protocol option '%s'", d.Val())
+ case "strict_sni_host":
+ caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol > strict_sni_host in this position will be removed soon; move up to the servers block instead")
+
+ if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
+ return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
}
- }
+ boolVal := true
+ if d.Val() == "insecure_off" {
+ boolVal = false
+ }
+ serverOpts.StrictSNIHost = &boolVal
- default:
- return nil, d.Errf("unrecognized servers option '%s'", d.Val())
+ default:
+ return nil, d.Errf("unrecognized protocol option '%s'", d.Val())
+ }
}
+
+ default:
+ return nil, d.Errf("unrecognized servers option '%s'", d.Val())
}
}
return serverOpts, nil