mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 10:06:24 +05:00
Make opts struct instead of map[string]interface{} for http
This commit is contained in:
committed by
Dan Christian Bogos
parent
a254569772
commit
a214c505de
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user