Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
reverseproxy: Fix host and port on requests; fix Caddyfile parser
Matthew Holt committed
Sep 11, 2019 at 18:53 UTC
758269124ef5d6d83cb4e8d8eeb095f5b025250e
2 files changed
+128
-94
modules/caddyhttp/reverseproxy/caddyfile.go
+95
-93
@@ -376,108 +376,110 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
376
// }
377
//
378
func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
379
- for d.NextBlock(0) {
380
- switch d.Val() {
381
- case "read_buffer":
382
- if !d.NextArg() {
383
- return d.ArgErr()
384
- }
385
- size, err := humanize.ParseBytes(d.Val())
386
- if err != nil {
387
- return d.Errf("invalid read buffer size '%s': %v", d.Val(), err)
388
- }
389
- h.ReadBufferSize = int(size)
379
+ for d.Next() {
380
+ for d.NextBlock(0) {
381
+ switch d.Val() {
382
+ case "read_buffer":
383
+ if !d.NextArg() {
384
+ return d.ArgErr()
385
+ }
386
+ size, err := humanize.ParseBytes(d.Val())
387
+ if err != nil {
388
+ return d.Errf("invalid read buffer size '%s': %v", d.Val(), err)
389
+ }
390
+ h.ReadBufferSize = int(size)
391
391
- case "write_buffer":
392
- if !d.NextArg() {
393
- return d.ArgErr()
394
- }
395
- size, err := humanize.ParseBytes(d.Val())
396
- if err != nil {
397
- return d.Errf("invalid write buffer size '%s': %v", d.Val(), err)
398
- }
399
- h.WriteBufferSize = int(size)
392
+ case "write_buffer":
393
+ if !d.NextArg() {
394
+ return d.ArgErr()
395
+ }
396
+ size, err := humanize.ParseBytes(d.Val())
397
+ if err != nil {
398
+ return d.Errf("invalid write buffer size '%s': %v", d.Val(), err)
399
+ }
400
+ h.WriteBufferSize = int(size)
401
401
- case "dial_timeout":
402
- if !d.NextArg() {
403
- return d.ArgErr()
404
- }
405
- dur, err := time.ParseDuration(d.Val())
406
- if err != nil {
407
- return d.Errf("bad timeout value '%s': %v", d.Val(), err)
408
- }
409
- h.DialTimeout = caddy.Duration(dur)
402
+ case "dial_timeout":
403
+ if !d.NextArg() {
404
+ return d.ArgErr()
405
+ }
406
+ dur, err := time.ParseDuration(d.Val())
407
+ if err != nil {
408
+ return d.Errf("bad timeout value '%s': %v", d.Val(), err)
409
+ }
410
+ h.DialTimeout = caddy.Duration(dur)
411
411
- case "tls_client_auth":
412
- args := d.RemainingArgs()
413
- if len(args) != 2 {
414
- return d.ArgErr()
415
- }
416
- if h.TLS == nil {
417
- h.TLS = new(TLSConfig)
418
- }
419
- h.TLS.ClientCertificateFile = args[0]
420
- h.TLS.ClientCertificateKeyFile = args[1]
412
+ case "tls_client_auth":
413
+ args := d.RemainingArgs()
414
+ if len(args) != 2 {
415
+ return d.ArgErr()
416
+ }
417
+ if h.TLS == nil {
418
+ h.TLS = new(TLSConfig)
419
+ }
420
+ h.TLS.ClientCertificateFile = args[0]
421
+ h.TLS.ClientCertificateKeyFile = args[1]
422
422
- case "tls":
423
- if h.TLS == nil {
424
- h.TLS = new(TLSConfig)
425
- }
423
+ case "tls":
424
+ if h.TLS == nil {
425
+ h.TLS = new(TLSConfig)
426
+ }
427
427
- case "tls_insecure_skip_verify":
428
- if d.NextArg() {
429
- return d.ArgErr()
430
- }
431
- if h.TLS == nil {
432
- h.TLS = new(TLSConfig)
433
- }
434
- h.TLS.InsecureSkipVerify = true
428
+ case "tls_insecure_skip_verify":
429
+ if d.NextArg() {
430
+ return d.ArgErr()
431
+ }
432
+ if h.TLS == nil {
433
+ h.TLS = new(TLSConfig)
434
+ }
435
+ h.TLS.InsecureSkipVerify = true
436
436
- case "tls_timeout":
437
- if !d.NextArg() {
438
- return d.ArgErr()
439
- }
440
- dur, err := time.ParseDuration(d.Val())
441
- if err != nil {
442
- return d.Errf("bad timeout value '%s': %v", d.Val(), err)
443
- }
444
- if h.TLS == nil {
445
- h.TLS = new(TLSConfig)
446
- }
447
- h.TLS.HandshakeTimeout = caddy.Duration(dur)
437
+ case "tls_timeout":
438
+ if !d.NextArg() {
439
+ return d.ArgErr()
440
+ }
441
+ dur, err := time.ParseDuration(d.Val())
442
+ if err != nil {
443
+ return d.Errf("bad timeout value '%s': %v", d.Val(), err)
444
+ }
445
+ if h.TLS == nil {
446
+ h.TLS = new(TLSConfig)
447
+ }
448
+ h.TLS.HandshakeTimeout = caddy.Duration(dur)
449
449
- case "keepalive":
450
- if !d.NextArg() {
451
- return d.ArgErr()
452
- }
453
- if h.KeepAlive == nil {
454
- h.KeepAlive = new(KeepAlive)
455
- }
456
- if d.Val() == "off" {
457
- var disable bool
458
- h.KeepAlive.Enabled = &disable
459
- }
460
- dur, err := time.ParseDuration(d.Val())
461
- if err != nil {
462
- return d.Errf("bad duration value '%s': %v", d.Val(), err)
463
- }
464
- h.KeepAlive.IdleConnTimeout = caddy.Duration(dur)
450
+ case "keepalive":
451
+ if !d.NextArg() {
452
+ return d.ArgErr()
453
+ }
454
+ if h.KeepAlive == nil {
455
+ h.KeepAlive = new(KeepAlive)
456
+ }
457
+ if d.Val() == "off" {
458
+ var disable bool
459
+ h.KeepAlive.Enabled = &disable
460
+ }
461
+ dur, err := time.ParseDuration(d.Val())
462
+ if err != nil {
463
+ return d.Errf("bad duration value '%s': %v", d.Val(), err)
464
+ }
465
+ h.KeepAlive.IdleConnTimeout = caddy.Duration(dur)
466
466
- case "keepalive_idle_conns":
467
- if !d.NextArg() {
468
- return d.ArgErr()
469
- }
470
- num, err := strconv.Atoi(d.Val())
471
- if err != nil {
472
- return d.Errf("bad integer value '%s': %v", d.Val(), err)
473
- }
474
- if h.KeepAlive == nil {
475
- h.KeepAlive = new(KeepAlive)
476
- }
477
- h.KeepAlive.MaxIdleConns = num
467
+ case "keepalive_idle_conns":
468
+ if !d.NextArg() {
469
+ return d.ArgErr()
470
+ }
471
+ num, err := strconv.Atoi(d.Val())
472
+ if err != nil {
473
+ return d.Errf("bad integer value '%s': %v", d.Val(), err)
474
+ }
475
+ if h.KeepAlive == nil {
476
+ h.KeepAlive = new(KeepAlive)
477
+ }
478
+ h.KeepAlive.MaxIdleConns = num
479
479
- default:
480
- return d.Errf("unrecognized subdirective %s", d.Val())
480
+ default:
481
+ return d.Errf("unrecognized subdirective %s", d.Val())
482
+ }
483
}
484
}
485
return nil
modules/caddyhttp/reverseproxy/reverseproxy.go
+33
-1
@@ -145,6 +145,26 @@ func (h *Handler) Provision(ctx caddy.Context) error {
145
146
var allUpstreams []*Upstream
147
for _, upstream := range h.Upstreams {
148
+ // if a port was not specified (and the network type uses
149
+ // ports), then maybe we can figure out the default port
150
+ netw, host, port, err := caddy.SplitNetworkAddress(upstream.Dial)
151
+ if err != nil && port == "" && !strings.Contains(netw, "unix") {
152
+ if host == "" {
153
+ // assume all that was given was the host, no port
154
+ host = upstream.Dial
155
+ }
156
+ // a port was not specified, but we may be able to
157
+ // infer it if we know the standard ports on which
158
+ // the transport protocol operates
159
+ if ht, ok := h.Transport.(*HTTPTransport); ok {
160
+ defaultPort := "80"
161
+ if ht.TLS != nil {
162
+ defaultPort = "443"
163
+ }
164
+ upstream.Dial = caddy.JoinNetworkAddress(netw, host, defaultPort)
165
+ }
166
+ }
167
+
168
// upstreams are allowed to map to only a single host,
169
// but an upstream's address may semantically represent
170
// multiple addresses, so make sure to handle each
@@ -474,7 +494,19 @@ func (h Handler) tryAgain(start time.Time, proxyErr error) bool {
494
// given upstream host. It must modify ONLY the request URL.
495
func (h Handler) directRequest(req *http.Request, upstream *Upstream) {
496
if req.URL.Host == "" {
477
- req.URL.Host = upstream.dialInfo.Address
497
+ // we need a host, so set the upstream's host address
498
+ fullHost := upstream.dialInfo.Address
499
+
500
+ // but if the port matches the scheme, strip the port because
501
+ // it's weird to make a request like http://example.com:80/.
502
+ host, port, err := net.SplitHostPort(fullHost)
503
+ if err == nil &&
504
+ (req.URL.Scheme == "http" && port == "80") ||
505
+ (req.URL.Scheme == "https" && port == "443") {
506
+ fullHost = host
507
+ }
508
+
509
+ req.URL.Host = fullHost
510
}
511
}
512