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