Make ClientOpts of type struct in httpcfg

This commit is contained in:
ionutboangiu
2021-10-20 17:07:44 +03:00
committed by Dan Christian Bogos
parent 5a92ce47cb
commit 9ba6df7fc0
14 changed files with 227 additions and 177 deletions

View File

@@ -104,10 +104,12 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) {
Items: make(map[string]*ItemOpt),
Opts: &StorDBOpts{},
},
tlsCfg: new(TLSCfg),
cacheCfg: &CacheCfg{Partitions: make(map[string]*CacheParamCfg)},
listenCfg: new(ListenCfg),
httpCfg: &HTTPCfg{ClientOpts: make(map[string]interface{})},
tlsCfg: new(TLSCfg),
cacheCfg: &CacheCfg{Partitions: make(map[string]*CacheParamCfg)},
listenCfg: new(ListenCfg),
httpCfg: &HTTPCfg{
ClientOpts: &HTTPClientOpts{},
},
filterSCfg: new(FilterSCfg),
cdrsCfg: &CdrsCfg{Opts: &CdrsOpts{
Accounts: []*utils.DynamicBoolOpt{},

View File

@@ -197,7 +197,7 @@ const CGRATES_CFG_JSON = `
"use_basic_auth": false, // use basic authentication
"auth_users": {}, // basic authentication usernames and base64-encoded passwords (eg: { "username1": "cGFzc3dvcmQ=", "username2": "cGFzc3dvcmQy "})
"client_opts":{
"skipTlsVerify": false, // if enabled Http Client will accept any TLS certificate
"skipTLSVerification": false, // if enabled Http Client will accept any TLS certificate
// the options to configure the http.Transport
"tlsHandshakeTimeout": "10s",
"disableKeepAlives": false,

View File

@@ -919,7 +919,7 @@ func testCGRConfigReloadConfigFromStringSessionS(t *testing.T) {
}
var rcv string
expected := `{"sessions":{"accounts_conns":[],"actions_conns":[],"alterable_fields":[],"attributes_conns":["*localhost"],"cdrs_conns":["*internal"],"channel_sync_interval":"0","chargers_conns":["*localhost"],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":true,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","opts":{"*accountS":[],"*attributeS":[],"*attributesDerivedReply":[],"*blockerError":[],"*cdrS":[],"*cdrsDerivedReply":[],"*chargeable":[],"*chargerS":[],"*debitInterval":[],"*forceDuration":[],"*initiate":[],"*lastUsage":[],"*lastUsed":[],"*maxDelay":[],"*maxUsage":[],"*message":[],"*resourceS":[],"*resourcesAllocate":[],"*resourcesAuthorize":[],"*resourcesDerivedReply":[],"*resourcesRelease":[],"*routeS":[],"*routesDerivedReply":[],"*statS":[],"*statsDerivedReply":[],"*terminate":[],"*thresholdS":[],"*thresholdsDerivedReply":[],"*ttl":[],"*update":[],"*usage":[]},"rates_conns":[],"replication_conns":[],"resources_conns":["*localhost"],"routes_conns":["*localhost"],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}`
expected := `{"sessions":{"accounts_conns":[],"actions_conns":[],"alterable_fields":[],"attributes_conns":["*localhost"],"cdrs_conns":["*internal"],"channel_sync_interval":"0","chargers_conns":["*localhost"],"client_protocol":1,"default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":true,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","opts":{"*accountS":[],"*attributeS":[],"*attributesDerivedReply":[],"*blockerError":[],"*cdrS":[],"*cdrsDerivedReply":[],"*chargeable":[],"*chargerS":[],"*debitInterval":[],"*forceDuration":[],"*initiate":[],"*maxUsage":[],"*message":[],"*resourceS":[],"*resourcesAllocate":[],"*resourcesAuthorize":[],"*resourcesDerivedReply":[],"*resourcesRelease":[],"*routeS":[],"*routesDerivedReply":[],"*statS":[],"*statsDerivedReply":[],"*terminate":[],"*thresholdS":[],"*thresholdsDerivedReply":[],"*ttl":[],"*ttlLastUsage":[],"*ttlLastUsed":[],"*ttlMaxDelay":[],"*ttlUsage":[],"*update":[]},"rates_conns":[],"replication_conns":[],"resources_conns":["*localhost"],"routes_conns":["*localhost"],"session_indexes":[],"stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]}}`
if err := cfg.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Sections: []string{SessionSJSON}}, &rcv); err != nil {
t.Error(err)
} else if expected != rcv {

View File

@@ -1719,7 +1719,7 @@ func TestDfHttpJsonCfg(t *testing.T) {
Use_basic_auth: utils.BoolPointer(false),
Auth_users: utils.MapStringStringPointer(map[string]string{}),
Client_opts: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,

View File

@@ -3956,7 +3956,7 @@ func TestV1GetConfigHTTP(t *testing.T) {
utils.HTTPUseBasicAuthCfg: false,
utils.HTTPAuthUsersCfg: map[string]string{},
utils.HTTPClientOptsCfg: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
@@ -5080,7 +5080,7 @@ func TestV1GetConfigAsJSONAccounts(t *testing.T) {
func TestV1GetConfigAsJSONHTTP(t *testing.T) {
var reply string
expected := `{"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0","forceAttemptHttp2":true,"idleConnTimeout":"90s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"}}`
expected := `{"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0","forceAttemptHttp2":true,"idleConnTimeout":"90s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0","skipTLSVerification":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"}}`
cfgCgr := NewDefaultCGRConfig()
if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Sections: []string{HTTPJSON}}, &reply); err != nil {
t.Error(err)

View File

@@ -19,10 +19,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package config
import (
"crypto/tls"
"net"
"net/http"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/utils"
)
type HTTPClientOpts struct {
Transport *http.Transport
Dialer *net.Dialer
}
// HTTPCfg is the HTTP config section
type HTTPCfg struct {
JsonRPCURL string // JSON RPC relative URL ("" to disable)
@@ -32,7 +41,7 @@ type HTTPCfg struct {
CDRsURL string // CDRS relative URL ("" to disable)
UseBasicAuth bool // Use basic auth for HTTP API
AuthUsers map[string]string // Basic auth user:password map (base64 passwords)
ClientOpts map[string]interface{}
ClientOpts *HTTPClientOpts
}
// loadHTTPCfg loads the Http section of the configuration
@@ -44,6 +53,86 @@ func (httpcfg *HTTPCfg) Load(ctx *context.Context, jsnCfg ConfigDB, _ *CGRConfig
return httpcfg.loadFromJSONCfg(jsnHTTPCfg)
}
func newDialer(jsnCfg *HTTPClientOptsJson) (dialer *net.Dialer, err error) {
if jsnCfg == nil {
return
}
dialer = &net.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 (httpOpts *HTTPClientOpts) loadFromJSONCfg(jsnCfg *HTTPClientOptsJson) (err error) {
if jsnCfg == nil {
return
}
httpOpts.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
}
if jsnCfg.SkipTLSVerification != nil {
httpOpts.Transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: *jsnCfg.SkipTLSVerification}
}
if jsnCfg.TLSHandshakeTimeout != nil {
if httpOpts.Transport.TLSHandshakeTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.TLSHandshakeTimeout); err != nil {
return
}
}
if jsnCfg.DisableKeepAlives != nil {
httpOpts.Transport.DisableKeepAlives = *jsnCfg.DisableKeepAlives
}
if jsnCfg.DisableCompression != nil {
httpOpts.Transport.DisableCompression = *jsnCfg.DisableCompression
}
if jsnCfg.MaxIdleConns != nil {
httpOpts.Transport.MaxIdleConns = *jsnCfg.MaxIdleConns
}
if jsnCfg.MaxIdleConnsPerHost != nil {
httpOpts.Transport.MaxIdleConnsPerHost = *jsnCfg.MaxIdleConnsPerHost
}
if jsnCfg.MaxConnsPerHost != nil {
httpOpts.Transport.MaxConnsPerHost = *jsnCfg.MaxConnsPerHost
}
if jsnCfg.IdleConnTimeout != nil {
if httpOpts.Transport.IdleConnTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.IdleConnTimeout); err != nil {
return
}
}
if jsnCfg.ResponseHeaderTimeout != nil {
if httpOpts.Transport.ResponseHeaderTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.ResponseHeaderTimeout); err != nil {
return
}
}
if jsnCfg.ExpectContinueTimeout != nil {
if httpOpts.Transport.ExpectContinueTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.ExpectContinueTimeout); err != nil {
return
}
}
if jsnCfg.ForceAttemptHTTP2 != nil {
httpOpts.Transport.ForceAttemptHTTP2 = *jsnCfg.ForceAttemptHTTP2
}
if httpOpts.Dialer, err = newDialer(jsnCfg); err != nil {
return
}
httpOpts.Transport.DialContext = httpOpts.Dialer.DialContext
return
}
// loadFromJSONCfg loads Database config from JsonCfg
func (httpcfg *HTTPCfg) loadFromJSONCfg(jsnHTTPCfg *HTTPJsonCfg) (err error) {
if jsnHTTPCfg == nil {
@@ -71,18 +160,28 @@ func (httpcfg *HTTPCfg) loadFromJSONCfg(jsnHTTPCfg *HTTPJsonCfg) (err error) {
httpcfg.AuthUsers = *jsnHTTPCfg.Auth_users
}
if jsnHTTPCfg.Client_opts != nil {
for k, v := range jsnHTTPCfg.Client_opts {
httpcfg.ClientOpts[k] = v
}
err = httpcfg.ClientOpts.loadFromJSONCfg(jsnHTTPCfg.Client_opts)
}
return nil
}
// AsMapInterface returns the config as a map[string]interface{}
func (httpcfg HTTPCfg) AsMapInterface(string) interface{} {
clientOpts := make(map[string]interface{})
for k, v := range httpcfg.ClientOpts {
clientOpts[k] = v
clientOpts := map[string]interface{}{
utils.HTTPClientSkipTLSVerificationCfg: httpcfg.ClientOpts.Transport.TLSClientConfig.InsecureSkipVerify,
utils.HTTPClientTLSHandshakeTimeoutCfg: httpcfg.ClientOpts.Transport.TLSHandshakeTimeout,
utils.HTTPClientDisableKeepAlivesCfg: httpcfg.ClientOpts.Transport.DisableKeepAlives,
utils.HTTPClientDisableCompressionCfg: httpcfg.ClientOpts.Transport.DisableCompression,
utils.HTTPClientMaxIdleConnsCfg: httpcfg.ClientOpts.Transport.MaxIdleConns,
utils.HTTPClientMaxIdleConnsPerHostCfg: httpcfg.ClientOpts.Transport.MaxIdleConnsPerHost,
utils.HTTPClientMaxConnsPerHostCfg: httpcfg.ClientOpts.Transport.MaxConnsPerHost,
utils.HTTPClientIdleConnTimeoutCfg: httpcfg.ClientOpts.Transport.IdleConnTimeout,
utils.HTTPClientResponseHeaderTimeoutCfg: httpcfg.ClientOpts.Transport.ResponseHeaderTimeout,
utils.HTTPClientExpectContinueTimeoutCfg: httpcfg.ClientOpts.Transport.ExpectContinueTimeout,
utils.HTTPClientForceAttemptHTTP2Cfg: httpcfg.ClientOpts.Transport.ForceAttemptHTTP2,
utils.HTTPClientDialTimeoutCfg: httpcfg.ClientOpts.Dialer.Timeout,
utils.HTTPClientDialFallbackDelayCfg: httpcfg.ClientOpts.Dialer.FallbackDelay,
utils.HTTPClientDialKeepAliveCfg: httpcfg.ClientOpts.Dialer.KeepAlive,
}
return map[string]interface{}{
utils.HTTPJsonRPCURLCfg: httpcfg.JsonRPCURL,
@@ -99,6 +198,33 @@ func (httpcfg HTTPCfg) AsMapInterface(string) interface{} {
func (HTTPCfg) SName() string { return HTTPJSON }
func (httpcfg HTTPCfg) CloneSection() Section { return httpcfg.Clone() }
func (httpOpts *HTTPClientOpts) Clone() (cln *HTTPClientOpts) {
transport := &http.Transport{
Proxy: httpOpts.Transport.Proxy,
TLSClientConfig: httpOpts.Transport.TLSClientConfig,
TLSHandshakeTimeout: httpOpts.Transport.TLSHandshakeTimeout,
DisableKeepAlives: httpOpts.Transport.DisableKeepAlives,
DisableCompression: httpOpts.Transport.DisableCompression,
MaxIdleConns: httpOpts.Transport.MaxIdleConns,
MaxIdleConnsPerHost: httpOpts.Transport.MaxIdleConnsPerHost,
MaxConnsPerHost: httpOpts.Transport.MaxConnsPerHost,
IdleConnTimeout: httpOpts.Transport.IdleConnTimeout,
ResponseHeaderTimeout: httpOpts.Transport.ResponseHeaderTimeout,
ExpectContinueTimeout: httpOpts.Transport.ExpectContinueTimeout,
ForceAttemptHTTP2: httpOpts.Transport.ForceAttemptHTTP2,
}
dialer := &net.Dialer{
Timeout: httpOpts.Dialer.Timeout,
DualStack: httpOpts.Dialer.DualStack,
KeepAlive: httpOpts.Dialer.KeepAlive,
FallbackDelay: httpOpts.Dialer.FallbackDelay,
}
return &HTTPClientOpts{
Transport: transport,
Dialer: dialer,
}
}
// Clone returns a deep copy of HTTPCfg
func (httpcfg HTTPCfg) Clone() (cln *HTTPCfg) {
cln = &HTTPCfg{
@@ -109,17 +235,31 @@ func (httpcfg HTTPCfg) Clone() (cln *HTTPCfg) {
CDRsURL: httpcfg.CDRsURL,
UseBasicAuth: httpcfg.UseBasicAuth,
AuthUsers: make(map[string]string),
ClientOpts: make(map[string]interface{}),
ClientOpts: httpcfg.ClientOpts.Clone(),
}
for u, a := range httpcfg.AuthUsers {
cln.AuthUsers[u] = a
}
for o, val := range httpcfg.ClientOpts {
cln.ClientOpts[o] = val
}
return
}
type HTTPClientOptsJson struct {
SkipTLSVerification *bool `json:"skipTLSVerification"`
TLSHandshakeTimeout *string `json:"tlsHandshakeTimeout"`
DisableKeepAlives *bool `json:"disableKeepAlives"`
DisableCompression *bool `json:"disableCompression"`
MaxIdleConns *int `json:"maxIdleConns"`
MaxIdleConnsPerHost *int `json:"maxConnsPerHost"`
MaxConnsPerHost *int `json:"maxConnsPerHost"`
IdleConnTimeout *string `json:"IdleConnTimeout"`
ResponseHeaderTimeout *string `json:"responseHeaderTimeout"`
ExpectContinueTimeout *string `json:"expectContinueTransport"`
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
@@ -129,9 +269,57 @@ type HTTPJsonCfg struct {
Http_Cdrs *string
Use_basic_auth *bool
Auth_users *map[string]string
Client_opts map[string]interface{}
Client_opts *HTTPClientOptsJson
}
func diffHTTPClientOptsJsonCfg(d *HTTPClientOptsJson, v1, v2 *HTTPClientOpts) *HTTPClientOptsJson {
if d == nil {
d = new(HTTPClientOptsJson)
}
if v1.Transport.TLSClientConfig.InsecureSkipVerify != v2.Transport.TLSClientConfig.InsecureSkipVerify {
d.SkipTLSVerification = utils.BoolPointer(v2.Transport.TLSClientConfig.InsecureSkipVerify)
}
if v1.Transport.TLSHandshakeTimeout != v2.Transport.TLSHandshakeTimeout {
d.TLSHandshakeTimeout = utils.StringPointer(v2.Transport.TLSHandshakeTimeout.String())
}
if v1.Transport.DisableKeepAlives != v2.Transport.DisableKeepAlives {
d.DisableKeepAlives = utils.BoolPointer(v2.Transport.DisableKeepAlives)
}
if v1.Transport.DisableCompression != v2.Transport.DisableCompression {
d.DisableCompression = utils.BoolPointer(v2.Transport.DisableCompression)
}
if v1.Transport.MaxIdleConns != v2.Transport.MaxIdleConns {
d.MaxIdleConns = utils.IntPointer(v2.Transport.MaxIdleConns)
}
if v1.Transport.MaxIdleConnsPerHost != v2.Transport.MaxIdleConnsPerHost {
d.MaxIdleConnsPerHost = utils.IntPointer(v2.Transport.MaxIdleConnsPerHost)
}
if v1.Transport.MaxConnsPerHost != v2.Transport.MaxConnsPerHost {
d.MaxConnsPerHost = utils.IntPointer(v2.Transport.MaxConnsPerHost)
}
if v1.Transport.IdleConnTimeout != v2.Transport.IdleConnTimeout {
d.IdleConnTimeout = utils.StringPointer(v2.Transport.IdleConnTimeout.String())
}
if v1.Transport.ResponseHeaderTimeout != v2.Transport.ResponseHeaderTimeout {
d.ResponseHeaderTimeout = utils.StringPointer(v2.Transport.ResponseHeaderTimeout.String())
}
if v1.Transport.ExpectContinueTimeout != v2.Transport.ExpectContinueTimeout {
d.ExpectContinueTimeout = utils.StringPointer(v2.Transport.ExpectContinueTimeout.String())
}
if v1.Transport.ForceAttemptHTTP2 != v2.Transport.ForceAttemptHTTP2 {
d.ForceAttemptHTTP2 = utils.BoolPointer(v2.Transport.ForceAttemptHTTP2)
}
if v1.Dialer.Timeout != v2.Dialer.Timeout {
d.DialTimeout = utils.StringPointer(v2.Dialer.Timeout.String())
}
if v1.Dialer.FallbackDelay != v2.Dialer.FallbackDelay {
d.DialFallbackDelay = utils.StringPointer(v2.Dialer.FallbackDelay.String())
}
if v1.Dialer.KeepAlive != v2.Dialer.KeepAlive {
d.DialKeepAlive = utils.StringPointer(v2.Dialer.KeepAlive.String())
}
return d
}
func diffHTTPJsonCfg(d *HTTPJsonCfg, v1, v2 *HTTPCfg) *HTTPJsonCfg {
if d == nil {
d = new(HTTPJsonCfg)
@@ -158,7 +346,7 @@ func diffHTTPJsonCfg(d *HTTPJsonCfg, v1, v2 *HTTPCfg) *HTTPJsonCfg {
if !utils.MapStringStringEqual(v1.AuthUsers, v2.AuthUsers) {
d.Auth_users = &v2.AuthUsers
}
d.Client_opts = diffMap(d.Client_opts, v1.ClientOpts, v2.ClientOpts)
d.Client_opts = diffHTTPClientOptsJsonCfg(d.Client_opts, v1.ClientOpts, v2.ClientOpts)
return d
}

View File

@@ -43,7 +43,7 @@ func TestHTTPCfgloadFromJsonCfg(t *testing.T) {
UseBasicAuth: false,
AuthUsers: map[string]string{},
ClientOpts: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
@@ -85,7 +85,7 @@ func TestHTTPCfgAsMapInterface(t *testing.T) {
utils.HTTPUseBasicAuthCfg: false,
utils.HTTPAuthUsersCfg: map[string]string{},
utils.HTTPClientOptsCfg: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
@@ -129,7 +129,7 @@ func TestHTTPCfgAsMapInterface1(t *testing.T) {
"user2": "authenticated",
},
utils.HTTPClientOptsCfg: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
@@ -164,14 +164,14 @@ func TestHTTPCfgClone(t *testing.T) {
"user": "pass",
},
ClientOpts: map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
},
}
rcv := ban.Clone()
if !reflect.DeepEqual(ban, rcv) {
t.Errorf("Expected: %+v\nReceived: %+v", utils.ToJSON(ban), utils.ToJSON(rcv))
}
if rcv.ClientOpts[utils.HTTPClientTLSClientConfigCfg] = ""; ban.ClientOpts[utils.HTTPClientTLSClientConfigCfg] != false {
if rcv.ClientOpts[utils.HTTPClientSkipTLSVerificationCfg] = ""; ban.ClientOpts[utils.HTTPClientSkipTLSVerificationCfg] != false {
t.Errorf("Expected clone to not modify the cloned")
}
if rcv.AuthUsers["user"] = ""; ban.AuthUsers["user"] != "pass" {

View File

@@ -176,7 +176,7 @@
// "use_basic_auth": false, // use basic authentication
// "auth_users": {}, // basic authentication usernames and base64-encoded passwords (eg: { "username1": "cGFzc3dvcmQ=", "username2": "cGFzc3dvcmQy "})
// "client_opts":{
// "skipTlsVerify": false, // if enabled Http Client will accept any TLS certificate
// "skipTLSVerification": false, // if enabled Http Client will accept any TLS certificate
// // the options to configure the http.Transport
// "tlsHandshakeTimeout": "10s",
// "disableKeepAlives": false,

View File

@@ -16,13 +16,9 @@ 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
@@ -33,7 +29,7 @@ var (
)
func init() {
httpPstrTransport, _ = NewHTTPTransport(config.CgrConfig().HTTPCfg().ClientOpts)
httpPstrTransport = config.CgrConfig().HTTPCfg().ClientOpts.Transport
}
// SetConnManager is the exported method to set the connectionManager used when operate on an account.
@@ -50,122 +46,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

@@ -29,7 +29,7 @@ import (
func TestNewHTTPTransport(t *testing.T) {
opts := map[string]interface{}{
utils.HTTPClientTLSClientConfigCfg: false,
utils.HTTPClientSkipTLSVerificationCfg: false,
utils.HTTPClientTLSHandshakeTimeoutCfg: "10s",
utils.HTTPClientDisableKeepAlivesCfg: false,
utils.HTTPClientDisableCompressionCfg: false,
@@ -138,7 +138,7 @@ func TestNewHTTPTransport(t *testing.T) {
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}
opts[utils.HTTPClientTLSClientConfigCfg] = "string"
opts[utils.HTTPClientSkipTLSVerificationCfg] = "string"
if _, err := NewHTTPTransport(opts); err == nil {
t.Error("Expected error but the transport was builded succesfully")
}

View File

@@ -155,7 +155,7 @@ package general_tests
// t.Errorf("\nExpected %+v ,\n received: %+v", utils.ToIJSON(cfgStr), utils.ToIJSON(rpl4))
// }
// cfgStr = "{\"http\":{\"auth_users\":{},\"client_opts\":{\"dialFallbackDelay\":\"300ms\",\"dialKeepAlive\":\"30s\",\"dialTimeout\":\"30s\",\"disableCompression\":false,\"disableKeepAlives\":false,\"expectContinueTimeout\":\"0\",\"forceAttemptHttp2\":true,\"idleConnTimeout\":\"90s\",\"maxConnsPerHost\":0,\"maxIdleConns\":100,\"maxIdleConnsPerHost\":2,\"responseHeaderTimeout\":\"0\",\"skipTlsVerify\":false,\"tlsHandshakeTimeout\":\"10s\"},\"freeswitch_cdrs_url\":\"/freeswitch_json\",\"http_cdrs\":\"/cdr_http\",\"json_rpc_url\":\"/jsonrpc\",\"registrars_url\":\"/registrar\",\"use_basic_auth\":false,\"ws_url\":\"/ws\"}}"
// cfgStr = "{\"http\":{\"auth_users\":{},\"client_opts\":{\"dialFallbackDelay\":\"300ms\",\"dialKeepAlive\":\"30s\",\"dialTimeout\":\"30s\",\"disableCompression\":false,\"disableKeepAlives\":false,\"expectContinueTimeout\":\"0\",\"forceAttemptHttp2\":true,\"idleConnTimeout\":\"90s\",\"maxConnsPerHost\":0,\"maxIdleConns\":100,\"maxIdleConnsPerHost\":2,\"responseHeaderTimeout\":\"0\",\"skipTLSVerification\":false,\"tlsHandshakeTimeout\":\"10s\"},\"freeswitch_cdrs_url\":\"/freeswitch_json\",\"http_cdrs\":\"/cdr_http\",\"json_rpc_url\":\"/jsonrpc\",\"registrars_url\":\"/registrar\",\"use_basic_auth\":false,\"ws_url\":\"/ws\"}}"
// var rpl5 string
// if err := testRPC.Call(context.Background(), utils.ConfigSv1GetConfigAsJSON, &config.SectionWithAPIOpts{

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/birpc/context"
@@ -50,12 +48,14 @@ type GlobalVarS struct {
// Start should handle the sercive start
func (gv *GlobalVarS) Start(*context.Context, context.CancelFunc) error {
ees.SetFailedPostCacheTTL(gv.cfg.GeneralCfg().FailedPostsTTL)
return gv.initHTTPTransport()
engine.SetHTTPPstrTransport(gv.cfg.HTTPCfg().ClientOpts.Transport)
return nil
}
// Reload handles the change of config
func (gv *GlobalVarS) Reload(*context.Context, context.CancelFunc) error {
return gv.initHTTPTransport()
engine.SetHTTPPstrTransport(gv.cfg.HTTPCfg().ClientOpts.Transport)
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

@@ -55,13 +55,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)

View File

@@ -1786,7 +1786,7 @@ const (
HTTPAuthUsersCfg = "auth_users"
HTTPClientOptsCfg = "client_opts"
HTTPClientTLSClientConfigCfg = "skipTlsVerify"
HTTPClientSkipTLSVerificationCfg = "skipTLSVerification"
HTTPClientTLSHandshakeTimeoutCfg = "tlsHandshakeTimeout"
HTTPClientDisableKeepAlivesCfg = "disableKeepAlives"
HTTPClientDisableCompressionCfg = "disableCompression"