github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/http/transports.go (about) 1 // Copyright (c) 2015-2022 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package http 19 20 import ( 21 "context" 22 "crypto/tls" 23 "crypto/x509" 24 "net/http" 25 "syscall" 26 "time" 27 28 "github.com/minio/pkg/v2/certs" 29 ) 30 31 // tlsClientSessionCacheSize is the cache size for client sessions. 32 var tlsClientSessionCacheSize = 100 33 34 // ConnSettings - contains connection settings. 35 type ConnSettings struct { 36 DialContext DialContext // Custom dialContext, DialTimeout is ignored if this is already setup. 37 LookupHost LookupHost // Custom lookupHost, is nil on containerized deployments. 38 DialTimeout time.Duration 39 40 // TLS Settings 41 RootCAs *x509.CertPool 42 CipherSuites []uint16 43 CurvePreferences []tls.CurveID 44 45 // HTTP2 46 EnableHTTP2 bool 47 48 // TCP Options 49 TCPOptions TCPOptions 50 } 51 52 func (s ConnSettings) getDefaultTransport(maxIdleConnsPerHost int) *http.Transport { 53 if maxIdleConnsPerHost <= 0 { 54 maxIdleConnsPerHost = 1024 55 } 56 57 dialContext := s.DialContext 58 if dialContext == nil { 59 dialContext = DialContextWithLookupHost(s.LookupHost, NewInternodeDialContext(s.DialTimeout, s.TCPOptions)) 60 } 61 62 tlsClientConfig := tls.Config{ 63 RootCAs: s.RootCAs, 64 CipherSuites: s.CipherSuites, 65 CurvePreferences: s.CurvePreferences, 66 ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize), 67 } 68 69 // For more details about various values used here refer 70 // https://golang.org/pkg/net/http/#Transport documentation 71 tr := &http.Transport{ 72 Proxy: http.ProxyFromEnvironment, 73 DialContext: dialContext, 74 MaxIdleConnsPerHost: maxIdleConnsPerHost, 75 WriteBufferSize: 32 << 10, // 32KiB moving up from 4KiB default 76 ReadBufferSize: 32 << 10, // 32KiB moving up from 4KiB default 77 IdleConnTimeout: 15 * time.Second, 78 ResponseHeaderTimeout: 15 * time.Minute, // Conservative timeout is the default (for MinIO internode) 79 TLSHandshakeTimeout: 10 * time.Second, 80 TLSClientConfig: &tlsClientConfig, 81 ForceAttemptHTTP2: s.EnableHTTP2, 82 // Go net/http automatically unzip if content-type is 83 // gzip disable this feature, as we are always interested 84 // in raw stream. 85 DisableCompression: true, 86 } 87 88 // https://github.com/golang/go/issues/23559 89 // https://github.com/golang/go/issues/42534 90 // https://github.com/golang/go/issues/43989 91 // https://github.com/golang/go/issues/33425 92 // https://github.com/golang/go/issues/29246 93 // if tlsConfig != nil { 94 // trhttp2, _ := http2.ConfigureTransports(tr) 95 // if trhttp2 != nil { 96 // // ReadIdleTimeout is the timeout after which a health check using ping 97 // // frame will be carried out if no frame is received on the 98 // // connection. 5 minutes is sufficient time for any idle connection. 99 // trhttp2.ReadIdleTimeout = 5 * time.Minute 100 // // PingTimeout is the timeout after which the connection will be closed 101 // // if a response to Ping is not received. 102 // trhttp2.PingTimeout = dialTimeout 103 // // DisableCompression, if true, prevents the Transport from 104 // // requesting compression with an "Accept-Encoding: gzip" 105 // trhttp2.DisableCompression = true 106 // } 107 // } 108 109 return tr 110 } 111 112 // NewInternodeHTTPTransport returns transport for internode MinIO connections. 113 func (s ConnSettings) NewInternodeHTTPTransport(maxIdleConnsPerHost int) func() http.RoundTripper { 114 tr := s.getDefaultTransport(maxIdleConnsPerHost) 115 116 // Settings specific to internode requests. 117 tr.TLSHandshakeTimeout = 15 * time.Second 118 119 return func() http.RoundTripper { 120 return tr 121 } 122 } 123 124 // NewCustomHTTPProxyTransport is used only for proxied requests, specifically 125 // only supports HTTP/1.1 126 func (s ConnSettings) NewCustomHTTPProxyTransport() func() *http.Transport { 127 s.EnableHTTP2 = false 128 tr := s.getDefaultTransport(0) 129 130 // Settings specific to proxied requests. 131 tr.ResponseHeaderTimeout = 30 * time.Minute 132 133 return func() *http.Transport { 134 return tr 135 } 136 } 137 138 // NewHTTPTransportWithTimeout allows setting a timeout for response headers 139 func (s ConnSettings) NewHTTPTransportWithTimeout(timeout time.Duration) *http.Transport { 140 tr := s.getDefaultTransport(0) 141 142 // Settings specific to this transport. 143 tr.ResponseHeaderTimeout = timeout 144 return tr 145 } 146 147 // NewHTTPTransportWithClientCerts returns a new http configuration used for 148 // communicating with client cert authentication. 149 func (s ConnSettings) NewHTTPTransportWithClientCerts(ctx context.Context, clientCert, clientKey string) (*http.Transport, error) { 150 transport := s.NewHTTPTransportWithTimeout(1 * time.Minute) 151 if clientCert != "" && clientKey != "" { 152 c, err := certs.NewManager(ctx, clientCert, clientKey, tls.LoadX509KeyPair) 153 if err != nil { 154 return nil, err 155 } 156 if c != nil { 157 c.UpdateReloadDuration(10 * time.Second) 158 c.ReloadOnSignal(syscall.SIGHUP) // allow reloads upon SIGHUP 159 transport.TLSClientConfig.GetClientCertificate = c.GetClientCertificate 160 } 161 } 162 return transport, nil 163 } 164 165 // NewRemoteTargetHTTPTransport returns a new http configuration 166 // used while communicating with the remote replication targets. 167 func (s ConnSettings) NewRemoteTargetHTTPTransport(insecure bool) func() *http.Transport { 168 tr := s.getDefaultTransport(0) 169 170 tr.TLSHandshakeTimeout = 10 * time.Second 171 tr.ResponseHeaderTimeout = 0 172 tr.TLSClientConfig.InsecureSkipVerify = insecure 173 174 return func() *http.Transport { 175 return tr 176 } 177 }