diff --git a/docs/07.Reference/7.02.Filters.md b/docs/07.Reference/7.02.Filters.md index 17627e37f0..c4467d662e 100644 --- a/docs/07.Reference/7.02.Filters.md +++ b/docs/07.Reference/7.02.Filters.md @@ -3,6 +3,7 @@ - [Proxy](#proxy) - [Health Check](#health-check) + - [Request Host](#request-host) - [Configuration](#configuration) - [Results](#results) - [SimpleHTTPProxy](#simplehttpproxy) @@ -248,6 +249,38 @@ pools: type: contains ``` +### Request Host + +By default, if the client's request host is `example.com` and the pools.servers.url is IP-based, Easegress will forward the request to the backend with the host `example.com`. However, if `pools.servers.url` is a domain, such as `http://demo.com:9090`, Easegress will automatically update the request's host to `demo.com:9090` before sending it to the backend. To prevent this and retain the original client request host, use the `keepHost` option as shown below: + +```yaml +kind: Proxy +name: proxy-example-3 +pools: +- servers: + - url: http://demo.com:9090 + keepHost: true + loadBalance: + policy: roundRobin +maxRedirection: 10 +``` + +Conversely, if your `pools.servers.url` is IP-based and you prefer the backend request to use this IP, activate the `setUpstreamHost` option as illustrated below: + +```yaml +kind: Proxy +name: proxy-example-4 +pools: +- setUpstreamHost: true + servers: + - url: http://demo.com:9090 + loadBalance: + policy: roundRobin +maxRedirection: 10 +``` + +Note that `keepHost` takes precedence over `setUpstreamHost` because `keepHost` applies to individual servers, whereas `setUpstreamHost` affects the entire pool. + ### Configuration | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | @@ -1746,6 +1779,7 @@ Rules to revise request header. | circuitBreakerPolicy | string | CircuitBreaker policy name | No | | failureCodes | []int | Proxy return result of failureCode when backend resposne's status code in failureCodes. The default value is 5xx | No | | healthCheck | ProxyHealthCheckSpec | Health check. Full example with details in [Proxy Health Check](#health-check) | No | +| setUpstreamHost | bool | Set request host to the host of backend server url if true. Default is false. | No | ### proxy.Server diff --git a/pkg/filters/proxies/httpproxy/pool.go b/pkg/filters/proxies/httpproxy/pool.go index e8f8d8edc0..6e04ba9b99 100644 --- a/pkg/filters/proxies/httpproxy/pool.go +++ b/pkg/filters/proxies/httpproxy/pool.go @@ -135,7 +135,7 @@ func removeHopByHopHeaders(h http.Header) { */ } -func (spCtx *serverPoolContext) prepareRequest(svr *Server, ctx stdcontext.Context, mirror bool) error { +func (spCtx *serverPoolContext) prepareRequest(pool *ServerPool, svr *Server, ctx stdcontext.Context, mirror bool) error { req := spCtx.req u := req.Std().URL @@ -154,6 +154,7 @@ func (spCtx *serverPoolContext) prepareRequest(svr *Server, ctx stdcontext.Conte if err != nil { return err } + svrHost := stdr.Host stdr.Header = req.HTTPHeader().Clone() removeHopByHopHeaders(stdr.Header) @@ -164,6 +165,13 @@ func (spCtx *serverPoolContext) prepareRequest(svr *Server, ctx stdcontext.Conte stdr.Host = req.Host() } + // set upstream host if server is explicitly told to set the host of the request. + // KeepHost has higher priority than SetUpstreamHost. + if pool.spec.SetUpstreamHost && !svr.KeepHost { + stdr.Host = svrHost + stdr.Header.Add("Host", svrHost) + } + if spCtx.span != nil { spCtx.span.InjectHTTP(stdr) } @@ -352,7 +360,7 @@ func (sp *ServerPool) handleMirror(spCtx *serverPoolContext) { return } - err := spCtx.prepareRequest(svr, spCtx.req.Context(), true) + err := spCtx.prepareRequest(sp, svr, spCtx.req.Context(), true) if err != nil { logger.Errorf("%s: failed to prepare request: %v", sp.Name, err) return @@ -463,7 +471,7 @@ func (sp *ServerPool) doHandle(stdctx stdcontext.Context, spCtx *serverPoolConte // prepare the request to send. statResult := &gohttpstat.Result{} stdctx = gohttpstat.WithHTTPStat(stdctx, statResult) - if err := spCtx.prepareRequest(svr, stdctx, false); err != nil { + if err := spCtx.prepareRequest(sp, svr, stdctx, false); err != nil { logger.Errorf("%s: failed to prepare request: %v", sp.Name, err) return serverPoolError{http.StatusInternalServerError, resultInternalError} } diff --git a/pkg/filters/proxies/serverpool.go b/pkg/filters/proxies/serverpool.go index 228a245745..fbd0147cc8 100644 --- a/pkg/filters/proxies/serverpool.go +++ b/pkg/filters/proxies/serverpool.go @@ -47,6 +47,7 @@ type ServerPoolBase struct { type ServerPoolBaseSpec struct { ServerTags []string `json:"serverTags,omitempty" jsonschema:"uniqueItems=true"` Servers []*Server `json:"servers,omitempty"` + SetUpstreamHost bool `json:"setUpstreamHost,omitempty"` ServiceRegistry string `json:"serviceRegistry,omitempty"` ServiceName string `json:"serviceName,omitempty"` LoadBalance *LoadBalanceSpec `json:"loadBalance,omitempty"`