Make opts struct instead of map[string]interface{} for http

This commit is contained in:
ionutboangiu
2021-11-18 17:36:52 +02:00
committed by Dan Christian Bogos
parent a254569772
commit a214c505de
10 changed files with 228 additions and 343 deletions

View File

@@ -24,6 +24,7 @@ import (
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
@@ -131,7 +132,8 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) {
cfg.cacheCfg.Partitions = make(map[string]*CacheParamCfg)
cfg.listenCfg = new(ListenCfg)
cfg.httpCfg = new(HTTPCfg)
cfg.httpCfg.ClientOpts = make(map[string]interface{})
cfg.httpCfg.dialer = &net.Dialer{}
cfg.httpCfg.ClientOpts = &http.Transport{}
cfg.filterSCfg = new(FilterSCfg)
cfg.ralsCfg = new(RalsCfg)
cfg.ralsCfg.MaxComputedUsage = make(map[string]time.Duration)

View File

@@ -1773,21 +1773,21 @@ func TestDfHttpJsonCfg(t *testing.T) {
Http_Cdrs: utils.StringPointer("/cdr_http"),
Use_basic_auth: utils.BoolPointer(false),
Auth_users: utils.MapStringStringPointer(map[string]string{}),
Client_opts: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
utils.HTTPClientMaxIdleConnsCfg: 100.,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2.,
utils.HTTPClientMaxConnsPerHostCfg: 0.,
utils.HTTPClientIdleConnTimeoutCfg: "90s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0",
utils.HTTPClientExpectContinueTimeoutCfg: "0",
utils.HTTPClientForceAttemptHTTP2Cfg: true,
utils.HTTPClientDialTimeoutCfg: "30s",
utils.HTTPClientDialFallbackDelayCfg: "300ms",
utils.HTTPClientDialKeepAliveCfg: "30s",
Client_opts: &HTTPClientOptsJson{
SkipTLSVerify: utils.BoolPointer(false),
TLSHandshakeTimeout: utils.StringPointer("10s"),
DisableKeepAlives: utils.BoolPointer(false),
DisableCompression: utils.BoolPointer(false),
MaxIdleConns: utils.IntPointer(100),
MaxIdleConnsPerHost: utils.IntPointer(2),
MaxConnsPerHost: utils.IntPointer(0),
IdleConnTimeout: utils.StringPointer("90s"),
ResponseHeaderTimeout: utils.StringPointer("0"),
ExpectContinueTimeout: utils.StringPointer("0"),
ForceAttemptHTTP2: utils.BoolPointer(true),
DialTimeout: utils.StringPointer("30s"),
DialFallbackDelay: utils.StringPointer("300ms"),
DialKeepAlive: utils.StringPointer("30s"),
},
}
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))

File diff suppressed because one or more lines are too long

View File

@@ -19,6 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package config
import (
"crypto/tls"
"net"
"net/http"
"github.com/cgrates/cgrates/utils"
)
@@ -31,7 +35,81 @@ type HTTPCfg struct {
HTTPCDRsURL string // CDRS relative URL ("" to disable)
HTTPUseBasicAuth bool // Use basic auth for HTTP API
HTTPAuthUsers map[string]string // Basic auth user:password map (base64 passwords)
ClientOpts map[string]interface{}
ClientOpts *http.Transport
dialer *net.Dialer
}
func newDialer(dialer *net.Dialer, jsnCfg *HTTPClientOptsJson) (err error) {
if jsnCfg == nil {
return
}
dialer.DualStack = true
if jsnCfg.DialTimeout != nil {
if dialer.Timeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.DialTimeout); err != nil {
return
}
}
if jsnCfg.DialFallbackDelay != nil {
if dialer.FallbackDelay, err = utils.ParseDurationWithNanosecs(*jsnCfg.DialFallbackDelay); err != nil {
return
}
}
if jsnCfg.DialKeepAlive != nil {
if dialer.KeepAlive, err = utils.ParseDurationWithNanosecs(*jsnCfg.DialKeepAlive); err != nil {
return
}
}
return
}
func loadTransportFromJSONCfg(httpOpts *http.Transport, httpDialer *net.Dialer, jsnCfg *HTTPClientOptsJson) (err error) {
if jsnCfg == nil {
return
}
httpOpts.Proxy = http.ProxyFromEnvironment
if jsnCfg.SkipTLSVerify != nil {
httpOpts.TLSClientConfig = &tls.Config{InsecureSkipVerify: *jsnCfg.SkipTLSVerify}
}
if jsnCfg.TLSHandshakeTimeout != nil {
if httpOpts.TLSHandshakeTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.TLSHandshakeTimeout); err != nil {
return
}
}
if jsnCfg.DisableKeepAlives != nil {
httpOpts.DisableKeepAlives = *jsnCfg.DisableKeepAlives
}
if jsnCfg.DisableCompression != nil {
httpOpts.DisableCompression = *jsnCfg.DisableCompression
}
if jsnCfg.MaxIdleConns != nil {
httpOpts.MaxIdleConns = *jsnCfg.MaxIdleConns
}
if jsnCfg.MaxIdleConnsPerHost != nil {
httpOpts.MaxIdleConnsPerHost = *jsnCfg.MaxIdleConnsPerHost
}
if jsnCfg.MaxConnsPerHost != nil {
httpOpts.MaxConnsPerHost = *jsnCfg.MaxConnsPerHost
}
if jsnCfg.IdleConnTimeout != nil {
if httpOpts.IdleConnTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.IdleConnTimeout); err != nil {
return
}
}
if jsnCfg.ResponseHeaderTimeout != nil {
if httpOpts.ResponseHeaderTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.ResponseHeaderTimeout); err != nil {
return
}
}
if jsnCfg.ExpectContinueTimeout != nil {
if httpOpts.ExpectContinueTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.ExpectContinueTimeout); err != nil {
return
}
}
if jsnCfg.ForceAttemptHTTP2 != nil {
httpOpts.ForceAttemptHTTP2 = *jsnCfg.ForceAttemptHTTP2
}
httpOpts.DialContext = httpDialer.DialContext
return
}
// loadFromJSONCfg loads Database config from JsonCfg
@@ -61,18 +139,34 @@ func (httpcfg *HTTPCfg) loadFromJSONCfg(jsnHTTPCfg *HTTPJsonCfg) (err error) {
httpcfg.HTTPAuthUsers = *jsnHTTPCfg.Auth_users
}
if jsnHTTPCfg.Client_opts != nil {
for k, v := range jsnHTTPCfg.Client_opts {
httpcfg.ClientOpts[k] = v
if err = newDialer(httpcfg.dialer, jsnHTTPCfg.Client_opts); err != nil {
return
}
err = loadTransportFromJSONCfg(httpcfg.ClientOpts, httpcfg.dialer, jsnHTTPCfg.Client_opts)
}
return nil
}
// AsMapInterface returns the config as a map[string]interface{}
func (httpcfg *HTTPCfg) AsMapInterface() map[string]interface{} {
clientOpts := make(map[string]interface{})
for k, v := range httpcfg.ClientOpts {
clientOpts[k] = v
clientOpts := map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: httpcfg.ClientOpts.TLSHandshakeTimeout.String(),
utils.HTTPClientDisableKeepAlivesCfg: httpcfg.ClientOpts.DisableKeepAlives,
utils.HTTPClientDisableCompressionCfg: httpcfg.ClientOpts.DisableCompression,
utils.HTTPClientMaxIdleConnsCfg: httpcfg.ClientOpts.MaxIdleConns,
utils.HTTPClientMaxIdleConnsPerHostCfg: httpcfg.ClientOpts.MaxIdleConnsPerHost,
utils.HTTPClientMaxConnsPerHostCfg: httpcfg.ClientOpts.MaxConnsPerHost,
utils.HTTPClientIdleConnTimeoutCfg: httpcfg.ClientOpts.IdleConnTimeout.String(),
utils.HTTPClientResponseHeaderTimeoutCfg: httpcfg.ClientOpts.ResponseHeaderTimeout.String(),
utils.HTTPClientExpectContinueTimeoutCfg: httpcfg.ClientOpts.ExpectContinueTimeout.String(),
utils.HTTPClientForceAttemptHTTP2Cfg: httpcfg.ClientOpts.ForceAttemptHTTP2,
utils.HTTPClientDialTimeoutCfg: httpcfg.dialer.Timeout.String(),
utils.HTTPClientDialFallbackDelayCfg: httpcfg.dialer.FallbackDelay.String(),
utils.HTTPClientDialKeepAliveCfg: httpcfg.dialer.KeepAlive.String(),
}
if httpcfg.ClientOpts.TLSClientConfig != nil {
clientOpts[utils.HTTPClientTLSClientConfigCfg] = httpcfg.ClientOpts.TLSClientConfig.InsecureSkipVerify
}
return map[string]interface{}{
utils.HTTPJsonRPCURLCfg: httpcfg.HTTPJsonRPCURL,
@@ -88,6 +182,12 @@ func (httpcfg *HTTPCfg) AsMapInterface() map[string]interface{} {
// Clone returns a deep copy of HTTPCfg
func (httpcfg HTTPCfg) Clone() (cln *HTTPCfg) {
dialer := &net.Dialer{
Timeout: httpcfg.dialer.Timeout,
DualStack: httpcfg.dialer.DualStack,
KeepAlive: httpcfg.dialer.KeepAlive,
FallbackDelay: httpcfg.dialer.FallbackDelay,
}
cln = &HTTPCfg{
HTTPJsonRPCURL: httpcfg.HTTPJsonRPCURL,
RegistrarSURL: httpcfg.RegistrarSURL,
@@ -96,13 +196,11 @@ func (httpcfg HTTPCfg) Clone() (cln *HTTPCfg) {
HTTPCDRsURL: httpcfg.HTTPCDRsURL,
HTTPUseBasicAuth: httpcfg.HTTPUseBasicAuth,
HTTPAuthUsers: make(map[string]string),
ClientOpts: make(map[string]interface{}),
ClientOpts: httpcfg.ClientOpts.Clone(),
dialer: dialer,
}
for u, a := range httpcfg.HTTPAuthUsers {
cln.HTTPAuthUsers[u] = a
}
for o, val := range httpcfg.ClientOpts {
cln.ClientOpts[o] = val
}
return
}

View File

@@ -18,8 +18,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package config
import (
"crypto/tls"
"net"
"net/http"
"reflect"
"testing"
"time"
"github.com/cgrates/cgrates/utils"
)
@@ -42,28 +46,34 @@ func TestHTTPCfgloadFromJsonCfg(t *testing.T) {
HTTPCDRsURL: "/cdr_http",
HTTPUseBasicAuth: false,
HTTPAuthUsers: map[string]string{},
ClientOpts: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
utils.HTTPClientMaxIdleConnsCfg: 100.,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2.,
utils.HTTPClientMaxConnsPerHostCfg: 0.,
utils.HTTPClientIdleConnTimeoutCfg: "90s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0",
utils.HTTPClientExpectContinueTimeoutCfg: "0",
utils.HTTPClientForceAttemptHTTP2Cfg: true,
utils.HTTPClientDialTimeoutCfg: "30s",
utils.HTTPClientDialFallbackDelayCfg: "300ms",
utils.HTTPClientDialKeepAliveCfg: "30s",
ClientOpts: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
},
TLSHandshakeTimeout: 10 * time.Second,
DisableKeepAlives: false,
DisableCompression: false,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 2,
MaxConnsPerHost: 0,
IdleConnTimeout: 90 * time.Second,
ResponseHeaderTimeout: 0,
ExpectContinueTimeout: 0,
ForceAttemptHTTP2: true,
},
dialer: &net.Dialer{
Timeout: 30 * time.Second,
FallbackDelay: 300 * time.Millisecond,
KeepAlive: 30 * time.Second,
DualStack: true,
},
}
cfgJsn := NewDefaultCGRConfig()
if err = cfgJsn.httpCfg.loadFromJSONCfg(cfgJSONStr); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expected, cfgJsn.httpCfg) {
t.Errorf("Expected %+v \n, received %+v", utils.ToJSON(expected), utils.ToJSON(cfgJsn.httpCfg))
} else if !reflect.DeepEqual(expected.AsMapInterface(), cfgJsn.httpCfg.AsMapInterface()) {
t.Errorf("Expected %+v \n, received %+v", expected.AsMapInterface(), cfgJsn.httpCfg.AsMapInterface())
}
}
@@ -84,12 +94,12 @@ func TestHTTPCfgAsMapInterface(t *testing.T) {
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
utils.HTTPClientMaxIdleConnsCfg: 100.,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2.,
utils.HTTPClientMaxConnsPerHostCfg: 0.,
utils.HTTPClientIdleConnTimeoutCfg: "90s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0",
utils.HTTPClientExpectContinueTimeoutCfg: "0",
utils.HTTPClientMaxIdleConnsCfg: 100,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2,
utils.HTTPClientMaxConnsPerHostCfg: 0,
utils.HTTPClientIdleConnTimeoutCfg: "1m30s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0s",
utils.HTTPClientExpectContinueTimeoutCfg: "0s",
utils.HTTPClientForceAttemptHTTP2Cfg: true,
utils.HTTPClientDialTimeoutCfg: "30s",
utils.HTTPClientDialFallbackDelayCfg: "300ms",
@@ -128,12 +138,12 @@ func TestHTTPCfgAsMapInterface1(t *testing.T) {
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
utils.HTTPClientMaxIdleConnsCfg: 100.,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2.,
utils.HTTPClientMaxConnsPerHostCfg: 0.,
utils.HTTPClientIdleConnTimeoutCfg: "90s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0",
utils.HTTPClientExpectContinueTimeoutCfg: "0",
utils.HTTPClientMaxIdleConnsCfg: 100,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2,
utils.HTTPClientMaxConnsPerHostCfg: 0,
utils.HTTPClientIdleConnTimeoutCfg: "1m30s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0s",
utils.HTTPClientExpectContinueTimeoutCfg: "0s",
utils.HTTPClientForceAttemptHTTP2Cfg: true,
utils.HTTPClientDialTimeoutCfg: "30s",
utils.HTTPClientDialFallbackDelayCfg: "300ms",
@@ -143,7 +153,7 @@ func TestHTTPCfgAsMapInterface1(t *testing.T) {
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
t.Error(err)
} else if rcv := cgrCfg.httpCfg.AsMapInterface(); !reflect.DeepEqual(rcv, eMap) {
t.Errorf("Expected %+v, received %+v", eMap, rcv)
t.Errorf("Expected %+v, received %+v", utils.ToJSON(eMap), utils.ToJSON(rcv))
}
}
@@ -158,15 +168,35 @@ func TestHTTPCfgClone(t *testing.T) {
HTTPAuthUsers: map[string]string{
"user": "pass",
},
ClientOpts: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
ClientOpts: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
},
TLSHandshakeTimeout: 10 * time.Second,
DisableKeepAlives: false,
DisableCompression: false,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 2,
MaxConnsPerHost: 0,
IdleConnTimeout: 90 * time.Second,
ResponseHeaderTimeout: 0,
ExpectContinueTimeout: 0,
ForceAttemptHTTP2: true,
},
dialer: &net.Dialer{
Timeout: 30 * time.Second,
FallbackDelay: 300 * time.Millisecond,
KeepAlive: 30 * time.Second,
DualStack: true,
},
}
rcv := ban.Clone()
if !reflect.DeepEqual(ban, rcv) {
t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv))
if !reflect.DeepEqual(rcv.AsMapInterface(), ban.AsMapInterface()) {
t.Errorf("Expected: %+v\nReceived: %+v", ban.AsMapInterface(),
rcv.AsMapInterface())
}
if rcv.ClientOpts[utils.HTTPClientTLSClientConfigCfg] = ""; ban.ClientOpts[utils.HTTPClientTLSClientConfigCfg] != false {
if rcv.ClientOpts.MaxIdleConns = 50; ban.ClientOpts.MaxIdleConns != 100 {
t.Errorf("Expected clone to not modify the cloned")
}
if rcv.HTTPAuthUsers["user"] = ""; ban.HTTPAuthUsers["user"] != "pass" {

View File

@@ -59,6 +59,23 @@ type ListenJsonCfg struct {
Http_tls *string
}
type HTTPClientOptsJson struct {
SkipTLSVerify *bool `json:"skipTlsVerify"`
TLSHandshakeTimeout *string `json:"tlsHandshakeTimeout"`
DisableKeepAlives *bool `json:"disableKeepAlives"`
DisableCompression *bool `json:"disableCompression"`
MaxIdleConns *int `json:"maxIdleConns"`
MaxIdleConnsPerHost *int `json:"maxIdleConnsPerHost"`
MaxConnsPerHost *int `json:"maxConnsPerHost"`
IdleConnTimeout *string `json:"IdleConnTimeout"`
ResponseHeaderTimeout *string `json:"responseHeaderTimeout"`
ExpectContinueTimeout *string `json:"expectContinueTimeout"`
ForceAttemptHTTP2 *bool `json:"forceAttemptHttp2"`
DialTimeout *string `json:"dialTimeout"`
DialFallbackDelay *string `json:"dialFallbackDelay"`
DialKeepAlive *string `json:"dialKeepAlive"`
}
// HTTP config section
type HTTPJsonCfg struct {
Json_rpc_url *string
@@ -68,7 +85,7 @@ type HTTPJsonCfg struct {
Http_Cdrs *string
Use_basic_auth *bool
Auth_users *map[string]string
Client_opts map[string]interface{}
Client_opts *HTTPClientOptsJson
}
type TlsJsonCfg struct {

View File

@@ -16,17 +16,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package engine
import (
"crypto/tls"
"net"
"net/http"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
)
// this file will contain all the global variable that are used by other subsystems
@@ -40,7 +35,7 @@ var (
func init() {
dm = NewDataManager(NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items), config.CgrConfig().CacheCfg(), connMgr)
httpPstrTransport, _ = NewHTTPTransport(config.CgrConfig().HTTPCfg().ClientOpts)
httpPstrTransport = config.CgrConfig().HTTPCfg().ClientOpts
}
// SetDataStorage is the exported method to set the storage getter.
@@ -67,122 +62,3 @@ func SetHTTPPstrTransport(pstrTransport *http.Transport) {
func GetHTTPPstrTransport() *http.Transport {
return httpPstrTransport
}
// NewHTTPTransport will create a new transport for HTTP client
func NewHTTPTransport(opts map[string]interface{}) (trsp *http.Transport, err error) {
trsp = &http.Transport{
Proxy: http.ProxyFromEnvironment,
}
if val, has := opts[utils.HTTPClientTLSClientConfigCfg]; has {
var skipTLSVerify bool
if skipTLSVerify, err = utils.IfaceAsBool(val); err != nil {
return
}
trsp.TLSClientConfig = &tls.Config{InsecureSkipVerify: skipTLSVerify}
}
if val, has := opts[utils.HTTPClientTLSHandshakeTimeoutCfg]; has {
var tlsHndTimeout time.Duration
if tlsHndTimeout, err = utils.IfaceAsDuration(val); err != nil {
return
}
trsp.TLSHandshakeTimeout = tlsHndTimeout
}
if val, has := opts[utils.HTTPClientDisableKeepAlivesCfg]; has {
var disKeepAlives bool
if disKeepAlives, err = utils.IfaceAsBool(val); err != nil {
return
}
trsp.DisableKeepAlives = disKeepAlives
}
if val, has := opts[utils.HTTPClientDisableCompressionCfg]; has {
var disCmp bool
if disCmp, err = utils.IfaceAsBool(val); err != nil {
return
}
trsp.DisableCompression = disCmp
}
if val, has := opts[utils.HTTPClientMaxIdleConnsCfg]; has {
var maxIdleConns int64
if maxIdleConns, err = utils.IfaceAsTInt64(val); err != nil {
return
}
trsp.MaxIdleConns = int(maxIdleConns)
}
if val, has := opts[utils.HTTPClientMaxIdleConnsPerHostCfg]; has {
var maxIdleConns int64
if maxIdleConns, err = utils.IfaceAsTInt64(val); err != nil {
return
}
trsp.MaxIdleConnsPerHost = int(maxIdleConns)
}
if val, has := opts[utils.HTTPClientMaxConnsPerHostCfg]; has {
var maxConns int64
if maxConns, err = utils.IfaceAsTInt64(val); err != nil {
return
}
trsp.MaxConnsPerHost = int(maxConns)
}
if val, has := opts[utils.HTTPClientIdleConnTimeoutCfg]; has {
var idleTimeout time.Duration
if idleTimeout, err = utils.IfaceAsDuration(val); err != nil {
return
}
trsp.IdleConnTimeout = idleTimeout
}
if val, has := opts[utils.HTTPClientResponseHeaderTimeoutCfg]; has {
var responseTimeout time.Duration
if responseTimeout, err = utils.IfaceAsDuration(val); err != nil {
return
}
trsp.ResponseHeaderTimeout = responseTimeout
}
if val, has := opts[utils.HTTPClientExpectContinueTimeoutCfg]; has {
var continueTimeout time.Duration
if continueTimeout, err = utils.IfaceAsDuration(val); err != nil {
return
}
trsp.ExpectContinueTimeout = continueTimeout
}
if val, has := opts[utils.HTTPClientForceAttemptHTTP2Cfg]; has {
var forceHTTP2 bool
if forceHTTP2, err = utils.IfaceAsBool(val); err != nil {
return
}
trsp.ForceAttemptHTTP2 = forceHTTP2
}
var dial *net.Dialer
if dial, err = newDialer(opts); err != nil {
return
}
trsp.DialContext = dial.DialContext
return
}
// newDialer returns the objects that creates the DialContext function
func newDialer(opts map[string]interface{}) (dial *net.Dialer, err error) {
dial = &net.Dialer{
DualStack: true,
}
if val, has := opts[utils.HTTPClientDialTimeoutCfg]; has {
var timeout time.Duration
if timeout, err = utils.IfaceAsDuration(val); err != nil {
return
}
dial.Timeout = timeout
}
if val, has := opts[utils.HTTPClientDialFallbackDelayCfg]; has {
var fallDelay time.Duration
if fallDelay, err = utils.IfaceAsDuration(val); err != nil {
return
}
dial.FallbackDelay = fallDelay
}
if val, has := opts[utils.HTTPClientDialKeepAliveCfg]; has {
var keepAlive time.Duration
if keepAlive, err = utils.IfaceAsDuration(val); err != nil {
return
}
dial.KeepAlive = keepAlive
}
return
}

View File

@@ -18,132 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"crypto/tls"
"net"
"net/http"
"testing"
"time"
"github.com/cgrates/cgrates/utils"
)
func TestNewHTTPTransport(t *testing.T) {
opts := map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
utils.HTTPClientMaxIdleConnsCfg: 100.,
utils.HTTPClientMaxIdleConnsPerHostCfg: 2.,
utils.HTTPClientMaxConnsPerHostCfg: 0.,
utils.HTTPClientIdleConnTimeoutCfg: "90s",
utils.HTTPClientResponseHeaderTimeoutCfg: "0",
utils.HTTPClientExpectContinueTimeoutCfg: "0",
utils.HTTPClientForceAttemptHTTP2Cfg: true,
utils.HTTPClientDialTimeoutCfg: "30s",
utils.HTTPClientDialFallbackDelayCfg: "300ms",
utils.HTTPClientDialKeepAliveCfg: "30s",
}
expDialer := &net.Dialer{
DualStack: true,
Timeout: 30 * time.Second,
FallbackDelay: 300 * time.Millisecond,
KeepAlive: 30 * time.Second,
}
if dial, err := newDialer(opts); err != nil {
t.Fatal(err)
} else if !(expDialer != nil && dial != nil &&
expDialer.DualStack == dial.DualStack &&
expDialer.Timeout == dial.Timeout &&
expDialer.FallbackDelay == dial.FallbackDelay &&
expDialer.KeepAlive == dial.KeepAlive) {
t.Errorf("Expected %+v, received %+v", expDialer, dial)
}
expTransport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
TLSHandshakeTimeout: 10 * time.Second,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 2,
MaxConnsPerHost: 0,
IdleConnTimeout: 90 * time.Second,
ForceAttemptHTTP2: true,
}
if trsp, err := NewHTTPTransport(opts); err != nil {
t.Fatal(err)
} else if !(expTransport != nil && trsp != nil && // the dial options are not included
expTransport.TLSClientConfig.InsecureSkipVerify == trsp.TLSClientConfig.InsecureSkipVerify &&
expTransport.TLSHandshakeTimeout == trsp.TLSHandshakeTimeout &&
expTransport.DisableKeepAlives == trsp.DisableKeepAlives &&
expTransport.DisableCompression == trsp.DisableCompression &&
expTransport.MaxIdleConns == trsp.MaxIdleConns &&
expTransport.MaxIdleConnsPerHost == trsp.MaxIdleConnsPerHost &&
expTransport.MaxConnsPerHost == trsp.MaxConnsPerHost &&
expTransport.IdleConnTimeout == trsp.IdleConnTimeout &&
expTransport.ResponseHeaderTimeout == trsp.ResponseHeaderTimeout &&
expTransport.ExpectContinueTimeout == trsp.ExpectContinueTimeout &&
expTransport.ForceAttemptHTTP2 == trsp.ForceAttemptHTTP2) {
t.Errorf("Expected %+v, received %+v", expTransport, trsp)
}
opts[utils.HTTPClientDialKeepAliveCfg] = "30as"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientDialFallbackDelayCfg] = "300ams"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientDialTimeoutCfg] = "30as"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientForceAttemptHTTP2Cfg] = "string"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientExpectContinueTimeoutCfg] = "0a"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientResponseHeaderTimeoutCfg] = "0a"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientIdleConnTimeoutCfg] = "90as"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientMaxConnsPerHostCfg] = "not a number"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientMaxIdleConnsPerHostCfg] = "not a number"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientMaxIdleConnsCfg] = "not a number"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientDisableCompressionCfg] = "string"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientDisableKeepAlivesCfg] = "string"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientTLSHandshakeTimeoutCfg] = "10as"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientTLSClientConfigCfg] = "string"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
}
func TestSetHTTPPstrTransport(t *testing.T) {
tmp := httpPstrTransport
SetHTTPPstrTransport(nil)

View File

@@ -19,8 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package services
import (
"fmt"
"net/http"
"sync"
"github.com/cgrates/cgrates/ees"
@@ -50,12 +48,14 @@ type GlobalVarS struct {
func (gv *GlobalVarS) Start() (err error) {
engine.SetRoundingDecimals(gv.cfg.GeneralCfg().RoundingDecimals)
ees.SetFailedPostCacheTTL(gv.cfg.GeneralCfg().FailedPostsTTL)
return gv.initHTTPTransport()
engine.SetHTTPPstrTransport(gv.cfg.HTTPCfg().ClientOpts)
return nil
}
// Reload handles the change of config
func (gv *GlobalVarS) Reload() (err error) {
return gv.initHTTPTransport()
engine.SetHTTPPstrTransport(gv.cfg.HTTPCfg().ClientOpts)
return nil
}
// Shutdown stops the service
@@ -77,13 +77,3 @@ func (gv *GlobalVarS) ServiceName() string {
func (gv *GlobalVarS) ShouldRun() bool {
return true
}
func (gv *GlobalVarS) initHTTPTransport() (err error) {
var trsp *http.Transport
if trsp, err = engine.NewHTTPTransport(gv.cfg.HTTPCfg().ClientOpts); err != nil {
utils.Logger.Crit(fmt.Sprintf("Could not configure the http transport: %s exiting!", err))
return
}
engine.SetHTTPPstrTransport(trsp)
return
}

View File

@@ -53,13 +53,6 @@ func TestGlobalVarsReload(t *testing.T) {
if err3 != true {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", true, err3)
}
cfg.HTTPCfg().ClientOpts = map[string]interface{}{
utils.HTTPClientTLSHandshakeTimeoutCfg: false,
}
err = srv.(*GlobalVarS).initHTTPTransport()
if err == nil || err.Error() != "cannot convert field: false to time.Duration" {
t.Errorf("\nExpected <nil>, \nReceived <%+v>", err)
}
err = srv.Shutdown()
if err != nil {
t.Errorf("\nExpected <nil>, \nReceived <%+v>", err)