@marcel91200 / caddy Mirror · read-only / commits / 750d0b83
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 12, 18:15 UTC

caddyfile: Normalize & flatten all unmarshalers (#6037)

Francis Lavoie committed Jan 23, 2024 at 19:36 UTC 750d0b83319ac0ea6b7f057b8270c19404c3d6fa
44 files changed +2887 -2874
caddyconfig/caddyfile/adapter.go
+14 -18
@@ -92,30 +92,26 @@ func FormattingDifference(filename string, body []byte) (caddyconfig.Warning, bo
92 }, true
93 }
94
95 -// Unmarshaler is a type that can unmarshal
96 -// Caddyfile tokens to set itself up for a
97 -// JSON encoding. The goal of an unmarshaler
98 -// is not to set itself up for actual use,
99 -// but to set itself up for being marshaled
100 -// into JSON. Caddyfile-unmarshaled values
101 -// will not be used directly; they will be
102 -// encoded as JSON and then used from that.
103 -// Implementations must be able to support
104 -// multiple segments (instances of their
105 -// directive or batch of tokens); typically
106 -// this means wrapping all token logic in
107 -// a loop: `for d.Next() { ... }`.
95 +// Unmarshaler is a type that can unmarshal Caddyfile tokens to
96 +// set itself up for a JSON encoding. The goal of an unmarshaler
97 +// is not to set itself up for actual use, but to set itself up for
98 +// being marshaled into JSON. Caddyfile-unmarshaled values will not
99 +// be used directly; they will be encoded as JSON and then used from
100 +// that. Implementations _may_ be able to support multiple segments
101 +// (instances of their directive or batch of tokens); typically this
102 +// means wrapping parsing logic in a loop: `for d.Next() { ... }`.
103 +// More commonly, only a single segment is supported, so a simple
104 +// `d.Next()` at the start should be used to consume the module
105 +// identifier token (directive name, etc).
106 type Unmarshaler interface {
107 UnmarshalCaddyfile(d *Dispenser) error
108 }
109
110 // ServerType is a type that can evaluate a Caddyfile and set up a caddy config.
111 type ServerType interface {
114 - // Setup takes the server blocks which
115 - // contain tokens, as well as options
116 - // (e.g. CLI flags) and creates a Caddy
117 - // config, along with any warnings or
118 - // an error.
112 + // Setup takes the server blocks which contain tokens,
113 + // as well as options (e.g. CLI flags) and creates a
114 + // Caddy config, along with any warnings or an error.
115 Setup([]ServerBlock, map[string]any) (*caddy.Config, []caddyconfig.Warning, error)
116 }
117
caddyconfig/httpcaddyfile/builtins.go
+534 -552
@@ -59,11 +59,8 @@ func init() {
59 //
60 // bind <addresses...>
61 func parseBind(h Helper) ([]ConfigValue, error) {
62 - var lnHosts []string
63 - for h.Next() {
64 - lnHosts = append(lnHosts, h.RemainingArgs()...)
65 - }
66 - return h.NewBindAddresses(lnHosts), nil
62 + h.Next() // consume directive name
63 + return []ConfigValue{{Class: "bind", Value: h.RemainingArgs()}}, nil
64 }
65
66 // parseTLS parses the tls directive. Syntax:
@@ -98,6 +95,8 @@ func parseBind(h Helper) ([]ConfigValue, error) {
95 // insecure_secrets_log <log_file>
96 // }
97 func parseTLS(h Helper) ([]ConfigValue, error) {
98 + h.Next() // consume directive name
99 +
100 cp := new(caddytls.ConnectionPolicy)
101 var fileLoader caddytls.FileLoader
102 var folderLoader caddytls.FolderLoader
@@ -110,423 +109,421 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
109 var onDemand bool
110 var reusePrivateKeys bool
111
113 - for h.Next() {
114 - // file certificate loader
115 - firstLine := h.RemainingArgs()
116 - switch len(firstLine) {
117 - case 0:
118 - case 1:
119 - if firstLine[0] == "internal" {
120 - internalIssuer = new(caddytls.InternalIssuer)
121 - } else if !strings.Contains(firstLine[0], "@") {
122 - return nil, h.Err("single argument must either be 'internal' or an email address")
123 - } else {
124 - if acmeIssuer == nil {
125 - acmeIssuer = new(caddytls.ACMEIssuer)
126 - }
127 - acmeIssuer.Email = firstLine[0]
128 - }
129 -
130 - case 2:
131 - certFilename := firstLine[0]
132 - keyFilename := firstLine[1]
133 -
134 - // tag this certificate so if multiple certs match, specifically
135 - // this one that the user has provided will be used, see #2588:
136 - // https://github.com/caddyserver/caddy/issues/2588 ... but we
137 - // must be careful about how we do this; being careless will
138 - // lead to failed handshakes
139 - //
140 - // we need to remember which cert files we've seen, since we
141 - // must load each cert only once; otherwise, they each get a
142 - // different tag... since a cert loaded twice has the same
143 - // bytes, it will overwrite the first one in the cache, and
144 - // only the last cert (and its tag) will survive, so any conn
145 - // policy that is looking for any tag other than the last one
146 - // to be loaded won't find it, and TLS handshakes will fail
147 - // (see end of issue #3004)
148 - //
149 - // tlsCertTags maps certificate filenames to their tag.
150 - // This is used to remember which tag is used for each
151 - // certificate files, since we need to avoid loading
152 - // the same certificate files more than once, overwriting
153 - // previous tags
154 - tlsCertTags, ok := h.State["tlsCertTags"].(map[string]string)
155 - if !ok {
156 - tlsCertTags = make(map[string]string)
157 - h.State["tlsCertTags"] = tlsCertTags
112 + // file certificate loader
113 + firstLine := h.RemainingArgs()
114 + switch len(firstLine) {
115 + case 0:
116 + case 1:
117 + if firstLine[0] == "internal" {
118 + internalIssuer = new(caddytls.InternalIssuer)
119 + } else if !strings.Contains(firstLine[0], "@") {
120 + return nil, h.Err("single argument must either be 'internal' or an email address")
121 + } else {
122 + if acmeIssuer == nil {
123 + acmeIssuer = new(caddytls.ACMEIssuer)
124 }
125 + acmeIssuer.Email = firstLine[0]
126 + }
127
160 - tag, ok := tlsCertTags[certFilename]
161 - if !ok {
162 - // haven't seen this cert file yet, let's give it a tag
163 - // and add a loader for it
164 - tag = fmt.Sprintf("cert%d", len(tlsCertTags))
165 - fileLoader = append(fileLoader, caddytls.CertKeyFilePair{
166 - Certificate: certFilename,
167 - Key: keyFilename,
168 - Tags: []string{tag},
169 - })
170 - // remember this for next time we see this cert file
171 - tlsCertTags[certFilename] = tag
172 - }
173 - certSelector.AnyTag = append(certSelector.AnyTag, tag)
128 + case 2:
129 + certFilename := firstLine[0]
130 + keyFilename := firstLine[1]
131 +
132 + // tag this certificate so if multiple certs match, specifically
133 + // this one that the user has provided will be used, see #2588:
134 + // https://github.com/caddyserver/caddy/issues/2588 ... but we
135 + // must be careful about how we do this; being careless will
136 + // lead to failed handshakes
137 + //
138 + // we need to remember which cert files we've seen, since we
139 + // must load each cert only once; otherwise, they each get a
140 + // different tag... since a cert loaded twice has the same
141 + // bytes, it will overwrite the first one in the cache, and
142 + // only the last cert (and its tag) will survive, so any conn
143 + // policy that is looking for any tag other than the last one
144 + // to be loaded won't find it, and TLS handshakes will fail
145 + // (see end of issue #3004)
146 + //
147 + // tlsCertTags maps certificate filenames to their tag.
148 + // This is used to remember which tag is used for each
149 + // certificate files, since we need to avoid loading
150 + // the same certificate files more than once, overwriting
151 + // previous tags
152 + tlsCertTags, ok := h.State["tlsCertTags"].(map[string]string)
153 + if !ok {
154 + tlsCertTags = make(map[string]string)
155 + h.State["tlsCertTags"] = tlsCertTags
156 + }
157
175 - default:
176 - return nil, h.ArgErr()
158 + tag, ok := tlsCertTags[certFilename]
159 + if !ok {
160 + // haven't seen this cert file yet, let's give it a tag
161 + // and add a loader for it
162 + tag = fmt.Sprintf("cert%d", len(tlsCertTags))
163 + fileLoader = append(fileLoader, caddytls.CertKeyFilePair{
164 + Certificate: certFilename,
165 + Key: keyFilename,
166 + Tags: []string{tag},
167 + })
168 + // remember this for next time we see this cert file
169 + tlsCertTags[certFilename] = tag
170 }
171 + certSelector.AnyTag = append(certSelector.AnyTag, tag)
172
179 - var hasBlock bool
180 - for nesting := h.Nesting(); h.NextBlock(nesting); {
181 - hasBlock = true
173 + default:
174 + return nil, h.ArgErr()
175 + }
176 +
177 + var hasBlock bool
178 + for h.NextBlock(0) {
179 + hasBlock = true
180
183 - switch h.Val() {
184 - case "protocols":
185 - args := h.RemainingArgs()
186 - if len(args) == 0 {
187 - return nil, h.Errf("protocols requires one or two arguments")
181 + switch h.Val() {
182 + case "protocols":
183 + args := h.RemainingArgs()
184 + if len(args) == 0 {
185 + return nil, h.Errf("protocols requires one or two arguments")
186 + }
187 + if len(args) > 0 {
188 + if _, ok := caddytls.SupportedProtocols[args[0]]; !ok {
189 + return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[0])
190 }
189 - if len(args) > 0 {
190 - if _, ok := caddytls.SupportedProtocols[args[0]]; !ok {
191 - return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[0])
192 - }
193 - cp.ProtocolMin = args[0]
191 + cp.ProtocolMin = args[0]
192 + }
193 + if len(args) > 1 {
194 + if _, ok := caddytls.SupportedProtocols[args[1]]; !ok {
195 + return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[1])
196 }
195 - if len(args) > 1 {
196 - if _, ok := caddytls.SupportedProtocols[args[1]]; !ok {
197 - return nil, h.Errf("wrong protocol name or protocol not supported: '%s'", args[1])
198 - }
199 - cp.ProtocolMax = args[1]
197 + cp.ProtocolMax = args[1]
198 + }
199 +
200 + case "ciphers":
201 + for h.NextArg() {
202 + if !caddytls.CipherSuiteNameSupported(h.Val()) {
203 + return nil, h.Errf("wrong cipher suite name or cipher suite not supported: '%s'", h.Val())
204 }
205 + cp.CipherSuites = append(cp.CipherSuites, h.Val())
206 + }
207
202 - case "ciphers":
203 - for h.NextArg() {
204 - if !caddytls.CipherSuiteNameSupported(h.Val()) {
205 - return nil, h.Errf("wrong cipher suite name or cipher suite not supported: '%s'", h.Val())
206 - }
207 - cp.CipherSuites = append(cp.CipherSuites, h.Val())
208 + case "curves":
209 + for h.NextArg() {
210 + if _, ok := caddytls.SupportedCurves[h.Val()]; !ok {
211 + return nil, h.Errf("Wrong curve name or curve not supported: '%s'", h.Val())
212 }
213 + cp.Curves = append(cp.Curves, h.Val())
214 + }
215
210 - case "curves":
211 - for h.NextArg() {
212 - if _, ok := caddytls.SupportedCurves[h.Val()]; !ok {
213 - return nil, h.Errf("Wrong curve name or curve not supported: '%s'", h.Val())
216 + case "client_auth":
217 + cp.ClientAuthentication = &caddytls.ClientAuthentication{}
218 + for nesting := h.Nesting(); h.NextBlock(nesting); {
219 + subdir := h.Val()
220 + switch subdir {
221 + case "verifier":
222 + if !h.NextArg() {
223 + return nil, h.ArgErr()
224 }
215 - cp.Curves = append(cp.Curves, h.Val())
216 - }
225
218 - case "client_auth":
219 - cp.ClientAuthentication = &caddytls.ClientAuthentication{}
220 - for nesting := h.Nesting(); h.NextBlock(nesting); {
221 - subdir := h.Val()
222 - switch subdir {
223 - case "verifier":
224 - if !h.NextArg() {
225 - return nil, h.ArgErr()
226 - }
226 + vType := h.Val()
227 + modID := "tls.client_auth." + vType
228 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
229 + if err != nil {
230 + return nil, err
231 + }
232
228 - vType := h.Val()
229 - modID := "tls.client_auth." + vType
230 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
231 - if err != nil {
232 - return nil, err
233 - }
233 + _, ok := unm.(caddytls.ClientCertificateVerifier)
234 + if !ok {
235 + return nil, h.Dispenser.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
236 + }
237
235 - _, ok := unm.(caddytls.ClientCertificateVerifier)
236 - if !ok {
237 - return nil, h.Dispenser.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
238 - }
238 + cp.ClientAuthentication.VerifiersRaw = append(cp.ClientAuthentication.VerifiersRaw, caddyconfig.JSONModuleObject(unm, "verifier", vType, h.warnings))
239 + case "mode":
240 + if !h.Args(&cp.ClientAuthentication.Mode) {
241 + return nil, h.ArgErr()
242 + }
243 + if h.NextArg() {
244 + return nil, h.ArgErr()
245 + }
246
240 - cp.ClientAuthentication.VerifiersRaw = append(cp.ClientAuthentication.VerifiersRaw, caddyconfig.JSONModuleObject(unm, "verifier", vType, h.warnings))
241 - case "mode":
242 - if !h.Args(&cp.ClientAuthentication.Mode) {
243 - return nil, h.ArgErr()
244 - }
245 - if h.NextArg() {
246 - return nil, h.ArgErr()
247 - }
247 + case "trusted_ca_cert",
248 + "trusted_leaf_cert":
249 + if !h.NextArg() {
250 + return nil, h.ArgErr()
251 + }
252 + if subdir == "trusted_ca_cert" {
253 + cp.ClientAuthentication.TrustedCACerts = append(cp.ClientAuthentication.TrustedCACerts, h.Val())
254 + } else {
255 + cp.ClientAuthentication.TrustedLeafCerts = append(cp.ClientAuthentication.TrustedLeafCerts, h.Val())
256 + }
257
249 - case "trusted_ca_cert",
250 - "trusted_leaf_cert":
251 - if !h.NextArg() {
252 - return nil, h.ArgErr()
258 + case "trusted_ca_cert_file",
259 + "trusted_leaf_cert_file":
260 + if !h.NextArg() {
261 + return nil, h.ArgErr()
262 + }
263 + filename := h.Val()
264 + certDataPEM, err := os.ReadFile(filename)
265 + if err != nil {
266 + return nil, err
267 + }
268 + // while block is not nil, we have more certificates in the file
269 + for block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {
270 + if block.Type != "CERTIFICATE" {
271 + return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
272 }
254 - if subdir == "trusted_ca_cert" {
255 - cp.ClientAuthentication.TrustedCACerts = append(cp.ClientAuthentication.TrustedCACerts, h.Val())
273 + if subdir == "trusted_ca_cert_file" {
274 + cp.ClientAuthentication.TrustedCACerts = append(
275 + cp.ClientAuthentication.TrustedCACerts,
276 + base64.StdEncoding.EncodeToString(block.Bytes),
277 + )
278 } else {
257 - cp.ClientAuthentication.TrustedLeafCerts = append(cp.ClientAuthentication.TrustedLeafCerts, h.Val())
258 - }
259 -
260 - case "trusted_ca_cert_file",
261 - "trusted_leaf_cert_file":
262 - if !h.NextArg() {
263 - return nil, h.ArgErr()
264 - }
265 - filename := h.Val()
266 - certDataPEM, err := os.ReadFile(filename)
267 - if err != nil {
268 - return nil, err
279 + cp.ClientAuthentication.TrustedLeafCerts = append(
280 + cp.ClientAuthentication.TrustedLeafCerts,
281 + base64.StdEncoding.EncodeToString(block.Bytes),
282 + )
283 }
270 - // while block is not nil, we have more certificates in the file
271 - for block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {
272 - if block.Type != "CERTIFICATE" {
273 - return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
274 - }
275 - if subdir == "trusted_ca_cert_file" {
276 - cp.ClientAuthentication.TrustedCACerts = append(
277 - cp.ClientAuthentication.TrustedCACerts,
278 - base64.StdEncoding.EncodeToString(block.Bytes),
279 - )
280 - } else {
281 - cp.ClientAuthentication.TrustedLeafCerts = append(
282 - cp.ClientAuthentication.TrustedLeafCerts,
283 - base64.StdEncoding.EncodeToString(block.Bytes),
284 - )
285 - }
286 - }
287 - // if we decoded nothing, return an error
288 - if len(cp.ClientAuthentication.TrustedCACerts) == 0 && len(cp.ClientAuthentication.TrustedLeafCerts) == 0 {
289 - return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
290 - }
291 -
292 - default:
293 - return nil, h.Errf("unknown subdirective for client_auth: %s", subdir)
284 }
295 - }
285 + // if we decoded nothing, return an error
286 + if len(cp.ClientAuthentication.TrustedCACerts) == 0 && len(cp.ClientAuthentication.TrustedLeafCerts) == 0 {
287 + return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
288 + }
289
297 - case "alpn":
298 - args := h.RemainingArgs()
299 - if len(args) == 0 {
300 - return nil, h.ArgErr()
290 + default:
291 + return nil, h.Errf("unknown subdirective for client_auth: %s", subdir)
292 }
302 - cp.ALPN = args
293 + }
294
304 - case "load":
305 - folderLoader = append(folderLoader, h.RemainingArgs()...)
295 + case "alpn":
296 + args := h.RemainingArgs()
297 + if len(args) == 0 {
298 + return nil, h.ArgErr()
299 + }
300 + cp.ALPN = args
301
307 - case "ca":
308 - arg := h.RemainingArgs()
309 - if len(arg) != 1 {
310 - return nil, h.ArgErr()
311 - }
312 - if acmeIssuer == nil {
313 - acmeIssuer = new(caddytls.ACMEIssuer)
314 - }
315 - acmeIssuer.CA = arg[0]
302 + case "load":
303 + folderLoader = append(folderLoader, h.RemainingArgs()...)
304
317 - case "key_type":
318 - arg := h.RemainingArgs()
319 - if len(arg) != 1 {
320 - return nil, h.ArgErr()
321 - }
322 - keyType = arg[0]
305 + case "ca":
306 + arg := h.RemainingArgs()
307 + if len(arg) != 1 {
308 + return nil, h.ArgErr()
309 + }
310 + if acmeIssuer == nil {
311 + acmeIssuer = new(caddytls.ACMEIssuer)
312 + }
313 + acmeIssuer.CA = arg[0]
314
324 - case "eab":
325 - arg := h.RemainingArgs()
326 - if len(arg) != 2 {
327 - return nil, h.ArgErr()
328 - }
329 - if acmeIssuer == nil {
330 - acmeIssuer = new(caddytls.ACMEIssuer)
331 - }
332 - acmeIssuer.ExternalAccount = &acme.EAB{
333 - KeyID: arg[0],
334 - MACKey: arg[1],
335 - }
315 + case "key_type":
316 + arg := h.RemainingArgs()
317 + if len(arg) != 1 {
318 + return nil, h.ArgErr()
319 + }
320 + keyType = arg[0]
321
337 - case "issuer":
338 - if !h.NextArg() {
339 - return nil, h.ArgErr()
340 - }
341 - modName := h.Val()
342 - modID := "tls.issuance." + modName
343 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
344 - if err != nil {
345 - return nil, err
346 - }
347 - issuer, ok := unm.(certmagic.Issuer)
348 - if !ok {
349 - return nil, h.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
350 - }
351 - issuers = append(issuers, issuer)
322 + case "eab":
323 + arg := h.RemainingArgs()
324 + if len(arg) != 2 {
325 + return nil, h.ArgErr()
326 + }
327 + if acmeIssuer == nil {
328 + acmeIssuer = new(caddytls.ACMEIssuer)
329 + }
330 + acmeIssuer.ExternalAccount = &acme.EAB{
331 + KeyID: arg[0],
332 + MACKey: arg[1],
333 + }
334
353 - case "get_certificate":
354 - if !h.NextArg() {
355 - return nil, h.ArgErr()
356 - }
357 - modName := h.Val()
358 - modID := "tls.get_certificate." + modName
359 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
360 - if err != nil {
361 - return nil, err
362 - }
363 - certManager, ok := unm.(certmagic.Manager)
364 - if !ok {
365 - return nil, h.Errf("module %s (%T) is not a certmagic.CertificateManager", modID, unm)
366 - }
367 - certManagers = append(certManagers, certManager)
335 + case "issuer":
336 + if !h.NextArg() {
337 + return nil, h.ArgErr()
338 + }
339 + modName := h.Val()
340 + modID := "tls.issuance." + modName
341 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
342 + if err != nil {
343 + return nil, err
344 + }
345 + issuer, ok := unm.(certmagic.Issuer)
346 + if !ok {
347 + return nil, h.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
348 + }
349 + issuers = append(issuers, issuer)
350
369 - case "dns":
370 - if !h.NextArg() {
371 - return nil, h.ArgErr()
372 - }
373 - provName := h.Val()
374 - if acmeIssuer == nil {
375 - acmeIssuer = new(caddytls.ACMEIssuer)
376 - }
377 - if acmeIssuer.Challenges == nil {
378 - acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
379 - }
380 - if acmeIssuer.Challenges.DNS == nil {
381 - acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
382 - }
383 - modID := "dns.providers." + provName
384 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
385 - if err != nil {
386 - return nil, err
387 - }
388 - acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
351 + case "get_certificate":
352 + if !h.NextArg() {
353 + return nil, h.ArgErr()
354 + }
355 + modName := h.Val()
356 + modID := "tls.get_certificate." + modName
357 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
358 + if err != nil {
359 + return nil, err
360 + }
361 + certManager, ok := unm.(certmagic.Manager)
362 + if !ok {
363 + return nil, h.Errf("module %s (%T) is not a certmagic.CertificateManager", modID, unm)
364 + }
365 + certManagers = append(certManagers, certManager)
366
390 - case "resolvers":
391 - args := h.RemainingArgs()
392 - if len(args) == 0 {
393 - return nil, h.ArgErr()
394 - }
395 - if acmeIssuer == nil {
396 - acmeIssuer = new(caddytls.ACMEIssuer)
397 - }
398 - if acmeIssuer.Challenges == nil {
399 - acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
400 - }
401 - if acmeIssuer.Challenges.DNS == nil {
402 - acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
403 - }
404 - acmeIssuer.Challenges.DNS.Resolvers = args
367 + case "dns":
368 + if !h.NextArg() {
369 + return nil, h.ArgErr()
370 + }
371 + provName := h.Val()
372 + if acmeIssuer == nil {
373 + acmeIssuer = new(caddytls.ACMEIssuer)
374 + }
375 + if acmeIssuer.Challenges == nil {
376 + acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
377 + }
378 + if acmeIssuer.Challenges.DNS == nil {
379 + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
380 + }
381 + modID := "dns.providers." + provName
382 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
383 + if err != nil {
384 + return nil, err
385 + }
386 + acmeIssuer.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, h.warnings)
387
406 - case "propagation_delay":
407 - arg := h.RemainingArgs()
408 - if len(arg) != 1 {
409 - return nil, h.ArgErr()
410 - }
411 - delayStr := arg[0]
412 - delay, err := caddy.ParseDuration(delayStr)
413 - if err != nil {
414 - return nil, h.Errf("invalid propagation_delay duration %s: %v", delayStr, err)
415 - }
416 - if acmeIssuer == nil {
417 - acmeIssuer = new(caddytls.ACMEIssuer)
418 - }
419 - if acmeIssuer.Challenges == nil {
420 - acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
421 - }
422 - if acmeIssuer.Challenges.DNS == nil {
423 - acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
424 - }
425 - acmeIssuer.Challenges.DNS.PropagationDelay = caddy.Duration(delay)
388 + case "resolvers":
389 + args := h.RemainingArgs()
390 + if len(args) == 0 {
391 + return nil, h.ArgErr()
392 + }
393 + if acmeIssuer == nil {
394 + acmeIssuer = new(caddytls.ACMEIssuer)
395 + }
396 + if acmeIssuer.Challenges == nil {
397 + acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
398 + }
399 + if acmeIssuer.Challenges.DNS == nil {
400 + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
401 + }
402 + acmeIssuer.Challenges.DNS.Resolvers = args
403
427 - case "propagation_timeout":
428 - arg := h.RemainingArgs()
429 - if len(arg) != 1 {
430 - return nil, h.ArgErr()
431 - }
432 - timeoutStr := arg[0]
433 - var timeout time.Duration
434 - if timeoutStr == "-1" {
435 - timeout = time.Duration(-1)
436 - } else {
437 - var err error
438 - timeout, err = caddy.ParseDuration(timeoutStr)
439 - if err != nil {
440 - return nil, h.Errf("invalid propagation_timeout duration %s: %v", timeoutStr, err)
441 - }
442 - }
443 - if acmeIssuer == nil {
444 - acmeIssuer = new(caddytls.ACMEIssuer)
445 - }
446 - if acmeIssuer.Challenges == nil {
447 - acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
448 - }
449 - if acmeIssuer.Challenges.DNS == nil {
450 - acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
451 - }
452 - acmeIssuer.Challenges.DNS.PropagationTimeout = caddy.Duration(timeout)
404 + case "propagation_delay":
405 + arg := h.RemainingArgs()
406 + if len(arg) != 1 {
407 + return nil, h.ArgErr()
408 + }
409 + delayStr := arg[0]
410 + delay, err := caddy.ParseDuration(delayStr)
411 + if err != nil {
412 + return nil, h.Errf("invalid propagation_delay duration %s: %v", delayStr, err)
413 + }
414 + if acmeIssuer == nil {
415 + acmeIssuer = new(caddytls.ACMEIssuer)
416 + }
417 + if acmeIssuer.Challenges == nil {
418 + acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
419 + }
420 + if acmeIssuer.Challenges.DNS == nil {
421 + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
422 + }
423 + acmeIssuer.Challenges.DNS.PropagationDelay = caddy.Duration(delay)
424
454 - case "dns_ttl":
455 - arg := h.RemainingArgs()
456 - if len(arg) != 1 {
457 - return nil, h.ArgErr()
458 - }
459 - ttlStr := arg[0]
460 - ttl, err := caddy.ParseDuration(ttlStr)
425 + case "propagation_timeout":
426 + arg := h.RemainingArgs()
427 + if len(arg) != 1 {
428 + return nil, h.ArgErr()
429 + }
430 + timeoutStr := arg[0]
431 + var timeout time.Duration
432 + if timeoutStr == "-1" {
433 + timeout = time.Duration(-1)
434 + } else {
435 + var err error
436 + timeout, err = caddy.ParseDuration(timeoutStr)
437 if err != nil {
462 - return nil, h.Errf("invalid dns_ttl duration %s: %v", ttlStr, err)
463 - }
464 - if acmeIssuer == nil {
465 - acmeIssuer = new(caddytls.ACMEIssuer)
466 - }
467 - if acmeIssuer.Challenges == nil {
468 - acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
438 + return nil, h.Errf("invalid propagation_timeout duration %s: %v", timeoutStr, err)
439 }
470 - if acmeIssuer.Challenges.DNS == nil {
471 - acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
472 - }
473 - acmeIssuer.Challenges.DNS.TTL = caddy.Duration(ttl)
440 + }
441 + if acmeIssuer == nil {
442 + acmeIssuer = new(caddytls.ACMEIssuer)
443 + }
444 + if acmeIssuer.Challenges == nil {
445 + acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
446 + }
447 + if acmeIssuer.Challenges.DNS == nil {
448 + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
449 + }
450 + acmeIssuer.Challenges.DNS.PropagationTimeout = caddy.Duration(timeout)
451
475 - case "dns_challenge_override_domain":
476 - arg := h.RemainingArgs()
477 - if len(arg) != 1 {
478 - return nil, h.ArgErr()
479 - }
480 - if acmeIssuer == nil {
481 - acmeIssuer = new(caddytls.ACMEIssuer)
482 - }
483 - if acmeIssuer.Challenges == nil {
484 - acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
485 - }
486 - if acmeIssuer.Challenges.DNS == nil {
487 - acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
488 - }
489 - acmeIssuer.Challenges.DNS.OverrideDomain = arg[0]
452 + case "dns_ttl":
453 + arg := h.RemainingArgs()
454 + if len(arg) != 1 {
455 + return nil, h.ArgErr()
456 + }
457 + ttlStr := arg[0]
458 + ttl, err := caddy.ParseDuration(ttlStr)
459 + if err != nil {
460 + return nil, h.Errf("invalid dns_ttl duration %s: %v", ttlStr, err)
461 + }
462 + if acmeIssuer == nil {
463 + acmeIssuer = new(caddytls.ACMEIssuer)
464 + }
465 + if acmeIssuer.Challenges == nil {
466 + acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
467 + }
468 + if acmeIssuer.Challenges.DNS == nil {
469 + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
470 + }
471 + acmeIssuer.Challenges.DNS.TTL = caddy.Duration(ttl)
472
491 - case "ca_root":
492 - arg := h.RemainingArgs()
493 - if len(arg) != 1 {
494 - return nil, h.ArgErr()
495 - }
496 - if acmeIssuer == nil {
497 - acmeIssuer = new(caddytls.ACMEIssuer)
498 - }
499 - acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, arg[0])
473 + case "dns_challenge_override_domain":
474 + arg := h.RemainingArgs()
475 + if len(arg) != 1 {
476 + return nil, h.ArgErr()
477 + }
478 + if acmeIssuer == nil {
479 + acmeIssuer = new(caddytls.ACMEIssuer)
480 + }
481 + if acmeIssuer.Challenges == nil {
482 + acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
483 + }
484 + if acmeIssuer.Challenges.DNS == nil {
485 + acmeIssuer.Challenges.DNS = new(caddytls.DNSChallengeConfig)
486 + }
487 + acmeIssuer.Challenges.DNS.OverrideDomain = arg[0]
488
501 - case "on_demand":
502 - if h.NextArg() {
503 - return nil, h.ArgErr()
504 - }
505 - onDemand = true
489 + case "ca_root":
490 + arg := h.RemainingArgs()
491 + if len(arg) != 1 {
492 + return nil, h.ArgErr()
493 + }
494 + if acmeIssuer == nil {
495 + acmeIssuer = new(caddytls.ACMEIssuer)
496 + }
497 + acmeIssuer.TrustedRootsPEMFiles = append(acmeIssuer.TrustedRootsPEMFiles, arg[0])
498
507 - case "reuse_private_keys":
508 - if h.NextArg() {
509 - return nil, h.ArgErr()
510 - }
511 - reusePrivateKeys = true
499 + case "on_demand":
500 + if h.NextArg() {
501 + return nil, h.ArgErr()
502 + }
503 + onDemand = true
504
513 - case "insecure_secrets_log":
514 - if !h.NextArg() {
515 - return nil, h.ArgErr()
516 - }
517 - cp.InsecureSecretsLog = h.Val()
505 + case "reuse_private_keys":
506 + if h.NextArg() {
507 + return nil, h.ArgErr()
508 + }
509 + reusePrivateKeys = true
510
519 - default:
520 - return nil, h.Errf("unknown subdirective: %s", h.Val())
511 + case "insecure_secrets_log":
512 + if !h.NextArg() {
513 + return nil, h.ArgErr()
514 }
522 - }
515 + cp.InsecureSecretsLog = h.Val()
516
524 - // a naked tls directive is not allowed
525 - if len(firstLine) == 0 && !hasBlock {
526 - return nil, h.ArgErr()
517 + default:
518 + return nil, h.Errf("unknown subdirective: %s", h.Val())
519 }
520 }
521
522 + // a naked tls directive is not allowed
523 + if len(firstLine) == 0 && !hasBlock {
524 + return nil, h.ArgErr()
525 + }
526 +
527 // begin building the final config values
528 configVals := []ConfigValue{}
529
@@ -646,10 +643,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
643 //
644 // root [<matcher>] <path>
645 func parseRoot(h Helper) ([]ConfigValue, error) {
649 - // consume directive name
650 - if !h.NextArg() {
651 - return nil, h.ArgErr()
652 - }
646 + h.Next() // consume directive name
647
648 // count the tokens to determine what to do
649 argsCount := h.CountRemainingArgs()
@@ -673,11 +667,8 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
667 if err != nil {
668 return nil, err
669 }
670 + h.Next() // consume directive name again, matcher parsing does a reset
671
677 - // consume directive name, again, because extracting matcher does a reset
678 - if !h.NextArg() {
679 - return nil, h.ArgErr()
680 - }
672 // advance to the root path
673 if !h.NextArg() {
674 return nil, h.ArgErr()
@@ -690,17 +681,14 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
681 //
682 // fs <filesystem>
683 func parseFilesystem(h Helper) (caddyhttp.MiddlewareHandler, error) {
693 - var name string
694 - for h.Next() {
695 - if !h.NextArg() {
696 - return nil, h.ArgErr()
697 - }
698 - name = h.Val()
699 - if h.NextArg() {
700 - return nil, h.ArgErr()
701 - }
684 + h.Next() // consume directive name
685 + if !h.NextArg() {
686 + return nil, h.ArgErr()
687 }
703 - return caddyhttp.VarsMiddleware{"fs": name}, nil
688 + if h.NextArg() {
689 + return nil, h.ArgErr()
690 + }
691 + return caddyhttp.VarsMiddleware{"fs": h.Val()}, nil
692 }
693
694 // parseVars parses the vars directive. See its UnmarshalCaddyfile method for syntax.
@@ -720,10 +708,7 @@ func parseVars(h Helper) (caddyhttp.MiddlewareHandler, error) {
708 // respond with HTTP 200 and no Location header; redirect is performed
709 // with JS and a meta tag).
710 func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
723 - if !h.Next() {
724 - return nil, h.ArgErr()
725 - }
726 -
711 + h.Next() // consume directive name
712 if !h.NextArg() {
713 return nil, h.ArgErr()
714 }
@@ -739,8 +724,10 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
724 switch code {
725 case "permanent":
726 code = "301"
727 +
728 case "temporary", "":
729 code = "302"
730 +
731 case "html":
732 // Script tag comes first since that will better imitate a redirect in the browser's
733 // history, but the meta tag is a fallback for most non-JS clients.
@@ -758,6 +745,7 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
745 body = fmt.Sprintf(metaRedir, safeTo, safeTo, safeTo, safeTo)
746 hdr = http.Header{"Content-Type": []string{"text/html; charset=utf-8"}}
747 code = "200" // don't redirect non-browser clients
748 +
749 default:
750 // Allow placeholders for the code
751 if strings.HasPrefix(code, "{") {
@@ -796,10 +784,7 @@ func parseRedir(h Helper) (caddyhttp.MiddlewareHandler, error) {
784 func parseRespond(h Helper) (caddyhttp.MiddlewareHandler, error) {
785 sr := new(caddyhttp.StaticResponse)
786 err := sr.UnmarshalCaddyfile(h.Dispenser)
799 - if err != nil {
800 - return nil, err
801 - }
802 - return sr, nil
787 + return sr, err
788 }
789
790 // parseAbort parses the abort directive.
@@ -815,10 +800,7 @@ func parseAbort(h Helper) (caddyhttp.MiddlewareHandler, error) {
800 func parseError(h Helper) (caddyhttp.MiddlewareHandler, error) {
801 se := new(caddyhttp.StaticError)
802 err := se.UnmarshalCaddyfile(h.Dispenser)
818 - if err != nil {
819 - return nil, err
820 - }
821 - return se, nil
803 + return se, err
804 }
805
806 // parseRoute parses the route directive.
@@ -844,11 +826,11 @@ func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
826 }
827
828 func parseHandleErrors(h Helper) ([]ConfigValue, error) {
847 - h.Next()
848 - args := h.RemainingArgs()
829 + h.Next() // consume directive name
830 +
831 expression := ""
832 + args := h.RemainingArgs()
833 if len(args) > 0 {
851 - expression = ""
834 codes := []string{}
835 for _, val := range args {
836 if len(val) != 3 {
@@ -951,184 +933,185 @@ func parseLog(h Helper) ([]ConfigValue, error) {
933 // level. The parseAsGlobalOption parameter is used to distinguish any differing logic
934 // between the two.
935 func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue, error) {
936 + h.Next() // consume option name
937 +
938 // When the globalLogNames parameter is passed in, we make
939 // modifications to the parsing behavior.
940 parseAsGlobalOption := globalLogNames != nil
941
942 var configValues []ConfigValue
959 - for h.Next() {
960 - // Logic below expects that a name is always present when a
961 - // global option is being parsed; or an optional override
962 - // is supported for access logs.
963 - var logName string
943
965 - if parseAsGlobalOption {
966 - if h.NextArg() {
967 - logName = h.Val()
944 + // Logic below expects that a name is always present when a
945 + // global option is being parsed; or an optional override
946 + // is supported for access logs.
947 + var logName string
948
969 - // Only a single argument is supported.
970 - if h.NextArg() {
971 - return nil, h.ArgErr()
972 - }
973 - } else {
974 - // If there is no log name specified, we
975 - // reference the default logger. See the
976 - // setupNewDefault function in the logging
977 - // package for where this is configured.
978 - logName = caddy.DefaultLoggerName
979 - }
949 + if parseAsGlobalOption {
950 + if h.NextArg() {
951 + logName = h.Val()
952
981 - // Verify this name is unused.
982 - _, used := globalLogNames[logName]
983 - if used {
984 - return nil, h.Err("duplicate global log option for: " + logName)
953 + // Only a single argument is supported.
954 + if h.NextArg() {
955 + return nil, h.ArgErr()
956 }
986 - globalLogNames[logName] = struct{}{}
957 } else {
988 - // An optional override of the logger name can be provided;
989 - // otherwise a default will be used, like "log0", "log1", etc.
990 - if h.NextArg() {
991 - logName = h.Val()
958 + // If there is no log name specified, we
959 + // reference the default logger. See the
960 + // setupNewDefault function in the logging
961 + // package for where this is configured.
962 + logName = caddy.DefaultLoggerName
963 + }
964
993 - // Only a single argument is supported.
994 - if h.NextArg() {
995 - return nil, h.ArgErr()
996 - }
997 - }
965 + // Verify this name is unused.
966 + _, used := globalLogNames[logName]
967 + if used {
968 + return nil, h.Err("duplicate global log option for: " + logName)
969 }
970 + globalLogNames[logName] = struct{}{}
971 + } else {
972 + // An optional override of the logger name can be provided;
973 + // otherwise a default will be used, like "log0", "log1", etc.
974 + if h.NextArg() {
975 + logName = h.Val()
976
1000 - cl := new(caddy.CustomLog)
977 + // Only a single argument is supported.
978 + if h.NextArg() {
979 + return nil, h.ArgErr()
980 + }
981 + }
982 + }
983
1002 - // allow overriding the current site block's hostnames for this logger;
1003 - // this is useful for setting up loggers per subdomain in a site block
1004 - // with a wildcard domain
1005 - customHostnames := []string{}
984 + cl := new(caddy.CustomLog)
985
1007 - for h.NextBlock(0) {
1008 - switch h.Val() {
1009 - case "hostnames":
1010 - if parseAsGlobalOption {
1011 - return nil, h.Err("hostnames is not allowed in the log global options")
1012 - }
1013 - args := h.RemainingArgs()
1014 - if len(args) == 0 {
1015 - return nil, h.ArgErr()
1016 - }
1017 - customHostnames = append(customHostnames, args...)
986 + // allow overriding the current site block's hostnames for this logger;
987 + // this is useful for setting up loggers per subdomain in a site block
988 + // with a wildcard domain
989 + customHostnames := []string{}
990
1019 - case "output":
1020 - if !h.NextArg() {
1021 - return nil, h.ArgErr()
1022 - }
1023 - moduleName := h.Val()
1024 -
1025 - // can't use the usual caddyfile.Unmarshaler flow with the
1026 - // standard writers because they are in the caddy package
1027 - // (because they are the default) and implementing that
1028 - // interface there would unfortunately create circular import
1029 - var wo caddy.WriterOpener
1030 - switch moduleName {
1031 - case "stdout":
1032 - wo = caddy.StdoutWriter{}
1033 - case "stderr":
1034 - wo = caddy.StderrWriter{}
1035 - case "discard":
1036 - wo = caddy.DiscardWriter{}
1037 - default:
1038 - modID := "caddy.logging.writers." + moduleName
1039 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
1040 - if err != nil {
1041 - return nil, err
1042 - }
1043 - var ok bool
1044 - wo, ok = unm.(caddy.WriterOpener)
1045 - if !ok {
1046 - return nil, h.Errf("module %s (%T) is not a WriterOpener", modID, unm)
1047 - }
1048 - }
1049 - cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
991 + for h.NextBlock(0) {
992 + switch h.Val() {
993 + case "hostnames":
994 + if parseAsGlobalOption {
995 + return nil, h.Err("hostnames is not allowed in the log global options")
996 + }
997 + args := h.RemainingArgs()
998 + if len(args) == 0 {
999 + return nil, h.ArgErr()
1000 + }
1001 + customHostnames = append(customHostnames, args...)
1002
1051 - case "format":
1052 - if !h.NextArg() {
1053 - return nil, h.ArgErr()
1054 - }
1055 - moduleName := h.Val()
1056 - moduleID := "caddy.logging.encoders." + moduleName
1057 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, moduleID)
1003 + case "output":
1004 + if !h.NextArg() {
1005 + return nil, h.ArgErr()
1006 + }
1007 + moduleName := h.Val()
1008 +
1009 + // can't use the usual caddyfile.Unmarshaler flow with the
1010 + // standard writers because they are in the caddy package
1011 + // (because they are the default) and implementing that
1012 + // interface there would unfortunately create circular import
1013 + var wo caddy.WriterOpener
1014 + switch moduleName {
1015 + case "stdout":
1016 + wo = caddy.StdoutWriter{}
1017 + case "stderr":
1018 + wo = caddy.StderrWriter{}
1019 + case "discard":
1020 + wo = caddy.DiscardWriter{}
1021 + default:
1022 + modID := "caddy.logging.writers." + moduleName
1023 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
1024 if err != nil {
1025 return nil, err
1026 }
1061 - enc, ok := unm.(zapcore.Encoder)
1027 + var ok bool
1028 + wo, ok = unm.(caddy.WriterOpener)
1029 if !ok {
1063 - return nil, h.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
1030 + return nil, h.Errf("module %s (%T) is not a WriterOpener", modID, unm)
1031 }
1065 - cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings)
1032 + }
1033 + cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
1034
1067 - case "level":
1068 - if !h.NextArg() {
1069 - return nil, h.ArgErr()
1070 - }
1071 - cl.Level = h.Val()
1072 - if h.NextArg() {
1073 - return nil, h.ArgErr()
1074 - }
1035 + case "format":
1036 + if !h.NextArg() {
1037 + return nil, h.ArgErr()
1038 + }
1039 + moduleName := h.Val()
1040 + moduleID := "caddy.logging.encoders." + moduleName
1041 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, moduleID)
1042 + if err != nil {
1043 + return nil, err
1044 + }
1045 + enc, ok := unm.(zapcore.Encoder)
1046 + if !ok {
1047 + return nil, h.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
1048 + }
1049 + cl.EncoderRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, h.warnings)
1050
1076 - case "include":
1077 - if !parseAsGlobalOption {
1078 - return nil, h.Err("include is not allowed in the log directive")
1079 - }
1080 - for h.NextArg() {
1081 - cl.Include = append(cl.Include, h.Val())
1082 - }
1051 + case "level":
1052 + if !h.NextArg() {
1053 + return nil, h.ArgErr()
1054 + }
1055 + cl.Level = h.Val()
1056 + if h.NextArg() {
1057 + return nil, h.ArgErr()
1058 + }
1059
1084 - case "exclude":
1085 - if !parseAsGlobalOption {
1086 - return nil, h.Err("exclude is not allowed in the log directive")
1087 - }
1088 - for h.NextArg() {
1089 - cl.Exclude = append(cl.Exclude, h.Val())
1090 - }
1060 + case "include":
1061 + if !parseAsGlobalOption {
1062 + return nil, h.Err("include is not allowed in the log directive")
1063 + }
1064 + for h.NextArg() {
1065 + cl.Include = append(cl.Include, h.Val())
1066 + }
1067
1092 - default:
1093 - return nil, h.Errf("unrecognized subdirective: %s", h.Val())
1068 + case "exclude":
1069 + if !parseAsGlobalOption {
1070 + return nil, h.Err("exclude is not allowed in the log directive")
1071 + }
1072 + for h.NextArg() {
1073 + cl.Exclude = append(cl.Exclude, h.Val())
1074 }
1075 +
1076 + default:
1077 + return nil, h.Errf("unrecognized subdirective: %s", h.Val())
1078 }
1079 + }
1080
1097 - var val namedCustomLog
1098 - val.hostnames = customHostnames
1081 + var val namedCustomLog
1082 + val.hostnames = customHostnames
1083
1100 - isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))
1084 + isEmptyConfig := reflect.DeepEqual(cl, new(caddy.CustomLog))
1085
1102 - // Skip handling of empty logging configs
1086 + // Skip handling of empty logging configs
1087
1104 - if parseAsGlobalOption {
1105 - // Use indicated name for global log options
1088 + if parseAsGlobalOption {
1089 + // Use indicated name for global log options
1090 + val.name = logName
1091 + } else {
1092 + if logName != "" {
1093 val.name = logName
1107 - } else {
1108 - if logName != "" {
1109 - val.name = logName
1110 - } else if !isEmptyConfig {
1111 - // Construct a log name for server log streams
1112 - logCounter, ok := h.State["logCounter"].(int)
1113 - if !ok {
1114 - logCounter = 0
1115 - }
1116 - val.name = fmt.Sprintf("log%d", logCounter)
1117 - logCounter++
1118 - h.State["logCounter"] = logCounter
1119 - }
1120 - if val.name != "" {
1121 - cl.Include = []string{"http.log.access." + val.name}
1094 + } else if !isEmptyConfig {
1095 + // Construct a log name for server log streams
1096 + logCounter, ok := h.State["logCounter"].(int)
1097 + if !ok {
1098 + logCounter = 0
1099 }
1100 + val.name = fmt.Sprintf("log%d", logCounter)
1101 + logCounter++
1102 + h.State["logCounter"] = logCounter
1103 }
1124 - if !isEmptyConfig {
1125 - val.log = cl
1104 + if val.name != "" {
1105 + cl.Include = []string{"http.log.access." + val.name}
1106 }
1127 - configValues = append(configValues, ConfigValue{
1128 - Class: "custom_log",
1129 - Value: val,
1130 - })
1107 }
1108 + if !isEmptyConfig {
1109 + val.log = cl
1110 + }
1111 + configValues = append(configValues, ConfigValue{
1112 + Class: "custom_log",
1113 + Value: val,
1114 + })
1115 return configValues, nil
1116 }
1117
@@ -1136,10 +1119,9 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
1119 //
1120 // skip_log [<matcher>]
1121 func parseSkipLog(h Helper) (caddyhttp.MiddlewareHandler, error) {
1139 - for h.Next() {
1140 - if h.NextArg() {
1141 - return nil, h.ArgErr()
1142 - }
1122 + h.Next() // consume directive name
1123 + if h.NextArg() {
1124 + return nil, h.ArgErr()
1125 }
1126 return caddyhttp.VarsMiddleware{"skip_log": true}, nil
1127 }
caddyconfig/httpcaddyfile/directives.go
-6
@@ -271,12 +271,6 @@ func (h Helper) GroupRoutes(vals []ConfigValue) {
271 }
272 }
273
274 -// NewBindAddresses returns config values relevant to adding
275 -// listener bind addresses to the config.
276 -func (h Helper) NewBindAddresses(addrs []string) []ConfigValue {
277 - return []ConfigValue{{Class: "bind", Value: addrs}}
278 -}
279 -
274 // WithDispenser returns a new instance based on d. All others Helper
275 // fields are copied, so typically maps are shared with this new instance.
276 func (h Helper) WithDispenser(d *caddyfile.Dispenser) Helper {
caddyconfig/httpcaddyfile/httptype.go
+57 -52
@@ -1381,68 +1381,73 @@ func (st *ServerType) compileEncodedMatcherSets(sblock serverBlock) ([]caddy.Mod
1381 }
1382
1383 func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.ModuleMap) error {
1384 - for d.Next() {
1385 - // this is the "name" for "named matchers"
1386 - definitionName := d.Val()
1384 + d.Next() // advance to the first token
1385
1388 - if _, ok := matchers[definitionName]; ok {
1389 - return fmt.Errorf("matcher is defined more than once: %s", definitionName)
1386 + // this is the "name" for "named matchers"
1387 + definitionName := d.Val()
1388 +
1389 + if _, ok := matchers[definitionName]; ok {
1390 + return fmt.Errorf("matcher is defined more than once: %s", definitionName)
1391 + }
1392 + matchers[definitionName] = make(caddy.ModuleMap)
1393 +
1394 + // given a matcher name and the tokens following it, parse
1395 + // the tokens as a matcher module and record it
1396 + makeMatcher := func(matcherName string, tokens []caddyfile.Token) error {
1397 + mod, err := caddy.GetModule("http.matchers." + matcherName)
1398 + if err != nil {
1399 + return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
1400 }
1391 - matchers[definitionName] = make(caddy.ModuleMap)
1401 + unm, ok := mod.New().(caddyfile.Unmarshaler)
1402 + if !ok {
1403 + return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
1404 + }
1405 + err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
1406 + if err != nil {
1407 + return err
1408 + }
1409 + rm, ok := unm.(caddyhttp.RequestMatcher)
1410 + if !ok {
1411 + return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
1412 + }
1413 + matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
1414 + return nil
1415 + }
1416
1393 - // given a matcher name and the tokens following it, parse
1394 - // the tokens as a matcher module and record it
1395 - makeMatcher := func(matcherName string, tokens []caddyfile.Token) error {
1396 - mod, err := caddy.GetModule("http.matchers." + matcherName)
1397 - if err != nil {
1398 - return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
1399 - }
1400 - unm, ok := mod.New().(caddyfile.Unmarshaler)
1401 - if !ok {
1402 - return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
1403 - }
1404 - err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
1417 + // if the next token is quoted, we can assume it's not a matcher name
1418 + // and that it's probably an 'expression' matcher
1419 + if d.NextArg() {
1420 + if d.Token().Quoted() {
1421 + // since it was missing the matcher name, we insert a token
1422 + // in front of the expression token itself
1423 + err := makeMatcher("expression", []caddyfile.Token{
1424 + {Text: "expression", File: d.File(), Line: d.Line()},
1425 + d.Token(),
1426 + })
1427 if err != nil {
1428 return err
1429 }
1408 - rm, ok := unm.(caddyhttp.RequestMatcher)
1409 - if !ok {
1410 - return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
1411 - }
1412 - matchers[definitionName][matcherName] = caddyconfig.JSON(rm, nil)
1430 return nil
1431 }
1432
1416 - // if the next token is quoted, we can assume it's not a matcher name
1417 - // and that it's probably an 'expression' matcher
1418 - if d.NextArg() {
1419 - if d.Token().Quoted() {
1420 - err := makeMatcher("expression", []caddyfile.Token{d.Token()})
1421 - if err != nil {
1422 - return err
1423 - }
1424 - continue
1425 - }
1426 -
1427 - // if it wasn't quoted, then we need to rewind after calling
1428 - // d.NextArg() so the below properly grabs the matcher name
1429 - d.Prev()
1430 - }
1433 + // if it wasn't quoted, then we need to rewind after calling
1434 + // d.NextArg() so the below properly grabs the matcher name
1435 + d.Prev()
1436 + }
1437
1432 - // in case there are multiple instances of the same matcher, concatenate
1433 - // their tokens (we expect that UnmarshalCaddyfile should be able to
1434 - // handle more than one segment); otherwise, we'd overwrite other
1435 - // instances of the matcher in this set
1436 - tokensByMatcherName := make(map[string][]caddyfile.Token)
1437 - for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
1438 - matcherName := d.Val()
1439 - tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
1440 - }
1441 - for matcherName, tokens := range tokensByMatcherName {
1442 - err := makeMatcher(matcherName, tokens)
1443 - if err != nil {
1444 - return err
1445 - }
1438 + // in case there are multiple instances of the same matcher, concatenate
1439 + // their tokens (we expect that UnmarshalCaddyfile should be able to
1440 + // handle more than one segment); otherwise, we'd overwrite other
1441 + // instances of the matcher in this set
1442 + tokensByMatcherName := make(map[string][]caddyfile.Token)
1443 + for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
1444 + matcherName := d.Val()
1445 + tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
1446 + }
1447 + for matcherName, tokens := range tokensByMatcherName {
1448 + err := makeMatcher(matcherName, tokens)
1449 + if err != nil {
1450 + return err
1451 }
1452 }
1453 return nil
caddyconfig/httpcaddyfile/options.go
+182 -183
@@ -62,105 +62,103 @@ func init() {
62 func parseOptTrue(d *caddyfile.Dispenser, _ any) (any, error) { return true, nil }
63
64 func parseOptHTTPPort(d *caddyfile.Dispenser, _ any) (any, error) {
65 + d.Next() // consume option name
66 var httpPort int
66 - for d.Next() {
67 - var httpPortStr string
68 - if !d.AllArgs(&httpPortStr) {
69 - return 0, d.ArgErr()
70 - }
71 - var err error
72 - httpPort, err = strconv.Atoi(httpPortStr)
73 - if err != nil {
74 - return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err)
75 - }
67 + var httpPortStr string
68 + if !d.AllArgs(&httpPortStr) {
69 + return 0, d.ArgErr()
70 + }
71 + var err error
72 + httpPort, err = strconv.Atoi(httpPortStr)
73 + if err != nil {
74 + return 0, d.Errf("converting port '%s' to integer value: %v", httpPortStr, err)
75 }
76 return httpPort, nil
77 }
78
79 func parseOptHTTPSPort(d *caddyfile.Dispenser, _ any) (any, error) {
80 + d.Next() // consume option name
81 var httpsPort int
82 - for d.Next() {
83 - var httpsPortStr string
84 - if !d.AllArgs(&httpsPortStr) {
85 - return 0, d.ArgErr()
86 - }
87 - var err error
88 - httpsPort, err = strconv.Atoi(httpsPortStr)
89 - if err != nil {
90 - return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err)
91 - }
82 + var httpsPortStr string
83 + if !d.AllArgs(&httpsPortStr) {
84 + return 0, d.ArgErr()
85 + }
86 + var err error
87 + httpsPort, err = strconv.Atoi(httpsPortStr)
88 + if err != nil {
89 + return 0, d.Errf("converting port '%s' to integer value: %v", httpsPortStr, err)
90 }
91 return httpsPort, nil
92 }
93
94 func parseOptOrder(d *caddyfile.Dispenser, _ any) (any, error) {
97 - newOrder := directiveOrder
95 + d.Next() // consume option name
96
99 - for d.Next() {
100 - // get directive name
101 - if !d.Next() {
102 - return nil, d.ArgErr()
103 - }
104 - dirName := d.Val()
105 - if _, ok := registeredDirectives[dirName]; !ok {
106 - return nil, d.Errf("%s is not a registered directive", dirName)
107 - }
97 + // get directive name
98 + if !d.Next() {
99 + return nil, d.ArgErr()
100 + }
101 + dirName := d.Val()
102 + if _, ok := registeredDirectives[dirName]; !ok {
103 + return nil, d.Errf("%s is not a registered directive", dirName)
104 + }
105
109 - // get positional token
110 - if !d.Next() {
111 - return nil, d.ArgErr()
112 - }
113 - pos := d.Val()
106 + // get positional token
107 + if !d.Next() {
108 + return nil, d.ArgErr()
109 + }
110 + pos := d.Val()
111
115 - // if directive exists, first remove it
116 - for i, d := range newOrder {
117 - if d == dirName {
118 - newOrder = append(newOrder[:i], newOrder[i+1:]...)
119 - break
120 - }
121 - }
112 + newOrder := directiveOrder
113
123 - // act on the positional
124 - switch pos {
125 - case "first":
126 - newOrder = append([]string{dirName}, newOrder...)
127 - if d.NextArg() {
128 - return nil, d.ArgErr()
129 - }
130 - directiveOrder = newOrder
131 - return newOrder, nil
132 - case "last":
133 - newOrder = append(newOrder, dirName)
134 - if d.NextArg() {
135 - return nil, d.ArgErr()
136 - }
137 - directiveOrder = newOrder
138 - return newOrder, nil
139 - case "before":
140 - case "after":
141 - default:
142 - return nil, d.Errf("unknown positional '%s'", pos)
114 + // if directive exists, first remove it
115 + for i, d := range newOrder {
116 + if d == dirName {
117 + newOrder = append(newOrder[:i], newOrder[i+1:]...)
118 + break
119 }
120 + }
121
145 - // get name of other directive
146 - if !d.NextArg() {
122 + // act on the positional
123 + switch pos {
124 + case "first":
125 + newOrder = append([]string{dirName}, newOrder...)
126 + if d.NextArg() {
127 return nil, d.ArgErr()
128 }
149 - otherDir := d.Val()
129 + directiveOrder = newOrder
130 + return newOrder, nil
131 + case "last":
132 + newOrder = append(newOrder, dirName)
133 if d.NextArg() {
134 return nil, d.ArgErr()
135 }
136 + directiveOrder = newOrder
137 + return newOrder, nil
138 + case "before":
139 + case "after":
140 + default:
141 + return nil, d.Errf("unknown positional '%s'", pos)
142 + }
143 +
144 + // get name of other directive
145 + if !d.NextArg() {
146 + return nil, d.ArgErr()
147 + }
148 + otherDir := d.Val()
149 + if d.NextArg() {
150 + return nil, d.ArgErr()
151 + }
152
154 - // insert directive into proper position
155 - for i, d := range newOrder {
156 - if d == otherDir {
157 - if pos == "before" {
158 - newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...)
159 - } else if pos == "after" {
160 - newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...)
161 - }
162 - break
153 + // insert directive into proper position
154 + for i, d := range newOrder {
155 + if d == otherDir {
156 + if pos == "before" {
157 + newOrder = append(newOrder[:i], append([]string{dirName}, newOrder[i:]...)...)
158 + } else if pos == "after" {
159 + newOrder = append(newOrder[:i+1], append([]string{dirName}, newOrder[i+1:]...)...)
160 }
161 + break
162 }
163 }
164
@@ -223,57 +221,58 @@ func parseOptACMEDNS(d *caddyfile.Dispenser, _ any) (any, error) {
221
222 func parseOptACMEEAB(d *caddyfile.Dispenser, _ any) (any, error) {
223 eab := new(acme.EAB)
226 - for d.Next() {
227 - if d.NextArg() {
228 - return nil, d.ArgErr()
229 - }
230 - for nesting := d.Nesting(); d.NextBlock(nesting); {
231 - switch d.Val() {
232 - case "key_id":
233 - if !d.NextArg() {
234 - return nil, d.ArgErr()
235 - }
236 - eab.KeyID = d.Val()
237 -
238 - case "mac_key":
239 - if !d.NextArg() {
240 - return nil, d.ArgErr()
241 - }
242 - eab.MACKey = d.Val()
243 -
244 - default:
245 - return nil, d.Errf("unrecognized parameter '%s'", d.Val())
224 + d.Next() // consume option name
225 + if d.NextArg() {
226 + return nil, d.ArgErr()
227 + }
228 + for d.NextBlock(0) {
229 + switch d.Val() {
230 + case "key_id":
231 + if !d.NextArg() {
232 + return nil, d.ArgErr()
233 + }
234 + eab.KeyID = d.Val()
235 +
236 + case "mac_key":
237 + if !d.NextArg() {
238 + return nil, d.ArgErr()
239 }
240 + eab.MACKey = d.Val()
241 +
242 + default:
243 + return nil, d.Errf("unrecognized parameter '%s'", d.Val())
244 }
245 }
246 return eab, nil
247 }
248
249 func parseOptCertIssuer(d *caddyfile.Dispenser, existing any) (any, error) {
250 + d.Next() // consume option name
251 +
252 var issuers []certmagic.Issuer
253 if existing != nil {
254 issuers = existing.([]certmagic.Issuer)
255 }
257 - for d.Next() { // consume option name
258 - if !d.Next() { // get issuer module name
259 - return nil, d.ArgErr()
260 - }
261 - modID := "tls.issuance." + d.Val()
262 - unm, err := caddyfile.UnmarshalModule(d, modID)
263 - if err != nil {
264 - return nil, err
265 - }
266 - iss, ok := unm.(certmagic.Issuer)
267 - if !ok {
268 - return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
269 - }
270 - issuers = append(issuers, iss)
256 +
257 + // get issuer module name
258 + if !d.Next() {
259 + return nil, d.ArgErr()
260 + }
261 + modID := "tls.issuance." + d.Val()
262 + unm, err := caddyfile.UnmarshalModule(d, modID)
263 + if err != nil {
264 + return nil, err
265 + }
266 + iss, ok := unm.(certmagic.Issuer)
267 + if !ok {
268 + return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
269 }
270 + issuers = append(issuers, iss)
271 return issuers, nil
272 }
273
274 func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {
276 - d.Next() // consume parameter name
275 + d.Next() // consume option name
276 if !d.Next() {
277 return "", d.ArgErr()
278 }
@@ -285,7 +284,7 @@ func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {
284 }
285
286 func parseOptStringList(d *caddyfile.Dispenser, _ any) (any, error) {
288 - d.Next() // consume parameter name
287 + d.Next() // consume option name
288 val := d.RemainingArgs()
289 if len(val) == 0 {
290 return "", d.ArgErr()
@@ -294,33 +293,33 @@ func parseOptStringList(d *caddyfile.Dispenser, _ any) (any, error) {
293 }
294
295 func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
296 + d.Next() // consume option name
297 +
298 adminCfg := new(caddy.AdminConfig)
298 - for d.Next() {
299 - if d.NextArg() {
300 - listenAddress := d.Val()
301 - if listenAddress == "off" {
302 - adminCfg.Disabled = true
303 - if d.Next() { // Do not accept any remaining options including block
304 - return nil, d.Err("No more option is allowed after turning off admin config")
305 - }
306 - } else {
307 - adminCfg.Listen = listenAddress
308 - if d.NextArg() { // At most 1 arg is allowed
309 - return nil, d.ArgErr()
310 - }
299 + if d.NextArg() {
300 + listenAddress := d.Val()
301 + if listenAddress == "off" {
302 + adminCfg.Disabled = true
303 + if d.Next() { // Do not accept any remaining options including block
304 + return nil, d.Err("No more option is allowed after turning off admin config")
305 + }
306 + } else {
307 + adminCfg.Listen = listenAddress
308 + if d.NextArg() { // At most 1 arg is allowed
309 + return nil, d.ArgErr()
310 }
311 }
313 - for nesting := d.Nesting(); d.NextBlock(nesting); {
314 - switch d.Val() {
315 - case "enforce_origin":
316 - adminCfg.EnforceOrigin = true
312 + }
313 + for d.NextBlock(0) {
314 + switch d.Val() {
315 + case "enforce_origin":
316 + adminCfg.EnforceOrigin = true
317
318 - case "origins":
319 - adminCfg.Origins = d.RemainingArgs()
318 + case "origins":
319 + adminCfg.Origins = d.RemainingArgs()
320
321 - default:
322 - return nil, d.Errf("unrecognized parameter '%s'", d.Val())
323 - }
321 + default:
322 + return nil, d.Errf("unrecognized parameter '%s'", d.Val())
323 }
324 }
325 if adminCfg.Listen == "" && !adminCfg.Disabled {
@@ -330,57 +329,57 @@ func parseOptAdmin(d *caddyfile.Dispenser, _ any) (any, error) {
329 }
330
331 func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) {
332 + d.Next() // consume option name
333 + if d.NextArg() {
334 + return nil, d.ArgErr()
335 + }
336 +
337 var ond *caddytls.OnDemandConfig
334 - for d.Next() {
335 - if d.NextArg() {
336 - return nil, d.ArgErr()
337 - }
338 - for nesting := d.Nesting(); d.NextBlock(nesting); {
339 - switch d.Val() {
340 - case "ask":
341 - if !d.NextArg() {
342 - return nil, d.ArgErr()
343 - }
344 - if ond == nil {
345 - ond = new(caddytls.OnDemandConfig)
346 - }
347 - ond.Ask = d.Val()
348 -
349 - case "interval":
350 - if !d.NextArg() {
351 - return nil, d.ArgErr()
352 - }
353 - dur, err := caddy.ParseDuration(d.Val())
354 - if err != nil {
355 - return nil, err
356 - }
357 - if ond == nil {
358 - ond = new(caddytls.OnDemandConfig)
359 - }
360 - if ond.RateLimit == nil {
361 - ond.RateLimit = new(caddytls.RateLimit)
362 - }
363 - ond.RateLimit.Interval = caddy.Duration(dur)
364 -
365 - case "burst":
366 - if !d.NextArg() {
367 - return nil, d.ArgErr()
368 - }
369 - burst, err := strconv.Atoi(d.Val())
370 - if err != nil {
371 - return nil, err
372 - }
373 - if ond == nil {
374 - ond = new(caddytls.OnDemandConfig)
375 - }
376 - if ond.RateLimit == nil {
377 - ond.RateLimit = new(caddytls.RateLimit)
378 - }
379 - ond.RateLimit.Burst = burst
380 -
381 - default:
382 - return nil, d.Errf("unrecognized parameter '%s'", d.Val())
338 + for d.NextBlock(0) {
339 + switch d.Val() {
340 + case "ask":
341 + if !d.NextArg() {
342 + return nil, d.ArgErr()
343 + }
344 + if ond == nil {
345 + ond = new(caddytls.OnDemandConfig)
346 + }
347 + ond.Ask = d.Val()
348 +
349 + case "interval":
350 + if !d.NextArg() {
351 + return nil, d.ArgErr()
352 + }
353 + dur, err := caddy.ParseDuration(d.Val())
354 + if err != nil {
355 + return nil, err
356 }
357 + if ond == nil {
358 + ond = new(caddytls.OnDemandConfig)
359 + }
360 + if ond.RateLimit == nil {
361 + ond.RateLimit = new(caddytls.RateLimit)
362 + }
363 + ond.RateLimit.Interval = caddy.Duration(dur)
364 +
365 + case "burst":
366 + if !d.NextArg() {
367 + return nil, d.ArgErr()
368 + }
369 + burst, err := strconv.Atoi(d.Val())
370 + if err != nil {
371 + return nil, err
372 + }
373 + if ond == nil {
374 + ond = new(caddytls.OnDemandConfig)
375 + }
376 + if ond.RateLimit == nil {
377 + ond.RateLimit = new(caddytls.RateLimit)
378 + }
379 + ond.RateLimit.Burst = burst
380 +
381 + default:
382 + return nil, d.Errf("unrecognized parameter '%s'", d.Val())
383 }
384 }
385 if ond == nil {
@@ -390,7 +389,7 @@ func parseOptOnDemand(d *caddyfile.Dispenser, _ any) (any, error) {
389 }
390
391 func parseOptPersistConfig(d *caddyfile.Dispenser, _ any) (any, error) {
393 - d.Next() // consume parameter name
392 + d.Next() // consume option name
393 if !d.Next() {
394 return "", d.ArgErr()
395 }
@@ -405,7 +404,7 @@ func parseOptPersistConfig(d *caddyfile.Dispenser, _ any) (any, error) {
404 }
405
406 func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ any) (any, error) {
408 - d.Next() // consume parameter name
407 + d.Next() // consume option name
408 if !d.Next() {
409 return "", d.ArgErr()
410 }
caddyconfig/httpcaddyfile/pkiapp.go
+98 -98
@@ -48,124 +48,124 @@ func init() {
48 //
49 // When the CA ID is unspecified, 'local' is assumed.
50 func parsePKIApp(d *caddyfile.Dispenser, existingVal any) (any, error) {
51 - pki := &caddypki.PKI{CAs: make(map[string]*caddypki.CA)}
51 + d.Next() // consume app name
52
53 - for d.Next() {
54 - for nesting := d.Nesting(); d.NextBlock(nesting); {
55 - switch d.Val() {
56 - case "ca":
57 - pkiCa := new(caddypki.CA)
53 + pki := &caddypki.PKI{
54 + CAs: make(map[string]*caddypki.CA),
55 + }
56 + for d.NextBlock(0) {
57 + switch d.Val() {
58 + case "ca":
59 + pkiCa := new(caddypki.CA)
60 + if d.NextArg() {
61 + pkiCa.ID = d.Val()
62 if d.NextArg() {
59 - pkiCa.ID = d.Val()
60 - if d.NextArg() {
63 + return nil, d.ArgErr()
64 + }
65 + }
66 + if pkiCa.ID == "" {
67 + pkiCa.ID = caddypki.DefaultCAID
68 + }
69 +
70 + for nesting := d.Nesting(); d.NextBlock(nesting); {
71 + switch d.Val() {
72 + case "name":
73 + if !d.NextArg() {
74 return nil, d.ArgErr()
75 }
63 - }
64 - if pkiCa.ID == "" {
65 - pkiCa.ID = caddypki.DefaultCAID
66 - }
76 + pkiCa.Name = d.Val()
77
68 - for nesting := d.Nesting(); d.NextBlock(nesting); {
69 - switch d.Val() {
70 - case "name":
71 - if !d.NextArg() {
72 - return nil, d.ArgErr()
73 - }
74 - pkiCa.Name = d.Val()
78 + case "root_cn":
79 + if !d.NextArg() {
80 + return nil, d.ArgErr()
81 + }
82 + pkiCa.RootCommonName = d.Val()
83
76 - case "root_cn":
77 - if !d.NextArg() {
78 - return nil, d.ArgErr()
79 - }
80 - pkiCa.RootCommonName = d.Val()
84 + case "intermediate_cn":
85 + if !d.NextArg() {
86 + return nil, d.ArgErr()
87 + }
88 + pkiCa.IntermediateCommonName = d.Val()
89
82 - case "intermediate_cn":
83 - if !d.NextArg() {
84 - return nil, d.ArgErr()
85 - }
86 - pkiCa.IntermediateCommonName = d.Val()
90 + case "intermediate_lifetime":
91 + if !d.NextArg() {
92 + return nil, d.ArgErr()
93 + }
94 + dur, err := caddy.ParseDuration(d.Val())
95 + if err != nil {
96 + return nil, err
97 + }
98 + pkiCa.IntermediateLifetime = caddy.Duration(dur)
99
88 - case "intermediate_lifetime":
89 - if !d.NextArg() {
90 - return nil, d.ArgErr()
91 - }
92 - dur, err := caddy.ParseDuration(d.Val())
93 - if err != nil {
94 - return nil, err
95 - }
96 - pkiCa.IntermediateLifetime = caddy.Duration(dur)
100 + case "root":
101 + if pkiCa.Root == nil {
102 + pkiCa.Root = new(caddypki.KeyPair)
103 + }
104 + for nesting := d.Nesting(); d.NextBlock(nesting); {
105 + switch d.Val() {
106 + case "cert":
107 + if !d.NextArg() {
108 + return nil, d.ArgErr()
109 + }
110 + pkiCa.Root.Certificate = d.Val()
111
98 - case "root":
99 - if pkiCa.Root == nil {
100 - pkiCa.Root = new(caddypki.KeyPair)
101 - }
102 - for nesting := d.Nesting(); d.NextBlock(nesting); {
103 - switch d.Val() {
104 - case "cert":
105 - if !d.NextArg() {
106 - return nil, d.ArgErr()
107 - }
108 - pkiCa.Root.Certificate = d.Val()
109 -
110 - case "key":
111 - if !d.NextArg() {
112 - return nil, d.ArgErr()
113 - }
114 - pkiCa.Root.PrivateKey = d.Val()
115 -
116 - case "format":
117 - if !d.NextArg() {
118 - return nil, d.ArgErr()
119 - }
120 - pkiCa.Root.Format = d.Val()
121 -
122 - default:
123 - return nil, d.Errf("unrecognized pki ca root option '%s'", d.Val())
112 + case "key":
113 + if !d.NextArg() {
114 + return nil, d.ArgErr()
115 }
125 - }
116 + pkiCa.Root.PrivateKey = d.Val()
117
127 - case "intermediate":
128 - if pkiCa.Intermediate == nil {
129 - pkiCa.Intermediate = new(caddypki.KeyPair)
130 - }
131 - for nesting := d.Nesting(); d.NextBlock(nesting); {
132 - switch d.Val() {
133 - case "cert":
134 - if !d.NextArg() {
135 - return nil, d.ArgErr()
136 - }
137 - pkiCa.Intermediate.Certificate = d.Val()
138 -
139 - case "key":
140 - if !d.NextArg() {
141 - return nil, d.ArgErr()
142 - }
143 - pkiCa.Intermediate.PrivateKey = d.Val()
144 -
145 - case "format":
146 - if !d.NextArg() {
147 - return nil, d.ArgErr()
148 - }
149 - pkiCa.Intermediate.Format = d.Val()
150 -
151 - default:
152 - return nil, d.Errf("unrecognized pki ca intermediate option '%s'", d.Val())
118 + case "format":
119 + if !d.NextArg() {
120 + return nil, d.ArgErr()
121 }
122 + pkiCa.Root.Format = d.Val()
123 +
124 + default:
125 + return nil, d.Errf("unrecognized pki ca root option '%s'", d.Val())
126 }
127 + }
128
156 - default:
157 - return nil, d.Errf("unrecognized pki ca option '%s'", d.Val())
129 + case "intermediate":
130 + if pkiCa.Intermediate == nil {
131 + pkiCa.Intermediate = new(caddypki.KeyPair)
132 }
159 - }
133 + for nesting := d.Nesting(); d.NextBlock(nesting); {
134 + switch d.Val() {
135 + case "cert":
136 + if !d.NextArg() {
137 + return nil, d.ArgErr()
138 + }
139 + pkiCa.Intermediate.Certificate = d.Val()
140
161 - pki.CAs[pkiCa.ID] = pkiCa
141 + case "key":
142 + if !d.NextArg() {
143 + return nil, d.ArgErr()
144 + }
145 + pkiCa.Intermediate.PrivateKey = d.Val()
146
163 - default:
164 - return nil, d.Errf("unrecognized pki option '%s'", d.Val())
147 + case "format":
148 + if !d.NextArg() {
149 + return nil, d.ArgErr()
150 + }
151 + pkiCa.Intermediate.Format = d.Val()
152 +
153 + default:
154 + return nil, d.Errf("unrecognized pki ca intermediate option '%s'", d.Val())
155 + }
156 + }
157 +
158 + default:
159 + return nil, d.Errf("unrecognized pki ca option '%s'", d.Val())
160 + }
161 }
162 +
163 + pki.CAs[pkiCa.ID] = pkiCa
164 +
165 + default:
166 + return nil, d.Errf("unrecognized pki option '%s'", d.Val())
167 }
168 }
168 -
169 return pki, nil
170 }
171
caddyconfig/httpcaddyfile/serveroptions.go
+200 -200
@@ -53,235 +53,235 @@ type serverOptions struct {
53 }
54
55 func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
56 + d.Next() // consume option name
57 +
58 serverOpts := serverOptions{}
57 - for d.Next() {
59 + if d.NextArg() {
60 + serverOpts.ListenerAddress = d.Val()
61 if d.NextArg() {
59 - serverOpts.ListenerAddress = d.Val()
60 - if d.NextArg() {
62 + return nil, d.ArgErr()
63 + }
64 + }
65 + for d.NextBlock(0) {
66 + switch d.Val() {
67 + case "name":
68 + if serverOpts.ListenerAddress == "" {
69 + return nil, d.Errf("cannot set a name for a server without a listener address")
70 + }
71 + if !d.NextArg() {
72 return nil, d.ArgErr()
73 }
63 - }
64 - for nesting := d.Nesting(); d.NextBlock(nesting); {
65 - switch d.Val() {
66 - case "name":
67 - if serverOpts.ListenerAddress == "" {
68 - return nil, d.Errf("cannot set a name for a server without a listener address")
74 + serverOpts.Name = d.Val()
75 +
76 + case "listener_wrappers":
77 + for nesting := d.Nesting(); d.NextBlock(nesting); {
78 + modID := "caddy.listeners." + d.Val()
79 + unm, err := caddyfile.UnmarshalModule(d, modID)
80 + if err != nil {
81 + return nil, err
82 }
70 - if !d.NextArg() {
71 - return nil, d.ArgErr()
83 + listenerWrapper, ok := unm.(caddy.ListenerWrapper)
84 + if !ok {
85 + return nil, fmt.Errorf("module %s (%T) is not a listener wrapper", modID, unm)
86 }
73 - serverOpts.Name = d.Val()
87 + jsonListenerWrapper := caddyconfig.JSONModuleObject(
88 + listenerWrapper,
89 + "wrapper",
90 + listenerWrapper.(caddy.Module).CaddyModule().ID.Name(),
91 + nil,
92 + )
93 + serverOpts.ListenerWrappersRaw = append(serverOpts.ListenerWrappersRaw, jsonListenerWrapper)
94 + }
95
75 - case "listener_wrappers":
76 - for nesting := d.Nesting(); d.NextBlock(nesting); {
77 - modID := "caddy.listeners." + d.Val()
78 - unm, err := caddyfile.UnmarshalModule(d, modID)
96 + case "timeouts":
97 + for nesting := d.Nesting(); d.NextBlock(nesting); {
98 + switch d.Val() {
99 + case "read_body":
100 + if !d.NextArg() {
101 + return nil, d.ArgErr()
102 + }
103 + dur, err := caddy.ParseDuration(d.Val())
104 if err != nil {
80 - return nil, err
105 + return nil, d.Errf("parsing read_body timeout duration: %v", err)
106 }
82 - listenerWrapper, ok := unm.(caddy.ListenerWrapper)
83 - if !ok {
84 - return nil, fmt.Errorf("module %s (%T) is not a listener wrapper", modID, unm)
107 + serverOpts.ReadTimeout = caddy.Duration(dur)
108 +
109 + case "read_header":
110 + if !d.NextArg() {
111 + return nil, d.ArgErr()
112 }
86 - jsonListenerWrapper := caddyconfig.JSONModuleObject(
87 - listenerWrapper,
88 - "wrapper",
89 - listenerWrapper.(caddy.Module).CaddyModule().ID.Name(),
90 - nil,
91 - )
92 - serverOpts.ListenerWrappersRaw = append(serverOpts.ListenerWrappersRaw, jsonListenerWrapper)
93 - }
113 + dur, err := caddy.ParseDuration(d.Val())
114 + if err != nil {
115 + return nil, d.Errf("parsing read_header timeout duration: %v", err)
116 + }
117 + serverOpts.ReadHeaderTimeout = caddy.Duration(dur)
118
95 - case "timeouts":
96 - for nesting := d.Nesting(); d.NextBlock(nesting); {
97 - switch d.Val() {
98 - case "read_body":
99 - if !d.NextArg() {
100 - return nil, d.ArgErr()
101 - }
102 - dur, err := caddy.ParseDuration(d.Val())
103 - if err != nil {
104 - return nil, d.Errf("parsing read_body timeout duration: %v", err)
105 - }
106 - serverOpts.ReadTimeout = caddy.Duration(dur)
107 -
108 - case "read_header":
109 - if !d.NextArg() {
110 - return nil, d.ArgErr()
111 - }
112 - dur, err := caddy.ParseDuration(d.Val())
113 - if err != nil {
114 - return nil, d.Errf("parsing read_header timeout duration: %v", err)
115 - }
116 - serverOpts.ReadHeaderTimeout = caddy.Duration(dur)
117 -
118 - case "write":
119 - if !d.NextArg() {
120 - return nil, d.ArgErr()
121 - }
122 - dur, err := caddy.ParseDuration(d.Val())
123 - if err != nil {
124 - return nil, d.Errf("parsing write timeout duration: %v", err)
125 - }
126 - serverOpts.WriteTimeout = caddy.Duration(dur)
127 -
128 - case "idle":
129 - if !d.NextArg() {
130 - return nil, d.ArgErr()
131 - }
132 - dur, err := caddy.ParseDuration(d.Val())
133 - if err != nil {
134 - return nil, d.Errf("parsing idle timeout duration: %v", err)
135 - }
136 - serverOpts.IdleTimeout = caddy.Duration(dur)
137 -
138 - default:
139 - return nil, d.Errf("unrecognized timeouts option '%s'", d.Val())
119 + case "write":
120 + if !d.NextArg() {
121 + return nil, d.ArgErr()
122 }
141 - }
142 - case "keepalive_interval":
143 - if !d.NextArg() {
144 - return nil, d.ArgErr()
145 - }
146 - dur, err := caddy.ParseDuration(d.Val())
147 - if err != nil {
148 - return nil, d.Errf("parsing keepalive interval duration: %v", err)
149 - }
150 - serverOpts.KeepAliveInterval = caddy.Duration(dur)
123 + dur, err := caddy.ParseDuration(d.Val())
124 + if err != nil {
125 + return nil, d.Errf("parsing write timeout duration: %v", err)
126 + }
127 + serverOpts.WriteTimeout = caddy.Duration(dur)
128
152 - case "max_header_size":
153 - var sizeStr string
154 - if !d.AllArgs(&sizeStr) {
155 - return nil, d.ArgErr()
156 - }
157 - size, err := humanize.ParseBytes(sizeStr)
158 - if err != nil {
159 - return nil, d.Errf("parsing max_header_size: %v", err)
160 - }
161 - serverOpts.MaxHeaderBytes = int(size)
129 + case "idle":
130 + if !d.NextArg() {
131 + return nil, d.ArgErr()
132 + }
133 + dur, err := caddy.ParseDuration(d.Val())
134 + if err != nil {
135 + return nil, d.Errf("parsing idle timeout duration: %v", err)
136 + }
137 + serverOpts.IdleTimeout = caddy.Duration(dur)
138
163 - case "enable_full_duplex":
164 - if d.NextArg() {
165 - return nil, d.ArgErr()
139 + default:
140 + return nil, d.Errf("unrecognized timeouts option '%s'", d.Val())
141 }
167 - serverOpts.EnableFullDuplex = true
142 + }
143 + case "keepalive_interval":
144 + if !d.NextArg() {
145 + return nil, d.ArgErr()
146 + }
147 + dur, err := caddy.ParseDuration(d.Val())
148 + if err != nil {
149 + return nil, d.Errf("parsing keepalive interval duration: %v", err)
150 + }
151 + serverOpts.KeepAliveInterval = caddy.Duration(dur)
152
169 - case "log_credentials":
170 - if d.NextArg() {
171 - return nil, d.ArgErr()
172 - }
173 - serverOpts.ShouldLogCredentials = true
153 + case "max_header_size":
154 + var sizeStr string
155 + if !d.AllArgs(&sizeStr) {
156 + return nil, d.ArgErr()
157 + }
158 + size, err := humanize.ParseBytes(sizeStr)
159 + if err != nil {
160 + return nil, d.Errf("parsing max_header_size: %v", err)
161 + }
162 + serverOpts.MaxHeaderBytes = int(size)
163
175 - case "protocols":
176 - protos := d.RemainingArgs()
177 - for _, proto := range protos {
178 - if proto != "h1" && proto != "h2" && proto != "h2c" && proto != "h3" {
179 - return nil, d.Errf("unknown protocol '%s': expected h1, h2, h2c, or h3", proto)
180 - }
181 - if sliceContains(serverOpts.Protocols, proto) {
182 - return nil, d.Errf("protocol %s specified more than once", proto)
183 - }
184 - serverOpts.Protocols = append(serverOpts.Protocols, proto)
185 - }
186 - if nesting := d.Nesting(); d.NextBlock(nesting) {
187 - return nil, d.ArgErr()
188 - }
164 + case "enable_full_duplex":
165 + if d.NextArg() {
166 + return nil, d.ArgErr()
167 + }
168 + serverOpts.EnableFullDuplex = true
169
190 - case "strict_sni_host":
191 - if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
192 - return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
193 - }
194 - boolVal := true
195 - if d.Val() == "insecure_off" {
196 - boolVal = false
197 - }
198 - serverOpts.StrictSNIHost = &boolVal
170 + case "log_credentials":
171 + if d.NextArg() {
172 + return nil, d.ArgErr()
173 + }
174 + serverOpts.ShouldLogCredentials = true
175
200 - case "trusted_proxies":
201 - if !d.NextArg() {
202 - return nil, d.Err("trusted_proxies expects an IP range source module name as its first argument")
203 - }
204 - modID := "http.ip_sources." + d.Val()
205 - unm, err := caddyfile.UnmarshalModule(d, modID)
206 - if err != nil {
207 - return nil, err
176 + case "protocols":
177 + protos := d.RemainingArgs()
178 + for _, proto := range protos {
179 + if proto != "h1" && proto != "h2" && proto != "h2c" && proto != "h3" {
180 + return nil, d.Errf("unknown protocol '%s': expected h1, h2, h2c, or h3", proto)
181 }
209 - source, ok := unm.(caddyhttp.IPRangeSource)
210 - if !ok {
211 - return nil, fmt.Errorf("module %s (%T) is not an IP range source", modID, unm)
182 + if sliceContains(serverOpts.Protocols, proto) {
183 + return nil, d.Errf("protocol %s specified more than once", proto)
184 }
213 - jsonSource := caddyconfig.JSONModuleObject(
214 - source,
215 - "source",
216 - source.(caddy.Module).CaddyModule().ID.Name(),
217 - nil,
218 - )
219 - serverOpts.TrustedProxiesRaw = jsonSource
185 + serverOpts.Protocols = append(serverOpts.Protocols, proto)
186 + }
187 + if nesting := d.Nesting(); d.NextBlock(nesting) {
188 + return nil, d.ArgErr()
189 + }
190 +
191 + case "strict_sni_host":
192 + if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
193 + return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
194 + }
195 + boolVal := true
196 + if d.Val() == "insecure_off" {
197 + boolVal = false
198 + }
199 + serverOpts.StrictSNIHost = &boolVal
200 +
201 + case "trusted_proxies":
202 + if !d.NextArg() {
203 + return nil, d.Err("trusted_proxies expects an IP range source module name as its first argument")
204 + }
205 + modID := "http.ip_sources." + d.Val()
206 + unm, err := caddyfile.UnmarshalModule(d, modID)
207 + if err != nil {
208 + return nil, err
209 + }
210 + source, ok := unm.(caddyhttp.IPRangeSource)
211 + if !ok {
212 + return nil, fmt.Errorf("module %s (%T) is not an IP range source", modID, unm)
213 + }
214 + jsonSource := caddyconfig.JSONModuleObject(
215 + source,
216 + "source",
217 + source.(caddy.Module).CaddyModule().ID.Name(),
218 + nil,
219 + )
220 + serverOpts.TrustedProxiesRaw = jsonSource
221 +
222 + case "trusted_proxies_strict":
223 + if d.NextArg() {
224 + return nil, d.ArgErr()
225 + }
226 + serverOpts.TrustedProxiesStrict = 1
227
221 - case "trusted_proxies_strict":
222 - if d.NextArg() {
223 - return nil, d.ArgErr()
228 + case "client_ip_headers":
229 + headers := d.RemainingArgs()
230 + for _, header := range headers {
231 + if sliceContains(serverOpts.ClientIPHeaders, header) {
232 + return nil, d.Errf("client IP header %s specified more than once", header)
233 }
225 - serverOpts.TrustedProxiesStrict = 1
234 + serverOpts.ClientIPHeaders = append(serverOpts.ClientIPHeaders, header)
235 + }
236 + if nesting := d.Nesting(); d.NextBlock(nesting) {
237 + return nil, d.ArgErr()
238 + }
239 +
240 + case "metrics":
241 + if d.NextArg() {
242 + return nil, d.ArgErr()
243 + }
244 + if nesting := d.Nesting(); d.NextBlock(nesting) {
245 + return nil, d.ArgErr()
246 + }
247 + serverOpts.Metrics = new(caddyhttp.Metrics)
248 +
249 + // TODO: DEPRECATED. (August 2022)
250 + case "protocol":
251 + caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol sub-option will be removed soon")
252
227 - case "client_ip_headers":
228 - headers := d.RemainingArgs()
229 - for _, header := range headers {
230 - if sliceContains(serverOpts.ClientIPHeaders, header) {
231 - return nil, d.Errf("client IP header %s specified more than once", header)
253 + for nesting := d.Nesting(); d.NextBlock(nesting); {
254 + switch d.Val() {
255 + case "allow_h2c":
256 + caddy.Log().Named("caddyfile").Warn("DEPRECATED: allow_h2c will be removed soon; use protocols option instead")
257 +
258 + if d.NextArg() {
259 + return nil, d.ArgErr()
260 }
233 - serverOpts.ClientIPHeaders = append(serverOpts.ClientIPHeaders, header)
234 - }
235 - if nesting := d.Nesting(); d.NextBlock(nesting) {
236 - return nil, d.ArgErr()
237 - }
261 + if sliceContains(serverOpts.Protocols, "h2c") {
262 + return nil, d.Errf("protocol h2c already specified")
263 + }
264 + serverOpts.Protocols = append(serverOpts.Protocols, "h2c")
265
239 - case "metrics":
240 - if d.NextArg() {
241 - return nil, d.ArgErr()
242 - }
243 - if nesting := d.Nesting(); d.NextBlock(nesting) {
244 - return nil, d.ArgErr()
245 - }
246 - serverOpts.Metrics = new(caddyhttp.Metrics)
247 -
248 - // TODO: DEPRECATED. (August 2022)
249 - case "protocol":
250 - caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol sub-option will be removed soon")
251 -
252 - for nesting := d.Nesting(); d.NextBlock(nesting); {
253 - switch d.Val() {
254 - case "allow_h2c":
255 - caddy.Log().Named("caddyfile").Warn("DEPRECATED: allow_h2c will be removed soon; use protocols option instead")
256 -
257 - if d.NextArg() {
258 - return nil, d.ArgErr()
259 - }
260 - if sliceContains(serverOpts.Protocols, "h2c") {
261 - return nil, d.Errf("protocol h2c already specified")
262 - }
263 - serverOpts.Protocols = append(serverOpts.Protocols, "h2c")
264 -
265 - case "strict_sni_host":
266 - caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol > strict_sni_host in this position will be removed soon; move up to the servers block instead")
267 -
268 - if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
269 - return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
270 - }
271 - boolVal := true
272 - if d.Val() == "insecure_off" {
273 - boolVal = false
274 - }
275 - serverOpts.StrictSNIHost = &boolVal
276 -
277 - default:
278 - return nil, d.Errf("unrecognized protocol option '%s'", d.Val())
266 + case "strict_sni_host":
267 + caddy.Log().Named("caddyfile").Warn("DEPRECATED: protocol > strict_sni_host in this position will be removed soon; move up to the servers block instead")
268 +
269 + if d.NextArg() && d.Val() != "insecure_off" && d.Val() != "on" {
270 + return nil, d.Errf("strict_sni_host only supports 'on' or 'insecure_off', got '%s'", d.Val())
271 }
280 - }
272 + boolVal := true
273 + if d.Val() == "insecure_off" {
274 + boolVal = false
275 + }
276 + serverOpts.StrictSNIHost = &boolVal
277
282 - default:
283 - return nil, d.Errf("unrecognized servers option '%s'", d.Val())
278 + default:
279 + return nil, d.Errf("unrecognized protocol option '%s'", d.Val())
280 + }
281 }
282 +
283 + default:
284 + return nil, d.Errf("unrecognized servers option '%s'", d.Val())
285 }
286 }
287 return serverOpts, nil
caddytest/integration/caddyfile_adapt/push.txt new
+78
@@ -0,0 +1,78 @@
1 +:80
2 +
3 +push * /foo.txt
4 +
5 +push {
6 + GET /foo.txt
7 +}
8 +
9 +push {
10 + GET /foo.txt
11 + HEAD /foo.txt
12 +}
13 +
14 +push {
15 + headers {
16 + Foo bar
17 + }
18 +}
19 +----------
20 +{
21 + "apps": {
22 + "http": {
23 + "servers": {
24 + "srv0": {
25 + "listen": [
26 + ":80"
27 + ],
28 + "routes": [
29 + {
30 + "handle": [
31 + {
32 + "handler": "push",
33 + "resources": [
34 + {
35 + "target": "/foo.txt"
36 + }
37 + ]
38 + },
39 + {
40 + "handler": "push",
41 + "resources": [
42 + {
43 + "method": "GET",
44 + "target": "/foo.txt"
45 + }
46 + ]
47 + },
48 + {
49 + "handler": "push",
50 + "resources": [
51 + {
52 + "method": "GET",
53 + "target": "/foo.txt"
54 + },
55 + {
56 + "method": "HEAD",
57 + "target": "/foo.txt"
58 + }
59 + ]
60 + },
61 + {
62 + "handler": "push",
63 + "headers": {
64 + "set": {
65 + "Foo": [
66 + "bar"
67 + ]
68 + }
69 + }
70 + }
71 + ]
72 + }
73 + ]
74 + }
75 + }
76 + }
77 + }
78 +}
\ No newline at end of file
modules/caddyevents/eventsconfig/caddyfile.go
+1 -7
@@ -40,14 +40,8 @@ func init() {
40 //
41 // If <event> is *, then it will bind to all events.
42 func parseApp(d *caddyfile.Dispenser, _ any) (any, error) {
43 + d.Next() // consume option name
44 app := new(caddyevents.App)
44 -
45 - // consume the option name
46 - if !d.Next() {
47 - return nil, d.ArgErr()
48 - }
49 -
50 - // handle the block
45 for d.NextBlock(0) {
46 switch d.Val() {
47 case "on":
modules/caddyhttp/caddyauth/caddyfile.go
+40 -40
@@ -34,56 +34,56 @@ func init() {
34 //
35 // If no hash algorithm is supplied, bcrypt will be assumed.
36 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
37 + h.Next() // consume directive name
38 +
39 var ba HTTPBasicAuth
40 ba.HashCache = new(Cache)
41
40 - for h.Next() {
41 - var cmp Comparer
42 - args := h.RemainingArgs()
42 + var cmp Comparer
43 + args := h.RemainingArgs()
44
44 - var hashName string
45 - switch len(args) {
46 - case 0:
47 - hashName = "bcrypt"
48 - case 1:
49 - hashName = args[0]
50 - case 2:
51 - hashName = args[0]
52 - ba.Realm = args[1]
53 - default:
54 - return nil, h.ArgErr()
55 - }
56 -
57 - switch hashName {
58 - case "bcrypt":
59 - cmp = BcryptHash{}
60 - case "scrypt":
61 - cmp = ScryptHash{}
62 - default:
63 - return nil, h.Errf("unrecognized hash algorithm: %s", hashName)
64 - }
45 + var hashName string
46 + switch len(args) {
47 + case 0:
48 + hashName = "bcrypt"
49 + case 1:
50 + hashName = args[0]
51 + case 2:
52 + hashName = args[0]
53 + ba.Realm = args[1]
54 + default:
55 + return nil, h.ArgErr()
56 + }
57
66 - ba.HashRaw = caddyconfig.JSONModuleObject(cmp, "algorithm", hashName, nil)
58 + switch hashName {
59 + case "bcrypt":
60 + cmp = BcryptHash{}
61 + case "scrypt":
62 + cmp = ScryptHash{}
63 + default:
64 + return nil, h.Errf("unrecognized hash algorithm: %s", hashName)
65 + }
66
68 - for h.NextBlock(0) {
69 - username := h.Val()
67 + ba.HashRaw = caddyconfig.JSONModuleObject(cmp, "algorithm", hashName, nil)
68
71 - var b64Pwd, b64Salt string
72 - h.Args(&b64Pwd, &b64Salt)
73 - if h.NextArg() {
74 - return nil, h.ArgErr()
75 - }
69 + for h.NextBlock(0) {
70 + username := h.Val()
71
77 - if username == "" || b64Pwd == "" {
78 - return nil, h.Err("username and password cannot be empty or missing")
79 - }
72 + var b64Pwd, b64Salt string
73 + h.Args(&b64Pwd, &b64Salt)
74 + if h.NextArg() {
75 + return nil, h.ArgErr()
76 + }
77
81 - ba.AccountList = append(ba.AccountList, Account{
82 - Username: username,
83 - Password: b64Pwd,
84 - Salt: b64Salt,
85 - })
78 + if username == "" || b64Pwd == "" {
79 + return nil, h.Err("username and password cannot be empty or missing")
80 }
81 +
82 + ba.AccountList = append(ba.AccountList, Account{
83 + Username: username,
84 + Password: b64Pwd,
85 + Salt: b64Salt,
86 + })
87 }
88
89 return Authentication{
modules/caddyhttp/celmatcher.go
+20 -6
@@ -176,13 +176,27 @@ func (m MatchExpression) Match(r *http.Request) bool {
176
177 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
178 func (m *MatchExpression) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
179 - for d.Next() {
180 - if d.CountRemainingArgs() > 1 {
181 - m.Expr = strings.Join(d.RemainingArgsRaw(), " ")
182 - } else {
183 - m.Expr = d.Val()
184 - }
179 + d.Next() // consume matcher name
180 +
181 + // if there's multiple args, then we need to keep the raw
182 + // tokens because the user may have used quotes within their
183 + // CEL expression (e.g. strings) and we should retain that
184 + if d.CountRemainingArgs() > 1 {
185 + m.Expr = strings.Join(d.RemainingArgsRaw(), " ")
186 + return nil
187 }
188 +
189 + // there should at least be one arg
190 + if !d.NextArg() {
191 + return d.ArgErr()
192 + }
193 +
194 + // if there's only one token, then we can safely grab the
195 + // cleaned token (no quotes) and use that as the expression
196 + // because there's no valid CEL expression that is only a
197 + // quoted string; commonly quotes are used in Caddyfile to
198 + // define the expression
199 + m.Expr = d.Val()
200 return nil
201 }
202
modules/caddyhttp/encode/caddyfile.go
+45 -47
@@ -54,62 +54,60 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
54 //
55 // Specifying the formats on the first line will use those formats' defaults.
56 func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
57 - var prefer []string
57 + d.Next() // consume directive name
58
59 - responseMatchers := make(map[string]caddyhttp.ResponseMatcher)
59 + prefer := []string{}
60 + for _, arg := range d.RemainingArgs() {
61 + mod, err := caddy.GetModule("http.encoders." + arg)
62 + if err != nil {
63 + return d.Errf("finding encoder module '%s': %v", mod, err)
64 + }
65 + encoding, ok := mod.New().(Encoding)
66 + if !ok {
67 + return d.Errf("module %s is not an HTTP encoding", mod)
68 + }
69 + if enc.EncodingsRaw == nil {
70 + enc.EncodingsRaw = make(caddy.ModuleMap)
71 + }
72 + enc.EncodingsRaw[arg] = caddyconfig.JSON(encoding, nil)
73 + prefer = append(prefer, arg)
74 + }
75
61 - for d.Next() {
62 - for _, arg := range d.RemainingArgs() {
63 - mod, err := caddy.GetModule("http.encoders." + arg)
76 + responseMatchers := make(map[string]caddyhttp.ResponseMatcher)
77 + for d.NextBlock(0) {
78 + switch d.Val() {
79 + case "minimum_length":
80 + if !d.NextArg() {
81 + return d.ArgErr()
82 + }
83 + minLength, err := strconv.Atoi(d.Val())
84 if err != nil {
65 - return d.Errf("finding encoder module '%s': %v", mod, err)
85 + return err
86 }
67 - encoding, ok := mod.New().(Encoding)
87 + enc.MinLength = minLength
88 + case "match":
89 + err := caddyhttp.ParseNamedResponseMatcher(d.NewFromNextSegment(), responseMatchers)
90 + if err != nil {
91 + return err
92 + }
93 + matcher := responseMatchers["match"]
94 + enc.Matcher = &matcher
95 + default:
96 + name := d.Val()
97 + modID := "http.encoders." + name
98 + unm, err := caddyfile.UnmarshalModule(d, modID)
99 + if err != nil {
100 + return err
101 + }
102 + encoding, ok := unm.(Encoding)
103 if !ok {
69 - return d.Errf("module %s is not an HTTP encoding", mod)
104 + return d.Errf("module %s is not an HTTP encoding; is %T", modID, unm)
105 }
106 if enc.EncodingsRaw == nil {
107 enc.EncodingsRaw = make(caddy.ModuleMap)
108 }
74 - enc.EncodingsRaw[arg] = caddyconfig.JSON(encoding, nil)
75 - prefer = append(prefer, arg)
76 - }
77 -
78 - for d.NextBlock(0) {
79 - switch d.Val() {
80 - case "minimum_length":
81 - if !d.NextArg() {
82 - return d.ArgErr()
83 - }
84 - minLength, err := strconv.Atoi(d.Val())
85 - if err != nil {
86 - return err
87 - }
88 - enc.MinLength = minLength
89 - case "match":
90 - err := caddyhttp.ParseNamedResponseMatcher(d.NewFromNextSegment(), responseMatchers)
91 - if err != nil {
92 - return err
93 - }
94 - matcher := responseMatchers["match"]
95 - enc.Matcher = &matcher
96 - default:
97 - name := d.Val()
98 - modID := "http.encoders." + name
99 - unm, err := caddyfile.UnmarshalModule(d, modID)
100 - if err != nil {
101 - return err
102 - }
103 - encoding, ok := unm.(Encoding)
104 - if !ok {
105 - return d.Errf("module %s is not an HTTP encoding; is %T", modID, unm)
106 - }
107 - if enc.EncodingsRaw == nil {
108 - enc.EncodingsRaw = make(caddy.ModuleMap)
109 - }
110 - enc.EncodingsRaw[name] = caddyconfig.JSON(encoding, nil)
111 - prefer = append(prefer, name)
112 - }
109 + enc.EncodingsRaw[name] = caddyconfig.JSON(encoding, nil)
110 + prefer = append(prefer, name)
111 }
112 }
113
modules/caddyhttp/encode/gzip/gzip.go
+9 -10
@@ -44,17 +44,16 @@ func (Gzip) CaddyModule() caddy.ModuleInfo {
44
45 // UnmarshalCaddyfile sets up the handler from Caddyfile tokens.
46 func (g *Gzip) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
47 - for d.Next() {
48 - if !d.NextArg() {
49 - continue
50 - }
51 - levelStr := d.Val()
52 - level, err := strconv.Atoi(levelStr)
53 - if err != nil {
54 - return err
55 - }
56 - g.Level = level
47 + d.Next() // consume option name
48 + if !d.NextArg() {
49 + return nil
50 }
51 + levelStr := d.Val()
52 + level, err := strconv.Atoi(levelStr)
53 + if err != nil {
54 + return err
55 + }
56 + g.Level = level
57 return nil
58 }
59
modules/caddyhttp/fileserver/caddyfile.go
+1 -1
@@ -223,7 +223,7 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
223
224 // parse out the optional try policy
225 var tryPolicy string
226 - for nesting := h.Nesting(); h.NextBlock(nesting); {
226 + for h.NextBlock(0) {
227 switch h.Val() {
228 case "policy":
229 if tryPolicy != "" {
modules/caddyhttp/fileserver/matcher.go
+1
@@ -127,6 +127,7 @@ func (MatchFile) CaddyModule() caddy.ModuleInfo {
127 // try_policy first_exist|smallest_size|largest_size|most_recently_modified
128 // }
129 func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
130 + // iterate to merge multiple matchers into one
131 for d.Next() {
132 m.TryFiles = append(m.TryFiles, d.RemainingArgs()...)
133 for d.NextBlock(0) {
modules/caddyhttp/headers/caddyfile.go
+90 -98
@@ -47,14 +47,12 @@ func init() {
47 // ? conditionally sets a value only if the header field is not already set,
48 // and > sets a field with defer enabled.
49 func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
50 - if !h.Next() {
51 - return nil, h.ArgErr()
52 - }
53 -
50 + h.Next() // consume directive name
51 matcherSet, err := h.ExtractMatcherSet()
52 if err != nil {
53 return nil, err
54 }
55 + h.Next() // consume the directive name again (matcher parsing resets)
56
57 makeHandler := func() Handler {
58 return Handler{
@@ -65,73 +63,71 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
63 }
64 handler, handlerWithRequire := makeHandler(), makeHandler()
65
68 - for h.Next() {
69 - // first see if headers are in the initial line
70 - var hasArgs bool
66 + // first see if headers are in the initial line
67 + var hasArgs bool
68 + if h.NextArg() {
69 + hasArgs = true
70 + field := h.Val()
71 + var value, replacement string
72 if h.NextArg() {
72 - hasArgs = true
73 - field := h.Val()
74 - var value, replacement string
75 - if h.NextArg() {
76 - value = h.Val()
77 - }
78 - if h.NextArg() {
79 - replacement = h.Val()
80 - }
81 - err := applyHeaderOp(
82 - handler.Response.HeaderOps,
83 - handler.Response,
84 - field,
85 - value,
86 - replacement,
87 - )
88 - if err != nil {
89 - return nil, h.Err(err.Error())
90 - }
91 - if len(handler.Response.HeaderOps.Delete) > 0 {
92 - handler.Response.Deferred = true
93 - }
73 + value = h.Val()
74 }
75 + if h.NextArg() {
76 + replacement = h.Val()
77 + }
78 + err := applyHeaderOp(
79 + handler.Response.HeaderOps,
80 + handler.Response,
81 + field,
82 + value,
83 + replacement,
84 + )
85 + if err != nil {
86 + return nil, h.Err(err.Error())
87 + }
88 + if len(handler.Response.HeaderOps.Delete) > 0 {
89 + handler.Response.Deferred = true
90 + }
91 + }
92
96 - // if not, they should be in a block
97 - for h.NextBlock(0) {
98 - field := h.Val()
99 - if field == "defer" {
100 - handler.Response.Deferred = true
101 - continue
102 - }
103 - if hasArgs {
104 - return nil, h.Err("cannot specify headers in both arguments and block") // because it would be weird
105 - }
93 + // if not, they should be in a block
94 + for h.NextBlock(0) {
95 + field := h.Val()
96 + if field == "defer" {
97 + handler.Response.Deferred = true
98 + continue
99 + }
100 + if hasArgs {
101 + return nil, h.Err("cannot specify headers in both arguments and block") // because it would be weird
102 + }
103
107 - // sometimes it is habitual for users to suffix a field name with a colon,
108 - // as if they were writing a curl command or something; see
109 - // https://caddy.community/t/v2-reverse-proxy-please-add-cors-example-to-the-docs/7349/19
110 - field = strings.TrimSuffix(field, ":")
104 + // sometimes it is habitual for users to suffix a field name with a colon,
105 + // as if they were writing a curl command or something; see
106 + // https://caddy.community/t/v2-reverse-proxy-please-add-cors-example-to-the-docs/7349/19
107 + field = strings.TrimSuffix(field, ":")
108
112 - var value, replacement string
113 - if h.NextArg() {
114 - value = h.Val()
115 - }
116 - if h.NextArg() {
117 - replacement = h.Val()
118 - }
109 + var value, replacement string
110 + if h.NextArg() {
111 + value = h.Val()
112 + }
113 + if h.NextArg() {
114 + replacement = h.Val()
115 + }
116
120 - handlerToUse := handler
121 - if strings.HasPrefix(field, "?") {
122 - handlerToUse = handlerWithRequire
123 - }
117 + handlerToUse := handler
118 + if strings.HasPrefix(field, "?") {
119 + handlerToUse = handlerWithRequire
120 + }
121
125 - err := applyHeaderOp(
126 - handlerToUse.Response.HeaderOps,
127 - handlerToUse.Response,
128 - field,
129 - value,
130 - replacement,
131 - )
132 - if err != nil {
133 - return nil, h.Err(err.Error())
134 - }
122 + err := applyHeaderOp(
123 + handlerToUse.Response.HeaderOps,
124 + handlerToUse.Response,
125 + field,
126 + value,
127 + replacement,
128 + )
129 + if err != nil {
130 + return nil, h.Err(err.Error())
131 }
132 }
133
@@ -151,55 +147,51 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
147 //
148 // request_header [<matcher>] [[+|-]<field> [<value|regexp>] [<replacement>]]
149 func parseReqHdrCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
154 - if !h.Next() {
155 - return nil, h.ArgErr()
156 - }
157 -
150 + h.Next() // consume directive name
151 matcherSet, err := h.ExtractMatcherSet()
152 if err != nil {
153 return nil, err
154 }
155 + h.Next() // consume the directive name again (matcher parsing resets)
156
157 configValues := []httpcaddyfile.ConfigValue{}
158
165 - for h.Next() {
166 - if !h.NextArg() {
167 - return nil, h.ArgErr()
168 - }
169 - field := h.Val()
159 + if !h.NextArg() {
160 + return nil, h.ArgErr()
161 + }
162 + field := h.Val()
163
171 - hdr := Handler{
172 - Request: &HeaderOps{},
173 - }
164 + hdr := Handler{
165 + Request: &HeaderOps{},
166 + }
167
175 - // sometimes it is habitual for users to suffix a field name with a colon,
176 - // as if they were writing a curl command or something; see
177 - // https://caddy.community/t/v2-reverse-proxy-please-add-cors-example-to-the-docs/7349/19
178 - field = strings.TrimSuffix(field, ":")
168 + // sometimes it is habitual for users to suffix a field name with a colon,
169 + // as if they were writing a curl command or something; see
170 + // https://caddy.community/t/v2-reverse-proxy-please-add-cors-example-to-the-docs/7349/19
171 + field = strings.TrimSuffix(field, ":")
172
180 - var value, replacement string
181 - if h.NextArg() {
182 - value = h.Val()
183 - }
173 + var value, replacement string
174 + if h.NextArg() {
175 + value = h.Val()
176 + }
177 + if h.NextArg() {
178 + replacement = h.Val()
179 if h.NextArg() {
185 - replacement = h.Val()
186 - if h.NextArg() {
187 - return nil, h.ArgErr()
188 - }
180 + return nil, h.ArgErr()
181 }
182 + }
183
191 - if hdr.Request == nil {
192 - hdr.Request = new(HeaderOps)
193 - }
194 - if err := CaddyfileHeaderOp(hdr.Request, field, value, replacement); err != nil {
195 - return nil, h.Err(err.Error())
196 - }
184 + if hdr.Request == nil {
185 + hdr.Request = new(HeaderOps)
186 + }
187 + if err := CaddyfileHeaderOp(hdr.Request, field, value, replacement); err != nil {
188 + return nil, h.Err(err.Error())
189 + }
190
198 - configValues = append(configValues, h.NewRoute(matcherSet, hdr)...)
191 + configValues = append(configValues, h.NewRoute(matcherSet, hdr)...)
192
200 - if h.NextArg() {
201 - return nil, h.ArgErr()
202 - }
193 + if h.NextArg() {
194 + return nil, h.ArgErr()
195 }
196 return configValues, nil
197 }
modules/caddyhttp/ip_matchers.go
+23 -25
@@ -79,24 +79,23 @@ func (MatchRemoteIP) CaddyModule() caddy.ModuleInfo {
79
80 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
81 func (m *MatchRemoteIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
82 - for d.Next() {
83 - for d.NextArg() {
84 - if d.Val() == "forwarded" {
85 - if len(m.Ranges) > 0 {
86 - return d.Err("if used, 'forwarded' must be first argument")
87 - }
88 - m.Forwarded = true
89 - continue
90 - }
91 - if d.Val() == "private_ranges" {
92 - m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
93 - continue
82 + d.Next() // consume matcher name
83 + for d.NextArg() {
84 + if d.Val() == "forwarded" {
85 + if len(m.Ranges) > 0 {
86 + return d.Err("if used, 'forwarded' must be first argument")
87 }
95 - m.Ranges = append(m.Ranges, d.Val())
88 + m.Forwarded = true
89 + continue
90 }
97 - if d.NextBlock(0) {
98 - return d.Err("malformed remote_ip matcher: blocks are not supported")
91 + if d.Val() == "private_ranges" {
92 + m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
93 + continue
94 }
95 + m.Ranges = append(m.Ranges, d.Val())
96 + }
97 + if d.NextBlock(0) {
98 + return d.Err("malformed remote_ip matcher: blocks are not supported")
99 }
100 return nil
101 }
@@ -189,17 +188,16 @@ func (MatchClientIP) CaddyModule() caddy.ModuleInfo {
188
189 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
190 func (m *MatchClientIP) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
192 - for d.Next() {
193 - for d.NextArg() {
194 - if d.Val() == "private_ranges" {
195 - m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
196 - continue
197 - }
198 - m.Ranges = append(m.Ranges, d.Val())
199 - }
200 - if d.NextBlock(0) {
201 - return d.Err("malformed client_ip matcher: blocks are not supported")
191 + d.Next() // consume matcher name
192 + for d.NextArg() {
193 + if d.Val() == "private_ranges" {
194 + m.Ranges = append(m.Ranges, PrivateRangesCIDR()...)
195 + continue
196 }
197 + m.Ranges = append(m.Ranges, d.Val())
198 + }
199 + if d.NextBlock(0) {
200 + return d.Err("malformed client_ip matcher: blocks are not supported")
201 }
202 return nil
203 }
modules/caddyhttp/map/caddyfile.go
+54 -55
@@ -42,74 +42,73 @@ func init() {
42 // However, for convenience, there may be fewer outputs than destinations and any missing
43 // outputs will be filled in implicitly.
44 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
45 + h.Next() // consume directive name
46 +
47 var handler Handler
48
47 - for h.Next() {
48 - // source
49 - if !h.NextArg() {
50 - return nil, h.ArgErr()
51 - }
52 - handler.Source = h.Val()
49 + // source
50 + if !h.NextArg() {
51 + return nil, h.ArgErr()
52 + }
53 + handler.Source = h.Val()
54
54 - // destinations
55 - handler.Destinations = h.RemainingArgs()
56 - if len(handler.Destinations) == 0 {
57 - return nil, h.Err("missing destination argument(s)")
58 - }
59 - for _, dest := range handler.Destinations {
60 - if shorthand := httpcaddyfile.WasReplacedPlaceholderShorthand(dest); shorthand != "" {
61 - return nil, h.Errf("destination %s conflicts with a Caddyfile placeholder shorthand", shorthand)
62 - }
55 + // destinations
56 + handler.Destinations = h.RemainingArgs()
57 + if len(handler.Destinations) == 0 {
58 + return nil, h.Err("missing destination argument(s)")
59 + }
60 + for _, dest := range handler.Destinations {
61 + if shorthand := httpcaddyfile.WasReplacedPlaceholderShorthand(dest); shorthand != "" {
62 + return nil, h.Errf("destination %s conflicts with a Caddyfile placeholder shorthand", shorthand)
63 }
64 + }
65
65 - // mappings
66 - for h.NextBlock(0) {
67 - // defaults are a special case
68 - if h.Val() == "default" {
69 - if len(handler.Defaults) > 0 {
70 - return nil, h.Err("defaults already defined")
71 - }
72 - handler.Defaults = h.RemainingArgs()
73 - for len(handler.Defaults) < len(handler.Destinations) {
74 - handler.Defaults = append(handler.Defaults, "")
75 - }
76 - continue
77 - }
78 -
79 - // every line maps an input value to one or more outputs
80 - in := h.Val()
81 - var outs []any
82 - for h.NextArg() {
83 - val := h.ScalarVal()
84 - if val == "-" {
85 - outs = append(outs, nil)
86 - } else {
87 - outs = append(outs, val)
88 - }
66 + // mappings
67 + for h.NextBlock(0) {
68 + // defaults are a special case
69 + if h.Val() == "default" {
70 + if len(handler.Defaults) > 0 {
71 + return nil, h.Err("defaults already defined")
72 }
90 -
91 - // cannot have more outputs than destinations
92 - if len(outs) > len(handler.Destinations) {
93 - return nil, h.Err("too many outputs")
73 + handler.Defaults = h.RemainingArgs()
74 + for len(handler.Defaults) < len(handler.Destinations) {
75 + handler.Defaults = append(handler.Defaults, "")
76 }
77 + continue
78 + }
79
96 - // for convenience, can have fewer outputs than destinations, but the
97 - // underlying handler won't accept that, so we fill in nil values
98 - for len(outs) < len(handler.Destinations) {
80 + // every line maps an input value to one or more outputs
81 + in := h.Val()
82 + var outs []any
83 + for h.NextArg() {
84 + val := h.ScalarVal()
85 + if val == "-" {
86 outs = append(outs, nil)
100 - }
101 -
102 - // create the mapping
103 - mapping := Mapping{Outputs: outs}
104 - if strings.HasPrefix(in, "~") {
105 - mapping.InputRegexp = in[1:]
87 } else {
107 - mapping.Input = in
88 + outs = append(outs, val)
89 }
90 + }
91
110 - handler.Mappings = append(handler.Mappings, mapping)
92 + // cannot have more outputs than destinations
93 + if len(outs) > len(handler.Destinations) {
94 + return nil, h.Err("too many outputs")
95 }
112 - }
96
97 + // for convenience, can have fewer outputs than destinations, but the
98 + // underlying handler won't accept that, so we fill in nil values
99 + for len(outs) < len(handler.Destinations) {
100 + outs = append(outs, nil)
101 + }
102 +
103 + // create the mapping
104 + mapping := Mapping{Outputs: outs}
105 + if strings.HasPrefix(in, "~") {
106 + mapping.InputRegexp = in[1:]
107 + } else {
108 + mapping.Input = in
109 + }
110 +
111 + handler.Mappings = append(handler.Mappings, mapping)
112 + }
113 return handler, nil
114 }
modules/caddyhttp/matchers.go
+9
@@ -225,6 +225,7 @@ func (MatchHost) CaddyModule() caddy.ModuleInfo {
225
226 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
227 func (m *MatchHost) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
228 + // iterate to merge multiple matchers into one
229 for d.Next() {
230 *m = append(*m, d.RemainingArgs()...)
231 if d.NextBlock(0) {
@@ -632,6 +633,7 @@ func (MatchPath) CELLibrary(ctx caddy.Context) (cel.Library, error) {
633
634 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
635 func (m *MatchPath) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
636 + // iterate to merge multiple matchers into one
637 for d.Next() {
638 *m = append(*m, d.RemainingArgs()...)
639 if d.NextBlock(0) {
@@ -716,6 +718,7 @@ func (MatchMethod) CaddyModule() caddy.ModuleInfo {
718
719 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
720 func (m *MatchMethod) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
721 + // iterate to merge multiple matchers into one
722 for d.Next() {
723 *m = append(*m, d.RemainingArgs()...)
724 if d.NextBlock(0) {
@@ -770,6 +773,7 @@ func (m *MatchQuery) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
773 if *m == nil {
774 *m = make(map[string][]string)
775 }
776 + // iterate to merge multiple matchers into one
777 for d.Next() {
778 for _, query := range d.RemainingArgs() {
779 if query == "" {
@@ -868,6 +872,7 @@ func (m *MatchHeader) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
872 if *m == nil {
873 *m = make(map[string][]string)
874 }
875 + // iterate to merge multiple matchers into one
876 for d.Next() {
877 var field, val string
878 if !d.Args(&field) {
@@ -1002,6 +1007,7 @@ func (m *MatchHeaderRE) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1007 if *m == nil {
1008 *m = make(map[string]*MatchRegexp)
1009 }
1010 + // iterate to merge multiple matchers into one
1011 for d.Next() {
1012 var first, second, third string
1013 if !d.Args(&first, &second) {
@@ -1166,6 +1172,7 @@ func (m MatchProtocol) Match(r *http.Request) bool {
1172
1173 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
1174 func (m *MatchProtocol) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1175 + // iterate to merge multiple matchers into one
1176 for d.Next() {
1177 var proto string
1178 if !d.Args(&proto) {
@@ -1207,6 +1214,7 @@ func (MatchNot) CaddyModule() caddy.ModuleInfo {
1214
1215 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
1216 func (m *MatchNot) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1217 + // iterate to merge multiple matchers into one
1218 for d.Next() {
1219 matcherSet, err := ParseCaddyfileNestedMatcherSet(d)
1220 if err != nil {
@@ -1331,6 +1339,7 @@ func (mre *MatchRegexp) Match(input string, repl *caddy.Replacer) bool {
1339
1340 // UnmarshalCaddyfile implements caddyfile.Unmarshaler.
1341 func (mre *MatchRegexp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1342 + // iterate to merge multiple matchers into one
1343 for d.Next() {
1344 // If this is the second iteration of the loop
1345 // then there's more than one path_regexp matcher
modules/caddyhttp/proxyprotocol/module.go
+30 -30
@@ -39,40 +39,40 @@ func (ListenerWrapper) CaddyModule() caddy.ModuleInfo {
39 // fallback_policy <policy>
40 // }
41 func (w *ListenerWrapper) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
42 - for d.Next() {
43 - // No same-line options are supported
44 - if d.NextArg() {
45 - return d.ArgErr()
46 - }
42 + d.Next() // consume wrapper name
43
48 - for d.NextBlock(0) {
49 - switch d.Val() {
50 - case "timeout":
51 - if !d.NextArg() {
52 - return d.ArgErr()
53 - }
54 - dur, err := caddy.ParseDuration(d.Val())
55 - if err != nil {
56 - return d.Errf("parsing proxy_protocol timeout duration: %v", err)
57 - }
58 - w.Timeout = caddy.Duration(dur)
44 + // No same-line options are supported
45 + if d.NextArg() {
46 + return d.ArgErr()
47 + }
48
60 - case "allow":
61 - w.Allow = append(w.Allow, d.RemainingArgs()...)
62 - case "deny":
63 - w.Deny = append(w.Deny, d.RemainingArgs()...)
64 - case "fallback_policy":
65 - if !d.NextArg() {
66 - return d.ArgErr()
67 - }
68 - p, err := parsePolicy(d.Val())
69 - if err != nil {
70 - return d.WrapErr(err)
71 - }
72 - w.FallbackPolicy = p
73 - default:
49 + for d.NextBlock(0) {
50 + switch d.Val() {
51 + case "timeout":
52 + if !d.NextArg() {
53 return d.ArgErr()
54 }
55 + dur, err := caddy.ParseDuration(d.Val())
56 + if err != nil {
57 + return d.Errf("parsing proxy_protocol timeout duration: %v", err)
58 + }
59 + w.Timeout = caddy.Duration(dur)
60 +
61 + case "allow":
62 + w.Allow = append(w.Allow, d.RemainingArgs()...)
63 + case "deny":
64 + w.Deny = append(w.Deny, d.RemainingArgs()...)
65 + case "fallback_policy":
66 + if !d.NextArg() {
67 + return d.ArgErr()
68 + }
69 + p, err := parsePolicy(d.Val())
70 + if err != nil {
71 + return d.WrapErr(err)
72 + }
73 + w.FallbackPolicy = p
74 + default:
75 + return d.ArgErr()
76 }
77 }
78 return nil
modules/caddyhttp/push/caddyfile.go
+45 -45
@@ -44,63 +44,63 @@ func init() {
44 // Placeholders are accepted in resource and header field
45 // name and value and replacement tokens.
46 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
47 - handler := new(Handler)
48 -
49 - for h.Next() {
50 - if h.NextArg() {
51 - handler.Resources = append(handler.Resources, Resource{Target: h.Val()})
52 - }
47 + h.Next() // consume directive name
48
54 - // optional block
55 - for outerNesting := h.Nesting(); h.NextBlock(outerNesting); {
56 - switch h.Val() {
57 - case "headers":
58 - if h.NextArg() {
59 - return nil, h.ArgErr()
60 - }
61 - for innerNesting := h.Nesting(); h.NextBlock(innerNesting); {
62 - var err error
49 + handler := new(Handler)
50
64 - // include current token, which we treat as an argument here
65 - args := []string{h.Val()}
66 - args = append(args, h.RemainingArgs()...)
51 + // inline resources
52 + if h.NextArg() {
53 + handler.Resources = append(handler.Resources, Resource{Target: h.Val()})
54 + }
55
68 - if handler.Headers == nil {
69 - handler.Headers = new(HeaderConfig)
70 - }
56 + // optional block
57 + for h.NextBlock(0) {
58 + switch h.Val() {
59 + case "headers":
60 + if h.NextArg() {
61 + return nil, h.ArgErr()
62 + }
63 + for nesting := h.Nesting(); h.NextBlock(nesting); {
64 + var err error
65
72 - switch len(args) {
73 - case 1:
74 - err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], "", "")
75 - case 2:
76 - err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], "")
77 - case 3:
78 - err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], args[2])
79 - default:
80 - return nil, h.ArgErr()
81 - }
66 + // include current token, which we treat as an argument here
67 + args := []string{h.Val()}
68 + args = append(args, h.RemainingArgs()...)
69
83 - if err != nil {
84 - return nil, h.Err(err.Error())
85 - }
70 + if handler.Headers == nil {
71 + handler.Headers = new(HeaderConfig)
72 }
73
88 - case "GET", "HEAD":
89 - method := h.Val()
90 - if !h.NextArg() {
74 + switch len(args) {
75 + case 1:
76 + err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], "", "")
77 + case 2:
78 + err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], "")
79 + case 3:
80 + err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], args[2])
81 + default:
82 return nil, h.ArgErr()
83 }
93 - target := h.Val()
94 - handler.Resources = append(handler.Resources, Resource{
95 - Method: method,
96 - Target: target,
97 - })
84
99 - default:
100 - handler.Resources = append(handler.Resources, Resource{Target: h.Val()})
85 + if err != nil {
86 + return nil, h.Err(err.Error())
87 + }
88 + }
89 +
90 + case "GET", "HEAD":
91 + method := h.Val()
92 + if !h.NextArg() {
93 + return nil, h.ArgErr()
94 }
95 + target := h.Val()
96 + handler.Resources = append(handler.Resources, Resource{
97 + Method: method,
98 + Target: target,
99 + })
100 +
101 + default:
102 + handler.Resources = append(handler.Resources, Resource{Target: h.Val()})
103 }
104 }
104 -
105 return handler, nil
106 }
modules/caddyhttp/requestbody/caddyfile.go
+17 -16
@@ -26,25 +26,26 @@ func init() {
26 }
27
28 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
29 + h.Next() // consume directive name
30 +
31 rb := new(RequestBody)
32
31 - for h.Next() {
32 - // configuration should be in a block
33 - for h.NextBlock(0) {
34 - switch h.Val() {
35 - case "max_size":
36 - var sizeStr string
37 - if !h.AllArgs(&sizeStr) {
38 - return nil, h.ArgErr()
39 - }
40 - size, err := humanize.ParseBytes(sizeStr)
41 - if err != nil {
42 - return nil, h.Errf("parsing max_size: %v", err)
43 - }
44 - rb.MaxSize = int64(size)
45 - default:
46 - return nil, h.Errf("unrecognized servers option '%s'", h.Val())
33 + // configuration should be in a block
34 + for h.NextBlock(0) {
35 + switch h.Val() {
36 + case "max_size":
37 + var sizeStr string
38 + if !h.AllArgs(&sizeStr) {
39 + return nil, h.ArgErr()
40 + }
41 + size, err := humanize.ParseBytes(sizeStr)
42 + if err != nil {
43 + return nil, h.Errf("parsing max_size: %v", err)
44 }
45 + rb.MaxSize = int64(size)
46 +
47 + default:
48 + return nil, h.Errf("unrecognized servers option '%s'", h.Val())
49 }
50 }
51
modules/caddyhttp/responsematchers.go
+38 -40
@@ -67,55 +67,53 @@ func (rm ResponseMatcher) matchStatusCode(statusCode int) bool {
67 //
68 // @name [header <field> [<value>]] | [status <code...>]
69 func ParseNamedResponseMatcher(d *caddyfile.Dispenser, matchers map[string]ResponseMatcher) error {
70 - for d.Next() {
71 - definitionName := d.Val()
70 + d.Next() // consume matcher name
71 + definitionName := d.Val()
72
73 - if _, ok := matchers[definitionName]; ok {
74 - return d.Errf("matcher is defined more than once: %s", definitionName)
75 - }
73 + if _, ok := matchers[definitionName]; ok {
74 + return d.Errf("matcher is defined more than once: %s", definitionName)
75 + }
76
77 - matcher := ResponseMatcher{}
78 - for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
79 - switch d.Val() {
80 - case "header":
81 - if matcher.Headers == nil {
82 - matcher.Headers = http.Header{}
83 - }
77 + matcher := ResponseMatcher{}
78 + for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
79 + switch d.Val() {
80 + case "header":
81 + if matcher.Headers == nil {
82 + matcher.Headers = http.Header{}
83 + }
84
85 - // reuse the header request matcher's unmarshaler
86 - headerMatcher := MatchHeader(matcher.Headers)
87 - err := headerMatcher.UnmarshalCaddyfile(d.NewFromNextSegment())
88 - if err != nil {
89 - return err
90 - }
85 + // reuse the header request matcher's unmarshaler
86 + headerMatcher := MatchHeader(matcher.Headers)
87 + err := headerMatcher.UnmarshalCaddyfile(d.NewFromNextSegment())
88 + if err != nil {
89 + return err
90 + }
91
92 - matcher.Headers = http.Header(headerMatcher)
93 - case "status":
94 - if matcher.StatusCode == nil {
95 - matcher.StatusCode = []int{}
96 - }
92 + matcher.Headers = http.Header(headerMatcher)
93 + case "status":
94 + if matcher.StatusCode == nil {
95 + matcher.StatusCode = []int{}
96 + }
97
98 - args := d.RemainingArgs()
99 - if len(args) == 0 {
100 - return d.ArgErr()
101 - }
98 + args := d.RemainingArgs()
99 + if len(args) == 0 {
100 + return d.ArgErr()
101 + }
102
103 - for _, arg := range args {
104 - if len(arg) == 3 && strings.HasSuffix(arg, "xx") {
105 - arg = arg[:1]
106 - }
107 - statusNum, err := strconv.Atoi(arg)
108 - if err != nil {
109 - return d.Errf("bad status value '%s': %v", arg, err)
110 - }
111 - matcher.StatusCode = append(matcher.StatusCode, statusNum)
103 + for _, arg := range args {
104 + if len(arg) == 3 && strings.HasSuffix(arg, "xx") {
105 + arg = arg[:1]
106 }
113 - default:
114 - return d.Errf("unrecognized response matcher %s", d.Val())
107 + statusNum, err := strconv.Atoi(arg)
108 + if err != nil {
109 + return d.Errf("bad status value '%s': %v", arg, err)
110 + }
111 + matcher.StatusCode = append(matcher.StatusCode, statusNum)
112 }
113 + default:
114 + return d.Errf("unrecognized response matcher %s", d.Val())
115 }
117 -
118 - matchers[definitionName] = matcher
116 }
117 + matchers[definitionName] = matcher
118 return nil
119 }
modules/caddyhttp/reverseproxy/caddyfile.go
+465 -469
@@ -210,7 +210,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
210 }
211 }
212
213 - for nesting := d.Nesting(); d.NextBlock(nesting); {
213 + for d.NextBlock(0) {
214 // if the subdirective has an "@" prefix then we
215 // parse it as a response matcher for use with "handle_response"
216 if strings.HasPrefix(d.Val(), matcherPrefix) {
@@ -774,7 +774,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
774 }
775
776 // make sure there's no block, cause it doesn't make sense
777 - if d.NextBlock(1) {
777 + if nesting := d.Nesting(); d.NextBlock(nesting) {
778 return d.Errf("cannot define routes for 'replace_status', use 'handle_response' instead.")
779 }
780
@@ -930,297 +930,296 @@ func (h *Handler) FinalizeUnmarshalCaddyfile(helper httpcaddyfile.Helper) error
930 // max_idle_conns_per_host <count>
931 // }
932 func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
933 - for d.Next() {
934 - for d.NextBlock(0) {
935 - switch d.Val() {
936 - case "read_buffer":
937 - if !d.NextArg() {
938 - return d.ArgErr()
939 - }
940 - size, err := humanize.ParseBytes(d.Val())
941 - if err != nil {
942 - return d.Errf("invalid read buffer size '%s': %v", d.Val(), err)
943 - }
944 - h.ReadBufferSize = int(size)
945 -
946 - case "write_buffer":
947 - if !d.NextArg() {
948 - return d.ArgErr()
949 - }
950 - size, err := humanize.ParseBytes(d.Val())
951 - if err != nil {
952 - return d.Errf("invalid write buffer size '%s': %v", d.Val(), err)
953 - }
954 - h.WriteBufferSize = int(size)
933 + d.Next() // consume transport name
934 + for d.NextBlock(0) {
935 + switch d.Val() {
936 + case "read_buffer":
937 + if !d.NextArg() {
938 + return d.ArgErr()
939 + }
940 + size, err := humanize.ParseBytes(d.Val())
941 + if err != nil {
942 + return d.Errf("invalid read buffer size '%s': %v", d.Val(), err)
943 + }
944 + h.ReadBufferSize = int(size)
945
956 - case "read_timeout":
957 - if !d.NextArg() {
958 - return d.ArgErr()
959 - }
960 - timeout, err := caddy.ParseDuration(d.Val())
961 - if err != nil {
962 - return d.Errf("invalid read timeout duration '%s': %v", d.Val(), err)
963 - }
964 - h.ReadTimeout = caddy.Duration(timeout)
946 + case "write_buffer":
947 + if !d.NextArg() {
948 + return d.ArgErr()
949 + }
950 + size, err := humanize.ParseBytes(d.Val())
951 + if err != nil {
952 + return d.Errf("invalid write buffer size '%s': %v", d.Val(), err)
953 + }
954 + h.WriteBufferSize = int(size)
955
966 - case "write_timeout":
967 - if !d.NextArg() {
968 - return d.ArgErr()
969 - }
970 - timeout, err := caddy.ParseDuration(d.Val())
971 - if err != nil {
972 - return d.Errf("invalid write timeout duration '%s': %v", d.Val(), err)
973 - }
974 - h.WriteTimeout = caddy.Duration(timeout)
956 + case "read_timeout":
957 + if !d.NextArg() {
958 + return d.ArgErr()
959 + }
960 + timeout, err := caddy.ParseDuration(d.Val())
961 + if err != nil {
962 + return d.Errf("invalid read timeout duration '%s': %v", d.Val(), err)
963 + }
964 + h.ReadTimeout = caddy.Duration(timeout)
965
976 - case "max_response_header":
977 - if !d.NextArg() {
978 - return d.ArgErr()
979 - }
980 - size, err := humanize.ParseBytes(d.Val())
981 - if err != nil {
982 - return d.Errf("invalid max response header size '%s': %v", d.Val(), err)
983 - }
984 - h.MaxResponseHeaderSize = int64(size)
966 + case "write_timeout":
967 + if !d.NextArg() {
968 + return d.ArgErr()
969 + }
970 + timeout, err := caddy.ParseDuration(d.Val())
971 + if err != nil {
972 + return d.Errf("invalid write timeout duration '%s': %v", d.Val(), err)
973 + }
974 + h.WriteTimeout = caddy.Duration(timeout)
975
986 - case "proxy_protocol":
987 - if !d.NextArg() {
988 - return d.ArgErr()
989 - }
990 - switch proxyProtocol := d.Val(); proxyProtocol {
991 - case "v1", "v2":
992 - h.ProxyProtocol = proxyProtocol
993 - default:
994 - return d.Errf("invalid proxy protocol version '%s'", proxyProtocol)
995 - }
976 + case "max_response_header":
977 + if !d.NextArg() {
978 + return d.ArgErr()
979 + }
980 + size, err := humanize.ParseBytes(d.Val())
981 + if err != nil {
982 + return d.Errf("invalid max response header size '%s': %v", d.Val(), err)
983 + }
984 + h.MaxResponseHeaderSize = int64(size)
985
997 - case "dial_timeout":
998 - if !d.NextArg() {
999 - return d.ArgErr()
1000 - }
1001 - dur, err := caddy.ParseDuration(d.Val())
1002 - if err != nil {
1003 - return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1004 - }
1005 - h.DialTimeout = caddy.Duration(dur)
986 + case "proxy_protocol":
987 + if !d.NextArg() {
988 + return d.ArgErr()
989 + }
990 + switch proxyProtocol := d.Val(); proxyProtocol {
991 + case "v1", "v2":
992 + h.ProxyProtocol = proxyProtocol
993 + default:
994 + return d.Errf("invalid proxy protocol version '%s'", proxyProtocol)
995 + }
996
1007 - case "dial_fallback_delay":
1008 - if !d.NextArg() {
1009 - return d.ArgErr()
1010 - }
1011 - dur, err := caddy.ParseDuration(d.Val())
1012 - if err != nil {
1013 - return d.Errf("bad fallback delay value '%s': %v", d.Val(), err)
1014 - }
1015 - h.FallbackDelay = caddy.Duration(dur)
997 + case "dial_timeout":
998 + if !d.NextArg() {
999 + return d.ArgErr()
1000 + }
1001 + dur, err := caddy.ParseDuration(d.Val())
1002 + if err != nil {
1003 + return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1004 + }
1005 + h.DialTimeout = caddy.Duration(dur)
1006
1017 - case "response_header_timeout":
1018 - if !d.NextArg() {
1019 - return d.ArgErr()
1020 - }
1021 - dur, err := caddy.ParseDuration(d.Val())
1022 - if err != nil {
1023 - return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1024 - }
1025 - h.ResponseHeaderTimeout = caddy.Duration(dur)
1007 + case "dial_fallback_delay":
1008 + if !d.NextArg() {
1009 + return d.ArgErr()
1010 + }
1011 + dur, err := caddy.ParseDuration(d.Val())
1012 + if err != nil {
1013 + return d.Errf("bad fallback delay value '%s': %v", d.Val(), err)
1014 + }
1015 + h.FallbackDelay = caddy.Duration(dur)
1016
1027 - case "expect_continue_timeout":
1028 - if !d.NextArg() {
1029 - return d.ArgErr()
1030 - }
1031 - dur, err := caddy.ParseDuration(d.Val())
1032 - if err != nil {
1033 - return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1034 - }
1035 - h.ExpectContinueTimeout = caddy.Duration(dur)
1017 + case "response_header_timeout":
1018 + if !d.NextArg() {
1019 + return d.ArgErr()
1020 + }
1021 + dur, err := caddy.ParseDuration(d.Val())
1022 + if err != nil {
1023 + return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1024 + }
1025 + h.ResponseHeaderTimeout = caddy.Duration(dur)
1026
1037 - case "resolvers":
1038 - if h.Resolver == nil {
1039 - h.Resolver = new(UpstreamResolver)
1040 - }
1041 - h.Resolver.Addresses = d.RemainingArgs()
1042 - if len(h.Resolver.Addresses) == 0 {
1043 - return d.Errf("must specify at least one resolver address")
1044 - }
1027 + case "expect_continue_timeout":
1028 + if !d.NextArg() {
1029 + return d.ArgErr()
1030 + }
1031 + dur, err := caddy.ParseDuration(d.Val())
1032 + if err != nil {
1033 + return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1034 + }
1035 + h.ExpectContinueTimeout = caddy.Duration(dur)
1036
1046 - case "tls":
1047 - if h.TLS == nil {
1048 - h.TLS = new(TLSConfig)
1049 - }
1037 + case "resolvers":
1038 + if h.Resolver == nil {
1039 + h.Resolver = new(UpstreamResolver)
1040 + }
1041 + h.Resolver.Addresses = d.RemainingArgs()
1042 + if len(h.Resolver.Addresses) == 0 {
1043 + return d.Errf("must specify at least one resolver address")
1044 + }
1045
1051 - case "tls_client_auth":
1052 - if h.TLS == nil {
1053 - h.TLS = new(TLSConfig)
1054 - }
1055 - args := d.RemainingArgs()
1056 - switch len(args) {
1057 - case 1:
1058 - h.TLS.ClientCertificateAutomate = args[0]
1059 - case 2:
1060 - h.TLS.ClientCertificateFile = args[0]
1061 - h.TLS.ClientCertificateKeyFile = args[1]
1062 - default:
1063 - return d.ArgErr()
1064 - }
1046 + case "tls":
1047 + if h.TLS == nil {
1048 + h.TLS = new(TLSConfig)
1049 + }
1050
1066 - case "tls_insecure_skip_verify":
1067 - if d.NextArg() {
1068 - return d.ArgErr()
1069 - }
1070 - if h.TLS == nil {
1071 - h.TLS = new(TLSConfig)
1072 - }
1073 - h.TLS.InsecureSkipVerify = true
1051 + case "tls_client_auth":
1052 + if h.TLS == nil {
1053 + h.TLS = new(TLSConfig)
1054 + }
1055 + args := d.RemainingArgs()
1056 + switch len(args) {
1057 + case 1:
1058 + h.TLS.ClientCertificateAutomate = args[0]
1059 + case 2:
1060 + h.TLS.ClientCertificateFile = args[0]
1061 + h.TLS.ClientCertificateKeyFile = args[1]
1062 + default:
1063 + return d.ArgErr()
1064 + }
1065
1075 - case "tls_curves":
1076 - args := d.RemainingArgs()
1077 - if len(args) == 0 {
1078 - return d.ArgErr()
1079 - }
1080 - if h.TLS == nil {
1081 - h.TLS = new(TLSConfig)
1082 - }
1083 - h.TLS.Curves = args
1066 + case "tls_insecure_skip_verify":
1067 + if d.NextArg() {
1068 + return d.ArgErr()
1069 + }
1070 + if h.TLS == nil {
1071 + h.TLS = new(TLSConfig)
1072 + }
1073 + h.TLS.InsecureSkipVerify = true
1074
1085 - case "tls_timeout":
1086 - if !d.NextArg() {
1087 - return d.ArgErr()
1088 - }
1089 - dur, err := caddy.ParseDuration(d.Val())
1090 - if err != nil {
1091 - return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1092 - }
1093 - if h.TLS == nil {
1094 - h.TLS = new(TLSConfig)
1095 - }
1096 - h.TLS.HandshakeTimeout = caddy.Duration(dur)
1075 + case "tls_curves":
1076 + args := d.RemainingArgs()
1077 + if len(args) == 0 {
1078 + return d.ArgErr()
1079 + }
1080 + if h.TLS == nil {
1081 + h.TLS = new(TLSConfig)
1082 + }
1083 + h.TLS.Curves = args
1084
1098 - case "tls_trusted_ca_certs":
1099 - args := d.RemainingArgs()
1100 - if len(args) == 0 {
1101 - return d.ArgErr()
1102 - }
1103 - if h.TLS == nil {
1104 - h.TLS = new(TLSConfig)
1105 - }
1106 - h.TLS.RootCAPEMFiles = args
1085 + case "tls_timeout":
1086 + if !d.NextArg() {
1087 + return d.ArgErr()
1088 + }
1089 + dur, err := caddy.ParseDuration(d.Val())
1090 + if err != nil {
1091 + return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1092 + }
1093 + if h.TLS == nil {
1094 + h.TLS = new(TLSConfig)
1095 + }
1096 + h.TLS.HandshakeTimeout = caddy.Duration(dur)
1097
1108 - case "tls_server_name":
1109 - if !d.NextArg() {
1110 - return d.ArgErr()
1111 - }
1112 - if h.TLS == nil {
1113 - h.TLS = new(TLSConfig)
1114 - }
1115 - h.TLS.ServerName = d.Val()
1098 + case "tls_trusted_ca_certs":
1099 + args := d.RemainingArgs()
1100 + if len(args) == 0 {
1101 + return d.ArgErr()
1102 + }
1103 + if h.TLS == nil {
1104 + h.TLS = new(TLSConfig)
1105 + }
1106 + h.TLS.RootCAPEMFiles = args
1107
1117 - case "tls_renegotiation":
1118 - if h.TLS == nil {
1119 - h.TLS = new(TLSConfig)
1120 - }
1121 - if !d.NextArg() {
1122 - return d.ArgErr()
1123 - }
1124 - switch renegotiation := d.Val(); renegotiation {
1125 - case "never", "once", "freely":
1126 - h.TLS.Renegotiation = renegotiation
1127 - default:
1128 - return d.ArgErr()
1129 - }
1108 + case "tls_server_name":
1109 + if !d.NextArg() {
1110 + return d.ArgErr()
1111 + }
1112 + if h.TLS == nil {
1113 + h.TLS = new(TLSConfig)
1114 + }
1115 + h.TLS.ServerName = d.Val()
1116
1131 - case "tls_except_ports":
1132 - if h.TLS == nil {
1133 - h.TLS = new(TLSConfig)
1134 - }
1135 - h.TLS.ExceptPorts = d.RemainingArgs()
1136 - if len(h.TLS.ExceptPorts) == 0 {
1137 - return d.ArgErr()
1138 - }
1117 + case "tls_renegotiation":
1118 + if h.TLS == nil {
1119 + h.TLS = new(TLSConfig)
1120 + }
1121 + if !d.NextArg() {
1122 + return d.ArgErr()
1123 + }
1124 + switch renegotiation := d.Val(); renegotiation {
1125 + case "never", "once", "freely":
1126 + h.TLS.Renegotiation = renegotiation
1127 + default:
1128 + return d.ArgErr()
1129 + }
1130
1140 - case "keepalive":
1141 - if !d.NextArg() {
1142 - return d.ArgErr()
1143 - }
1144 - if h.KeepAlive == nil {
1145 - h.KeepAlive = new(KeepAlive)
1146 - }
1147 - if d.Val() == "off" {
1148 - var disable bool
1149 - h.KeepAlive.Enabled = &disable
1150 - break
1151 - }
1152 - dur, err := caddy.ParseDuration(d.Val())
1153 - if err != nil {
1154 - return d.Errf("bad duration value '%s': %v", d.Val(), err)
1155 - }
1156 - h.KeepAlive.IdleConnTimeout = caddy.Duration(dur)
1131 + case "tls_except_ports":
1132 + if h.TLS == nil {
1133 + h.TLS = new(TLSConfig)
1134 + }
1135 + h.TLS.ExceptPorts = d.RemainingArgs()
1136 + if len(h.TLS.ExceptPorts) == 0 {
1137 + return d.ArgErr()
1138 + }
1139
1158 - case "keepalive_interval":
1159 - if !d.NextArg() {
1160 - return d.ArgErr()
1161 - }
1162 - dur, err := caddy.ParseDuration(d.Val())
1163 - if err != nil {
1164 - return d.Errf("bad interval value '%s': %v", d.Val(), err)
1165 - }
1166 - if h.KeepAlive == nil {
1167 - h.KeepAlive = new(KeepAlive)
1168 - }
1169 - h.KeepAlive.ProbeInterval = caddy.Duration(dur)
1140 + case "keepalive":
1141 + if !d.NextArg() {
1142 + return d.ArgErr()
1143 + }
1144 + if h.KeepAlive == nil {
1145 + h.KeepAlive = new(KeepAlive)
1146 + }
1147 + if d.Val() == "off" {
1148 + var disable bool
1149 + h.KeepAlive.Enabled = &disable
1150 + break
1151 + }
1152 + dur, err := caddy.ParseDuration(d.Val())
1153 + if err != nil {
1154 + return d.Errf("bad duration value '%s': %v", d.Val(), err)
1155 + }
1156 + h.KeepAlive.IdleConnTimeout = caddy.Duration(dur)
1157
1171 - case "keepalive_idle_conns":
1172 - if !d.NextArg() {
1173 - return d.ArgErr()
1174 - }
1175 - num, err := strconv.Atoi(d.Val())
1176 - if err != nil {
1177 - return d.Errf("bad integer value '%s': %v", d.Val(), err)
1178 - }
1179 - if h.KeepAlive == nil {
1180 - h.KeepAlive = new(KeepAlive)
1181 - }
1182 - h.KeepAlive.MaxIdleConns = num
1158 + case "keepalive_interval":
1159 + if !d.NextArg() {
1160 + return d.ArgErr()
1161 + }
1162 + dur, err := caddy.ParseDuration(d.Val())
1163 + if err != nil {
1164 + return d.Errf("bad interval value '%s': %v", d.Val(), err)
1165 + }
1166 + if h.KeepAlive == nil {
1167 + h.KeepAlive = new(KeepAlive)
1168 + }
1169 + h.KeepAlive.ProbeInterval = caddy.Duration(dur)
1170
1184 - case "keepalive_idle_conns_per_host":
1185 - if !d.NextArg() {
1186 - return d.ArgErr()
1187 - }
1188 - num, err := strconv.Atoi(d.Val())
1189 - if err != nil {
1190 - return d.Errf("bad integer value '%s': %v", d.Val(), err)
1191 - }
1192 - if h.KeepAlive == nil {
1193 - h.KeepAlive = new(KeepAlive)
1194 - }
1195 - h.KeepAlive.MaxIdleConnsPerHost = num
1171 + case "keepalive_idle_conns":
1172 + if !d.NextArg() {
1173 + return d.ArgErr()
1174 + }
1175 + num, err := strconv.Atoi(d.Val())
1176 + if err != nil {
1177 + return d.Errf("bad integer value '%s': %v", d.Val(), err)
1178 + }
1179 + if h.KeepAlive == nil {
1180 + h.KeepAlive = new(KeepAlive)
1181 + }
1182 + h.KeepAlive.MaxIdleConns = num
1183
1197 - case "versions":
1198 - h.Versions = d.RemainingArgs()
1199 - if len(h.Versions) == 0 {
1200 - return d.ArgErr()
1201 - }
1184 + case "keepalive_idle_conns_per_host":
1185 + if !d.NextArg() {
1186 + return d.ArgErr()
1187 + }
1188 + num, err := strconv.Atoi(d.Val())
1189 + if err != nil {
1190 + return d.Errf("bad integer value '%s': %v", d.Val(), err)
1191 + }
1192 + if h.KeepAlive == nil {
1193 + h.KeepAlive = new(KeepAlive)
1194 + }
1195 + h.KeepAlive.MaxIdleConnsPerHost = num
1196
1203 - case "compression":
1204 - if d.NextArg() {
1205 - if d.Val() == "off" {
1206 - var disable bool
1207 - h.Compression = &disable
1208 - }
1209 - }
1197 + case "versions":
1198 + h.Versions = d.RemainingArgs()
1199 + if len(h.Versions) == 0 {
1200 + return d.ArgErr()
1201 + }
1202
1211 - case "max_conns_per_host":
1212 - if !d.NextArg() {
1213 - return d.ArgErr()
1214 - }
1215 - num, err := strconv.Atoi(d.Val())
1216 - if err != nil {
1217 - return d.Errf("bad integer value '%s': %v", d.Val(), err)
1203 + case "compression":
1204 + if d.NextArg() {
1205 + if d.Val() == "off" {
1206 + var disable bool
1207 + h.Compression = &disable
1208 }
1219 - h.MaxConnsPerHost = num
1209 + }
1210
1221 - default:
1222 - return d.Errf("unrecognized subdirective %s", d.Val())
1211 + case "max_conns_per_host":
1212 + if !d.NextArg() {
1213 + return d.ArgErr()
1214 + }
1215 + num, err := strconv.Atoi(d.Val())
1216 + if err != nil {
1217 + return d.Errf("bad integer value '%s': %v", d.Val(), err)
1218 }
1219 + h.MaxConnsPerHost = num
1220 +
1221 + default:
1222 + return d.Errf("unrecognized subdirective %s", d.Val())
1223 }
1224 }
1225 return nil
@@ -1241,25 +1240,25 @@ func parseCopyResponseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHan
1240 // status <status>
1241 // }
1242 func (h *CopyResponseHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1244 - for d.Next() {
1245 - args := d.RemainingArgs()
1246 - if len(args) == 1 {
1247 - if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
1248 - h.StatusCode = caddyhttp.WeakString(args[0])
1249 - break
1250 - }
1243 + d.Next() // consume directive name
1244 +
1245 + args := d.RemainingArgs()
1246 + if len(args) == 1 {
1247 + if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
1248 + h.StatusCode = caddyhttp.WeakString(args[0])
1249 + return nil
1250 }
1251 + }
1252
1253 - for d.NextBlock(0) {
1254 - switch d.Val() {
1255 - case "status":
1256 - if !d.NextArg() {
1257 - return d.ArgErr()
1258 - }
1259 - h.StatusCode = caddyhttp.WeakString(d.Val())
1260 - default:
1261 - return d.Errf("unrecognized subdirective '%s'", d.Val())
1253 + for d.NextBlock(0) {
1254 + switch d.Val() {
1255 + case "status":
1256 + if !d.NextArg() {
1257 + return d.ArgErr()
1258 }
1259 + h.StatusCode = caddyhttp.WeakString(d.Val())
1260 + default:
1261 + return d.Errf("unrecognized subdirective '%s'", d.Val())
1262 }
1263 }
1264 return nil
@@ -1281,23 +1280,23 @@ func parseCopyResponseHeadersCaddyfile(h httpcaddyfile.Helper) (caddyhttp.Middle
1280 // exclude <fields...>
1281 // }
1282 func (h *CopyResponseHeadersHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1284 - for d.Next() {
1285 - args := d.RemainingArgs()
1286 - if len(args) > 0 {
1287 - return d.ArgErr()
1288 - }
1283 + d.Next() // consume directive name
1284
1290 - for d.NextBlock(0) {
1291 - switch d.Val() {
1292 - case "include":
1293 - h.Include = append(h.Include, d.RemainingArgs()...)
1285 + args := d.RemainingArgs()
1286 + if len(args) > 0 {
1287 + return d.ArgErr()
1288 + }
1289
1295 - case "exclude":
1296 - h.Exclude = append(h.Exclude, d.RemainingArgs()...)
1290 + for d.NextBlock(0) {
1291 + switch d.Val() {
1292 + case "include":
1293 + h.Include = append(h.Include, d.RemainingArgs()...)
1294
1298 - default:
1299 - return d.Errf("unrecognized subdirective '%s'", d.Val())
1300 - }
1295 + case "exclude":
1296 + h.Exclude = append(h.Exclude, d.RemainingArgs()...)
1297 +
1298 + default:
1299 + return d.Errf("unrecognized subdirective '%s'", d.Val())
1300 }
1301 }
1302 return nil
@@ -1315,89 +1314,88 @@ func (h *CopyResponseHeadersHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser)
1314 // dial_fallback_delay <timeout>
1315 // }
1316 func (u *SRVUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1318 - for d.Next() {
1319 - args := d.RemainingArgs()
1320 - if len(args) > 1 {
1321 - return d.ArgErr()
1322 - }
1323 - if len(args) > 0 {
1324 - u.Name = args[0]
1325 - }
1317 + d.Next() // consume upstream source name
1318
1327 - for d.NextBlock(0) {
1328 - switch d.Val() {
1329 - case "service":
1330 - if !d.NextArg() {
1331 - return d.ArgErr()
1332 - }
1333 - if u.Service != "" {
1334 - return d.Errf("srv service has already been specified")
1335 - }
1336 - u.Service = d.Val()
1319 + args := d.RemainingArgs()
1320 + if len(args) > 1 {
1321 + return d.ArgErr()
1322 + }
1323 + if len(args) > 0 {
1324 + u.Name = args[0]
1325 + }
1326
1338 - case "proto":
1339 - if !d.NextArg() {
1340 - return d.ArgErr()
1341 - }
1342 - if u.Proto != "" {
1343 - return d.Errf("srv proto has already been specified")
1344 - }
1345 - u.Proto = d.Val()
1327 + for d.NextBlock(0) {
1328 + switch d.Val() {
1329 + case "service":
1330 + if !d.NextArg() {
1331 + return d.ArgErr()
1332 + }
1333 + if u.Service != "" {
1334 + return d.Errf("srv service has already been specified")
1335 + }
1336 + u.Service = d.Val()
1337
1347 - case "name":
1348 - if !d.NextArg() {
1349 - return d.ArgErr()
1350 - }
1351 - if u.Name != "" {
1352 - return d.Errf("srv name has already been specified")
1353 - }
1354 - u.Name = d.Val()
1338 + case "proto":
1339 + if !d.NextArg() {
1340 + return d.ArgErr()
1341 + }
1342 + if u.Proto != "" {
1343 + return d.Errf("srv proto has already been specified")
1344 + }
1345 + u.Proto = d.Val()
1346
1356 - case "refresh":
1357 - if !d.NextArg() {
1358 - return d.ArgErr()
1359 - }
1360 - dur, err := caddy.ParseDuration(d.Val())
1361 - if err != nil {
1362 - return d.Errf("parsing refresh interval duration: %v", err)
1363 - }
1364 - u.Refresh = caddy.Duration(dur)
1347 + case "name":
1348 + if !d.NextArg() {
1349 + return d.ArgErr()
1350 + }
1351 + if u.Name != "" {
1352 + return d.Errf("srv name has already been specified")
1353 + }
1354 + u.Name = d.Val()
1355
1366 - case "resolvers":
1367 - if u.Resolver == nil {
1368 - u.Resolver = new(UpstreamResolver)
1369 - }
1370 - u.Resolver.Addresses = d.RemainingArgs()
1371 - if len(u.Resolver.Addresses) == 0 {
1372 - return d.Errf("must specify at least one resolver address")
1373 - }
1356 + case "refresh":
1357 + if !d.NextArg() {
1358 + return d.ArgErr()
1359 + }
1360 + dur, err := caddy.ParseDuration(d.Val())
1361 + if err != nil {
1362 + return d.Errf("parsing refresh interval duration: %v", err)
1363 + }
1364 + u.Refresh = caddy.Duration(dur)
1365
1375 - case "dial_timeout":
1376 - if !d.NextArg() {
1377 - return d.ArgErr()
1378 - }
1379 - dur, err := caddy.ParseDuration(d.Val())
1380 - if err != nil {
1381 - return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1382 - }
1383 - u.DialTimeout = caddy.Duration(dur)
1366 + case "resolvers":
1367 + if u.Resolver == nil {
1368 + u.Resolver = new(UpstreamResolver)
1369 + }
1370 + u.Resolver.Addresses = d.RemainingArgs()
1371 + if len(u.Resolver.Addresses) == 0 {
1372 + return d.Errf("must specify at least one resolver address")
1373 + }
1374
1385 - case "dial_fallback_delay":
1386 - if !d.NextArg() {
1387 - return d.ArgErr()
1388 - }
1389 - dur, err := caddy.ParseDuration(d.Val())
1390 - if err != nil {
1391 - return d.Errf("bad delay value '%s': %v", d.Val(), err)
1392 - }
1393 - u.FallbackDelay = caddy.Duration(dur)
1375 + case "dial_timeout":
1376 + if !d.NextArg() {
1377 + return d.ArgErr()
1378 + }
1379 + dur, err := caddy.ParseDuration(d.Val())
1380 + if err != nil {
1381 + return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1382 + }
1383 + u.DialTimeout = caddy.Duration(dur)
1384
1395 - default:
1396 - return d.Errf("unrecognized srv option '%s'", d.Val())
1385 + case "dial_fallback_delay":
1386 + if !d.NextArg() {
1387 + return d.ArgErr()
1388 + }
1389 + dur, err := caddy.ParseDuration(d.Val())
1390 + if err != nil {
1391 + return d.Errf("bad delay value '%s': %v", d.Val(), err)
1392 }
1393 + u.FallbackDelay = caddy.Duration(dur)
1394 +
1395 + default:
1396 + return d.Errf("unrecognized srv option '%s'", d.Val())
1397 }
1398 }
1400 -
1399 return nil
1400 }
1401
@@ -1413,105 +1411,104 @@ func (u *SRVUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1411 // versions ipv4|ipv6
1412 // }
1413 func (u *AUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1416 - for d.Next() {
1417 - args := d.RemainingArgs()
1418 - if len(args) > 2 {
1419 - return d.ArgErr()
1420 - }
1421 - if len(args) > 0 {
1422 - u.Name = args[0]
1423 - if len(args) == 2 {
1424 - u.Port = args[1]
1425 - }
1414 + d.Next() // consume upstream source name
1415 +
1416 + args := d.RemainingArgs()
1417 + if len(args) > 2 {
1418 + return d.ArgErr()
1419 + }
1420 + if len(args) > 0 {
1421 + u.Name = args[0]
1422 + if len(args) == 2 {
1423 + u.Port = args[1]
1424 }
1425 + }
1426
1428 - for d.NextBlock(0) {
1429 - switch d.Val() {
1430 - case "name":
1431 - if !d.NextArg() {
1432 - return d.ArgErr()
1433 - }
1434 - if u.Name != "" {
1435 - return d.Errf("a name has already been specified")
1436 - }
1437 - u.Name = d.Val()
1427 + for d.NextBlock(0) {
1428 + switch d.Val() {
1429 + case "name":
1430 + if !d.NextArg() {
1431 + return d.ArgErr()
1432 + }
1433 + if u.Name != "" {
1434 + return d.Errf("a name has already been specified")
1435 + }
1436 + u.Name = d.Val()
1437
1439 - case "port":
1440 - if !d.NextArg() {
1441 - return d.ArgErr()
1442 - }
1443 - if u.Port != "" {
1444 - return d.Errf("a port has already been specified")
1445 - }
1446 - u.Port = d.Val()
1438 + case "port":
1439 + if !d.NextArg() {
1440 + return d.ArgErr()
1441 + }
1442 + if u.Port != "" {
1443 + return d.Errf("a port has already been specified")
1444 + }
1445 + u.Port = d.Val()
1446
1448 - case "refresh":
1449 - if !d.NextArg() {
1450 - return d.ArgErr()
1451 - }
1452 - dur, err := caddy.ParseDuration(d.Val())
1453 - if err != nil {
1454 - return d.Errf("parsing refresh interval duration: %v", err)
1455 - }
1456 - u.Refresh = caddy.Duration(dur)
1447 + case "refresh":
1448 + if !d.NextArg() {
1449 + return d.ArgErr()
1450 + }
1451 + dur, err := caddy.ParseDuration(d.Val())
1452 + if err != nil {
1453 + return d.Errf("parsing refresh interval duration: %v", err)
1454 + }
1455 + u.Refresh = caddy.Duration(dur)
1456
1458 - case "resolvers":
1459 - if u.Resolver == nil {
1460 - u.Resolver = new(UpstreamResolver)
1461 - }
1462 - u.Resolver.Addresses = d.RemainingArgs()
1463 - if len(u.Resolver.Addresses) == 0 {
1464 - return d.Errf("must specify at least one resolver address")
1465 - }
1457 + case "resolvers":
1458 + if u.Resolver == nil {
1459 + u.Resolver = new(UpstreamResolver)
1460 + }
1461 + u.Resolver.Addresses = d.RemainingArgs()
1462 + if len(u.Resolver.Addresses) == 0 {
1463 + return d.Errf("must specify at least one resolver address")
1464 + }
1465
1467 - case "dial_timeout":
1468 - if !d.NextArg() {
1469 - return d.ArgErr()
1470 - }
1471 - dur, err := caddy.ParseDuration(d.Val())
1472 - if err != nil {
1473 - return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1474 - }
1475 - u.DialTimeout = caddy.Duration(dur)
1466 + case "dial_timeout":
1467 + if !d.NextArg() {
1468 + return d.ArgErr()
1469 + }
1470 + dur, err := caddy.ParseDuration(d.Val())
1471 + if err != nil {
1472 + return d.Errf("bad timeout value '%s': %v", d.Val(), err)
1473 + }
1474 + u.DialTimeout = caddy.Duration(dur)
1475
1477 - case "dial_fallback_delay":
1478 - if !d.NextArg() {
1479 - return d.ArgErr()
1480 - }
1481 - dur, err := caddy.ParseDuration(d.Val())
1482 - if err != nil {
1483 - return d.Errf("bad delay value '%s': %v", d.Val(), err)
1484 - }
1485 - u.FallbackDelay = caddy.Duration(dur)
1476 + case "dial_fallback_delay":
1477 + if !d.NextArg() {
1478 + return d.ArgErr()
1479 + }
1480 + dur, err := caddy.ParseDuration(d.Val())
1481 + if err != nil {
1482 + return d.Errf("bad delay value '%s': %v", d.Val(), err)
1483 + }
1484 + u.FallbackDelay = caddy.Duration(dur)
1485
1487 - case "versions":
1488 - args := d.RemainingArgs()
1489 - if len(args) == 0 {
1490 - return d.Errf("must specify at least one version")
1491 - }
1486 + case "versions":
1487 + args := d.RemainingArgs()
1488 + if len(args) == 0 {
1489 + return d.Errf("must specify at least one version")
1490 + }
1491
1493 - if u.Versions == nil {
1494 - u.Versions = &IPVersions{}
1495 - }
1492 + if u.Versions == nil {
1493 + u.Versions = &IPVersions{}
1494 + }
1495
1497 - trueBool := true
1498 - for _, arg := range args {
1499 - switch arg {
1500 - case "ipv4":
1501 - u.Versions.IPv4 = &trueBool
1502 - case "ipv6":
1503 - u.Versions.IPv6 = &trueBool
1504 - default:
1505 - return d.Errf("unsupported version: '%s'", arg)
1506 - }
1496 + trueBool := true
1497 + for _, arg := range args {
1498 + switch arg {
1499 + case "ipv4":
1500 + u.Versions.IPv4 = &trueBool
1501 + case "ipv6":
1502 + u.Versions.IPv6 = &trueBool
1503 + default:
1504 + return d.Errf("unsupported version: '%s'", arg)
1505 }
1508 -
1509 - default:
1510 - return d.Errf("unrecognized a option '%s'", d.Val())
1506 }
1507 +
1508 + default:
1509 + return d.Errf("unrecognized a option '%s'", d.Val())
1510 }
1511 }
1514 -
1512 return nil
1513 }
1514
@@ -1521,26 +1518,25 @@ func (u *AUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1518 // <source> [...]
1519 // }
1520 func (u *MultiUpstreams) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
1524 - for d.Next() {
1525 - if d.NextArg() {
1526 - return d.ArgErr()
1527 - }
1521 + d.Next() // consume upstream source name
1522
1529 - for nesting := d.Nesting(); d.NextBlock(nesting); {
1530 - dynModule := d.Val()
1531 - modID := "http.reverse_proxy.upstreams." + dynModule
1532 - unm, err := caddyfile.UnmarshalModule(d, modID)
1533 - if err != nil {
1534 - return err
1535 - }
1536 - source, ok := unm.(UpstreamSource)
1537 - if !ok {
1538 - return d.Errf("module %s (%T) is not an UpstreamSource", modID, unm)
1539 - }
1540 - u.SourcesRaw = append(u.SourcesRaw, caddyconfig.JSONModuleObject(source, "source", dynModule, nil))
1541 - }
1523 + if d.NextArg() {
1524 + return d.ArgErr()
1525 }
1526
1527 + for d.NextBlock(0) {
1528 + dynModule := d.Val()
1529 + modID := "http.reverse_proxy.upstreams." + dynModule
1530 + unm, err := caddyfile.UnmarshalModule(d, modID)
1531 + if err != nil {
1532 + return err
1533 + }
1534 + source, ok := unm.(UpstreamSource)
1535 + if !ok {
1536 + return d.Errf("module %s (%T) is not an UpstreamSource", modID, unm)
1537 + }
1538 + u.SourcesRaw = append(u.SourcesRaw, caddyconfig.JSONModuleObject(source, "source", dynModule, nil))
1539 + }
1540 return nil
1541 }
1542
modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+61 -62
@@ -46,76 +46,75 @@ func init() {
46 // capture_stderr
47 // }
48 func (t *Transport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
49 - for d.Next() {
50 - for d.NextBlock(0) {
51 - switch d.Val() {
52 - case "root":
53 - if !d.NextArg() {
54 - return d.ArgErr()
55 - }
56 - t.Root = d.Val()
57 -
58 - case "split":
59 - t.SplitPath = d.RemainingArgs()
60 - if len(t.SplitPath) == 0 {
61 - return d.ArgErr()
62 - }
49 + d.Next() // consume transport name
50 + for d.NextBlock(0) {
51 + switch d.Val() {
52 + case "root":
53 + if !d.NextArg() {
54 + return d.ArgErr()
55 + }
56 + t.Root = d.Val()
57
64 - case "env":
65 - args := d.RemainingArgs()
66 - if len(args) != 2 {
67 - return d.ArgErr()
68 - }
69 - if t.EnvVars == nil {
70 - t.EnvVars = make(map[string]string)
71 - }
72 - t.EnvVars[args[0]] = args[1]
58 + case "split":
59 + t.SplitPath = d.RemainingArgs()
60 + if len(t.SplitPath) == 0 {
61 + return d.ArgErr()
62 + }
63
74 - case "resolve_root_symlink":
75 - if d.NextArg() {
76 - return d.ArgErr()
77 - }
78 - t.ResolveRootSymlink = true
64 + case "env":
65 + args := d.RemainingArgs()
66 + if len(args) != 2 {
67 + return d.ArgErr()
68 + }
69 + if t.EnvVars == nil {
70 + t.EnvVars = make(map[string]string)
71 + }
72 + t.EnvVars[args[0]] = args[1]
73
80 - case "dial_timeout":
81 - if !d.NextArg() {
82 - return d.ArgErr()
83 - }
84 - dur, err := caddy.ParseDuration(d.Val())
85 - if err != nil {
86 - return d.Errf("bad timeout value %s: %v", d.Val(), err)
87 - }
88 - t.DialTimeout = caddy.Duration(dur)
74 + case "resolve_root_symlink":
75 + if d.NextArg() {
76 + return d.ArgErr()
77 + }
78 + t.ResolveRootSymlink = true
79
90 - case "read_timeout":
91 - if !d.NextArg() {
92 - return d.ArgErr()
93 - }
94 - dur, err := caddy.ParseDuration(d.Val())
95 - if err != nil {
96 - return d.Errf("bad timeout value %s: %v", d.Val(), err)
97 - }
98 - t.ReadTimeout = caddy.Duration(dur)
80 + case "dial_timeout":
81 + if !d.NextArg() {
82 + return d.ArgErr()
83 + }
84 + dur, err := caddy.ParseDuration(d.Val())
85 + if err != nil {
86 + return d.Errf("bad timeout value %s: %v", d.Val(), err)
87 + }
88 + t.DialTimeout = caddy.Duration(dur)
89
100 - case "write_timeout":
101 - if !d.NextArg() {
102 - return d.ArgErr()
103 - }
104 - dur, err := caddy.ParseDuration(d.Val())
105 - if err != nil {
106 - return d.Errf("bad timeout value %s: %v", d.Val(), err)
107 - }
108 - t.WriteTimeout = caddy.Duration(dur)
90 + case "read_timeout":
91 + if !d.NextArg() {
92 + return d.ArgErr()
93 + }
94 + dur, err := caddy.ParseDuration(d.Val())
95 + if err != nil {
96 + return d.Errf("bad timeout value %s: %v", d.Val(), err)
97 + }
98 + t.ReadTimeout = caddy.Duration(dur)
99
110 - case "capture_stderr":
111 - if d.NextArg() {
112 - return d.ArgErr()
113 - }
114 - t.CaptureStderr = true
100 + case "write_timeout":
101 + if !d.NextArg() {
102 + return d.ArgErr()
103 + }
104 + dur, err := caddy.ParseDuration(d.Val())
105 + if err != nil {
106 + return d.Errf("bad timeout value %s: %v", d.Val(), err)
107 + }
108 + t.WriteTimeout = caddy.Duration(dur)
109
116 - default:
117 - return d.Errf("unrecognized subdirective %s", d.Val())
110 + case "capture_stderr":
111 + if d.NextArg() {
112 + return d.ArgErr()
113 }
114 + t.CaptureStderr = true
115 +
116 + default:
117 + return d.Errf("unrecognized subdirective %s", d.Val())
118 }
119 }
120 return nil
modules/caddyhttp/reverseproxy/selectionpolicies.go
+60 -65
@@ -68,10 +68,9 @@ func (r RandomSelection) Select(pool UpstreamPool, request *http.Request, _ http
68
69 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
70 func (r *RandomSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
71 - for d.Next() {
72 - if d.NextArg() {
73 - return d.ArgErr()
74 - }
71 + d.Next() // consume policy name
72 + if d.NextArg() {
73 + return d.ArgErr()
74 }
75 return nil
76 }
@@ -98,22 +97,22 @@ func (WeightedRoundRobinSelection) CaddyModule() caddy.ModuleInfo {
97
98 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
99 func (r *WeightedRoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
101 - for d.Next() {
102 - args := d.RemainingArgs()
103 - if len(args) == 0 {
104 - return d.ArgErr()
105 - }
100 + d.Next() // consume policy name
101
107 - for _, weight := range args {
108 - weightInt, err := strconv.Atoi(weight)
109 - if err != nil {
110 - return d.Errf("invalid weight value '%s': %v", weight, err)
111 - }
112 - if weightInt < 1 {
113 - return d.Errf("invalid weight value '%s': weight should be non-zero and positive", weight)
114 - }
115 - r.Weights = append(r.Weights, weightInt)
102 + args := d.RemainingArgs()
103 + if len(args) == 0 {
104 + return d.ArgErr()
105 + }
106 +
107 + for _, weight := range args {
108 + weightInt, err := strconv.Atoi(weight)
109 + if err != nil {
110 + return d.Errf("invalid weight value '%s': %v", weight, err)
111 + }
112 + if weightInt < 1 {
113 + return d.Errf("invalid weight value '%s': weight should be non-zero and positive", weight)
114 }
115 + r.Weights = append(r.Weights, weightInt)
116 }
117 return nil
118 }
@@ -179,17 +178,17 @@ func (RandomChoiceSelection) CaddyModule() caddy.ModuleInfo {
178
179 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
180 func (r *RandomChoiceSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
182 - for d.Next() {
183 - if !d.NextArg() {
184 - return d.ArgErr()
185 - }
186 - chooseStr := d.Val()
187 - choose, err := strconv.Atoi(chooseStr)
188 - if err != nil {
189 - return d.Errf("invalid choice value '%s': %v", chooseStr, err)
190 - }
191 - r.Choose = choose
181 + d.Next() // consume policy name
182 +
183 + if !d.NextArg() {
184 + return d.ArgErr()
185 }
186 + chooseStr := d.Val()
187 + choose, err := strconv.Atoi(chooseStr)
188 + if err != nil {
189 + return d.Errf("invalid choice value '%s': %v", chooseStr, err)
190 + }
191 + r.Choose = choose
192 return nil
193 }
194
@@ -280,10 +279,9 @@ func (LeastConnSelection) Select(pool UpstreamPool, _ *http.Request, _ http.Resp
279
280 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
281 func (r *LeastConnSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
283 - for d.Next() {
284 - if d.NextArg() {
285 - return d.ArgErr()
286 - }
282 + d.Next() // consume policy name
283 + if d.NextArg() {
284 + return d.ArgErr()
285 }
286 return nil
287 }
@@ -320,10 +318,9 @@ func (r *RoundRobinSelection) Select(pool UpstreamPool, _ *http.Request, _ http.
318
319 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
320 func (r *RoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
323 - for d.Next() {
324 - if d.NextArg() {
325 - return d.ArgErr()
326 - }
321 + d.Next() // consume policy name
322 + if d.NextArg() {
323 + return d.ArgErr()
324 }
325 return nil
326 }
@@ -352,10 +349,9 @@ func (FirstSelection) Select(pool UpstreamPool, _ *http.Request, _ http.Response
349
350 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
351 func (r *FirstSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
355 - for d.Next() {
356 - if d.NextArg() {
357 - return d.ArgErr()
358 - }
352 + d.Next() // consume policy name
353 + if d.NextArg() {
354 + return d.ArgErr()
355 }
356 return nil
357 }
@@ -383,10 +379,9 @@ func (IPHashSelection) Select(pool UpstreamPool, req *http.Request, _ http.Respo
379
380 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
381 func (r *IPHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
386 - for d.Next() {
387 - if d.NextArg() {
388 - return d.ArgErr()
389 - }
382 + d.Next() // consume policy name
383 + if d.NextArg() {
384 + return d.ArgErr()
385 }
386 return nil
387 }
@@ -416,10 +411,9 @@ func (ClientIPHashSelection) Select(pool UpstreamPool, req *http.Request, _ http
411
412 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
413 func (r *ClientIPHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
419 - for d.Next() {
420 - if d.NextArg() {
421 - return d.ArgErr()
422 - }
414 + d.Next() // consume policy name
415 + if d.NextArg() {
416 + return d.ArgErr()
417 }
418 return nil
419 }
@@ -443,10 +437,9 @@ func (URIHashSelection) Select(pool UpstreamPool, req *http.Request, _ http.Resp
437
438 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
439 func (r *URIHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
446 - for d.Next() {
447 - if d.NextArg() {
448 - return d.ArgErr()
449 - }
440 + d.Next() // consume policy name
441 + if d.NextArg() {
442 + return d.ArgErr()
443 }
444 return nil
445 }
@@ -504,13 +497,14 @@ func (s QueryHashSelection) Select(pool UpstreamPool, req *http.Request, _ http.
497
498 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
499 func (s *QueryHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
507 - for d.Next() {
508 - if !d.NextArg() {
509 - return d.ArgErr()
510 - }
511 - s.Key = d.Val()
500 + d.Next() // consume policy name
501 +
502 + if !d.NextArg() {
503 + return d.ArgErr()
504 }
513 - for nesting := d.Nesting(); d.NextBlock(nesting); {
505 + s.Key = d.Val()
506 +
507 + for d.NextBlock(0) {
508 switch d.Val() {
509 case "fallback":
510 if !d.NextArg() {
@@ -583,13 +577,14 @@ func (s HeaderHashSelection) Select(pool UpstreamPool, req *http.Request, _ http
577
578 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
579 func (s *HeaderHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
586 - for d.Next() {
587 - if !d.NextArg() {
588 - return d.ArgErr()
589 - }
590 - s.Field = d.Val()
580 + d.Next() // consume policy name
581 +
582 + if !d.NextArg() {
583 + return d.ArgErr()
584 }
592 - for nesting := d.Nesting(); d.NextBlock(nesting); {
585 + s.Field = d.Val()
586 +
587 + for d.NextBlock(0) {
588 switch d.Val() {
589 case "fallback":
590 if !d.NextArg() {
@@ -708,7 +703,7 @@ func (s *CookieHashSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
703 default:
704 return d.ArgErr()
705 }
711 - for nesting := d.Nesting(); d.NextBlock(nesting); {
706 + for d.NextBlock(0) {
707 switch d.Val() {
708 case "fallback":
709 if !d.NextArg() {
modules/caddyhttp/rewrite/caddyfile.go
+71 -88
@@ -39,10 +39,7 @@ func init() {
39 // Only URI components which are given in <to> will be set in the resulting URI.
40 // See the docs for the rewrite handler for more information.
41 func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
42 - // consume directive name
43 - if !h.NextArg() {
44 - return nil, h.ArgErr()
45 - }
42 + h.Next() // consume directive name
43
44 // count the tokens to determine what to do
45 argsCount := h.CountRemainingArgs()
@@ -66,26 +63,9 @@ func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue,
63 if err != nil {
64 return nil, err
65 }
66 + h.Next() // consume directive name again, matcher parsing does a reset
67 + h.Next() // advance to the rewrite URI
68
70 - // consume directive name, again, because extracting matcher does a reset
71 - if !h.NextArg() {
72 - return nil, h.ArgErr()
73 - }
74 - // advance to the rewrite URI
75 - if !h.NextArg() {
76 - return nil, h.ArgErr()
77 - }
78 -
79 - var rewr Rewrite
80 - for h.Next() {
81 - if !h.NextArg() {
82 - return nil, h.ArgErr()
83 - }
84 - rewr.URI = h.Val()
85 - if h.NextArg() {
86 - return nil, h.ArgErr()
87 - }
88 - }
69 return h.NewRoute(userMatcherSet, Rewrite{URI: h.Val()}), nil
70 }
71
@@ -93,17 +73,14 @@ func parseCaddyfileRewrite(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue,
73 //
74 // method [<matcher>] <method>
75 func parseCaddyfileMethod(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
96 - var rewr Rewrite
97 - for h.Next() {
98 - if !h.NextArg() {
99 - return nil, h.ArgErr()
100 - }
101 - rewr.Method = h.Val()
102 - if h.NextArg() {
103 - return nil, h.ArgErr()
104 - }
76 + h.Next() // consume directive name
77 + if !h.NextArg() {
78 + return nil, h.ArgErr()
79 }
106 - return rewr, nil
80 + if h.NextArg() {
81 + return nil, h.ArgErr()
82 + }
83 + return Rewrite{Method: h.Val()}, nil
84 }
85
86 // parseCaddyfileURI sets up a handler for manipulating (but not "rewriting") the
@@ -118,65 +95,71 @@ func parseCaddyfileMethod(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler,
95 // path_regexp is used, then regular expression replacements will be performed
96 // on the path portion of the URI (and a limit cannot be set).
97 func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
98 + h.Next() // consume directive name
99 +
100 + args := h.RemainingArgs()
101 + if len(args) < 2 {
102 + return nil, h.ArgErr()
103 + }
104 +
105 var rewr Rewrite
122 - for h.Next() {
123 - args := h.RemainingArgs()
124 - if len(args) < 2 {
106 +
107 + switch args[0] {
108 + case "strip_prefix":
109 + if len(args) > 2 {
110 return nil, h.ArgErr()
111 }
127 - switch args[0] {
128 - case "strip_prefix":
129 - if len(args) > 2 {
130 - return nil, h.ArgErr()
131 - }
132 - rewr.StripPathPrefix = args[1]
133 - if !strings.HasPrefix(rewr.StripPathPrefix, "/") {
134 - rewr.StripPathPrefix = "/" + rewr.StripPathPrefix
135 - }
136 - case "strip_suffix":
137 - if len(args) > 2 {
138 - return nil, h.ArgErr()
139 - }
140 - rewr.StripPathSuffix = args[1]
141 - case "replace":
142 - var find, replace, lim string
143 - switch len(args) {
144 - case 4:
145 - lim = args[3]
146 - fallthrough
147 - case 3:
148 - find = args[1]
149 - replace = args[2]
150 - default:
151 - return nil, h.ArgErr()
152 - }
112 + rewr.StripPathPrefix = args[1]
113 + if !strings.HasPrefix(rewr.StripPathPrefix, "/") {
114 + rewr.StripPathPrefix = "/" + rewr.StripPathPrefix
115 + }
116
154 - var limInt int
155 - if lim != "" {
156 - var err error
157 - limInt, err = strconv.Atoi(lim)
158 - if err != nil {
159 - return nil, h.Errf("limit must be an integer; invalid: %v", err)
160 - }
161 - }
117 + case "strip_suffix":
118 + if len(args) > 2 {
119 + return nil, h.ArgErr()
120 + }
121 + rewr.StripPathSuffix = args[1]
122 +
123 + case "replace":
124 + var find, replace, lim string
125 + switch len(args) {
126 + case 4:
127 + lim = args[3]
128 + fallthrough
129 + case 3:
130 + find = args[1]
131 + replace = args[2]
132 + default:
133 + return nil, h.ArgErr()
134 + }
135
163 - rewr.URISubstring = append(rewr.URISubstring, substrReplacer{
164 - Find: find,
165 - Replace: replace,
166 - Limit: limInt,
167 - })
168 - case "path_regexp":
169 - if len(args) != 3 {
170 - return nil, h.ArgErr()
136 + var limInt int
137 + if lim != "" {
138 + var err error
139 + limInt, err = strconv.Atoi(lim)
140 + if err != nil {
141 + return nil, h.Errf("limit must be an integer; invalid: %v", err)
142 }
172 - find, replace := args[1], args[2]
173 - rewr.PathRegexp = append(rewr.PathRegexp, &regexReplacer{
174 - Find: find,
175 - Replace: replace,
176 - })
177 - default:
178 - return nil, h.Errf("unrecognized URI manipulation '%s'", args[0])
143 }
144 +
145 + rewr.URISubstring = append(rewr.URISubstring, substrReplacer{
146 + Find: find,
147 + Replace: replace,
148 + Limit: limInt,
149 + })
150 +
151 + case "path_regexp":
152 + if len(args) != 3 {
153 + return nil, h.ArgErr()
154 + }
155 + find, replace := args[1], args[2]
156 + rewr.PathRegexp = append(rewr.PathRegexp, &regexReplacer{
157 + Find: find,
158 + Replace: replace,
159 + })
160 +
161 + default:
162 + return nil, h.Errf("unrecognized URI manipulation '%s'", args[0])
163 }
164 return rewr, nil
165 }
@@ -190,9 +173,9 @@ func parseCaddyfileURI(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, err
173 // Only path matchers (with a `/` prefix) are supported as this is a shortcut
174 // for the handle directive with a strip_prefix rewrite.
175 func parseCaddyfileHandlePath(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
193 - if !h.Next() {
194 - return nil, h.ArgErr()
195 - }
176 + h.Next() // consume directive name
177 +
178 + // there must be a path matcher
179 if !h.NextArg() {
180 return nil, h.ArgErr()
181 }
modules/caddyhttp/staticerror.go
+25 -26
@@ -60,36 +60,35 @@ func (StaticError) CaddyModule() caddy.ModuleInfo {
60 // If there is just one argument (other than the matcher), it is considered
61 // to be a status code if it's a valid positive integer of 3 digits.
62 func (e *StaticError) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
63 - for d.Next() {
64 - args := d.RemainingArgs()
65 - switch len(args) {
66 - case 1:
67 - if len(args[0]) == 3 {
68 - if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
69 - e.StatusCode = WeakString(args[0])
70 - break
71 - }
63 + d.Next() // consume directive name
64 + args := d.RemainingArgs()
65 + switch len(args) {
66 + case 1:
67 + if len(args[0]) == 3 {
68 + if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
69 + e.StatusCode = WeakString(args[0])
70 + break
71 }
73 - e.Error = args[0]
74 - case 2:
75 - e.Error = args[0]
76 - e.StatusCode = WeakString(args[1])
77 - default:
78 - return d.ArgErr()
72 }
73 + e.Error = args[0]
74 + case 2:
75 + e.Error = args[0]
76 + e.StatusCode = WeakString(args[1])
77 + default:
78 + return d.ArgErr()
79 + }
80
81 - for d.NextBlock(0) {
82 - switch d.Val() {
83 - case "message":
84 - if e.Error != "" {
85 - return d.Err("message already specified")
86 - }
87 - if !d.AllArgs(&e.Error) {
88 - return d.ArgErr()
89 - }
90 - default:
91 - return d.Errf("unrecognized subdirective '%s'", d.Val())
81 + for d.NextBlock(0) {
82 + switch d.Val() {
83 + case "message":
84 + if e.Error != "" {
85 + return d.Err("message already specified")
86 }
87 + if !d.AllArgs(&e.Error) {
88 + return d.ArgErr()
89 + }
90 + default:
91 + return d.Errf("unrecognized subdirective '%s'", d.Val())
92 }
93 }
94 return nil
modules/caddyhttp/staticresp.go
+30 -31
@@ -138,41 +138,40 @@ func (StaticResponse) CaddyModule() caddy.ModuleInfo {
138 // If there is just one argument (other than the matcher), it is considered
139 // to be a status code if it's a valid positive integer of 3 digits.
140 func (s *StaticResponse) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
141 - for d.Next() {
142 - args := d.RemainingArgs()
143 - switch len(args) {
144 - case 1:
145 - if len(args[0]) == 3 {
146 - if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
147 - s.StatusCode = WeakString(args[0])
148 - break
149 - }
141 + d.Next() // consume directive name
142 + args := d.RemainingArgs()
143 + switch len(args) {
144 + case 1:
145 + if len(args[0]) == 3 {
146 + if num, err := strconv.Atoi(args[0]); err == nil && num > 0 {
147 + s.StatusCode = WeakString(args[0])
148 + break
149 }
151 - s.Body = args[0]
152 - case 2:
153 - s.Body = args[0]
154 - s.StatusCode = WeakString(args[1])
155 - default:
156 - return d.ArgErr()
150 }
151 + s.Body = args[0]
152 + case 2:
153 + s.Body = args[0]
154 + s.StatusCode = WeakString(args[1])
155 + default:
156 + return d.ArgErr()
157 + }
158
159 - for d.NextBlock(0) {
160 - switch d.Val() {
161 - case "body":
162 - if s.Body != "" {
163 - return d.Err("body already specified")
164 - }
165 - if !d.AllArgs(&s.Body) {
166 - return d.ArgErr()
167 - }
168 - case "close":
169 - if s.Close {
170 - return d.Err("close already specified")
171 - }
172 - s.Close = true
173 - default:
174 - return d.Errf("unrecognized subdirective '%s'", d.Val())
159 + for d.NextBlock(0) {
160 + switch d.Val() {
161 + case "body":
162 + if s.Body != "" {
163 + return d.Err("body already specified")
164 + }
165 + if !d.AllArgs(&s.Body) {
166 + return d.ArgErr()
167 }
168 + case "close":
169 + if s.Close {
170 + return d.Err("close already specified")
171 + }
172 + s.Close = true
173 + default:
174 + return d.Errf("unrecognized subdirective '%s'", d.Val())
175 }
176 }
177 return nil
modules/caddyhttp/templates/caddyfile.go
+36 -37
@@ -34,47 +34,46 @@ func init() {
34 // root <path>
35 // }
36 func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
37 + h.Next() // consume directive name
38 t := new(Templates)
38 - for h.Next() {
39 - for h.NextBlock(0) {
40 - switch h.Val() {
41 - case "mime":
42 - t.MIMETypes = h.RemainingArgs()
43 - if len(t.MIMETypes) == 0 {
44 - return nil, h.ArgErr()
45 - }
46 - case "between":
47 - t.Delimiters = h.RemainingArgs()
48 - if len(t.Delimiters) != 2 {
49 - return nil, h.ArgErr()
50 - }
51 - case "root":
52 - if !h.Args(&t.FileRoot) {
53 - return nil, h.ArgErr()
54 - }
55 - case "extensions":
56 - if h.NextArg() {
57 - return nil, h.ArgErr()
39 + for h.NextBlock(0) {
40 + switch h.Val() {
41 + case "mime":
42 + t.MIMETypes = h.RemainingArgs()
43 + if len(t.MIMETypes) == 0 {
44 + return nil, h.ArgErr()
45 + }
46 + case "between":
47 + t.Delimiters = h.RemainingArgs()
48 + if len(t.Delimiters) != 2 {
49 + return nil, h.ArgErr()
50 + }
51 + case "root":
52 + if !h.Args(&t.FileRoot) {
53 + return nil, h.ArgErr()
54 + }
55 + case "extensions":
56 + if h.NextArg() {
57 + return nil, h.ArgErr()
58 + }
59 + if t.ExtensionsRaw != nil {
60 + return nil, h.Err("extensions already specified")
61 + }
62 + for nesting := h.Nesting(); h.NextBlock(nesting); {
63 + extensionModuleName := h.Val()
64 + modID := "http.handlers.templates.functions." + extensionModuleName
65 + unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
66 + if err != nil {
67 + return nil, err
68 }
59 - if t.ExtensionsRaw != nil {
60 - return nil, h.Err("extensions already specified")
69 + cf, ok := unm.(CustomFunctions)
70 + if !ok {
71 + return nil, h.Errf("module %s (%T) does not provide template functions", modID, unm)
72 }
62 - for nesting := h.Nesting(); h.NextBlock(nesting); {
63 - extensionModuleName := h.Val()
64 - modID := "http.handlers.templates.functions." + extensionModuleName
65 - unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
66 - if err != nil {
67 - return nil, err
68 - }
69 - cf, ok := unm.(CustomFunctions)
70 - if !ok {
71 - return nil, h.Errf("module %s (%T) does not provide template functions", modID, unm)
72 - }
73 - if t.ExtensionsRaw == nil {
74 - t.ExtensionsRaw = make(caddy.ModuleMap)
75 - }
76 - t.ExtensionsRaw[extensionModuleName] = caddyconfig.JSON(cf, nil)
73 + if t.ExtensionsRaw == nil {
74 + t.ExtensionsRaw = make(caddy.ModuleMap)
75 }
76 + t.ExtensionsRaw[extensionModuleName] = caddyconfig.JSON(cf, nil)
77 }
78 }
79 }
modules/caddyhttp/tracing/module.go
+10 -12
@@ -88,20 +88,18 @@ func (ot *Tracing) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
88 "span": &ot.SpanName,
89 }
90
91 - for d.Next() {
92 - args := d.RemainingArgs()
93 - if len(args) > 0 {
94 - return d.ArgErr()
95 - }
91 + d.Next() // consume directive name
92 + if d.NextArg() {
93 + return d.ArgErr()
94 + }
95
97 - for d.NextBlock(0) {
98 - if dst, ok := paramsMap[d.Val()]; ok {
99 - if err := setParameter(d, dst); err != nil {
100 - return err
101 - }
102 - } else {
103 - return d.ArgErr()
96 + for d.NextBlock(0) {
97 + if dst, ok := paramsMap[d.Val()]; ok {
98 + if err := setParameter(d, dst); err != nil {
99 + return err
100 }
101 + } else {
102 + return d.ArgErr()
103 }
104 }
105 return nil
modules/caddyhttp/vars.go
+9 -7
@@ -68,6 +68,8 @@ func (m VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next H
68 // ...
69 // }
70 func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
71 + d.Next() // consume directive name
72 +
73 if *m == nil {
74 *m = make(VarsMiddleware)
75 }
@@ -94,15 +96,13 @@ func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
96 return nil
97 }
98
97 - for d.Next() {
98 - if err := nextVar(true); err != nil {
99 + if err := nextVar(true); err != nil {
100 + return err
101 + }
102 + for d.NextBlock(0) {
103 + if err := nextVar(false); err != nil {
104 return err
105 }
101 - for nesting := d.Nesting(); d.NextBlock(nesting); {
102 - if err := nextVar(false); err != nil {
103 - return err
104 - }
105 - }
106 }
107
108 return nil
@@ -135,6 +135,7 @@ func (m *VarsMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
135 if *m == nil {
136 *m = make(map[string][]string)
137 }
138 + // iterate to merge multiple matchers into one
139 for d.Next() {
140 var field string
141 if !d.Args(&field) {
@@ -216,6 +217,7 @@ func (m *MatchVarsRE) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
217 if *m == nil {
218 *m = make(map[string]*MatchRegexp)
219 }
220 + // iterate to merge multiple matchers into one
221 for d.Next() {
222 var first, second, third string
223 if !d.Args(&first, &second) {
modules/caddypki/acmeserver/caddyfile.go
+38 -39
@@ -34,53 +34,52 @@ func init() {
34 // resolvers <addresses...>
35 // }
36 func parseACMEServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
37 - if !h.Next() {
38 - return nil, h.ArgErr()
39 - }
40 -
37 + h.Next() // consume directive name
38 matcherSet, err := h.ExtractMatcherSet()
39 if err != nil {
40 return nil, err
41 }
42 + h.Next() // consume the directive name again (matcher parsing resets)
43 +
44 + // no inline args allowed
45 + if h.NextArg() {
46 + return nil, h.ArgErr()
47 + }
48
49 var acmeServer Handler
50 var ca *caddypki.CA
51
49 - for h.Next() {
50 - if h.NextArg() {
51 - return nil, h.ArgErr()
52 - }
53 - for h.NextBlock(0) {
54 - switch h.Val() {
55 - case "ca":
56 - if !h.AllArgs(&acmeServer.CA) {
57 - return nil, h.ArgErr()
58 - }
59 - if ca == nil {
60 - ca = new(caddypki.CA)
61 - }
62 - ca.ID = acmeServer.CA
63 - case "lifetime":
64 - if !h.NextArg() {
65 - return nil, h.ArgErr()
66 - }
67 -
68 - dur, err := caddy.ParseDuration(h.Val())
69 - if err != nil {
70 - return nil, err
71 - }
72 -
73 - if d := time.Duration(ca.IntermediateLifetime); d > 0 && dur > d {
74 - return nil, h.Errf("certificate lifetime (%s) exceeds intermediate certificate lifetime (%s)", dur, d)
75 - }
76 -
77 - acmeServer.Lifetime = caddy.Duration(dur)
78 -
79 - case "resolvers":
80 - acmeServer.Resolvers = h.RemainingArgs()
81 - if len(acmeServer.Resolvers) == 0 {
82 - return nil, h.Errf("must specify at least one resolver address")
83 - }
52 + for h.NextBlock(0) {
53 + switch h.Val() {
54 + case "ca":
55 + if !h.AllArgs(&acmeServer.CA) {
56 + return nil, h.ArgErr()
57 + }
58 + if ca == nil {
59 + ca = new(caddypki.CA)
60 + }
61 + ca.ID = acmeServer.CA
62 +
63 + case "lifetime":
64 + if !h.NextArg() {
65 + return nil, h.ArgErr()
66 + }
67 +
68 + dur, err := caddy.ParseDuration(h.Val())
69 + if err != nil {
70 + return nil, err
71 + }
72 +
73 + if d := time.Duration(ca.IntermediateLifetime); d > 0 && dur > d {
74 + return nil, h.Errf("certificate lifetime (%s) exceeds intermediate certificate lifetime (%s)", dur, d)
75 + }
76 +
77 + acmeServer.Lifetime = caddy.Duration(dur)
78 +
79 + case "resolvers":
80 + acmeServer.Resolvers = h.RemainingArgs()
81 + if len(acmeServer.Resolvers) == 0 {
82 + return nil, h.Errf("must specify at least one resolver address")
83 }
84 }
85 }
modules/caddytls/acmeissuer.go
+192 -191
@@ -277,218 +277,219 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss }
277 // }
278 // }
279 func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
280 - for d.Next() {
280 + d.Next() // consume issuer name
281 +
282 + if d.NextArg() {
283 + iss.CA = d.Val()
284 if d.NextArg() {
282 - iss.CA = d.Val()
283 - if d.NextArg() {
284 - return d.ArgErr()
285 - }
285 + return d.ArgErr()
286 }
287 - for nesting := d.Nesting(); d.NextBlock(nesting); {
288 - switch d.Val() {
289 - case "dir":
290 - if iss.CA != "" {
291 - return d.Errf("directory is already specified: %s", iss.CA)
292 - }
293 - if !d.AllArgs(&iss.CA) {
294 - return d.ArgErr()
295 - }
296 -
297 - case "test_dir":
298 - if !d.AllArgs(&iss.TestCA) {
299 - return d.ArgErr()
300 - }
287 + }
288
302 - case "email":
303 - if !d.AllArgs(&iss.Email) {
304 - return d.ArgErr()
305 - }
289 + for d.NextBlock(0) {
290 + switch d.Val() {
291 + case "dir":
292 + if iss.CA != "" {
293 + return d.Errf("directory is already specified: %s", iss.CA)
294 + }
295 + if !d.AllArgs(&iss.CA) {
296 + return d.ArgErr()
297 + }
298
307 - case "timeout":
308 - var timeoutStr string
309 - if !d.AllArgs(&timeoutStr) {
310 - return d.ArgErr()
311 - }
312 - timeout, err := caddy.ParseDuration(timeoutStr)
313 - if err != nil {
314 - return d.Errf("invalid timeout duration %s: %v", timeoutStr, err)
315 - }
316 - iss.ACMETimeout = caddy.Duration(timeout)
299 + case "test_dir":
300 + if !d.AllArgs(&iss.TestCA) {
301 + return d.ArgErr()
302 + }
303
318 - case "disable_http_challenge":
319 - if d.NextArg() {
320 - return d.ArgErr()
321 - }
322 - if iss.Challenges == nil {
323 - iss.Challenges = new(ChallengesConfig)
324 - }
325 - if iss.Challenges.HTTP == nil {
326 - iss.Challenges.HTTP = new(HTTPChallengeConfig)
327 - }
328 - iss.Challenges.HTTP.Disabled = true
304 + case "email":
305 + if !d.AllArgs(&iss.Email) {
306 + return d.ArgErr()
307 + }
308
330 - case "disable_tlsalpn_challenge":
331 - if d.NextArg() {
332 - return d.ArgErr()
333 - }
334 - if iss.Challenges == nil {
335 - iss.Challenges = new(ChallengesConfig)
336 - }
337 - if iss.Challenges.TLSALPN == nil {
338 - iss.Challenges.TLSALPN = new(TLSALPNChallengeConfig)
339 - }
340 - iss.Challenges.TLSALPN.Disabled = true
309 + case "timeout":
310 + var timeoutStr string
311 + if !d.AllArgs(&timeoutStr) {
312 + return d.ArgErr()
313 + }
314 + timeout, err := caddy.ParseDuration(timeoutStr)
315 + if err != nil {
316 + return d.Errf("invalid timeout duration %s: %v", timeoutStr, err)
317 + }
318 + iss.ACMETimeout = caddy.Duration(timeout)
319
342 - case "alt_http_port":
343 - if !d.NextArg() {
344 - return d.ArgErr()
345 - }
346 - port, err := strconv.Atoi(d.Val())
347 - if err != nil {
348 - return d.Errf("invalid port %s: %v", d.Val(), err)
349 - }
350 - if iss.Challenges == nil {
351 - iss.Challenges = new(ChallengesConfig)
352 - }
353 - if iss.Challenges.HTTP == nil {
354 - iss.Challenges.HTTP = new(HTTPChallengeConfig)
355 - }
356 - iss.Challenges.HTTP.AlternatePort = port
320 + case "disable_http_challenge":
321 + if d.NextArg() {
322 + return d.ArgErr()
323 + }
324 + if iss.Challenges == nil {
325 + iss.Challenges = new(ChallengesConfig)
326 + }
327 + if iss.Challenges.HTTP == nil {
328 + iss.Challenges.HTTP = new(HTTPChallengeConfig)
329 + }
330 + iss.Challenges.HTTP.Disabled = true
331
358 - case "alt_tlsalpn_port":
359 - if !d.NextArg() {
360 - return d.ArgErr()
361 - }
362 - port, err := strconv.Atoi(d.Val())
363 - if err != nil {
364 - return d.Errf("invalid port %s: %v", d.Val(), err)
365 - }
366 - if iss.Challenges == nil {
367 - iss.Challenges = new(ChallengesConfig)
368 - }
369 - if iss.Challenges.TLSALPN == nil {
370 - iss.Challenges.TLSALPN = new(TLSALPNChallengeConfig)
371 - }
372 - iss.Challenges.TLSALPN.AlternatePort = port
332 + case "disable_tlsalpn_challenge":
333 + if d.NextArg() {
334 + return d.ArgErr()
335 + }
336 + if iss.Challenges == nil {
337 + iss.Challenges = new(ChallengesConfig)
338 + }
339 + if iss.Challenges.TLSALPN == nil {
340 + iss.Challenges.TLSALPN = new(TLSALPNChallengeConfig)
341 + }
342 + iss.Challenges.TLSALPN.Disabled = true
343
374 - case "eab":
375 - iss.ExternalAccount = new(acme.EAB)
376 - if !d.AllArgs(&iss.ExternalAccount.KeyID, &iss.ExternalAccount.MACKey) {
377 - return d.ArgErr()
378 - }
344 + case "alt_http_port":
345 + if !d.NextArg() {
346 + return d.ArgErr()
347 + }
348 + port, err := strconv.Atoi(d.Val())
349 + if err != nil {
350 + return d.Errf("invalid port %s: %v", d.Val(), err)
351 + }
352 + if iss.Challenges == nil {
353 + iss.Challenges = new(ChallengesConfig)
354 + }
355 + if iss.Challenges.HTTP == nil {
356 + iss.Challenges.HTTP = new(HTTPChallengeConfig)
357 + }
358 + iss.Challenges.HTTP.AlternatePort = port
359
380 - case "trusted_roots":
381 - iss.TrustedRootsPEMFiles = d.RemainingArgs()
360 + case "alt_tlsalpn_port":
361 + if !d.NextArg() {
362 + return d.ArgErr()
363 + }
364 + port, err := strconv.Atoi(d.Val())
365 + if err != nil {
366 + return d.Errf("invalid port %s: %v", d.Val(), err)
367 + }
368 + if iss.Challenges == nil {
369 + iss.Challenges = new(ChallengesConfig)
370 + }
371 + if iss.Challenges.TLSALPN == nil {
372 + iss.Challenges.TLSALPN = new(TLSALPNChallengeConfig)
373 + }
374 + iss.Challenges.TLSALPN.AlternatePort = port
375
383 - case "dns":
384 - if !d.NextArg() {
385 - return d.ArgErr()
386 - }
387 - provName := d.Val()
388 - if iss.Challenges == nil {
389 - iss.Challenges = new(ChallengesConfig)
390 - }
391 - if iss.Challenges.DNS == nil {
392 - iss.Challenges.DNS = new(DNSChallengeConfig)
393 - }
394 - unm, err := caddyfile.UnmarshalModule(d, "dns.providers."+provName)
395 - if err != nil {
396 - return err
397 - }
398 - iss.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, nil)
376 + case "eab":
377 + iss.ExternalAccount = new(acme.EAB)
378 + if !d.AllArgs(&iss.ExternalAccount.KeyID, &iss.ExternalAccount.MACKey) {
379 + return d.ArgErr()
380 + }
381
400 - case "propagation_delay":
401 - if !d.NextArg() {
402 - return d.ArgErr()
403 - }
404 - delayStr := d.Val()
405 - delay, err := caddy.ParseDuration(delayStr)
406 - if err != nil {
407 - return d.Errf("invalid propagation_delay duration %s: %v", delayStr, err)
408 - }
409 - if iss.Challenges == nil {
410 - iss.Challenges = new(ChallengesConfig)
411 - }
412 - if iss.Challenges.DNS == nil {
413 - iss.Challenges.DNS = new(DNSChallengeConfig)
414 - }
415 - iss.Challenges.DNS.PropagationDelay = caddy.Duration(delay)
382 + case "trusted_roots":
383 + iss.TrustedRootsPEMFiles = d.RemainingArgs()
384
417 - case "propagation_timeout":
418 - if !d.NextArg() {
419 - return d.ArgErr()
420 - }
421 - timeoutStr := d.Val()
422 - var timeout time.Duration
423 - if timeoutStr == "-1" {
424 - timeout = time.Duration(-1)
425 - } else {
426 - var err error
427 - timeout, err = caddy.ParseDuration(timeoutStr)
428 - if err != nil {
429 - return d.Errf("invalid propagation_timeout duration %s: %v", timeoutStr, err)
430 - }
431 - }
432 - if iss.Challenges == nil {
433 - iss.Challenges = new(ChallengesConfig)
434 - }
435 - if iss.Challenges.DNS == nil {
436 - iss.Challenges.DNS = new(DNSChallengeConfig)
437 - }
438 - iss.Challenges.DNS.PropagationTimeout = caddy.Duration(timeout)
385 + case "dns":
386 + if !d.NextArg() {
387 + return d.ArgErr()
388 + }
389 + provName := d.Val()
390 + if iss.Challenges == nil {
391 + iss.Challenges = new(ChallengesConfig)
392 + }
393 + if iss.Challenges.DNS == nil {
394 + iss.Challenges.DNS = new(DNSChallengeConfig)
395 + }
396 + unm, err := caddyfile.UnmarshalModule(d, "dns.providers."+provName)
397 + if err != nil {
398 + return err
399 + }
400 + iss.Challenges.DNS.ProviderRaw = caddyconfig.JSONModuleObject(unm, "name", provName, nil)
401
440 - case "resolvers":
441 - if iss.Challenges == nil {
442 - iss.Challenges = new(ChallengesConfig)
443 - }
444 - if iss.Challenges.DNS == nil {
445 - iss.Challenges.DNS = new(DNSChallengeConfig)
446 - }
447 - iss.Challenges.DNS.Resolvers = d.RemainingArgs()
448 - if len(iss.Challenges.DNS.Resolvers) == 0 {
449 - return d.ArgErr()
450 - }
402 + case "propagation_delay":
403 + if !d.NextArg() {
404 + return d.ArgErr()
405 + }
406 + delayStr := d.Val()
407 + delay, err := caddy.ParseDuration(delayStr)
408 + if err != nil {
409 + return d.Errf("invalid propagation_delay duration %s: %v", delayStr, err)
410 + }
411 + if iss.Challenges == nil {
412 + iss.Challenges = new(ChallengesConfig)
413 + }
414 + if iss.Challenges.DNS == nil {
415 + iss.Challenges.DNS = new(DNSChallengeConfig)
416 + }
417 + iss.Challenges.DNS.PropagationDelay = caddy.Duration(delay)
418
452 - case "dns_ttl":
453 - if !d.NextArg() {
454 - return d.ArgErr()
455 - }
456 - ttlStr := d.Val()
457 - ttl, err := caddy.ParseDuration(ttlStr)
419 + case "propagation_timeout":
420 + if !d.NextArg() {
421 + return d.ArgErr()
422 + }
423 + timeoutStr := d.Val()
424 + var timeout time.Duration
425 + if timeoutStr == "-1" {
426 + timeout = time.Duration(-1)
427 + } else {
428 + var err error
429 + timeout, err = caddy.ParseDuration(timeoutStr)
430 if err != nil {
459 - return d.Errf("invalid dns_ttl duration %s: %v", ttlStr, err)
460 - }
461 - if iss.Challenges == nil {
462 - iss.Challenges = new(ChallengesConfig)
431 + return d.Errf("invalid propagation_timeout duration %s: %v", timeoutStr, err)
432 }
464 - if iss.Challenges.DNS == nil {
465 - iss.Challenges.DNS = new(DNSChallengeConfig)
466 - }
467 - iss.Challenges.DNS.TTL = caddy.Duration(ttl)
433 + }
434 + if iss.Challenges == nil {
435 + iss.Challenges = new(ChallengesConfig)
436 + }
437 + if iss.Challenges.DNS == nil {
438 + iss.Challenges.DNS = new(DNSChallengeConfig)
439 + }
440 + iss.Challenges.DNS.PropagationTimeout = caddy.Duration(timeout)
441
469 - case "dns_challenge_override_domain":
470 - arg := d.RemainingArgs()
471 - if len(arg) != 1 {
472 - return d.ArgErr()
473 - }
474 - if iss.Challenges == nil {
475 - iss.Challenges = new(ChallengesConfig)
476 - }
477 - if iss.Challenges.DNS == nil {
478 - iss.Challenges.DNS = new(DNSChallengeConfig)
479 - }
480 - iss.Challenges.DNS.OverrideDomain = arg[0]
442 + case "resolvers":
443 + if iss.Challenges == nil {
444 + iss.Challenges = new(ChallengesConfig)
445 + }
446 + if iss.Challenges.DNS == nil {
447 + iss.Challenges.DNS = new(DNSChallengeConfig)
448 + }
449 + iss.Challenges.DNS.Resolvers = d.RemainingArgs()
450 + if len(iss.Challenges.DNS.Resolvers) == 0 {
451 + return d.ArgErr()
452 + }
453
482 - case "preferred_chains":
483 - chainPref, err := ParseCaddyfilePreferredChainsOptions(d)
484 - if err != nil {
485 - return err
486 - }
487 - iss.PreferredChains = chainPref
454 + case "dns_ttl":
455 + if !d.NextArg() {
456 + return d.ArgErr()
457 + }
458 + ttlStr := d.Val()
459 + ttl, err := caddy.ParseDuration(ttlStr)
460 + if err != nil {
461 + return d.Errf("invalid dns_ttl duration %s: %v", ttlStr, err)
462 + }
463 + if iss.Challenges == nil {
464 + iss.Challenges = new(ChallengesConfig)
465 + }
466 + if iss.Challenges.DNS == nil {
467 + iss.Challenges.DNS = new(DNSChallengeConfig)
468 + }
469 + iss.Challenges.DNS.TTL = caddy.Duration(ttl)
470
489 - default:
490 - return d.Errf("unrecognized ACME issuer property: %s", d.Val())
471 + case "dns_challenge_override_domain":
472 + arg := d.RemainingArgs()
473 + if len(arg) != 1 {
474 + return d.ArgErr()
475 }
476 + if iss.Challenges == nil {
477 + iss.Challenges = new(ChallengesConfig)
478 + }
479 + if iss.Challenges.DNS == nil {
480 + iss.Challenges.DNS = new(DNSChallengeConfig)
481 + }
482 + iss.Challenges.DNS.OverrideDomain = arg[0]
483 +
484 + case "preferred_chains":
485 + chainPref, err := ParseCaddyfilePreferredChainsOptions(d)
486 + if err != nil {
487 + return err
488 + }
489 + iss.PreferredChains = chainPref
490 +
491 + default:
492 + return d.Errf("unrecognized ACME issuer property: %s", d.Val())
493 }
494 }
495 return nil
modules/caddytls/certmanagers.go
+15 -15
@@ -72,10 +72,9 @@ func (ts Tailscale) canHazCertificate(ctx context.Context, hello *tls.ClientHell
72 //
73 // ... tailscale
74 func (Tailscale) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
75 - for d.Next() {
76 - if d.NextArg() {
77 - return d.ArgErr()
78 - }
75 + d.Next() // consume cert manager name
76 + if d.NextArg() {
77 + return d.ArgErr()
78 }
79 return nil
80 }
@@ -169,17 +168,18 @@ func (hcg HTTPCertGetter) GetCertificate(ctx context.Context, hello *tls.ClientH
168 //
169 // ... http <url>
170 func (hcg *HTTPCertGetter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
172 - for d.Next() {
173 - if !d.NextArg() {
174 - return d.ArgErr()
175 - }
176 - hcg.URL = d.Val()
177 - if d.NextArg() {
178 - return d.ArgErr()
179 - }
180 - for nesting := d.Nesting(); d.NextBlock(nesting); {
181 - return d.Err("block not allowed here")
182 - }
171 + d.Next() // consume cert manager name
172 +
173 + if !d.NextArg() {
174 + return d.ArgErr()
175 + }
176 + hcg.URL = d.Val()
177 +
178 + if d.NextArg() {
179 + return d.ArgErr()
180 + }
181 + if d.NextBlock(0) {
182 + return d.Err("block not allowed here")
183 }
184 return nil
185 }
modules/caddytls/internalissuer.go
+22 -23
@@ -155,31 +155,30 @@ func (iss InternalIssuer) Issue(ctx context.Context, csr *x509.CertificateReques
155 // sign_with_root
156 // }
157 func (iss *InternalIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
158 - for d.Next() {
159 - for d.NextBlock(0) {
160 - switch d.Val() {
161 - case "ca":
162 - if !d.AllArgs(&iss.CA) {
163 - return d.ArgErr()
164 - }
165 -
166 - case "lifetime":
167 - if !d.NextArg() {
168 - return d.ArgErr()
169 - }
170 - dur, err := caddy.ParseDuration(d.Val())
171 - if err != nil {
172 - return err
173 - }
174 - iss.Lifetime = caddy.Duration(dur)
175 -
176 - case "sign_with_root":
177 - if d.NextArg() {
178 - return d.ArgErr()
179 - }
180 - iss.SignWithRoot = true
158 + d.Next() // consume issuer name
159 + for d.NextBlock(0) {
160 + switch d.Val() {
161 + case "ca":
162 + if !d.AllArgs(&iss.CA) {
163 + return d.ArgErr()
164 + }
165
166 + case "lifetime":
167 + if !d.NextArg() {
168 + return d.ArgErr()
169 + }
170 + dur, err := caddy.ParseDuration(d.Val())
171 + if err != nil {
172 + return err
173 }
174 + iss.Lifetime = caddy.Duration(dur)
175 +
176 + case "sign_with_root":
177 + if d.NextArg() {
178 + return d.ArgErr()
179 + }
180 + iss.SignWithRoot = true
181 +
182 }
183 }
184 return nil
modules/caddytls/zerosslissuer.go
+11 -12
@@ -208,21 +208,20 @@ func (iss *ZeroSSLIssuer) Revoke(ctx context.Context, cert certmagic.Certificate
208 //
209 // Any of the subdirectives for the ACME issuer can be used in the block.
210 func (iss *ZeroSSLIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
211 - for d.Next() {
211 + d.Next() // consume issuer name
212 + if d.NextArg() {
213 + iss.APIKey = d.Val()
214 if d.NextArg() {
213 - iss.APIKey = d.Val()
214 - if d.NextArg() {
215 - return d.ArgErr()
216 - }
215 + return d.ArgErr()
216 }
217 + }
218
219 - if iss.ACMEIssuer == nil {
220 - iss.ACMEIssuer = new(ACMEIssuer)
221 - }
222 - err := iss.ACMEIssuer.UnmarshalCaddyfile(d.NewFromNextSegment())
223 - if err != nil {
224 - return err
225 - }
219 + if iss.ACMEIssuer == nil {
220 + iss.ACMEIssuer = new(ACMEIssuer)
221 + }
222 + err := iss.ACMEIssuer.UnmarshalCaddyfile(d.NewFromNextSegment())
223 + if err != nil {
224 + return err
225 }
226 return nil
227 }
modules/filestorage/filestorage.go
+1 -1
@@ -55,7 +55,7 @@ func (s *FileStorage) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
55 if d.NextArg() {
56 return d.ArgErr()
57 }
58 - for nesting := d.Nesting(); d.NextBlock(nesting); {
58 + for d.NextBlock(0) {
59 switch d.Val() {
60 case "root":
61 if !d.NextArg() {
modules/logging/encoders.go
+15 -17
@@ -65,14 +65,13 @@ func (ce *ConsoleEncoder) Provision(_ caddy.Context) error {
65 // See the godoc on the LogEncoderConfig type for the syntax of
66 // subdirectives that are common to most/all encoders.
67 func (ce *ConsoleEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
68 - for d.Next() {
69 - if d.NextArg() {
70 - return d.ArgErr()
71 - }
72 - err := ce.LogEncoderConfig.UnmarshalCaddyfile(d)
73 - if err != nil {
74 - return err
75 - }
68 + d.Next() // consume encoder name
69 + if d.NextArg() {
70 + return d.ArgErr()
71 + }
72 + err := ce.LogEncoderConfig.UnmarshalCaddyfile(d)
73 + if err != nil {
74 + return err
75 }
76 return nil
77 }
@@ -106,14 +105,13 @@ func (je *JSONEncoder) Provision(_ caddy.Context) error {
105 // See the godoc on the LogEncoderConfig type for the syntax of
106 // subdirectives that are common to most/all encoders.
107 func (je *JSONEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
109 - for d.Next() {
110 - if d.NextArg() {
111 - return d.ArgErr()
112 - }
113 - err := je.LogEncoderConfig.UnmarshalCaddyfile(d)
114 - if err != nil {
115 - return err
116 - }
108 + d.Next() // consume encoder name
109 + if d.NextArg() {
110 + return d.ArgErr()
111 + }
112 + err := je.LogEncoderConfig.UnmarshalCaddyfile(d)
113 + if err != nil {
114 + return err
115 }
116 return nil
117 }
@@ -149,7 +147,7 @@ type LogEncoderConfig struct {
147 // level_format <format>
148 // }
149 func (lec *LogEncoderConfig) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
152 - for nesting := d.Nesting(); d.NextBlock(nesting); {
150 + for d.NextBlock(0) {
151 subdir := d.Val()
152 switch subdir {
153 case "time_local":
modules/logging/filewriter.go
+64 -65
@@ -154,73 +154,72 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
154 // omitted or set to a zero value, then Caddy's default value for that
155 // subdirective is used.
156 func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
157 - for d.Next() {
158 - if !d.NextArg() {
159 - return d.ArgErr()
160 - }
161 - fw.Filename = d.Val()
162 - if d.NextArg() {
163 - return d.ArgErr()
164 - }
157 + d.Next() // consume writer name
158 + if !d.NextArg() {
159 + return d.ArgErr()
160 + }
161 + fw.Filename = d.Val()
162 + if d.NextArg() {
163 + return d.ArgErr()
164 + }
165 +
166 + for d.NextBlock(0) {
167 + switch d.Val() {
168 + case "roll_disabled":
169 + var f bool
170 + fw.Roll = &f
171 + if d.NextArg() {
172 + return d.ArgErr()
173 + }
174 +
175 + case "roll_size":
176 + var sizeStr string
177 + if !d.AllArgs(&sizeStr) {
178 + return d.ArgErr()
179 + }
180 + size, err := humanize.ParseBytes(sizeStr)
181 + if err != nil {
182 + return d.Errf("parsing size: %v", err)
183 + }
184 + fw.RollSizeMB = int(math.Ceil(float64(size) / humanize.MiByte))
185
166 - for d.NextBlock(0) {
167 - switch d.Val() {
168 - case "roll_disabled":
169 - var f bool
170 - fw.Roll = &f
171 - if d.NextArg() {
172 - return d.ArgErr()
173 - }
174 -
175 - case "roll_size":
176 - var sizeStr string
177 - if !d.AllArgs(&sizeStr) {
178 - return d.ArgErr()
179 - }
180 - size, err := humanize.ParseBytes(sizeStr)
181 - if err != nil {
182 - return d.Errf("parsing size: %v", err)
183 - }
184 - fw.RollSizeMB = int(math.Ceil(float64(size) / humanize.MiByte))
185 -
186 - case "roll_uncompressed":
187 - var f bool
188 - fw.RollCompress = &f
189 - if d.NextArg() {
190 - return d.ArgErr()
191 - }
192 -
193 - case "roll_local_time":
194 - fw.RollLocalTime = true
195 - if d.NextArg() {
196 - return d.ArgErr()
197 - }
198 -
199 - case "roll_keep":
200 - var keepStr string
201 - if !d.AllArgs(&keepStr) {
202 - return d.ArgErr()
203 - }
204 - keep, err := strconv.Atoi(keepStr)
205 - if err != nil {
206 - return d.Errf("parsing roll_keep number: %v", err)
207 - }
208 - fw.RollKeep = keep
209 -
210 - case "roll_keep_for":
211 - var keepForStr string
212 - if !d.AllArgs(&keepForStr) {
213 - return d.ArgErr()
214 - }
215 - keepFor, err := caddy.ParseDuration(keepForStr)
216 - if err != nil {
217 - return d.Errf("parsing roll_keep_for duration: %v", err)
218 - }
219 - if keepFor < 0 {
220 - return d.Errf("negative roll_keep_for duration: %v", keepFor)
221 - }
222 - fw.RollKeepDays = int(math.Ceil(keepFor.Hours() / 24))
186 + case "roll_uncompressed":
187 + var f bool
188 + fw.RollCompress = &f
189 + if d.NextArg() {
190 + return d.ArgErr()
191 + }
192 +
193 + case "roll_local_time":
194 + fw.RollLocalTime = true
195 + if d.NextArg() {
196 + return d.ArgErr()
197 + }
198 +
199 + case "roll_keep":
200 + var keepStr string
201 + if !d.AllArgs(&keepStr) {
202 + return d.ArgErr()
203 + }
204 + keep, err := strconv.Atoi(keepStr)
205 + if err != nil {
206 + return d.Errf("parsing roll_keep number: %v", err)
207 + }
208 + fw.RollKeep = keep
209 +
210 + case "roll_keep_for":
211 + var keepForStr string
212 + if !d.AllArgs(&keepForStr) {
213 + return d.ArgErr()
214 + }
215 + keepFor, err := caddy.ParseDuration(keepForStr)
216 + if err != nil {
217 + return d.Errf("parsing roll_keep_for duration: %v", err)
218 + }
219 + if keepFor < 0 {
220 + return d.Errf("negative roll_keep_for duration: %v", keepFor)
221 }
222 + fw.RollKeepDays = int(math.Ceil(keepFor.Hours() / 24))
223 }
224 }
225 return nil
modules/logging/filterencoder.go
+32 -33
@@ -108,50 +108,49 @@ func (fe *FilterEncoder) Provision(ctx caddy.Context) error {
108 // }
109 // }
110 func (fe *FilterEncoder) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
111 - for d.Next() {
112 - for d.NextBlock(0) {
113 - switch d.Val() {
114 - case "wrap":
111 + d.Next() // consume encoder name
112 + for d.NextBlock(0) {
113 + switch d.Val() {
114 + case "wrap":
115 + if !d.NextArg() {
116 + return d.ArgErr()
117 + }
118 + moduleName := d.Val()
119 + moduleID := "caddy.logging.encoders." + moduleName
120 + unm, err := caddyfile.UnmarshalModule(d, moduleID)
121 + if err != nil {
122 + return err
123 + }
124 + enc, ok := unm.(zapcore.Encoder)
125 + if !ok {
126 + return d.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
127 + }
128 + fe.WrappedRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, nil)
129 +
130 + case "fields":
131 + for nesting := d.Nesting(); d.NextBlock(nesting); {
132 + field := d.Val()
133 if !d.NextArg() {
134 return d.ArgErr()
135 }
118 - moduleName := d.Val()
119 - moduleID := "caddy.logging.encoders." + moduleName
136 + filterName := d.Val()
137 + moduleID := "caddy.logging.encoders.filter." + filterName
138 unm, err := caddyfile.UnmarshalModule(d, moduleID)
139 if err != nil {
140 return err
141 }
124 - enc, ok := unm.(zapcore.Encoder)
142 + filter, ok := unm.(LogFieldFilter)
143 if !ok {
126 - return d.Errf("module %s (%T) is not a zapcore.Encoder", moduleID, unm)
144 + return d.Errf("module %s (%T) is not a logging.LogFieldFilter", moduleID, unm)
145 }
128 - fe.WrappedRaw = caddyconfig.JSONModuleObject(enc, "format", moduleName, nil)
129 -
130 - case "fields":
131 - for d.NextBlock(1) {
132 - field := d.Val()
133 - if !d.NextArg() {
134 - return d.ArgErr()
135 - }
136 - filterName := d.Val()
137 - moduleID := "caddy.logging.encoders.filter." + filterName
138 - unm, err := caddyfile.UnmarshalModule(d, moduleID)
139 - if err != nil {
140 - return err
141 - }
142 - filter, ok := unm.(LogFieldFilter)
143 - if !ok {
144 - return d.Errf("module %s (%T) is not a logging.LogFieldFilter", moduleID, unm)
145 - }
146 - if fe.FieldsRaw == nil {
147 - fe.FieldsRaw = make(map[string]json.RawMessage)
148 - }
149 - fe.FieldsRaw[field] = caddyconfig.JSONModuleObject(filter, "filter", filterName, nil)
146 + if fe.FieldsRaw == nil {
147 + fe.FieldsRaw = make(map[string]json.RawMessage)
148 }
151 -
152 - default:
153 - return d.Errf("unrecognized subdirective %s", d.Val())
149 + fe.FieldsRaw[field] = caddyconfig.JSONModuleObject(filter, "filter", filterName, nil)
150 }
151 +
152 + default:
153 + return d.Errf("unrecognized subdirective %s", d.Val())
154 }
155 }
156 return nil
modules/logging/filters.go
+106 -112
@@ -128,10 +128,9 @@ func (ReplaceFilter) CaddyModule() caddy.ModuleInfo {
128
129 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
130 func (f *ReplaceFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
131 - for d.Next() {
132 - if d.NextArg() {
133 - f.Value = d.Val()
134 - }
131 + d.Next() // consume filter name
132 + if d.NextArg() {
133 + f.Value = d.Val()
134 }
135 return nil
136 }
@@ -169,32 +168,31 @@ func (IPMaskFilter) CaddyModule() caddy.ModuleInfo {
168
169 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
170 func (m *IPMaskFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
172 - for d.Next() {
173 - for d.NextBlock(0) {
174 - switch d.Val() {
175 - case "ipv4":
176 - if !d.NextArg() {
177 - return d.ArgErr()
178 - }
179 - val, err := strconv.Atoi(d.Val())
180 - if err != nil {
181 - return d.Errf("error parsing %s: %v", d.Val(), err)
182 - }
183 - m.IPv4MaskRaw = val
184 -
185 - case "ipv6":
186 - if !d.NextArg() {
187 - return d.ArgErr()
188 - }
189 - val, err := strconv.Atoi(d.Val())
190 - if err != nil {
191 - return d.Errf("error parsing %s: %v", d.Val(), err)
192 - }
193 - m.IPv6MaskRaw = val
194 -
195 - default:
196 - return d.Errf("unrecognized subdirective %s", d.Val())
171 + d.Next() // consume filter name
172 + for d.NextBlock(0) {
173 + switch d.Val() {
174 + case "ipv4":
175 + if !d.NextArg() {
176 + return d.ArgErr()
177 + }
178 + val, err := strconv.Atoi(d.Val())
179 + if err != nil {
180 + return d.Errf("error parsing %s: %v", d.Val(), err)
181 + }
182 + m.IPv4MaskRaw = val
183 +
184 + case "ipv6":
185 + if !d.NextArg() {
186 + return d.ArgErr()
187 }
188 + val, err := strconv.Atoi(d.Val())
189 + if err != nil {
190 + return d.Errf("error parsing %s: %v", d.Val(), err)
191 + }
192 + m.IPv6MaskRaw = val
193 +
194 + default:
195 + return d.Errf("unrecognized subdirective %s", d.Val())
196 }
197 }
198 return nil
@@ -328,45 +326,44 @@ func (QueryFilter) CaddyModule() caddy.ModuleInfo {
326
327 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
328 func (m *QueryFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
331 - for d.Next() {
332 - for d.NextBlock(0) {
333 - qfa := queryFilterAction{}
334 - switch d.Val() {
335 - case "replace":
336 - if !d.NextArg() {
337 - return d.ArgErr()
338 - }
339 -
340 - qfa.Type = replaceAction
341 - qfa.Parameter = d.Val()
342 -
343 - if !d.NextArg() {
344 - return d.ArgErr()
345 - }
346 - qfa.Value = d.Val()
347 -
348 - case "hash":
349 - if !d.NextArg() {
350 - return d.ArgErr()
351 - }
352 -
353 - qfa.Type = hashAction
354 - qfa.Parameter = d.Val()
355 -
356 - case "delete":
357 - if !d.NextArg() {
358 - return d.ArgErr()
359 - }
360 -
361 - qfa.Type = deleteAction
362 - qfa.Parameter = d.Val()
363 -
364 - default:
365 - return d.Errf("unrecognized subdirective %s", d.Val())
329 + d.Next() // consume filter name
330 + for d.NextBlock(0) {
331 + qfa := queryFilterAction{}
332 + switch d.Val() {
333 + case "replace":
334 + if !d.NextArg() {
335 + return d.ArgErr()
336 }
337
368 - m.Actions = append(m.Actions, qfa)
338 + qfa.Type = replaceAction
339 + qfa.Parameter = d.Val()
340 +
341 + if !d.NextArg() {
342 + return d.ArgErr()
343 + }
344 + qfa.Value = d.Val()
345 +
346 + case "hash":
347 + if !d.NextArg() {
348 + return d.ArgErr()
349 + }
350 +
351 + qfa.Type = hashAction
352 + qfa.Parameter = d.Val()
353 +
354 + case "delete":
355 + if !d.NextArg() {
356 + return d.ArgErr()
357 + }
358 +
359 + qfa.Type = deleteAction
360 + qfa.Parameter = d.Val()
361 +
362 + default:
363 + return d.Errf("unrecognized subdirective %s", d.Val())
364 }
365 +
366 + m.Actions = append(m.Actions, qfa)
367 }
368 return nil
369 }
@@ -460,45 +457,44 @@ func (CookieFilter) CaddyModule() caddy.ModuleInfo {
457
458 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
459 func (m *CookieFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
463 - for d.Next() {
464 - for d.NextBlock(0) {
465 - cfa := cookieFilterAction{}
466 - switch d.Val() {
467 - case "replace":
468 - if !d.NextArg() {
469 - return d.ArgErr()
470 - }
471 -
472 - cfa.Type = replaceAction
473 - cfa.Name = d.Val()
474 -
475 - if !d.NextArg() {
476 - return d.ArgErr()
477 - }
478 - cfa.Value = d.Val()
479 -
480 - case "hash":
481 - if !d.NextArg() {
482 - return d.ArgErr()
483 - }
484 -
485 - cfa.Type = hashAction
486 - cfa.Name = d.Val()
487 -
488 - case "delete":
489 - if !d.NextArg() {
490 - return d.ArgErr()
491 - }
492 -
493 - cfa.Type = deleteAction
494 - cfa.Name = d.Val()
495 -
496 - default:
497 - return d.Errf("unrecognized subdirective %s", d.Val())
460 + d.Next() // consume filter name
461 + for d.NextBlock(0) {
462 + cfa := cookieFilterAction{}
463 + switch d.Val() {
464 + case "replace":
465 + if !d.NextArg() {
466 + return d.ArgErr()
467 + }
468 +
469 + cfa.Type = replaceAction
470 + cfa.Name = d.Val()
471 +
472 + if !d.NextArg() {
473 + return d.ArgErr()
474 }
475 + cfa.Value = d.Val()
476
500 - m.Actions = append(m.Actions, cfa)
477 + case "hash":
478 + if !d.NextArg() {
479 + return d.ArgErr()
480 + }
481 +
482 + cfa.Type = hashAction
483 + cfa.Name = d.Val()
484 +
485 + case "delete":
486 + if !d.NextArg() {
487 + return d.ArgErr()
488 + }
489 +
490 + cfa.Type = deleteAction
491 + cfa.Name = d.Val()
492 +
493 + default:
494 + return d.Errf("unrecognized subdirective %s", d.Val())
495 }
496 +
497 + m.Actions = append(m.Actions, cfa)
498 }
499 return nil
500 }
@@ -571,13 +567,12 @@ func (RegexpFilter) CaddyModule() caddy.ModuleInfo {
567
568 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
569 func (f *RegexpFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
574 - for d.Next() {
575 - if d.NextArg() {
576 - f.RawRegexp = d.Val()
577 - }
578 - if d.NextArg() {
579 - f.Value = d.Val()
580 - }
570 + d.Next() // consume filter name
571 + if d.NextArg() {
572 + f.RawRegexp = d.Val()
573 + }
574 + if d.NextArg() {
575 + f.Value = d.Val()
576 }
577 return nil
578 }
@@ -625,10 +620,9 @@ func (RenameFilter) CaddyModule() caddy.ModuleInfo {
620
621 // UnmarshalCaddyfile sets up the module from Caddyfile tokens.
622 func (f *RenameFilter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
628 - for d.Next() {
629 - if d.NextArg() {
630 - f.Name = d.Val()
631 - }
623 + d.Next() // consume filter name
624 + if d.NextArg() {
625 + f.Name = d.Val()
626 }
627 return nil
628 }
modules/logging/netwriter.go
+27 -28
@@ -117,35 +117,34 @@ func (nw NetWriter) OpenWriter() (io.WriteCloser, error) {
117 // soft_start
118 // }
119 func (nw *NetWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
120 - for d.Next() {
121 - if !d.NextArg() {
122 - return d.ArgErr()
123 - }
124 - nw.Address = d.Val()
125 - if d.NextArg() {
126 - return d.ArgErr()
127 - }
128 - for nesting := d.Nesting(); d.NextBlock(nesting); {
129 - switch d.Val() {
130 - case "dial_timeout":
131 - if !d.NextArg() {
132 - return d.ArgErr()
133 - }
134 - timeout, err := caddy.ParseDuration(d.Val())
135 - if err != nil {
136 - return d.Errf("invalid duration: %s", d.Val())
137 - }
138 - if d.NextArg() {
139 - return d.ArgErr()
140 - }
141 - nw.DialTimeout = caddy.Duration(timeout)
142 -
143 - case "soft_start":
144 - if d.NextArg() {
145 - return d.ArgErr()
146 - }
147 - nw.SoftStart = true
120 + d.Next() // consume writer name
121 + if !d.NextArg() {
122 + return d.ArgErr()
123 + }
124 + nw.Address = d.Val()
125 + if d.NextArg() {
126 + return d.ArgErr()
127 + }
128 + for d.NextBlock(0) {
129 + switch d.Val() {
130 + case "dial_timeout":
131 + if !d.NextArg() {
132 + return d.ArgErr()
133 + }
134 + timeout, err := caddy.ParseDuration(d.Val())
135 + if err != nil {
136 + return d.Errf("invalid duration: %s", d.Val())
137 + }
138 + if d.NextArg() {
139 + return d.ArgErr()
140 + }
141 + nw.DialTimeout = caddy.Duration(timeout)
142 +
143 + case "soft_start":
144 + if d.NextArg() {
145 + return d.ArgErr()
146 }
147 + nw.SoftStart = true
148 }
149 }
150 return nil
modules/metrics/metrics.go
+11 -12
@@ -78,19 +78,18 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
78 // disable_openmetrics
79 // }
80 func (m *Metrics) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
81 - for d.Next() {
82 - args := d.RemainingArgs()
83 - if len(args) > 0 {
84 - return d.ArgErr()
85 - }
81 + d.Next() // consume directive name
82 + args := d.RemainingArgs()
83 + if len(args) > 0 {
84 + return d.ArgErr()
85 + }
86
87 - for d.NextBlock(0) {
88 - switch d.Val() {
89 - case "disable_openmetrics":
90 - m.DisableOpenMetrics = true
91 - default:
92 - return d.Errf("unrecognized subdirective %q", d.Val())
93 - }
87 + for d.NextBlock(0) {
88 + switch d.Val() {
89 + case "disable_openmetrics":
90 + m.DisableOpenMetrics = true
91 + default:
92 + return d.Errf("unrecognized subdirective %q", d.Val())
93 }
94 }
95 return nil