mirror of
https://github.com/minio/minio.git
synced 2025-11-07 21:02:58 -05:00
Refactor HTTP transports (#16222)
This commit is contained in:
committed by
GitHub
parent
37e20f6ef2
commit
2d60bf8c50
177
internal/http/transports.go
Normal file
177
internal/http/transports.go
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2015-2022 MinIO, Inc.
|
||||
//
|
||||
// # This file is part of MinIO Object Storage stack
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
"net/http"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/minio/pkg/certs"
|
||||
"github.com/rs/dnscache"
|
||||
)
|
||||
|
||||
// tlsClientSessionCacheSize is the cache size for client sessions.
|
||||
var tlsClientSessionCacheSize = 100
|
||||
|
||||
// ConnSettings - contains connection settings.
|
||||
type ConnSettings struct {
|
||||
// If this is non-nil, DNSCache and DialTimeout are ignored.
|
||||
DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
|
||||
// Dial settings, used if DialContext is nil.
|
||||
DNSCache *dnscache.Resolver
|
||||
DialTimeout time.Duration
|
||||
|
||||
// TLS Settings
|
||||
RootCAs *x509.CertPool
|
||||
CipherSuites []uint16
|
||||
CurvePreferences []tls.CurveID
|
||||
|
||||
// HTTP2
|
||||
EnableHTTP2 bool
|
||||
}
|
||||
|
||||
func (s ConnSettings) getDefaultTransport() *http.Transport {
|
||||
dialContext := s.DialContext
|
||||
if dialContext == nil {
|
||||
dialContext = DialContextWithDNSCache(s.DNSCache, NewInternodeDialContext(s.DialTimeout))
|
||||
}
|
||||
|
||||
tlsClientConfig := tls.Config{
|
||||
RootCAs: s.RootCAs,
|
||||
CipherSuites: s.CipherSuites,
|
||||
CurvePreferences: s.CurvePreferences,
|
||||
ClientSessionCache: tls.NewLRUClientSessionCache(tlsClientSessionCacheSize),
|
||||
}
|
||||
|
||||
// For more details about various values used here refer
|
||||
// https://golang.org/pkg/net/http/#Transport documentation
|
||||
tr := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: dialContext,
|
||||
MaxIdleConnsPerHost: 1024,
|
||||
WriteBufferSize: 32 << 10, // 32KiB moving up from 4KiB default
|
||||
ReadBufferSize: 32 << 10, // 32KiB moving up from 4KiB default
|
||||
IdleConnTimeout: 15 * time.Second,
|
||||
ResponseHeaderTimeout: 15 * time.Minute, // Conservative timeout is the default (for MinIO internode)
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 10 * time.Second,
|
||||
TLSClientConfig: &tlsClientConfig,
|
||||
ForceAttemptHTTP2: s.EnableHTTP2,
|
||||
// Go net/http automatically unzip if content-type is
|
||||
// gzip disable this feature, as we are always interested
|
||||
// in raw stream.
|
||||
DisableCompression: true,
|
||||
}
|
||||
|
||||
// https://github.com/golang/go/issues/23559
|
||||
// https://github.com/golang/go/issues/42534
|
||||
// https://github.com/golang/go/issues/43989
|
||||
// https://github.com/golang/go/issues/33425
|
||||
// https://github.com/golang/go/issues/29246
|
||||
// if tlsConfig != nil {
|
||||
// trhttp2, _ := http2.ConfigureTransports(tr)
|
||||
// if trhttp2 != nil {
|
||||
// // ReadIdleTimeout is the timeout after which a health check using ping
|
||||
// // frame will be carried out if no frame is received on the
|
||||
// // connection. 5 minutes is sufficient time for any idle connection.
|
||||
// trhttp2.ReadIdleTimeout = 5 * time.Minute
|
||||
// // PingTimeout is the timeout after which the connection will be closed
|
||||
// // if a response to Ping is not received.
|
||||
// trhttp2.PingTimeout = dialTimeout
|
||||
// // DisableCompression, if true, prevents the Transport from
|
||||
// // requesting compression with an "Accept-Encoding: gzip"
|
||||
// trhttp2.DisableCompression = true
|
||||
// }
|
||||
// }
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
// NewInternodeHTTPTransport returns transport for internode MinIO connections.
|
||||
func (s ConnSettings) NewInternodeHTTPTransport() func() http.RoundTripper {
|
||||
tr := s.getDefaultTransport()
|
||||
|
||||
// Settings specific to internode requests.
|
||||
tr.TLSHandshakeTimeout = 15 * time.Minute
|
||||
tr.ExpectContinueTimeout = 15 * time.Minute
|
||||
|
||||
return func() http.RoundTripper {
|
||||
return tr
|
||||
}
|
||||
}
|
||||
|
||||
// NewCustomHTTPProxyTransport is used only for proxied requests, specifically
|
||||
// only supports HTTP/1.1
|
||||
func (s ConnSettings) NewCustomHTTPProxyTransport() func() *http.Transport {
|
||||
s.EnableHTTP2 = false
|
||||
tr := s.getDefaultTransport()
|
||||
|
||||
// Settings specific to proxied requests.
|
||||
tr.ResponseHeaderTimeout = 30 * time.Minute
|
||||
|
||||
return func() *http.Transport {
|
||||
return tr
|
||||
}
|
||||
}
|
||||
|
||||
// NewHTTPTransportWithTimeout allows setting a timeout for response headers
|
||||
func (s ConnSettings) NewHTTPTransportWithTimeout(timeout time.Duration) *http.Transport {
|
||||
tr := s.getDefaultTransport()
|
||||
|
||||
// Settings specific to this transport.
|
||||
tr.ResponseHeaderTimeout = timeout
|
||||
return tr
|
||||
}
|
||||
|
||||
// NewHTTPTransportWithClientCerts returns a new http configuration used for
|
||||
// communicating with client cert authentication.
|
||||
func (s ConnSettings) NewHTTPTransportWithClientCerts(ctx context.Context, clientCert, clientKey string) (*http.Transport, error) {
|
||||
transport := s.NewHTTPTransportWithTimeout(1 * time.Minute)
|
||||
if clientCert != "" && clientKey != "" {
|
||||
c, err := certs.NewManager(ctx, clientCert, clientKey, tls.LoadX509KeyPair)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c != nil {
|
||||
c.UpdateReloadDuration(10 * time.Second)
|
||||
c.ReloadOnSignal(syscall.SIGHUP) // allow reloads upon SIGHUP
|
||||
transport.TLSClientConfig.GetClientCertificate = c.GetClientCertificate
|
||||
}
|
||||
}
|
||||
return transport, nil
|
||||
}
|
||||
|
||||
// NewRemoteTargetHTTPTransport returns a new http configuration
|
||||
// used while communicating with the remote replication targets.
|
||||
func (s ConnSettings) NewRemoteTargetHTTPTransport() func() *http.Transport {
|
||||
tr := s.getDefaultTransport()
|
||||
|
||||
tr.TLSHandshakeTimeout = 5 * time.Second
|
||||
tr.ExpectContinueTimeout = 5 * time.Second
|
||||
tr.ResponseHeaderTimeout = 0
|
||||
|
||||
return func() *http.Transport {
|
||||
return tr
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user