diff --git a/bouncer.go b/bouncer.go index 5f02e27..379a4e3 100644 --- a/bouncer.go +++ b/bouncer.go @@ -243,17 +243,19 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam }, httpClient: &http.Client{ Transport: &http.Transport{ - MaxIdleConns: 10, - IdleConnTimeout: 30 * time.Second, - TLSClientConfig: tlsConfig, + MaxIdleConns: 10, + MaxIdleConnsPerHost: 10, + IdleConnTimeout: 30 * time.Second, + TLSClientConfig: tlsConfig, }, Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second, }, httpAppsecClient: &http.Client{ Transport: &http.Transport{ - MaxIdleConns: 10, - IdleConnTimeout: 30 * time.Second, - TLSClientConfig: tlsAppsecConfig, + MaxIdleConns: 10, + MaxIdleConnsPerHost: 10, + IdleConnTimeout: 30 * time.Second, + TLSClientConfig: tlsAppsecConfig, }, Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second, }, @@ -278,7 +280,7 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam log, bouncer.cacheClient, &http.Client{ - Transport: &http.Transport{MaxIdleConns: 10, IdleConnTimeout: 30 * time.Second}, + Transport: &http.Transport{MaxIdleConns: 10, MaxIdleConnsPerHost: 10, IdleConnTimeout: 30 * time.Second}, Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second, }, config.CaptchaProvider, @@ -801,6 +803,13 @@ func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) error { return nil } defer func() { + // net/http only returns a connection to the idle pool once its body has + // been read to EOF; closing early discards it. Drain here rather than at + // the end of the function so the 500 and non-200 paths, which return + // earlier, keep their connections too. + if _, errDrain := io.Copy(io.Discard, res.Body); errDrain != nil { + bouncer.log.Debug("appsecQuery:drainBody " + errDrain.Error()) + } if err = res.Body.Close(); err != nil { bouncer.log.Error("appsecQuery:closeBody " + err.Error()) } @@ -816,9 +825,6 @@ func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) error { return fmt.Errorf("appsecQuery statusCode:%d", res.StatusCode) } - if err != nil { - return fmt.Errorf("appsecQuery:readBody %w", err) - } return nil }