Skip to content

Commit 52e512c

Browse files
jkroepkeSuperQ
andauthored
http_config: Add host (#549)
* http_config: Add host --------- Signed-off-by: Jan-Otto Kröpke <[email protected]> Signed-off-by: Jan-Otto Kröpke <[email protected]> Co-authored-by: Ben Kochie <[email protected]>
1 parent 699b115 commit 52e512c

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

config/http_config.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ type HTTPClientConfig struct {
309309
// The omitempty flag is not set, because it would be hidden from the
310310
// marshalled configuration when set to false.
311311
EnableHTTP2 bool `yaml:"enable_http2" json:"enable_http2"`
312+
// Host optionally overrides the Host header to send.
313+
// If empty, the host from the URL will be used.
314+
Host string `yaml:"host,omitempty" json:"host,omitempty"`
312315
// Proxy configuration.
313316
ProxyConfig `yaml:",inline"`
314317
}
@@ -427,6 +430,7 @@ type httpClientOptions struct {
427430
http2Enabled bool
428431
idleConnTimeout time.Duration
429432
userAgent string
433+
host string
430434
}
431435

432436
// HTTPClientOption defines an option that can be applied to the HTTP client.
@@ -467,6 +471,13 @@ func WithUserAgent(ua string) HTTPClientOption {
467471
}
468472
}
469473

474+
// WithHost allows setting the host header.
475+
func WithHost(host string) HTTPClientOption {
476+
return func(opts *httpClientOptions) {
477+
opts.host = host
478+
}
479+
}
480+
470481
// NewClient returns a http.Client using the specified http.RoundTripper.
471482
func newClient(rt http.RoundTripper) *http.Client {
472483
return &http.Client{Transport: rt}
@@ -568,6 +579,10 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
568579
rt = NewUserAgentRoundTripper(opts.userAgent, rt)
569580
}
570581

582+
if opts.host != "" {
583+
rt = NewHostRoundTripper(opts.host, rt)
584+
}
585+
571586
// Return a new configured RoundTripper.
572587
return rt, nil
573588
}
@@ -1164,11 +1179,21 @@ type userAgentRoundTripper struct {
11641179
rt http.RoundTripper
11651180
}
11661181

1182+
type hostRoundTripper struct {
1183+
host string
1184+
rt http.RoundTripper
1185+
}
1186+
11671187
// NewUserAgentRoundTripper adds the user agent every request header.
11681188
func NewUserAgentRoundTripper(userAgent string, rt http.RoundTripper) http.RoundTripper {
11691189
return &userAgentRoundTripper{userAgent, rt}
11701190
}
11711191

1192+
// NewHostRoundTripper sets the [http.Request.Host] of every request.
1193+
func NewHostRoundTripper(host string, rt http.RoundTripper) http.RoundTripper {
1194+
return &hostRoundTripper{host, rt}
1195+
}
1196+
11721197
func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
11731198
req = cloneRequest(req)
11741199
req.Header.Set("User-Agent", rt.userAgent)
@@ -1181,6 +1206,19 @@ func (rt *userAgentRoundTripper) CloseIdleConnections() {
11811206
}
11821207
}
11831208

1209+
func (rt *hostRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
1210+
req = cloneRequest(req)
1211+
req.Host = rt.host
1212+
req.Header.Set("Host", rt.host)
1213+
return rt.rt.RoundTrip(req)
1214+
}
1215+
1216+
func (rt *hostRoundTripper) CloseIdleConnections() {
1217+
if ci, ok := rt.rt.(closeIdler); ok {
1218+
ci.CloseIdleConnections()
1219+
}
1220+
}
1221+
11841222
func (c HTTPClientConfig) String() string {
11851223
b, err := yaml.Marshal(c)
11861224
if err != nil {

config/http_config_test.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import (
3535
"testing"
3636
"time"
3737

38-
yaml "gopkg.in/yaml.v2"
38+
"gopkg.in/yaml.v2"
3939
)
4040

4141
const (
@@ -1671,6 +1671,32 @@ func TestOAuth2UserAgent(t *testing.T) {
16711671
}
16721672
}
16731673

1674+
func TestHost(t *testing.T) {
1675+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1676+
if r.Host != "localhost.localdomain" {
1677+
t.Fatalf("Expected Host header in request to be 'localhost.localdomain', got '%s'", r.Host)
1678+
}
1679+
1680+
w.Header().Add("Content-Type", "application/json")
1681+
}))
1682+
defer ts.Close()
1683+
1684+
config := DefaultHTTPClientConfig
1685+
1686+
rt, err := NewRoundTripperFromConfig(config, "test_host", WithHost("localhost.localdomain"))
1687+
if err != nil {
1688+
t.Fatal(err)
1689+
}
1690+
1691+
client := http.Client{
1692+
Transport: rt,
1693+
}
1694+
_, err = client.Get(ts.URL)
1695+
if err != nil {
1696+
t.Fatal(err)
1697+
}
1698+
}
1699+
16741700
func TestOAuth2WithFile(t *testing.T) {
16751701
var expectedAuth string
16761702
ts := newTestOAuthServer(t, &expectedAuth)

0 commit comments

Comments
 (0)