diff --git a/config/config.go b/config/config.go index de6d04b9307..d36f0e442a5 100644 --- a/config/config.go +++ b/config/config.go @@ -125,11 +125,14 @@ type PriceFloorFetcher struct { const MIN_COOKIE_SIZE_BYTES = 500 type HTTPClient struct { - MaxConnsPerHost int `mapstructure:"max_connections_per_host"` - MaxIdleConns int `mapstructure:"max_idle_connections"` - MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` - IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` - Throttle HTTPThrottle `mapstructure:"throttle"` + MaxConnsPerHost int `mapstructure:"max_connections_per_host"` + MaxIdleConns int `mapstructure:"max_idle_connections"` + MaxIdleConnsPerHost int `mapstructure:"max_idle_connections_per_host"` + IdleConnTimeout int `mapstructure:"idle_connection_timeout_seconds"` + TLSHandshakeTimeout int `mapstructure:"tls_handshake_timeout_seconds"` + ExpectContinueTimeout int `mapstructure:"expect_continue_timeout_seconds"` + Dialer Dialer `mapstructure:"dialer"` + Throttle HTTPThrottle `mapstructure:"throttle"` } type HTTPThrottle struct { @@ -145,6 +148,11 @@ type HTTPThrottle struct { ThrottleWindow int `mapstructure:"throttle_window"` } +type Dialer struct { + TimeoutSeconds int `mapstructure:"timeout_seconds"` + KeepAliveSeconds int `mapstructure:"keep_alive_seconds"` +} + func (cfg *Configuration) validate(v *viper.Viper) []error { var errs []error errs = cfg.AuctionTimeouts.validate(errs) @@ -963,6 +971,10 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("http_client.max_idle_connections", 400) v.SetDefault("http_client.max_idle_connections_per_host", 10) v.SetDefault("http_client.idle_connection_timeout_seconds", 60) + v.SetDefault("http_client.tls_handshake_timeout_seconds", 10) + v.SetDefault("http_client.expect_continue_timeout_seconds", 1) + v.SetDefault("http_client.dialer.timeout_seconds", 30) + v.SetDefault("http_client.dialer.keep_alive_seconds", 15) v.SetDefault("http_client.throttle.enable_throttling", false) v.SetDefault("http_client.throttle.simulate_throttling_only", false) v.SetDefault("http_client.throttle.long_queue_wait_threshold_ms", 50) @@ -972,6 +984,10 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("http_client_cache.max_idle_connections", 10) v.SetDefault("http_client_cache.max_idle_connections_per_host", 2) v.SetDefault("http_client_cache.idle_connection_timeout_seconds", 60) + v.SetDefault("http_client_cache.tls_handshake_timeout_seconds", 10) + v.SetDefault("http_client_cache.expect_continue_timeout_seconds", 1) + v.SetDefault("http_client_cache.dialer.timeout_seconds", 30) + v.SetDefault("http_client_cache.dialer.keep_alive_seconds", 15) // no metrics configured by default (metrics{host|database|username|password}) v.SetDefault("metrics.disabled_metrics.account_adapter_details", false) v.SetDefault("metrics.disabled_metrics.account_debug", true) @@ -1220,6 +1236,10 @@ func SetupViper(v *viper.Viper, filename string, bidderInfos BidderInfos) { v.SetDefault("price_floors.fetcher.http_client.max_idle_connections", 40) v.SetDefault("price_floors.fetcher.http_client.max_idle_connections_per_host", 2) v.SetDefault("price_floors.fetcher.http_client.idle_connection_timeout_seconds", 60) + v.SetDefault("price_floors.fetcher.http_client.tls_handshake_timeout_seconds", 10) + v.SetDefault("price_floors.fetcher.http_client.expect_continue_timeout_seconds", 1) + v.SetDefault("price_floors.fetcher.http_client.dialer.timeout_seconds", 30) + v.SetDefault("price_floors.fetcher.http_client.dialer.keep_alive_seconds", 15) v.SetDefault("price_floors.fetcher.max_retries", 10) v.SetDefault("account_defaults.events_enabled", false) diff --git a/router/router.go b/router/router.go index 05d0d992334..4bc156a1577 100644 --- a/router/router.go +++ b/router/router.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + "net" "net/http" "os" "strings" @@ -138,32 +139,50 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R generalHttpClient := &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - MaxConnsPerHost: cfg.Client.MaxConnsPerHost, - MaxIdleConns: cfg.Client.MaxIdleConns, - MaxIdleConnsPerHost: cfg.Client.MaxIdleConnsPerHost, - IdleConnTimeout: time.Duration(cfg.Client.IdleConnTimeout) * time.Second, - TLSClientConfig: &tls.Config{RootCAs: certPool}, + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: time.Duration(cfg.Client.Dialer.TimeoutSeconds) * time.Second, + KeepAlive: time.Duration(cfg.Client.Dialer.KeepAliveSeconds) * time.Second, + }), + MaxConnsPerHost: cfg.Client.MaxConnsPerHost, + MaxIdleConns: cfg.Client.MaxIdleConns, + MaxIdleConnsPerHost: cfg.Client.MaxIdleConnsPerHost, + IdleConnTimeout: time.Duration(cfg.Client.IdleConnTimeout) * time.Second, + TLSClientConfig: &tls.Config{RootCAs: certPool}, + TLSHandshakeTimeout: time.Duration(cfg.Client.TLSHandshakeTimeout) * time.Second, + ExpectContinueTimeout: time.Duration(cfg.Client.ExpectContinueTimeout) * time.Second, }, } cacheHttpClient := &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - MaxConnsPerHost: cfg.CacheClient.MaxConnsPerHost, - MaxIdleConns: cfg.CacheClient.MaxIdleConns, - MaxIdleConnsPerHost: cfg.CacheClient.MaxIdleConnsPerHost, - IdleConnTimeout: time.Duration(cfg.CacheClient.IdleConnTimeout) * time.Second, + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: time.Duration(cfg.CacheClient.Dialer.TimeoutSeconds) * time.Second, + KeepAlive: time.Duration(cfg.CacheClient.Dialer.KeepAliveSeconds) * time.Second, + }), + MaxConnsPerHost: cfg.CacheClient.MaxConnsPerHost, + MaxIdleConns: cfg.CacheClient.MaxIdleConns, + MaxIdleConnsPerHost: cfg.CacheClient.MaxIdleConnsPerHost, + IdleConnTimeout: time.Duration(cfg.CacheClient.IdleConnTimeout) * time.Second, + TLSHandshakeTimeout: time.Duration(cfg.CacheClient.TLSHandshakeTimeout) * time.Second, + ExpectContinueTimeout: time.Duration(cfg.CacheClient.ExpectContinueTimeout) * time.Second, }, } floorFechterHttpClient := &http.Client{ Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - MaxConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxConnsPerHost, - MaxIdleConns: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConns, - MaxIdleConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConnsPerHost, - IdleConnTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.IdleConnTimeout) * time.Second, + Proxy: http.ProxyFromEnvironment, + DialContext: defaultTransportDialContext(&net.Dialer{ + Timeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.Dialer.TimeoutSeconds) * time.Second, + KeepAlive: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.Dialer.KeepAliveSeconds) * time.Second, + }), + MaxConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxConnsPerHost, + MaxIdleConns: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConns, + MaxIdleConnsPerHost: cfg.PriceFloors.Fetcher.HttpClient.MaxIdleConnsPerHost, + IdleConnTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.IdleConnTimeout) * time.Second, + TLSHandshakeTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.TLSHandshakeTimeout) * time.Second, + ExpectContinueTimeout: time.Duration(cfg.PriceFloors.Fetcher.HttpClient.ExpectContinueTimeout) * time.Second, }, } @@ -292,6 +311,11 @@ func New(cfg *config.Configuration, rateConvertor *currency.RateConverter) (r *R return r, nil } +// defaultTransportDialContext returns the same dialer context as the default transport uses, copied from the library code. +func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) { + return dialer.DialContext +} + // Shutdown closes any dependencies of the router that may need closing func (r *Router) Shutdown() { glog.Info("[PBS Router] shutting down")