mirror of https://github.com/statping/statping
mTLS service check (http)
parent
47e8039761
commit
4618d56c18
8
Makefile
8
Makefile
|
@ -322,5 +322,13 @@ postman: clean compile
|
||||||
newman run -e dev/postman_environment.json dev/postman.json
|
newman run -e dev/postman_environment.json dev/postman.json
|
||||||
killall statping
|
killall statping
|
||||||
|
|
||||||
|
certs:
|
||||||
|
openssl req -newkey rsa:2048 \
|
||||||
|
-new -nodes -x509 \
|
||||||
|
-days 3650 \
|
||||||
|
-out cert.pem \
|
||||||
|
-keyout key.pem \
|
||||||
|
-subj "/C=US/ST=California/L=Santa Monica/O=Statping/OU=Development/CN=localhost"
|
||||||
|
|
||||||
.PHONY: all build build-all build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman
|
.PHONY: all build build-all build-alpine test-all test test-api docker frontend up down print_details lite sentry-release snapcraft build-linux build-mac build-win build-all postman
|
||||||
.SILENT: travis_s3_creds
|
.SILENT: travis_s3_creds
|
||||||
|
|
|
@ -285,7 +285,7 @@ func runOnce() error {
|
||||||
|
|
||||||
func checkGithubUpdates() (githubResponse, error) {
|
func checkGithubUpdates() (githubResponse, error) {
|
||||||
url := "https://api.github.com/repos/statping/statping/releases/latest"
|
url := "https://api.github.com/repos/statping/statping/releases/latest"
|
||||||
contents, _, err := utils.HttpRequest(url, "GET", nil, nil, nil, time.Duration(2*time.Second), true)
|
contents, _, err := utils.HttpRequest(url, "GET", nil, nil, nil, time.Duration(2*time.Second), true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return githubResponse{}, err
|
return githubResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,41 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label">Use TLS Certificate</label>
|
||||||
|
<div class="col-8 mt-1">
|
||||||
|
<span @click="service.use_tls = !!service.use_tls" class="switch float-left">
|
||||||
|
<input v-model="service.use_tls" type="checkbox" name="verify_ssl-option" class="switch" id="switch-use-tls" v-bind:checked="service.use_tls">
|
||||||
|
<label for="switch-use-tls" v-if="service.use_tls">Custom TLS Certificates for mTLS services</label>
|
||||||
|
<label for="switch-use-tls" v-if="!service.use_tls">Ignore TLS Certificates</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="service.use_tls" class="form-group row">
|
||||||
|
<label for="service_tls_cert" class="col-sm-4 col-form-label">TLS Client Certificate</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<textarea v-model="service.tls_cert" name="tls_cert" class="form-control" id="service_tls_cert"></textarea>
|
||||||
|
<small class="form-text text-muted">Absolute path to TLS Client Certificate file or in PEM format</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="service.use_tls" class="form-group row">
|
||||||
|
<label for="service_tls_cert_key" class="col-sm-4 col-form-label">TLS Client Key</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<textarea v-model="service.tls_cert_key" name="tls_cert_key" class="form-control" id="service_tls_cert_key"></textarea>
|
||||||
|
<small class="form-text text-muted">Absolute path to TLS Client Key file or in PEM format</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="service.use_tls" class="form-group row">
|
||||||
|
<label for="service_tls_cert_chain" class="col-sm-4 col-form-label">Root CA</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<textarea v-model="service.tls_cert_root" name="tls_cert_key" class="form-control" id="service_tls_cert_chain"></textarea>
|
||||||
|
<small class="form-text text-muted">Absolute path to Root CA file or in PEM format (optional)</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -235,6 +270,10 @@
|
||||||
notify_all_changes: true,
|
notify_all_changes: true,
|
||||||
notify_after: 2,
|
notify_after: 2,
|
||||||
public: true,
|
public: true,
|
||||||
|
use_tls: false,
|
||||||
|
tls_cert: "",
|
||||||
|
tls_cert_key: "",
|
||||||
|
tls_cert_root: "",
|
||||||
},
|
},
|
||||||
groups: [],
|
groups: [],
|
||||||
}
|
}
|
||||||
|
@ -247,12 +286,15 @@
|
||||||
watch: {
|
watch: {
|
||||||
in_service () {
|
in_service () {
|
||||||
this.service = this.in_service
|
this.service = this.in_service
|
||||||
|
if (this.service.tls_cert) {
|
||||||
|
this.service.use_tls = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
if (!this.$store.getters.groups) {
|
if (!this.$store.getters.groups) {
|
||||||
const groups = await Api.groups()
|
const groups = await Api.groups()
|
||||||
this.$store.commit('setGroups', groups)
|
this.$store.commit('setGroups', groups)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -289,6 +331,7 @@
|
||||||
delete s.last_success
|
delete s.last_success
|
||||||
delete s.latency
|
delete s.latency
|
||||||
delete s.online_24_hours
|
delete s.online_24_hours
|
||||||
|
delete s.use_tls
|
||||||
s.check_interval = parseInt(s.check_interval)
|
s.check_interval = parseInt(s.check_interval)
|
||||||
s.timeout = parseInt(s.timeout)
|
s.timeout = parseInt(s.timeout)
|
||||||
s.port = parseInt(s.port)
|
s.port = parseInt(s.port)
|
||||||
|
|
|
@ -143,7 +143,7 @@ func slackOAuth(r *http.Request) (*oAuth, error) {
|
||||||
// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
|
// slackIdentity will query the Slack API to fetch the users ID, username, and email address.
|
||||||
func (a *oAuth) slackIdentity() (*oAuth, error) {
|
func (a *oAuth) slackIdentity() (*oAuth, error) {
|
||||||
url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", a.Token)
|
url := fmt.Sprintf("https://slack.com/api/users.identity?token=%s", a.Token)
|
||||||
out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true)
|
out, resp, err := utils.HttpRequest(url, "GET", "application/x-www-form-urlencoded", nil, nil, 10*time.Second, true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a, err
|
return a, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ var Discorder = &discord{¬ifications.Notification{
|
||||||
|
|
||||||
// Send will send a HTTP Post to the discord API. It accepts type: []byte
|
// Send will send a HTTP Post to the discord API. It accepts type: []byte
|
||||||
func (d *discord) sendRequest(msg string) error {
|
func (d *discord) sendRequest(msg string) error {
|
||||||
_, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
|
_, _, err := utils.HttpRequest(Discorder.GetValue("host"), "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func (d *discord) OnSuccess(s *services.Service) error {
|
||||||
func (d *discord) OnTest() (string, error) {
|
func (d *discord) OnTest() (string, error) {
|
||||||
outError := errors.New("Incorrect discord URL, please confirm URL is correct")
|
outError := errors.New("Incorrect discord URL, please confirm URL is correct")
|
||||||
message := `{"content": "Testing the discord notifier"}`
|
message := `{"content": "Testing the discord notifier"}`
|
||||||
contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true)
|
contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true, nil)
|
||||||
if string(contents) == "" {
|
if string(contents) == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (l *lineNotifier) sendMessage(message string) (string, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
v.Set("message", message)
|
v.Set("message", message)
|
||||||
headers := []string{fmt.Sprintf("Authorization=Bearer %v", l.ApiSecret)}
|
headers := []string{fmt.Sprintf("Authorization=Bearer %v", l.ApiSecret)}
|
||||||
content, _, err := utils.HttpRequest("https://notify-api.line.me/api/notify", "POST", "application/x-www-form-urlencoded", headers, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true)
|
content, _, err := utils.HttpRequest("https://notify-api.line.me/api/notify", "POST", "application/x-www-form-urlencoded", headers, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true, nil)
|
||||||
return string(content), err
|
return string(content), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ func pushRequest(msg *pushArray) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
url := "https://push.statping.com/api/push"
|
url := "https://push.statping.com/api/push"
|
||||||
body, _, err = utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(20*time.Second), true)
|
body, _, err = utils.HttpRequest(url, "POST", "application/json", nil, bytes.NewBuffer(body), time.Duration(20*time.Second), true, nil)
|
||||||
return body, err
|
return body, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (t *pushover) sendMessage(message string) (string, error) {
|
||||||
v.Set("message", message)
|
v.Set("message", message)
|
||||||
rb := strings.NewReader(v.Encode())
|
rb := strings.NewReader(v.Encode())
|
||||||
|
|
||||||
content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true)
|
content, _, err := utils.HttpRequest(pushoverUrl, "POST", "application/x-www-form-urlencoded", nil, rb, time.Duration(10*time.Second), true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ var slacker = &slack{¬ifications.Notification{
|
||||||
|
|
||||||
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
|
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
|
||||||
func (s *slack) sendSlack(msg string) error {
|
func (s *slack) sendSlack(msg string) error {
|
||||||
_, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true)
|
_, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ func (s *slack) sendSlack(msg string) error {
|
||||||
|
|
||||||
func (s *slack) OnTest() (string, error) {
|
func (s *slack) OnTest() (string, error) {
|
||||||
testMsg := ReplaceVars(failingTemplate, exampleService, exampleFailure)
|
testMsg := ReplaceVars(failingTemplate, exampleService, exampleFailure)
|
||||||
contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true)
|
contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (t *telegram) sendMessage(message string) (string, error) {
|
||||||
v.Set("text", message)
|
v.Set("text", message)
|
||||||
rb := *strings.NewReader(v.Encode())
|
rb := *strings.NewReader(v.Encode())
|
||||||
|
|
||||||
contents, _, err := utils.HttpRequest(apiEndpoint, "GET", "application/x-www-form-urlencoded", nil, &rb, time.Duration(10*time.Second), true)
|
contents, _, err := utils.HttpRequest(apiEndpoint, "GET", "application/x-www-form-urlencoded", nil, &rb, time.Duration(10*time.Second), true, nil)
|
||||||
|
|
||||||
success, _ := telegramSuccess(contents)
|
success, _ := telegramSuccess(contents)
|
||||||
if !success {
|
if !success {
|
||||||
|
|
|
@ -72,7 +72,7 @@ func (t *twilio) sendMessage(message string) (string, error) {
|
||||||
|
|
||||||
authHeader := utils.Base64(fmt.Sprintf("%s:%s", t.ApiKey, t.ApiSecret))
|
authHeader := utils.Base64(fmt.Sprintf("%s:%s", t.ApiKey, t.ApiSecret))
|
||||||
|
|
||||||
contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true)
|
contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true, nil)
|
||||||
success, _ := twilioSuccess(contents)
|
success, _ := twilioSuccess(contents)
|
||||||
if !success {
|
if !success {
|
||||||
errorOut := twilioError(contents)
|
errorOut := twilioError(contents)
|
||||||
|
|
|
@ -2,13 +2,16 @@ package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/statping/statping/types"
|
"github.com/statping/statping/types"
|
||||||
|
"github.com/statping/statping/types/errors"
|
||||||
"github.com/statping/statping/types/failures"
|
"github.com/statping/statping/types/failures"
|
||||||
"github.com/statping/statping/types/hits"
|
"github.com/statping/statping/types/hits"
|
||||||
"github.com/statping/statping/utils"
|
"github.com/statping/statping/utils"
|
||||||
|
"io/ioutil"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,6 +19,43 @@ import (
|
||||||
|
|
||||||
const limitedFailures = 25
|
const limitedFailures = 25
|
||||||
|
|
||||||
|
func (s *Service) LoadTLSCert() (*tls.Config, error) {
|
||||||
|
if !s.TLSCert.Valid && !s.TLSCertKey.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// load TLS cert and key from file path or PEM format
|
||||||
|
var cert tls.Certificate
|
||||||
|
var err error
|
||||||
|
tlsCertExtension := utils.FileExtension(s.TLSCert.String)
|
||||||
|
tlsCertKeyExtension := utils.FileExtension(s.TLSCertKey.String)
|
||||||
|
if tlsCertExtension == "" && tlsCertKeyExtension == "" {
|
||||||
|
cert, err = tls.X509KeyPair([]byte(s.TLSCert.String), []byte(s.TLSCertKey.String))
|
||||||
|
} else {
|
||||||
|
cert, err = tls.LoadX509KeyPair(s.TLSCert.String, s.TLSCertKey.String)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "issue loading X509KeyPair")
|
||||||
|
}
|
||||||
|
|
||||||
|
// create Root CA pool or use Root CA provided
|
||||||
|
chainFile := s.TLSCert.String
|
||||||
|
if s.TLSCertRoot.String != "" {
|
||||||
|
chainFile = s.TLSCertRoot.String
|
||||||
|
}
|
||||||
|
caCert, err := ioutil.ReadFile(chainFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "issue reading cert file: "+chainFile)
|
||||||
|
}
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
|
|
||||||
|
return &tls.Config{
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) Duration() time.Duration {
|
func (s *Service) Duration() time.Duration {
|
||||||
return time.Duration(s.Interval) * time.Second
|
return time.Duration(s.Interval) * time.Second
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,8 +258,12 @@ func CheckHttp(s *Service, record bool) *Service {
|
||||||
contentType = "application/json"
|
contentType = "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
content, res, err = utils.HttpRequest(s.Domain, s.Method, contentType,
|
customTLS, err := s.LoadTLSCert()
|
||||||
headers, data, timeout, s.VerifySSL.Bool)
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, res, err = utils.HttpRequest(s.Domain, s.Method, contentType, headers, data, timeout, s.VerifySSL.Bool, customTLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if record {
|
if record {
|
||||||
recordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
recordFailure(s, fmt.Sprintf("HTTP Error %v", err))
|
||||||
|
|
|
@ -37,6 +37,9 @@ type Service struct {
|
||||||
VerifySSL null.NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin" yaml:"verify_ssl"`
|
VerifySSL null.NullBool `gorm:"default:false;column:verify_ssl" json:"verify_ssl" scope:"user,admin" yaml:"verify_ssl"`
|
||||||
Public null.NullBool `gorm:"default:true;column:public" json:"public" yaml:"public"`
|
Public null.NullBool `gorm:"default:true;column:public" json:"public" yaml:"public"`
|
||||||
GroupId int `gorm:"default:0;column:group_id" json:"group_id" yaml:"group_id"`
|
GroupId int `gorm:"default:0;column:group_id" json:"group_id" yaml:"group_id"`
|
||||||
|
TLSCert null.NullString `gorm:"column:tls_cert" json:"tls_cert" scope:"user,admin" yaml:"tls_cert"`
|
||||||
|
TLSCertKey null.NullString `gorm:"column:tls_cert_key" json:"tls_cert_key" scope:"user,admin" yaml:"tls_cert_key"`
|
||||||
|
TLSCertRoot null.NullString `gorm:"column:tls_cert_root" json:"tls_cert_root" scope:"user,admin" yaml:"tls_cert_root"`
|
||||||
Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin" yaml:"headers"`
|
Headers null.NullString `gorm:"column:headers" json:"headers" scope:"user,admin" yaml:"headers"`
|
||||||
Permalink null.NullString `gorm:"column:permalink;unique;" json:"permalink" yaml:"permalink"`
|
Permalink null.NullString `gorm:"column:permalink;unique;" json:"permalink" yaml:"permalink"`
|
||||||
Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin" yaml:"redirect"`
|
Redirect null.NullBool `gorm:"default:false;column:redirect" json:"redirect" scope:"user,admin" yaml:"redirect"`
|
||||||
|
|
|
@ -3,6 +3,7 @@ package utils
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeleteDirectory will attempt to delete a directory and all contents inside
|
// DeleteDirectory will attempt to delete a directory and all contents inside
|
||||||
|
@ -30,6 +31,15 @@ func FolderExists(folder string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileExtension returns the file extension based on a file path
|
||||||
|
func FileExtension(path string) string {
|
||||||
|
s := strings.Split(path, ".")
|
||||||
|
if len(s) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s[len(s)-1]
|
||||||
|
}
|
||||||
|
|
||||||
// FileExists returns true if a file exists
|
// FileExists returns true if a file exists
|
||||||
// exists := FileExists("assets/css/base.css")
|
// exists := FileExists("assets/css/base.css")
|
||||||
func FileExists(name string) bool {
|
func FileExists(name string) bool {
|
||||||
|
|
|
@ -197,7 +197,7 @@ func DurationReadable(d time.Duration) string {
|
||||||
// // body - The body or form data to send with HTTP request
|
// // body - The body or form data to send with HTTP request
|
||||||
// // timeout - Specific duration to timeout on. time.Duration(30 * time.Seconds)
|
// // timeout - Specific duration to timeout on. time.Duration(30 * time.Seconds)
|
||||||
// // You can use a HTTP Proxy if you HTTP_PROXY environment variable
|
// // You can use a HTTP Proxy if you HTTP_PROXY environment variable
|
||||||
func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration, verifySSL bool) ([]byte, *http.Response, error) {
|
func HttpRequest(url, method string, content interface{}, headers []string, body io.Reader, timeout time.Duration, verifySSL bool, customTLS *tls.Config) ([]byte, *http.Response, error) {
|
||||||
var err error
|
var err error
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
t1 := Now()
|
t1 := Now()
|
||||||
|
@ -247,6 +247,10 @@ func HttpRequest(url, method string, content interface{}, headers []string, body
|
||||||
return dialer.DialContext(ctx, network, addr)
|
return dialer.DialContext(ctx, network, addr)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if customTLS != nil {
|
||||||
|
transport.TLSClientConfig.RootCAs = customTLS.RootCAs
|
||||||
|
transport.TLSClientConfig.Certificates = customTLS.Certificates
|
||||||
|
}
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
|
|
Loading…
Reference in New Issue