diff --git a/caddyhttp/proxy/proxy.go b/caddyhttp/proxy/proxy.go index c4cd1960..68810c05 100644 --- a/caddyhttp/proxy/proxy.go +++ b/caddyhttp/proxy/proxy.go @@ -30,6 +30,8 @@ type Upstream interface { Select() *UpstreamHost // Checks if subpath is not an ignored path AllowedPath(string) bool + // Is Upstream in transparent mode? + Transparent() bool } // UpstreamHostDownFunc can be used to customize how Down behaves. @@ -94,6 +96,7 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { start := time.Now() for time.Now().Sub(start) < tryDuration { host := upstream.Select() + if host == nil { return http.StatusBadGateway, errUnreachable } @@ -125,6 +128,9 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { if v, ok := host.UpstreamHeaders["Host"]; ok { outreq.Host = replacer.Replace(v[len(v)-1]) } + if upstream.Transparent() { + host.UpstreamHeaders.Set("Host", host.Name) + } // modify headers for request that will be sent to the upstream host upHeaders := createHeadersByRules(host.UpstreamHeaders, r.Header, replacer) for k, v := range upHeaders { diff --git a/caddyhttp/proxy/proxy_test.go b/caddyhttp/proxy/proxy_test.go index 62c4118c..e13a3d46 100644 --- a/caddyhttp/proxy/proxy_test.go +++ b/caddyhttp/proxy/proxy_test.go @@ -687,6 +687,10 @@ func (u *fakeUpstream) AllowedPath(requestPath string) bool { return true } +func (u *fakeUpstream) Transparent() bool { + return true +} + // newWebSocketTestProxy returns a test proxy that will // redirect to the specified backendAddr. The function // also sets up the rules/environment for testing WebSocket @@ -729,6 +733,10 @@ func (u *fakeWsUpstream) AllowedPath(requestPath string) bool { return true } +func (u *fakeWsUpstream) Transparent() bool { + return true +} + // recorderHijacker is a ResponseRecorder that can // be hijacked. type recorderHijacker struct { diff --git a/caddyhttp/proxy/upstream.go b/caddyhttp/proxy/upstream.go index 64f8c551..67ca0957 100644 --- a/caddyhttp/proxy/upstream.go +++ b/caddyhttp/proxy/upstream.go @@ -26,6 +26,7 @@ type staticUpstream struct { Hosts HostPool Policy Policy insecureSkipVerify bool + transparent bool FailTimeout time.Duration MaxFails int32 @@ -54,6 +55,7 @@ func NewStaticUpstreams(c caddyfile.Dispenser) ([]Upstream, error) { FailTimeout: 10 * time.Second, MaxFails: 1, MaxConns: 0, + transparent: false, } if !c.Args(&upstream.from) { @@ -287,7 +289,7 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream) error { } u.downstreamHeaders.Add(header, value) case "transparent": - u.upstreamHeaders.Add("Host", "{host}") + u.transparent = true u.upstreamHeaders.Add("X-Real-IP", "{remote}") u.upstreamHeaders.Add("X-Forwarded-For", "{remote}") u.upstreamHeaders.Add("X-Forwarded-Proto", "{scheme}") @@ -366,6 +368,11 @@ func (u *staticUpstream) Select() *UpstreamHost { return u.Policy.Select(pool) } +// Transparent returns true if upstream in transparent mode +func (u *staticUpstream) Transparent() bool { + return u.transparent +} + func (u *staticUpstream) AllowedPath(requestPath string) bool { for _, ignoredSubPath := range u.IgnoredSubPaths { if httpserver.Path(path.Clean(requestPath)).Matches(path.Join(u.From(), ignoredSubPath)) { diff --git a/caddyhttp/proxy/upstream_test.go b/caddyhttp/proxy/upstream_test.go index 4fb990f6..5431962e 100644 --- a/caddyhttp/proxy/upstream_test.go +++ b/caddyhttp/proxy/upstream_test.go @@ -209,8 +209,8 @@ func TestParseBlock(t *testing.T) { for _, upstream := range upstreams { headers := upstream.Select().UpstreamHeaders - if _, ok := headers["Host"]; !ok { - t.Errorf("Test %d: Could not find the Host header", i+1) + if !upstream.Transparent() { + t.Errorf("Test %d: Upstream should be in transparent mode", i+1) } if _, ok := headers["X-Real-Ip"]; !ok {