diff options
Diffstat (limited to 'modules/caddyhttp/reverseproxy')
| -rw-r--r-- | modules/caddyhttp/reverseproxy/addresses.go | 41 | ||||
| -rw-r--r-- | modules/caddyhttp/reverseproxy/addresses_test.go | 38 | ||||
| -rw-r--r-- | modules/caddyhttp/reverseproxy/caddyfile.go | 21 | ||||
| -rw-r--r-- | modules/caddyhttp/reverseproxy/command.go | 21 | 
4 files changed, 106 insertions, 15 deletions
diff --git a/modules/caddyhttp/reverseproxy/addresses.go b/modules/caddyhttp/reverseproxy/addresses.go index 8152108..6078f11 100644 --- a/modules/caddyhttp/reverseproxy/addresses.go +++ b/modules/caddyhttp/reverseproxy/addresses.go @@ -40,7 +40,29 @@ func parseUpstreamDialAddress(upstreamAddr string) (string, string, error) {  		toURL, err := url.Parse(upstreamAddr)  		if err != nil { -			return "", "", fmt.Errorf("parsing upstream URL: %v", err) +			// if the error seems to be due to a port range, +			// try to replace the port range with a dummy +			// single port so that url.Parse() will succeed +			if strings.Contains(err.Error(), "invalid port") && strings.Contains(err.Error(), "-") { +				index := strings.LastIndex(upstreamAddr, ":") +				if index == -1 { +					return "", "", fmt.Errorf("parsing upstream URL: %v", err) +				} +				portRange := upstreamAddr[index+1:] +				if strings.Count(portRange, "-") != 1 { +					return "", "", fmt.Errorf("parsing upstream URL: parse \"%v\": port range invalid: %v", upstreamAddr, portRange) +				} +				toURL, err = url.Parse(strings.ReplaceAll(upstreamAddr, portRange, "0")) +				if err != nil { +					return "", "", fmt.Errorf("parsing upstream URL: %v", err) +				} +				port = portRange +			} else { +				return "", "", fmt.Errorf("parsing upstream URL: %v", err) +			} +		} +		if port == "" { +			port = toURL.Port()  		}  		// there is currently no way to perform a URL rewrite between choosing @@ -51,30 +73,27 @@ func parseUpstreamDialAddress(upstreamAddr string) (string, string, error) {  		}  		// ensure the port and scheme aren't in conflict -		urlPort := toURL.Port() -		if toURL.Scheme == "http" && urlPort == "443" { +		if toURL.Scheme == "http" && port == "443" {  			return "", "", fmt.Errorf("upstream address has conflicting scheme (http://) and port (:443, the HTTPS port)")  		} -		if toURL.Scheme == "https" && urlPort == "80" { +		if toURL.Scheme == "https" && port == "80" {  			return "", "", fmt.Errorf("upstream address has conflicting scheme (https://) and port (:80, the HTTP port)")  		} -		if toURL.Scheme == "h2c" && urlPort == "443" { +		if toURL.Scheme == "h2c" && port == "443" {  			return "", "", fmt.Errorf("upstream address has conflicting scheme (h2c://) and port (:443, the HTTPS port)")  		}  		// if port is missing, attempt to infer from scheme -		if toURL.Port() == "" { -			var toPort string +		if port == "" {  			switch toURL.Scheme {  			case "", "http", "h2c": -				toPort = "80" +				port = "80"  			case "https": -				toPort = "443" +				port = "443"  			} -			toURL.Host = net.JoinHostPort(toURL.Hostname(), toPort)  		} -		scheme, host, port = toURL.Scheme, toURL.Hostname(), toURL.Port() +		scheme, host = toURL.Scheme, toURL.Hostname()  	} else {  		var err error  		network, host, port, err = caddy.SplitNetworkAddress(upstreamAddr) diff --git a/modules/caddyhttp/reverseproxy/addresses_test.go b/modules/caddyhttp/reverseproxy/addresses_test.go index 6355c75..0c7ad7b 100644 --- a/modules/caddyhttp/reverseproxy/addresses_test.go +++ b/modules/caddyhttp/reverseproxy/addresses_test.go @@ -150,6 +150,24 @@ func TestParseUpstreamDialAddress(t *testing.T) {  			expectScheme:   "h2c",  		},  		{ +			input:          "localhost:1001-1009", +			expectHostPort: "localhost:1001-1009", +		}, +		{ +			input:          "{host}:1001-1009", +			expectHostPort: "{host}:1001-1009", +		}, +		{ +			input:          "http://localhost:1001-1009", +			expectHostPort: "localhost:1001-1009", +			expectScheme:   "http", +		}, +		{ +			input:          "https://localhost:1001-1009", +			expectHostPort: "localhost:1001-1009", +			expectScheme:   "https", +		}, +		{  			input:          "unix//var/php.sock",  			expectHostPort: "unix//var/php.sock",  		}, @@ -197,6 +215,26 @@ func TestParseUpstreamDialAddress(t *testing.T) {  			expectErr: true,  		},  		{ +			input:     "http://localhost:8001-8002-8003", +			expectErr: true, +		}, +		{ +			input:     "http://localhost:8001-8002/foo:bar", +			expectErr: true, +		}, +		{ +			input:     "http://localhost:8001-8002/foo:1", +			expectErr: true, +		}, +		{ +			input:     "http://localhost:8001-8002/foo:1-2", +			expectErr: true, +		}, +		{ +			input:     "http://localhost:8001-8002#foo:1", +			expectErr: true, +		}, +		{  			input:     "http://foo:443",  			expectErr: true,  		}, diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go index 728bc2f..a79bd09 100644 --- a/modules/caddyhttp/reverseproxy/caddyfile.go +++ b/modules/caddyhttp/reverseproxy/caddyfile.go @@ -15,6 +15,7 @@  package reverseproxy  import ( +	"fmt"  	"net/http"  	"reflect"  	"strconv" @@ -157,7 +158,25 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {  		}  		commonScheme = scheme -		h.Upstreams = append(h.Upstreams, &Upstream{Dial: dialAddr}) +		parsedAddr, err := caddy.ParseNetworkAddress(dialAddr) +		if err != nil { +			return d.WrapErr(err) +		} + +		if parsedAddr.StartPort == 0 && parsedAddr.EndPort == 0 { +			// unix networks don't have ports +			h.Upstreams = append(h.Upstreams, &Upstream{ +				Dial: dialAddr, +			}) +		} else { +			// expand a port range into multiple upstreams +			for i := parsedAddr.StartPort; i <= parsedAddr.EndPort; i++ { +				h.Upstreams = append(h.Upstreams, &Upstream{ +					Dial: caddy.JoinNetworkAddress("", parsedAddr.Host, fmt.Sprint(i)), +				}) +			} +		} +  		return nil  	} diff --git a/modules/caddyhttp/reverseproxy/command.go b/modules/caddyhttp/reverseproxy/command.go index bd3efcd..48fabd5 100644 --- a/modules/caddyhttp/reverseproxy/command.go +++ b/modules/caddyhttp/reverseproxy/command.go @@ -153,9 +153,24 @@ func cmdReverseProxy(fs caddycmd.Flags) (int, error) {  	upstreamPool := UpstreamPool{}  	for _, toAddr := range toAddresses { -		upstreamPool = append(upstreamPool, &Upstream{ -			Dial: toAddr, -		}) +		parsedAddr, err := caddy.ParseNetworkAddress(toAddr) +		if err != nil { +			return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid upstream address %s: %v", toAddr, err) +		} + +		if parsedAddr.StartPort == 0 && parsedAddr.EndPort == 0 { +			// unix networks don't have ports +			upstreamPool = append(upstreamPool, &Upstream{ +				Dial: toAddr, +			}) +		} else { +			// expand a port range into multiple upstreams +			for i := parsedAddr.StartPort; i <= parsedAddr.EndPort; i++ { +				upstreamPool = append(upstreamPool, &Upstream{ +					Dial: caddy.JoinNetworkAddress("", parsedAddr.Host, fmt.Sprint(i)), +				}) +			} +		}  	}  	handler := Handler{  | 
