123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- package http
- import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "github.com/BurntSushi/toml"
- )
- const (
- NoConnection string = "none"
- UnixDomainSocketConnection string = "unix"
- HttpConnection string = "http"
- )
- const (
- TlsOff string = "off"
- TlsStrict string = "strict"
- )
- type Config struct {
- ConnectionType string `toml:"-"` // connection type is not loaded from toml
- Socket string // filename for unix domain socket
- WorkDir string // directory for unix domain socket
- HttpUrl string // transaction manager URL for HTTP connection
- Timeout uint // timeout for overall client call (seconds), zero means timeout disabled
- DialTimeout uint // timeout for connecting to unix socket (seconds)
- HttpIdleConnTimeout uint // timeout for idle http connection (seconds), zero means timeout disabled
- HttpWriteBufferSize int // size of http connection write buffer (bytes), if zero then uses http.Transport default
- HttpReadBufferSize int // size of http connection read buffer (bytes), if zero then uses http.Transport default
- TlsMode string // whether TLS is enabled on HTTP connection (can be "off" or "strict")
- TlsRootCA string // path to file containing certificate for root CA (defaults to host's certificates)
- TlsClientCert string // path to file containing client certificate (or chain of certs)
- TlsClientKey string // path to file containing client's private key
- TlsInsecureSkipVerify bool // if true then does not verify that server certificate is CA signed
- }
- var NoConnectionConfig = Config{
- ConnectionType: NoConnection,
- TlsMode: TlsOff,
- }
- var DefaultConfig = Config{
- Timeout: 5,
- DialTimeout: 1,
- HttpIdleConnTimeout: 10,
- TlsMode: TlsOff,
- }
- func IsSocketConfigured(cfg Config) bool {
- return cfg.ConnectionType == UnixDomainSocketConnection
- }
- // This will accept path as any of the following and return relevant configuration:
- // - path set to "ignore"
- // - path to an ipc file
- // - path to a config file
- func FetchConfigOrIgnore(path string) (Config, error) {
- if path == "" || strings.EqualFold(path, "ignore") {
- return NoConnectionConfig, nil
- }
- return FetchConfig(path)
- }
- // FetchConfig sets up the configuration for the connection to a txn manager.
- // It will accept a path to an ipc file or a path to a config file,
- // and returns the full configuration info for the specified type of connection.
- func FetchConfig(path string) (Config, error) {
- info, err := os.Lstat(path)
- if err != nil {
- return Config{}, fmt.Errorf("unable to check whether connection details are specified as a config file or ipc file '%s', due to: %s", path, err)
- }
- var cfg Config
- isSocket := info.Mode()&os.ModeSocket != 0
- if isSocket {
- cfg = DefaultConfig
- cfg.ConnectionType = UnixDomainSocketConnection
- cfg.WorkDir, cfg.Socket = filepath.Split(path)
- } else {
- cfg, err = LoadConfigFile(path)
- if err != nil {
- return Config{}, fmt.Errorf("error reading config from '%s' due to: %s", path, err)
- }
- }
- return cfg, nil
- }
- func LoadConfigFile(path string) (Config, error) {
- cfg := DefaultConfig
- if _, err := toml.DecodeFile(path, &cfg); err != nil {
- return Config{}, err
- }
- cfg.TlsMode = strings.ToLower(cfg.TlsMode)
- if cfg.Socket != "" {
- cfg.ConnectionType = UnixDomainSocketConnection
- } else if cfg.HttpUrl != "" {
- cfg.ConnectionType = HttpConnection
- } else {
- return Config{}, fmt.Errorf("either Socket or HTTP connection must be specified in config file")
- }
- return cfg, nil
- }
- func (cfg *Config) Validate() error {
- switch cfg.ConnectionType {
- case "": // no connection type defined
- case NoConnection:
- case UnixDomainSocketConnection:
- if len(cfg.Socket) == 0 { //sanity check - should never occur
- return fmt.Errorf("ipc file configuration is missing for private transaction manager connection")
- }
- if len(cfg.HttpUrl) != 0 {
- return fmt.Errorf("HTTP URL and unix ipc file cannot both be specified for private transaction manager connection")
- }
- if cfg.TlsMode != TlsOff {
- return fmt.Errorf("TLS is not supported over unix domain socket for private transaction manager connection")
- }
- case HttpConnection:
- if len(cfg.Socket) != 0 {
- return fmt.Errorf("HTTP URL and unix ipc file cannot both be specified for private transaction manager connection")
- }
- if len(cfg.HttpUrl) == 0 { //sanity check - should never occur
- return fmt.Errorf("URL configuration is missing for private transaction manager HTTP connection")
- }
- switch cfg.TlsMode {
- case TlsOff:
- //no action needed
- case TlsStrict:
- if !strings.Contains(strings.ToLower(cfg.HttpUrl), "https") {
- return fmt.Errorf("connection is configured with TLS but HTTPS url is not specified")
- }
- if (len(cfg.TlsClientCert) == 0 && len(cfg.TlsClientKey) != 0) || (len(cfg.TlsClientCert) != 0 && len(cfg.TlsClientKey) == 0) {
- return fmt.Errorf("invalid details for HTTP connection with TLS, configuration must specify both clientCert and clientKey, or neither one")
- }
- default:
- return fmt.Errorf("invalid value for TLS mode in config file, must be either OFF or STRICT")
- }
- }
- return nil
- }
- //
- // Setters for the various config fields
- //
- func (cfg *Config) SetSocket(socketPath string) {
- cfg.ConnectionType = UnixDomainSocketConnection
- workDir, socketFilename := filepath.Split(socketPath)
- if workDir != "" {
- cfg.WorkDir = workDir
- }
- cfg.Socket = socketFilename
- }
- func (cfg *Config) SetHttpUrl(httpUrl string) {
- cfg.ConnectionType = HttpConnection
- cfg.HttpUrl = httpUrl
- }
- func (cfg *Config) SetTimeout(timeout uint) {
- cfg.Timeout = timeout
- }
- func (cfg *Config) SetDialTimeout(dialTimeout uint) {
- cfg.DialTimeout = dialTimeout
- }
- func (cfg *Config) SetHttpIdleConnTimeout(httpIdleConnTimeout uint) {
- cfg.HttpIdleConnTimeout = httpIdleConnTimeout
- }
- func (cfg *Config) SetHttpWriteBufferSize(httpWriteBufferSize int) {
- cfg.HttpWriteBufferSize = httpWriteBufferSize
- }
- func (cfg *Config) SetHttpReadBufferSize(httpReadBufferSize int) {
- cfg.HttpReadBufferSize = httpReadBufferSize
- }
- func (cfg *Config) SetTlsMode(tlsMode string) {
- cfg.TlsMode = tlsMode
- }
- func (cfg *Config) SetTlsRootCA(tlsRootCA string) {
- cfg.TlsRootCA = tlsRootCA
- }
- func (cfg *Config) SetTlsClientCert(tlsClientCert string) {
- cfg.TlsClientCert = tlsClientCert
- }
- func (cfg *Config) SetTlsClientKey(tlsClientKey string) {
- cfg.TlsClientKey = tlsClientKey
- }
- func (cfg *Config) SetTlsInsecureSkipVerify(tlsInsecureSkipVerify bool) {
- cfg.TlsInsecureSkipVerify = tlsInsecureSkipVerify
- }
|