diff --git a/main.go b/main.go index faf31a5..f45fce6 100644 --- a/main.go +++ b/main.go @@ -635,49 +635,67 @@ func newProxyDialContext(dialTimeout time.Duration) DialContext { // tlsClientSessionCacheSize is the cache size for TLS client sessions. const tlsClientSessionCacheSize = 100 -type RoundTripperWrapper struct { - enableTLS bool - ctx *cli.Context +type roundTripperWrapper struct { + enableTLS bool + cacert string + clientCert string + clientKey string + insecure bool + rwLocker sync.Mutex + transport http.RoundTripper + latestCacheTime time.Time } -func (rtw *RoundTripperWrapper) RoundTrip(req *http.Request) (*http.Response, error) { - tr := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: dialContextWithDNSCache(dnsCache, newProxyDialContext(10*time.Second)), - MaxIdleConnsPerHost: 1024, - WriteBufferSize: 32 << 10, // 32KiB moving up from 4KiB default - ReadBufferSize: 32 << 10, // 32KiB moving up from 4KiB default - IdleConnTimeout: 15 * time.Second, - TLSHandshakeTimeout: 15 * time.Second, - ExpectContinueTimeout: 15 * time.Second, - // Set this value so that the underlying transport round-tripper - // doesn't try to auto decode the body of objects with - // content-encoding set to `gzip`. - // - // Refer: - // https://golang.org/src/net/http/transport.go?h=roundTrip#L1843 - DisableCompression: true, - } - - if rtw.enableTLS { - // Keep TLS config. - tr.TLSClientConfig = &tls.Config{ - RootCAs: getCertPool(rtw.ctx.GlobalString("cacert")), - Certificates: getCertKeyPair(rtw.ctx.GlobalString("client-cert"), rtw.ctx.GlobalString("client-key")), - InsecureSkipVerify: rtw.ctx.GlobalBool("insecure"), - // Can't use SSLv3 because of POODLE and BEAST - // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher - // Can't use TLSv1.1 because of RC4 cipher usage - MinVersion: tls.VersionTLS12, - PreferServerCipherSuites: true, - ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize), +func (rtw *roundTripperWrapper) RoundTrip(req *http.Request) (*http.Response, error) { + rtw.rwLocker.Lock() + defer rtw.rwLocker.Unlock() + if rtw.transport == nil || time.Since(rtw.latestCacheTime) > time.Minute { + tr := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: dialContextWithDNSCache(dnsCache, newProxyDialContext(10*time.Second)), + MaxIdleConnsPerHost: 1024, + WriteBufferSize: 32 << 10, // 32KiB moving up from 4KiB default + ReadBufferSize: 32 << 10, // 32KiB moving up from 4KiB default + IdleConnTimeout: 15 * time.Second, + TLSHandshakeTimeout: 15 * time.Second, + ExpectContinueTimeout: 15 * time.Second, + // Set this value so that the underlying transport round-tripper + // doesn't try to auto decode the body of objects with + // content-encoding set to `gzip`. + // + // Refer: + // https://golang.org/src/net/http/transport.go?h=roundTrip#L1843 + DisableCompression: true, } + + if rtw.enableTLS { + // Keep TLS config. + tr.TLSClientConfig = &tls.Config{ + RootCAs: getCertPool(rtw.cacert), + Certificates: getCertKeyPair(rtw.clientCert, rtw.clientKey), + InsecureSkipVerify: rtw.insecure, + // Can't use SSLv3 because of POODLE and BEAST + // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher + // Can't use TLSv1.1 because of RC4 cipher usage + MinVersion: tls.VersionTLS12, + PreferServerCipherSuites: true, + ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize), + } + } + rtw.transport = tr + rtw.latestCacheTime = time.Now() } - return tr.RoundTrip(req) + return rtw.transport.RoundTrip(req) } func clientTransport(ctx *cli.Context, enableTLS bool) http.RoundTripper { - return &RoundTripperWrapper{ctx: ctx, enableTLS: enableTLS} + return &roundTripperWrapper{ + enableTLS: enableTLS, + cacert: ctx.GlobalString("cacert"), + clientCert: ctx.GlobalString("client-cert"), + clientKey: ctx.GlobalString("client-key"), + insecure: ctx.GlobalBool("insecure"), + } } func checkMain(ctx *cli.Context) {