@marcel91200 / caddy Mirror · read-only / commits / 53b6fab1
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 13, 04:15 UTC

caddyfile: Stricter parsing, error for brace on new line (#5505)

Francis Lavoie committed Apr 20, 2023 at 14:43 UTC 53b6fab125f3f2f149d59fcfe13b1e8b1735da56
5 files changed +499 -487
caddyconfig/caddyfile/parse.go
+3
@@ -520,6 +520,9 @@ func (p *parser) directive() error {
520 if !p.isNextOnNewLine() && p.Token().wasQuoted == 0 {
521 return p.Err("Unexpected next token after '{' on same line")
522 }
523 + if p.isNewLine() {
524 + return p.Err("Unexpected '{' on a new line; did you mean to place the '{' on the previous line?")
525 + }
526 } else if p.Val() == "{}" {
527 if p.isNextOnNewLine() && p.Token().wasQuoted == 0 {
528 return p.Err("Unexpected '{}' at end of line")
caddyconfig/caddyfile/parse_test.go
+8
@@ -293,6 +293,14 @@ func TestParseOneAndImport(t *testing.T) {
293 // Unexpected next token after '{' on same line
294 {`localhost
295 dir1 { a b }`, true, []string{"localhost"}, []int{}},
296 +
297 + // Unexpected '{' on a new line
298 + {`localhost
299 + dir1
300 + {
301 + a b
302 + }`, true, []string{"localhost"}, []int{}},
303 +
304 // Workaround with quotes
305 {`localhost
306 dir1 "{" a b "}"`, false, []string{"localhost"}, []int{5}},
modules/caddyhttp/reverseproxy/caddyfile.go
+486 -487
@@ -161,556 +161,555 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
161 return nil
162 }
163
164 - for d.Next() {
165 - for _, up := range d.RemainingArgs() {
166 - err := appendUpstream(up)
164 + d.Next() // consume the directive name
165 + for _, up := range d.RemainingArgs() {
166 + err := appendUpstream(up)
167 + if err != nil {
168 + return err
169 + }
170 + }
171 +
172 + for nesting := d.Nesting(); d.NextBlock(nesting); {
173 + // if the subdirective has an "@" prefix then we
174 + // parse it as a response matcher for use with "handle_response"
175 + if strings.HasPrefix(d.Val(), matcherPrefix) {
176 + err := caddyhttp.ParseNamedResponseMatcher(d.NewFromNextSegment(), h.responseMatchers)
177 if err != nil {
178 return err
179 }
180 + continue
181 }
182
172 - for d.NextBlock(0) {
173 - // if the subdirective has an "@" prefix then we
174 - // parse it as a response matcher for use with "handle_response"
175 - if strings.HasPrefix(d.Val(), matcherPrefix) {
176 - err := caddyhttp.ParseNamedResponseMatcher(d.NewFromNextSegment(), h.responseMatchers)
183 + switch d.Val() {
184 + case "to":
185 + args := d.RemainingArgs()
186 + if len(args) == 0 {
187 + return d.ArgErr()
188 + }
189 + for _, up := range args {
190 + err := appendUpstream(up)
191 if err != nil {
192 return err
193 }
180 - continue
194 }
195
183 - switch d.Val() {
184 - case "to":
185 - args := d.RemainingArgs()
186 - if len(args) == 0 {
187 - return d.ArgErr()
188 - }
189 - for _, up := range args {
190 - err := appendUpstream(up)
191 - if err != nil {
192 - return err
193 - }
194 - }
196 + case "dynamic":
197 + if !d.NextArg() {
198 + return d.ArgErr()
199 + }
200 + if h.DynamicUpstreams != nil {
201 + return d.Err("dynamic upstreams already specified")
202 + }
203 + dynModule := d.Val()
204 + modID := "http.reverse_proxy.upstreams." + dynModule
205 + unm, err := caddyfile.UnmarshalModule(d, modID)
206 + if err != nil {
207 + return err
208 + }
209 + source, ok := unm.(UpstreamSource)
210 + if !ok {
211 + return d.Errf("module %s (%T) is not an UpstreamSource", modID, unm)
212 + }
213 + h.DynamicUpstreamsRaw = caddyconfig.JSONModuleObject(source, "source", dynModule, nil)
214
196 - case "dynamic":
197 - if !d.NextArg() {
198 - return d.ArgErr()
199 - }
200 - if h.DynamicUpstreams != nil {
201 - return d.Err("dynamic upstreams already specified")
202 - }
203 - dynModule := d.Val()
204 - modID := "http.reverse_proxy.upstreams." + dynModule
205 - unm, err := caddyfile.UnmarshalModule(d, modID)
206 - if err != nil {
207 - return err
208 - }
209 - source, ok := unm.(UpstreamSource)
210 - if !ok {
211 - return d.Errf("module %s (%T) is not an UpstreamSource", modID, unm)
212 - }
213 - h.DynamicUpstreamsRaw = caddyconfig.JSONModuleObject(source, "source", dynModule, nil)
215 + case "lb_policy":
216 + if !d.NextArg() {
217 + return d.ArgErr()
218 + }
219 + if h.LoadBalancing != nil && h.LoadBalancing.SelectionPolicyRaw != nil {
220 + return d.Err("load balancing selection policy already specified")
221 + }
222 + name := d.Val()
223 + modID := "http.reverse_proxy.selection_policies." + name
224 + unm, err := caddyfile.UnmarshalModule(d, modID)
225 + if err != nil {
226 + return err
227 + }
228 + sel, ok := unm.(Selector)
229 + if !ok {
230 + return d.Errf("module %s (%T) is not a reverseproxy.Selector", modID, unm)
231 + }
232 + if h.LoadBalancing == nil {
233 + h.LoadBalancing = new(LoadBalancing)
234 + }
235 + h.LoadBalancing.SelectionPolicyRaw = caddyconfig.JSONModuleObject(sel, "policy", name, nil)
236
215 - case "lb_policy":
216 - if !d.NextArg() {
217 - return d.ArgErr()
218 - }
219 - if h.LoadBalancing != nil && h.LoadBalancing.SelectionPolicyRaw != nil {
220 - return d.Err("load balancing selection policy already specified")
221 - }
222 - name := d.Val()
223 - modID := "http.reverse_proxy.selection_policies." + name
224 - unm, err := caddyfile.UnmarshalModule(d, modID)
225 - if err != nil {
226 - return err
227 - }
228 - sel, ok := unm.(Selector)
229 - if !ok {
230 - return d.Errf("module %s (%T) is not a reverseproxy.Selector", modID, unm)
231 - }
232 - if h.LoadBalancing == nil {
233 - h.LoadBalancing = new(LoadBalancing)
234 - }
235 - h.LoadBalancing.SelectionPolicyRaw = caddyconfig.JSONModuleObject(sel, "policy", name, nil)
237 + case "lb_retries":
238 + if !d.NextArg() {
239 + return d.ArgErr()
240 + }
241 + tries, err := strconv.Atoi(d.Val())
242 + if err != nil {
243 + return d.Errf("bad lb_retries number '%s': %v", d.Val(), err)
244 + }
245 + if h.LoadBalancing == nil {
246 + h.LoadBalancing = new(LoadBalancing)
247 + }
248 + h.LoadBalancing.Retries = tries
249
237 - case "lb_retries":
238 - if !d.NextArg() {
239 - return d.ArgErr()
240 - }
241 - tries, err := strconv.Atoi(d.Val())
242 - if err != nil {
243 - return d.Errf("bad lb_retries number '%s': %v", d.Val(), err)
244 - }
245 - if h.LoadBalancing == nil {
246 - h.LoadBalancing = new(LoadBalancing)
247 - }
248 - h.LoadBalancing.Retries = tries
250 + case "lb_try_duration":
251 + if !d.NextArg() {
252 + return d.ArgErr()
253 + }
254 + if h.LoadBalancing == nil {
255 + h.LoadBalancing = new(LoadBalancing)
256 + }
257 + dur, err := caddy.ParseDuration(d.Val())
258 + if err != nil {
259 + return d.Errf("bad duration value %s: %v", d.Val(), err)
260 + }
261 + h.LoadBalancing.TryDuration = caddy.Duration(dur)
262
250 - case "lb_try_duration":
251 - if !d.NextArg() {
252 - return d.ArgErr()
253 - }
254 - if h.LoadBalancing == nil {
255 - h.LoadBalancing = new(LoadBalancing)
256 - }
257 - dur, err := caddy.ParseDuration(d.Val())
258 - if err != nil {
259 - return d.Errf("bad duration value %s: %v", d.Val(), err)
260 - }
261 - h.LoadBalancing.TryDuration = caddy.Duration(dur)
263 + case "lb_try_interval":
264 + if !d.NextArg() {
265 + return d.ArgErr()
266 + }
267 + if h.LoadBalancing == nil {
268 + h.LoadBalancing = new(LoadBalancing)
269 + }
270 + dur, err := caddy.ParseDuration(d.Val())
271 + if err != nil {
272 + return d.Errf("bad interval value '%s': %v", d.Val(), err)
273 + }
274 + h.LoadBalancing.TryInterval = caddy.Duration(dur)
275
263 - case "lb_try_interval":
264 - if !d.NextArg() {
265 - return d.ArgErr()
266 - }
267 - if h.LoadBalancing == nil {
268 - h.LoadBalancing = new(LoadBalancing)
269 - }
270 - dur, err := caddy.ParseDuration(d.Val())
271 - if err != nil {
272 - return d.Errf("bad interval value '%s': %v", d.Val(), err)
273 - }
274 - h.LoadBalancing.TryInterval = caddy.Duration(dur)
276 + case "lb_retry_match":
277 + matcherSet, err := caddyhttp.ParseCaddyfileNestedMatcherSet(d)
278 + if err != nil {
279 + return d.Errf("failed to parse lb_retry_match: %v", err)
280 + }
281 + if h.LoadBalancing == nil {
282 + h.LoadBalancing = new(LoadBalancing)
283 + }
284 + h.LoadBalancing.RetryMatchRaw = append(h.LoadBalancing.RetryMatchRaw, matcherSet)
285
276 - case "lb_retry_match":
277 - matcherSet, err := caddyhttp.ParseCaddyfileNestedMatcherSet(d)
278 - if err != nil {
279 - return d.Errf("failed to parse lb_retry_match: %v", err)
280 - }
281 - if h.LoadBalancing == nil {
282 - h.LoadBalancing = new(LoadBalancing)
283 - }
284 - h.LoadBalancing.RetryMatchRaw = append(h.LoadBalancing.RetryMatchRaw, matcherSet)
286 + case "health_uri":
287 + if !d.NextArg() {
288 + return d.ArgErr()
289 + }
290 + if h.HealthChecks == nil {
291 + h.HealthChecks = new(HealthChecks)
292 + }
293 + if h.HealthChecks.Active == nil {
294 + h.HealthChecks.Active = new(ActiveHealthChecks)
295 + }
296 + h.HealthChecks.Active.URI = d.Val()
297
286 - case "health_uri":
287 - if !d.NextArg() {
288 - return d.ArgErr()
289 - }
290 - if h.HealthChecks == nil {
291 - h.HealthChecks = new(HealthChecks)
292 - }
293 - if h.HealthChecks.Active == nil {
294 - h.HealthChecks.Active = new(ActiveHealthChecks)
295 - }
296 - h.HealthChecks.Active.URI = d.Val()
298 + case "health_path":
299 + if !d.NextArg() {
300 + return d.ArgErr()
301 + }
302 + if h.HealthChecks == nil {
303 + h.HealthChecks = new(HealthChecks)
304 + }
305 + if h.HealthChecks.Active == nil {
306 + h.HealthChecks.Active = new(ActiveHealthChecks)
307 + }
308 + h.HealthChecks.Active.Path = d.Val()
309 + caddy.Log().Named("config.adapter.caddyfile").Warn("the 'health_path' subdirective is deprecated, please use 'health_uri' instead!")
310
298 - case "health_path":
299 - if !d.NextArg() {
300 - return d.ArgErr()
301 - }
302 - if h.HealthChecks == nil {
303 - h.HealthChecks = new(HealthChecks)
304 - }
305 - if h.HealthChecks.Active == nil {
306 - h.HealthChecks.Active = new(ActiveHealthChecks)
307 - }
308 - h.HealthChecks.Active.Path = d.Val()
309 - caddy.Log().Named("config.adapter.caddyfile").Warn("the 'health_path' subdirective is deprecated, please use 'health_uri' instead!")
311 + case "health_port":
312 + if !d.NextArg() {
313 + return d.ArgErr()
314 + }
315 + if h.HealthChecks == nil {
316 + h.HealthChecks = new(HealthChecks)
317 + }
318 + if h.HealthChecks.Active == nil {
319 + h.HealthChecks.Active = new(ActiveHealthChecks)
320 + }
321 + portNum, err := strconv.Atoi(d.Val())
322 + if err != nil {
323 + return d.Errf("bad port number '%s': %v", d.Val(), err)
324 + }
325 + h.HealthChecks.Active.Port = portNum
326
311 - case "health_port":
312 - if !d.NextArg() {
313 - return d.ArgErr()
314 - }
315 - if h.HealthChecks == nil {
316 - h.HealthChecks = new(HealthChecks)
317 - }
318 - if h.HealthChecks.Active == nil {
319 - h.HealthChecks.Active = new(ActiveHealthChecks)
327 + case "health_headers":
328 + healthHeaders := make(http.Header)
329 + for nesting := d.Nesting(); d.NextBlock(nesting); {
330 + key := d.Val()
331 + values := d.RemainingArgs()
332 + if len(values) == 0 {
333 + values = append(values, "")
334 }
321 - portNum, err := strconv.Atoi(d.Val())
322 - if err != nil {
323 - return d.Errf("bad port number '%s': %v", d.Val(), err)
324 - }
325 - h.HealthChecks.Active.Port = portNum
335 + healthHeaders[key] = values
336 + }
337 + if h.HealthChecks == nil {
338 + h.HealthChecks = new(HealthChecks)
339 + }
340 + if h.HealthChecks.Active == nil {
341 + h.HealthChecks.Active = new(ActiveHealthChecks)
342 + }
343 + h.HealthChecks.Active.Headers = healthHeaders
344
327 - case "health_headers":
328 - healthHeaders := make(http.Header)
329 - for nesting := d.Nesting(); d.NextBlock(nesting); {
330 - key := d.Val()
331 - values := d.RemainingArgs()
332 - if len(values) == 0 {
333 - values = append(values, "")
334 - }
335 - healthHeaders[key] = values
336 - }
337 - if h.HealthChecks == nil {
338 - h.HealthChecks = new(HealthChecks)
339 - }
340 - if h.HealthChecks.Active == nil {
341 - h.HealthChecks.Active = new(ActiveHealthChecks)
342 - }
343 - h.HealthChecks.Active.Headers = healthHeaders
345 + case "health_interval":
346 + if !d.NextArg() {
347 + return d.ArgErr()
348 + }
349 + if h.HealthChecks == nil {
350 + h.HealthChecks = new(HealthChecks)
351 + }
352 + if h.HealthChecks.Active == nil {
353 + h.HealthChecks.Active = new(ActiveHealthChecks)
354 + }
355 + dur, err := caddy.ParseDuration(d.Val())
356 + if err != nil {
357 + return d.Errf("bad interval value %s: %v", d.Val(), err)
358 + }
359 + h.HealthChecks.Active.Interval = caddy.Duration(dur)
360
345 - case "health_interval":
346 - if !d.NextArg() {
347 - return d.ArgErr()
348 - }
349 - if h.HealthChecks == nil {
350 - h.HealthChecks = new(HealthChecks)
351 - }
352 - if h.HealthChecks.Active == nil {
353 - h.HealthChecks.Active = new(ActiveHealthChecks)
354 - }
355 - dur, err := caddy.ParseDuration(d.Val())
356 - if err != nil {
357 - return d.Errf("bad interval value %s: %v", d.Val(), err)
358 - }
359 - h.HealthChecks.Active.Interval = caddy.Duration(dur)
361 + case "health_timeout":
362 + if !d.NextArg() {
363 + return d.ArgErr()
364 + }
365 + if h.HealthChecks == nil {
366 + h.HealthChecks = new(HealthChecks)
367 + }
368 + if h.HealthChecks.Active == nil {
369 + h.HealthChecks.Active = new(ActiveHealthChecks)
370 + }
371 + dur, err := caddy.ParseDuration(d.Val())
372 + if err != nil {
373 + return d.Errf("bad timeout value %s: %v", d.Val(), err)
374 + }
375 + h.HealthChecks.Active.Timeout = caddy.Duration(dur)
376
361 - case "health_timeout":
362 - if !d.NextArg() {
363 - return d.ArgErr()
364 - }
365 - if h.HealthChecks == nil {
366 - h.HealthChecks = new(HealthChecks)
367 - }
368 - if h.HealthChecks.Active == nil {
369 - h.HealthChecks.Active = new(ActiveHealthChecks)
370 - }
371 - dur, err := caddy.ParseDuration(d.Val())
372 - if err != nil {
373 - return d.Errf("bad timeout value %s: %v", d.Val(), err)
374 - }
375 - h.HealthChecks.Active.Timeout = caddy.Duration(dur)
377 + case "health_status":
378 + if !d.NextArg() {
379 + return d.ArgErr()
380 + }
381 + if h.HealthChecks == nil {
382 + h.HealthChecks = new(HealthChecks)
383 + }
384 + if h.HealthChecks.Active == nil {
385 + h.HealthChecks.Active = new(ActiveHealthChecks)
386 + }
387 + val := d.Val()
388 + if len(val) == 3 && strings.HasSuffix(val, "xx") {
389 + val = val[:1]
390 + }
391 + statusNum, err := strconv.Atoi(val)
392 + if err != nil {
393 + return d.Errf("bad status value '%s': %v", d.Val(), err)
394 + }
395 + h.HealthChecks.Active.ExpectStatus = statusNum
396
377 - case "health_status":
378 - if !d.NextArg() {
379 - return d.ArgErr()
380 - }
381 - if h.HealthChecks == nil {
382 - h.HealthChecks = new(HealthChecks)
383 - }
384 - if h.HealthChecks.Active == nil {
385 - h.HealthChecks.Active = new(ActiveHealthChecks)
386 - }
387 - val := d.Val()
388 - if len(val) == 3 && strings.HasSuffix(val, "xx") {
389 - val = val[:1]
390 - }
391 - statusNum, err := strconv.Atoi(val)
392 - if err != nil {
393 - return d.Errf("bad status value '%s': %v", d.Val(), err)
394 - }
395 - h.HealthChecks.Active.ExpectStatus = statusNum
397 + case "health_body":
398 + if !d.NextArg() {
399 + return d.ArgErr()
400 + }
401 + if h.HealthChecks == nil {
402 + h.HealthChecks = new(HealthChecks)
403 + }
404 + if h.HealthChecks.Active == nil {
405 + h.HealthChecks.Active = new(ActiveHealthChecks)
406 + }
407 + h.HealthChecks.Active.ExpectBody = d.Val()
408
397 - case "health_body":
398 - if !d.NextArg() {
399 - return d.ArgErr()
400 - }
401 - if h.HealthChecks == nil {
402 - h.HealthChecks = new(HealthChecks)
403 - }
404 - if h.HealthChecks.Active == nil {
405 - h.HealthChecks.Active = new(ActiveHealthChecks)
406 - }
407 - h.HealthChecks.Active.ExpectBody = d.Val()
409 + case "max_fails":
410 + if !d.NextArg() {
411 + return d.ArgErr()
412 + }
413 + if h.HealthChecks == nil {
414 + h.HealthChecks = new(HealthChecks)
415 + }
416 + if h.HealthChecks.Passive == nil {
417 + h.HealthChecks.Passive = new(PassiveHealthChecks)
418 + }
419 + maxFails, err := strconv.Atoi(d.Val())
420 + if err != nil {
421 + return d.Errf("invalid maximum fail count '%s': %v", d.Val(), err)
422 + }
423 + h.HealthChecks.Passive.MaxFails = maxFails
424
409 - case "max_fails":
410 - if !d.NextArg() {
411 - return d.ArgErr()
412 - }
413 - if h.HealthChecks == nil {
414 - h.HealthChecks = new(HealthChecks)
415 - }
416 - if h.HealthChecks.Passive == nil {
417 - h.HealthChecks.Passive = new(PassiveHealthChecks)
418 - }
419 - maxFails, err := strconv.Atoi(d.Val())
420 - if err != nil {
421 - return d.Errf("invalid maximum fail count '%s': %v", d.Val(), err)
422 - }
423 - h.HealthChecks.Passive.MaxFails = maxFails
425 + case "fail_duration":
426 + if !d.NextArg() {
427 + return d.ArgErr()
428 + }
429 + if h.HealthChecks == nil {
430 + h.HealthChecks = new(HealthChecks)
431 + }
432 + if h.HealthChecks.Passive == nil {
433 + h.HealthChecks.Passive = new(PassiveHealthChecks)
434 + }
435 + dur, err := caddy.ParseDuration(d.Val())
436 + if err != nil {
437 + return d.Errf("bad duration value '%s': %v", d.Val(), err)
438 + }
439 + h.HealthChecks.Passive.FailDuration = caddy.Duration(dur)
440
425 - case "fail_duration":
426 - if !d.NextArg() {
427 - return d.ArgErr()
428 - }
429 - if h.HealthChecks == nil {
430 - h.HealthChecks = new(HealthChecks)
431 - }
432 - if h.HealthChecks.Passive == nil {
433 - h.HealthChecks.Passive = new(PassiveHealthChecks)
434 - }
435 - dur, err := caddy.ParseDuration(d.Val())
436 - if err != nil {
437 - return d.Errf("bad duration value '%s': %v", d.Val(), err)
438 - }
439 - h.HealthChecks.Passive.FailDuration = caddy.Duration(dur)
441 + case "unhealthy_request_count":
442 + if !d.NextArg() {
443 + return d.ArgErr()
444 + }
445 + if h.HealthChecks == nil {
446 + h.HealthChecks = new(HealthChecks)
447 + }
448 + if h.HealthChecks.Passive == nil {
449 + h.HealthChecks.Passive = new(PassiveHealthChecks)
450 + }
451 + maxConns, err := strconv.Atoi(d.Val())
452 + if err != nil {
453 + return d.Errf("invalid maximum connection count '%s': %v", d.Val(), err)
454 + }
455 + h.HealthChecks.Passive.UnhealthyRequestCount = maxConns
456
441 - case "unhealthy_request_count":
442 - if !d.NextArg() {
443 - return d.ArgErr()
444 - }
445 - if h.HealthChecks == nil {
446 - h.HealthChecks = new(HealthChecks)
447 - }
448 - if h.HealthChecks.Passive == nil {
449 - h.HealthChecks.Passive = new(PassiveHealthChecks)
457 + case "unhealthy_status":
458 + args := d.RemainingArgs()
459 + if len(args) == 0 {
460 + return d.ArgErr()
461 + }
462 + if h.HealthChecks == nil {
463 + h.HealthChecks = new(HealthChecks)
464 + }
465 + if h.HealthChecks.Passive == nil {
466 + h.HealthChecks.Passive = new(PassiveHealthChecks)
467 + }
468 + for _, arg := range args {
469 + if len(arg) == 3 && strings.HasSuffix(arg, "xx") {
470 + arg = arg[:1]
471 }
451 - maxConns, err := strconv.Atoi(d.Val())
472 + statusNum, err := strconv.Atoi(arg)
473 if err != nil {
453 - return d.Errf("invalid maximum connection count '%s': %v", d.Val(), err)
474 + return d.Errf("bad status value '%s': %v", d.Val(), err)
475 }
455 - h.HealthChecks.Passive.UnhealthyRequestCount = maxConns
476 + h.HealthChecks.Passive.UnhealthyStatus = append(h.HealthChecks.Passive.UnhealthyStatus, statusNum)
477 + }
478
457 - case "unhealthy_status":
458 - args := d.RemainingArgs()
459 - if len(args) == 0 {
460 - return d.ArgErr()
461 - }
462 - if h.HealthChecks == nil {
463 - h.HealthChecks = new(HealthChecks)
464 - }
465 - if h.HealthChecks.Passive == nil {
466 - h.HealthChecks.Passive = new(PassiveHealthChecks)
467 - }
468 - for _, arg := range args {
469 - if len(arg) == 3 && strings.HasSuffix(arg, "xx") {
470 - arg = arg[:1]
471 - }
472 - statusNum, err := strconv.Atoi(arg)
473 - if err != nil {
474 - return d.Errf("bad status value '%s': %v", d.Val(), err)
475 - }
476 - h.HealthChecks.Passive.UnhealthyStatus = append(h.HealthChecks.Passive.UnhealthyStatus, statusNum)
477 - }
479 + case "unhealthy_latency":
480 + if !d.NextArg() {
481 + return d.ArgErr()
482 + }
483 + if h.HealthChecks == nil {
484 + h.HealthChecks = new(HealthChecks)
485 + }
486 + if h.HealthChecks.Passive == nil {
487 + h.HealthChecks.Passive = new(PassiveHealthChecks)
488 + }
489 + dur, err := caddy.ParseDuration(d.Val())
490 + if err != nil {
491 + return d.Errf("bad duration value '%s': %v", d.Val(), err)
492 + }
493 + h.HealthChecks.Passive.UnhealthyLatency = caddy.Duration(dur)
494
479 - case "unhealthy_latency":
480 - if !d.NextArg() {
481 - return d.ArgErr()
482 - }
483 - if h.HealthChecks == nil {
484 - h.HealthChecks = new(HealthChecks)
485 - }
486 - if h.HealthChecks.Passive == nil {
487 - h.HealthChecks.Passive = new(PassiveHealthChecks)
488 - }
495 + case "flush_interval":
496 + if !d.NextArg() {
497 + return d.ArgErr()
498 + }
499 + if fi, err := strconv.Atoi(d.Val()); err == nil {
500 + h.FlushInterval = caddy.Duration(fi)
501 + } else {
502 dur, err := caddy.ParseDuration(d.Val())
503 if err != nil {
504 return d.Errf("bad duration value '%s': %v", d.Val(), err)
505 }
493 - h.HealthChecks.Passive.UnhealthyLatency = caddy.Duration(dur)
506 + h.FlushInterval = caddy.Duration(dur)
507 + }
508
495 - case "flush_interval":
496 - if !d.NextArg() {
497 - return d.ArgErr()
498 - }
499 - if fi, err := strconv.Atoi(d.Val()); err == nil {
500 - h.FlushInterval = caddy.Duration(fi)
501 - } else {
502 - dur, err := caddy.ParseDuration(d.Val())
503 - if err != nil {
504 - return d.Errf("bad duration value '%s': %v", d.Val(), err)
505 - }
506 - h.FlushInterval = caddy.Duration(dur)
507 - }
509 + case "request_buffers", "response_buffers":
510 + subdir := d.Val()
511 + if !d.NextArg() {
512 + return d.ArgErr()
513 + }
514 + size, err := humanize.ParseBytes(d.Val())
515 + if err != nil {
516 + return d.Errf("invalid byte size '%s': %v", d.Val(), err)
517 + }
518 + if d.NextArg() {
519 + return d.ArgErr()
520 + }
521 + if subdir == "request_buffers" {
522 + h.RequestBuffers = int64(size)
523 + } else if subdir == "response_buffers" {
524 + h.ResponseBuffers = int64(size)
525
509 - case "request_buffers", "response_buffers":
510 - subdir := d.Val()
511 - if !d.NextArg() {
512 - return d.ArgErr()
513 - }
514 - size, err := humanize.ParseBytes(d.Val())
515 - if err != nil {
516 - return d.Errf("invalid byte size '%s': %v", d.Val(), err)
517 - }
518 - if d.NextArg() {
519 - return d.ArgErr()
520 - }
521 - if subdir == "request_buffers" {
522 - h.RequestBuffers = int64(size)
523 - } else if subdir == "response_buffers" {
524 - h.ResponseBuffers = int64(size)
526 + }
527
526 - }
528 + // TODO: These three properties are deprecated; remove them sometime after v2.6.4
529 + case "buffer_requests": // TODO: deprecated
530 + if d.NextArg() {
531 + return d.ArgErr()
532 + }
533 + caddy.Log().Named("config.adapter.caddyfile").Warn("DEPRECATED: buffer_requests: use request_buffers instead (with a maximum buffer size)")
534 + h.DeprecatedBufferRequests = true
535 + case "buffer_responses": // TODO: deprecated
536 + if d.NextArg() {
537 + return d.ArgErr()
538 + }
539 + caddy.Log().Named("config.adapter.caddyfile").Warn("DEPRECATED: buffer_responses: use response_buffers instead (with a maximum buffer size)")
540 + h.DeprecatedBufferResponses = true
541 + case "max_buffer_size": // TODO: deprecated
542 + if !d.NextArg() {
543 + return d.ArgErr()
544 + }
545 + size, err := humanize.ParseBytes(d.Val())
546 + if err != nil {
547 + return d.Errf("invalid byte size '%s': %v", d.Val(), err)
548 + }
549 + if d.NextArg() {
550 + return d.ArgErr()
551 + }
552 + caddy.Log().Named("config.adapter.caddyfile").Warn("DEPRECATED: max_buffer_size: use request_buffers and/or response_buffers instead (with maximum buffer sizes)")
553 + h.DeprecatedMaxBufferSize = int64(size)
554
528 - // TODO: These three properties are deprecated; remove them sometime after v2.6.4
529 - case "buffer_requests": // TODO: deprecated
530 - if d.NextArg() {
531 - return d.ArgErr()
555 + case "trusted_proxies":
556 + for d.NextArg() {
557 + if d.Val() == "private_ranges" {
558 + h.TrustedProxies = append(h.TrustedProxies, caddyhttp.PrivateRangesCIDR()...)
559 + continue
560 }
533 - caddy.Log().Named("config.adapter.caddyfile").Warn("DEPRECATED: buffer_requests: use request_buffers instead (with a maximum buffer size)")
534 - h.DeprecatedBufferRequests = true
535 - case "buffer_responses": // TODO: deprecated
536 - if d.NextArg() {
537 - return d.ArgErr()
538 - }
539 - caddy.Log().Named("config.adapter.caddyfile").Warn("DEPRECATED: buffer_responses: use response_buffers instead (with a maximum buffer size)")
540 - h.DeprecatedBufferResponses = true
541 - case "max_buffer_size": // TODO: deprecated
542 - if !d.NextArg() {
543 - return d.ArgErr()
544 - }
545 - size, err := humanize.ParseBytes(d.Val())
546 - if err != nil {
547 - return d.Errf("invalid byte size '%s': %v", d.Val(), err)
548 - }
549 - if d.NextArg() {
550 - return d.ArgErr()
551 - }
552 - caddy.Log().Named("config.adapter.caddyfile").Warn("DEPRECATED: max_buffer_size: use request_buffers and/or response_buffers instead (with maximum buffer sizes)")
553 - h.DeprecatedMaxBufferSize = int64(size)
561 + h.TrustedProxies = append(h.TrustedProxies, d.Val())
562 + }
563
555 - case "trusted_proxies":
556 - for d.NextArg() {
557 - if d.Val() == "private_ranges" {
558 - h.TrustedProxies = append(h.TrustedProxies, caddyhttp.PrivateRangesCIDR()...)
559 - continue
560 - }
561 - h.TrustedProxies = append(h.TrustedProxies, d.Val())
562 - }
564 + case "header_up":
565 + var err error
566
564 - case "header_up":
565 - var err error
567 + if h.Headers == nil {
568 + h.Headers = new(headers.Handler)
569 + }
570 + if h.Headers.Request == nil {
571 + h.Headers.Request = new(headers.HeaderOps)
572 + }
573 + args := d.RemainingArgs()
574
567 - if h.Headers == nil {
568 - h.Headers = new(headers.Handler)
575 + switch len(args) {
576 + case 1:
577 + err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], "", "")
578 + case 2:
579 + // some lint checks, I guess
580 + if strings.EqualFold(args[0], "host") && (args[1] == "{hostport}" || args[1] == "{http.request.hostport}") {
581 + caddy.Log().Named("caddyfile").Warn("Unnecessary header_up Host: the reverse proxy's default behavior is to pass headers to the upstream")
582 }
570 - if h.Headers.Request == nil {
571 - h.Headers.Request = new(headers.HeaderOps)
583 + if strings.EqualFold(args[0], "x-forwarded-for") && (args[1] == "{remote}" || args[1] == "{http.request.remote}" || args[1] == "{remote_host}" || args[1] == "{http.request.remote.host}") {
584 + caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-For: the reverse proxy's default behavior is to pass headers to the upstream")
585 }
573 - args := d.RemainingArgs()
574 -
575 - switch len(args) {
576 - case 1:
577 - err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], "", "")
578 - case 2:
579 - // some lint checks, I guess
580 - if strings.EqualFold(args[0], "host") && (args[1] == "{hostport}" || args[1] == "{http.request.hostport}") {
581 - caddy.Log().Named("caddyfile").Warn("Unnecessary header_up Host: the reverse proxy's default behavior is to pass headers to the upstream")
582 - }
583 - if strings.EqualFold(args[0], "x-forwarded-for") && (args[1] == "{remote}" || args[1] == "{http.request.remote}" || args[1] == "{remote_host}" || args[1] == "{http.request.remote.host}") {
584 - caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-For: the reverse proxy's default behavior is to pass headers to the upstream")
585 - }
586 - if strings.EqualFold(args[0], "x-forwarded-proto") && (args[1] == "{scheme}" || args[1] == "{http.request.scheme}") {
587 - caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-Proto: the reverse proxy's default behavior is to pass headers to the upstream")
588 - }
589 - if strings.EqualFold(args[0], "x-forwarded-host") && (args[1] == "{host}" || args[1] == "{http.request.host}" || args[1] == "{hostport}" || args[1] == "{http.request.hostport}") {
590 - caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-Host: the reverse proxy's default behavior is to pass headers to the upstream")
591 - }
592 - err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], "")
593 - case 3:
594 - err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], args[2])
595 - default:
596 - return d.ArgErr()
586 + if strings.EqualFold(args[0], "x-forwarded-proto") && (args[1] == "{scheme}" || args[1] == "{http.request.scheme}") {
587 + caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-Proto: the reverse proxy's default behavior is to pass headers to the upstream")
588 }
598 -
599 - if err != nil {
600 - return d.Err(err.Error())
589 + if strings.EqualFold(args[0], "x-forwarded-host") && (args[1] == "{host}" || args[1] == "{http.request.host}" || args[1] == "{hostport}" || args[1] == "{http.request.hostport}") {
590 + caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-Host: the reverse proxy's default behavior is to pass headers to the upstream")
591 }
592 + err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], "")
593 + case 3:
594 + err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], args[2])
595 + default:
596 + return d.ArgErr()
597 + }
598
603 - case "header_down":
604 - var err error
605 -
606 - if h.Headers == nil {
607 - h.Headers = new(headers.Handler)
608 - }
609 - if h.Headers.Response == nil {
610 - h.Headers.Response = &headers.RespHeaderOps{
611 - HeaderOps: new(headers.HeaderOps),
612 - }
613 - }
614 - args := d.RemainingArgs()
615 - switch len(args) {
616 - case 1:
617 - err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], "", "")
618 - case 2:
619 - err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], "")
620 - case 3:
621 - err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], args[2])
622 - default:
623 - return d.ArgErr()
624 - }
599 + if err != nil {
600 + return d.Err(err.Error())
601 + }
602
626 - if err != nil {
627 - return d.Err(err.Error())
628 - }
603 + case "header_down":
604 + var err error
605
630 - case "method":
631 - if !d.NextArg() {
632 - return d.ArgErr()
633 - }
634 - if h.Rewrite == nil {
635 - h.Rewrite = &rewrite.Rewrite{}
636 - }
637 - h.Rewrite.Method = d.Val()
638 - if d.NextArg() {
639 - return d.ArgErr()
606 + if h.Headers == nil {
607 + h.Headers = new(headers.Handler)
608 + }
609 + if h.Headers.Response == nil {
610 + h.Headers.Response = &headers.RespHeaderOps{
611 + HeaderOps: new(headers.HeaderOps),
612 }
613 + }
614 + args := d.RemainingArgs()
615 + switch len(args) {
616 + case 1:
617 + err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], "", "")
618 + case 2:
619 + err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], "")
620 + case 3:
621 + err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], args[2])
622 + default:
623 + return d.ArgErr()
624 + }
625
642 - case "rewrite":
643 - if !d.NextArg() {
644 - return d.ArgErr()
645 - }
646 - if h.Rewrite == nil {
647 - h.Rewrite = &rewrite.Rewrite{}
648 - }
649 - h.Rewrite.URI = d.Val()
650 - if d.NextArg() {
651 - return d.ArgErr()
652 - }
626 + if err != nil {
627 + return d.Err(err.Error())
628 + }
629
654 - case "transport":
655 - if !d.NextArg() {
656 - return d.ArgErr()
657 - }
658 - if h.TransportRaw != nil {
659 - return d.Err("transport already specified")
660 - }
661 - transportModuleName = d.Val()
662 - modID := "http.reverse_proxy.transport." + transportModuleName
663 - unm, err := caddyfile.UnmarshalModule(d, modID)
664 - if err != nil {
665 - return err
666 - }
667 - rt, ok := unm.(http.RoundTripper)
668 - if !ok {
669 - return d.Errf("module %s (%T) is not a RoundTripper", modID, unm)
670 - }
671 - transport = rt
630 + case "method":
631 + if !d.NextArg() {
632 + return d.ArgErr()
633 + }
634 + if h.Rewrite == nil {
635 + h.Rewrite = &rewrite.Rewrite{}
636 + }
637 + h.Rewrite.Method = d.Val()
638 + if d.NextArg() {
639 + return d.ArgErr()
640 + }
641
673 - case "handle_response":
674 - // delegate the parsing of handle_response to the caller,
675 - // since we need the httpcaddyfile.Helper to parse subroutes.
676 - // See h.FinalizeUnmarshalCaddyfile
677 - h.handleResponseSegments = append(h.handleResponseSegments, d.NewFromNextSegment())
642 + case "rewrite":
643 + if !d.NextArg() {
644 + return d.ArgErr()
645 + }
646 + if h.Rewrite == nil {
647 + h.Rewrite = &rewrite.Rewrite{}
648 + }
649 + h.Rewrite.URI = d.Val()
650 + if d.NextArg() {
651 + return d.ArgErr()
652 + }
653
679 - case "replace_status":
680 - args := d.RemainingArgs()
681 - if len(args) != 1 && len(args) != 2 {
682 - return d.Errf("must have one or two arguments: an optional response matcher, and a status code")
683 - }
654 + case "transport":
655 + if !d.NextArg() {
656 + return d.ArgErr()
657 + }
658 + if h.TransportRaw != nil {
659 + return d.Err("transport already specified")
660 + }
661 + transportModuleName = d.Val()
662 + modID := "http.reverse_proxy.transport." + transportModuleName
663 + unm, err := caddyfile.UnmarshalModule(d, modID)
664 + if err != nil {
665 + return err
666 + }
667 + rt, ok := unm.(http.RoundTripper)
668 + if !ok {
669 + return d.Errf("module %s (%T) is not a RoundTripper", modID, unm)
670 + }
671 + transport = rt
672 +
673 + case "handle_response":
674 + // delegate the parsing of handle_response to the caller,
675 + // since we need the httpcaddyfile.Helper to parse subroutes.
676 + // See h.FinalizeUnmarshalCaddyfile
677 + h.handleResponseSegments = append(h.handleResponseSegments, d.NewFromNextSegment())
678 +
679 + case "replace_status":
680 + args := d.RemainingArgs()
681 + if len(args) != 1 && len(args) != 2 {
682 + return d.Errf("must have one or two arguments: an optional response matcher, and a status code")
683 + }
684
685 - responseHandler := caddyhttp.ResponseHandler{}
685 + responseHandler := caddyhttp.ResponseHandler{}
686
687 - if len(args) == 2 {
688 - if !strings.HasPrefix(args[0], matcherPrefix) {
689 - return d.Errf("must use a named response matcher, starting with '@'")
690 - }
691 - foundMatcher, ok := h.responseMatchers[args[0]]
692 - if !ok {
693 - return d.Errf("no named response matcher defined with name '%s'", args[0][1:])
694 - }
695 - responseHandler.Match = &foundMatcher
696 - responseHandler.StatusCode = caddyhttp.WeakString(args[1])
697 - } else if len(args) == 1 {
698 - responseHandler.StatusCode = caddyhttp.WeakString(args[0])
687 + if len(args) == 2 {
688 + if !strings.HasPrefix(args[0], matcherPrefix) {
689 + return d.Errf("must use a named response matcher, starting with '@'")
690 }
700 -
701 - // make sure there's no block, cause it doesn't make sense
702 - if d.NextBlock(1) {
703 - return d.Errf("cannot define routes for 'replace_status', use 'handle_response' instead.")
691 + foundMatcher, ok := h.responseMatchers[args[0]]
692 + if !ok {
693 + return d.Errf("no named response matcher defined with name '%s'", args[0][1:])
694 }
695 + responseHandler.Match = &foundMatcher
696 + responseHandler.StatusCode = caddyhttp.WeakString(args[1])
697 + } else if len(args) == 1 {
698 + responseHandler.StatusCode = caddyhttp.WeakString(args[0])
699 + }
700
706 - h.HandleResponse = append(
707 - h.HandleResponse,
708 - responseHandler,
709 - )
710 -
711 - default:
712 - return d.Errf("unrecognized subdirective %s", d.Val())
701 + // make sure there's no block, cause it doesn't make sense
702 + if d.NextBlock(1) {
703 + return d.Errf("cannot define routes for 'replace_status', use 'handle_response' instead.")
704 }
705 +
706 + h.HandleResponse = append(
707 + h.HandleResponse,
708 + responseHandler,
709 + )
710 +
711 + default:
712 + return d.Errf("unrecognized subdirective %s", d.Val())
713 }
714 }
715
modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+1
@@ -373,6 +373,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
373
374 // the rest of the config is specified by the user
375 // using the reverse_proxy directive syntax
376 + dispenser.Next() // consume the directive name
377 err = rpHandler.UnmarshalCaddyfile(dispenser)
378 if err != nil {
379 return nil, err
modules/caddyhttp/reverseproxy/forwardauth/caddyfile.go
+1
@@ -216,6 +216,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
216
217 // the rest of the config is specified by the user
218 // using the reverse_proxy directive syntax
219 + dispenser.Next() // consume the directive name
220 err = rpHandler.UnmarshalCaddyfile(dispenser)
221 if err != nil {
222 return nil, err