mirror of
https://github.com/nabbar/golib.git
synced 2025-12-24 11:51:02 +08:00
Package HTTP Client:
- defined default value for idles connection & max connection per host - rework client creation to prevent TCP FIN not send on close stream
This commit is contained in:
113
httpcli/cli.go
113
httpcli/cli.go
@@ -28,12 +28,13 @@ package httpcli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libptc "github.com/nabbar/golib/network/protocol"
|
||||
"golang.org/x/net/http2"
|
||||
@@ -49,34 +50,98 @@ const (
|
||||
ClientNetworkUDP = "udp"
|
||||
)
|
||||
|
||||
var trp = new(atomic.Value)
|
||||
|
||||
func init() {
|
||||
trp.Store(&http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: false,
|
||||
DisableCompression: false,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 1,
|
||||
MaxConnsPerHost: 25,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
TLSClientConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type FctHttpClient func() *http.Client
|
||||
|
||||
type HttpClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
func GetTransport(DisableKeepAlive, DisableCompression, ForceHTTP2 bool) *http.Transport {
|
||||
return &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: nil,
|
||||
DialTLSContext: nil,
|
||||
TLSClientConfig: nil,
|
||||
DisableKeepAlives: DisableKeepAlive,
|
||||
DisableCompression: DisableCompression,
|
||||
ForceAttemptHTTP2: ForceHTTP2,
|
||||
func ForceUpdateTransport(cfg *tls.Config, proxyUrl *url.URL) *http.Transport {
|
||||
t := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: cfg.Clone(),
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: false,
|
||||
DisableCompression: false,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 1,
|
||||
MaxConnsPerHost: 25,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
}
|
||||
|
||||
if proxyUrl != nil {
|
||||
t.Proxy = http.ProxyURL(proxyUrl)
|
||||
}
|
||||
|
||||
trp.Store(t)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func SetTransportTLS(tr *http.Transport, tls libtls.TLSConfig, servername string) {
|
||||
tr.TLSClientConfig = tls.TlsConfig(servername)
|
||||
}
|
||||
func GetTransport(tlsConfig *tls.Config, proxyURL *url.URL, DisableKeepAlive, DisableCompression, ForceHTTP2 bool) *http.Transport {
|
||||
var tr *http.Transport
|
||||
|
||||
func SetTransportProxy(tr *http.Transport, proxyUrl *url.URL) {
|
||||
tr.Proxy = http.ProxyURL(proxyUrl)
|
||||
if i := trp.Load(); i != nil {
|
||||
if t, k := i.(*http.Transport); k {
|
||||
tr = t.Clone()
|
||||
}
|
||||
}
|
||||
|
||||
if tr == nil {
|
||||
tr = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
DisableKeepAlives: false,
|
||||
DisableCompression: false,
|
||||
MaxIdleConns: 100,
|
||||
MaxIdleConnsPerHost: 1,
|
||||
MaxConnsPerHost: 25,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
ForceAttemptHTTP2: true,
|
||||
}
|
||||
}
|
||||
|
||||
tr.DisableCompression = DisableCompression
|
||||
tr.DisableKeepAlives = DisableKeepAlive
|
||||
tr.TLSClientConfig = tlsConfig.Clone()
|
||||
|
||||
if proxyURL != nil {
|
||||
tr.Proxy = http.ProxyURL(proxyURL)
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
func SetTransportDial(tr *http.Transport, forceIp bool, netw libptc.NetworkProtocol, ip, local string) {
|
||||
var (
|
||||
dial = &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}
|
||||
fctDial func(ctx context.Context, network, address string) (net.Conn, error)
|
||||
)
|
||||
|
||||
@@ -85,24 +150,24 @@ func SetTransportDial(tr *http.Transport, forceIp bool, netw libptc.NetworkProto
|
||||
Host: local,
|
||||
}
|
||||
fctDial = func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
dl := &net.Dialer{
|
||||
LocalAddr: &net.TCPAddr{
|
||||
IP: net.ParseIP(u.Hostname()),
|
||||
},
|
||||
dial.LocalAddr = &net.TCPAddr{
|
||||
IP: net.ParseIP(u.Hostname()),
|
||||
}
|
||||
return dl.DialContext(ctx, netw.Code(), ip)
|
||||
|
||||
return dial.DialContext(ctx, netw.Code(), ip)
|
||||
}
|
||||
} else if forceIp {
|
||||
fctDial = func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
dl := &net.Dialer{}
|
||||
return dl.DialContext(ctx, netw.Code(), ip)
|
||||
return dial.DialContext(ctx, netw.Code(), ip)
|
||||
}
|
||||
} else {
|
||||
dl := &net.Dialer{}
|
||||
fctDial = dl.DialContext
|
||||
fctDial = dial.DialContext
|
||||
}
|
||||
|
||||
tr.DialContext = fctDial
|
||||
tr.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return tls.DialWithDialer(dial, network, addr, tr.TLSClientConfig)
|
||||
}
|
||||
}
|
||||
|
||||
func GetClient(tr *http.Transport, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
|
||||
|
||||
@@ -62,11 +62,13 @@ type OptionProxy struct {
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Timeout time.Duration `json:"timeout" yaml:"timeout" toml:"timeout" mapstructure:"timeout"`
|
||||
Http2 bool `json:"http2" yaml:"http2" toml:"http2" mapstructure:"http2"`
|
||||
TLS OptionTLS `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
|
||||
ForceIP OptionForceIP `json:"force_ip" yaml:"force_ip" toml:"force_ip" mapstructure:"force_ip"`
|
||||
Proxy OptionProxy `json:"proxy" yaml:"proxy" toml:"proxy" mapstructure:"proxy"`
|
||||
Timeout time.Duration `json:"timeout" yaml:"timeout" toml:"timeout" mapstructure:"timeout"`
|
||||
DisableKeepAlive bool `json:"disable-keep-alive" yaml:"disable-keep-alive" toml:"disable-keep-alive" mapstructure:"disable-keep-alive"`
|
||||
DisableCompression bool `json:"disable-compression" yaml:"disable-compression" toml:"disable-compression" mapstructure:"disable-compression"`
|
||||
Http2 bool `json:"http2" yaml:"http2" toml:"http2" mapstructure:"http2"`
|
||||
TLS OptionTLS `json:"tls" yaml:"tls" toml:"tls" mapstructure:"tls"`
|
||||
ForceIP OptionForceIP `json:"force_ip" yaml:"force_ip" toml:"force_ip" mapstructure:"force_ip"`
|
||||
Proxy OptionProxy `json:"proxy" yaml:"proxy" toml:"proxy" mapstructure:"proxy"`
|
||||
}
|
||||
|
||||
func DefaultConfig(indent string) []byte {
|
||||
@@ -74,6 +76,8 @@ func DefaultConfig(indent string) []byte {
|
||||
res = bytes.NewBuffer(make([]byte, 0))
|
||||
def = []byte(`{
|
||||
"timeout":"0s",
|
||||
"disable-keep-alive": false,
|
||||
"disable-compression": false,
|
||||
"http2": true,
|
||||
"tls": ` + string(cmptls.DefaultConfig(cfgcst.JSONIndent)) + `,
|
||||
"force_ip": {
|
||||
@@ -119,7 +123,10 @@ func (o Options) Validate() liberr.Error {
|
||||
}
|
||||
|
||||
func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Client, liberr.Error) {
|
||||
var tls libtls.TLSConfig
|
||||
var (
|
||||
tls libtls.TLSConfig
|
||||
edp *url.URL
|
||||
)
|
||||
|
||||
if t, e := o._GetTLS(def); e != nil {
|
||||
return nil, e
|
||||
@@ -127,15 +134,7 @@ func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Clien
|
||||
tls = t
|
||||
}
|
||||
|
||||
var tr *http.Transport
|
||||
|
||||
tr = GetTransport(false, false, o.Http2)
|
||||
SetTransportTLS(tr, tls, "")
|
||||
SetTransportDial(tr, o.ForceIP.Enable, o.ForceIP.Net, o.ForceIP.IP, o.ForceIP.Local)
|
||||
|
||||
if o.Proxy.Enable && o.Proxy.Endpoint != nil {
|
||||
var edp *url.URL
|
||||
|
||||
edp = &url.URL{
|
||||
Scheme: o.Proxy.Endpoint.Scheme,
|
||||
Opaque: o.Proxy.Endpoint.Opaque,
|
||||
@@ -162,11 +161,15 @@ func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Clien
|
||||
}
|
||||
}
|
||||
|
||||
if edp != nil && len(edp.String()) > 0 {
|
||||
SetTransportProxy(tr, edp)
|
||||
if edp != nil && len(edp.String()) < 1 {
|
||||
edp = nil
|
||||
}
|
||||
}
|
||||
|
||||
var tr *http.Transport
|
||||
|
||||
tr = GetTransport(tls.TlsConfig(""), edp, o.DisableKeepAlive, o.DisableCompression, o.Http2)
|
||||
SetTransportDial(tr, o.ForceIP.Enable, o.ForceIP.Net, o.ForceIP.IP, o.ForceIP.Local)
|
||||
return GetClient(tr, o.Http2, o.Timeout)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user