mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/httputils: parse URL before creating HTTP transport (#6820)
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6740 --------- Signed-off-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
parent
a0d82a2a83
commit
e58dde6925
11 changed files with 30 additions and 16 deletions
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
addr = flag.String("datasource.url", "", "Datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect endpoint. Required parameter. "+
|
addr = flag.String("datasource.url", "", "Datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect endpoint. Required parameter. "+
|
||||||
"Supports address in the form of IP address with a port (e.g., 127.0.0.1:8428) or DNS SRV record. "+
|
"Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. "+
|
||||||
"See also -remoteRead.disablePathAppend and -datasource.showURL")
|
"See also -remoteRead.disablePathAppend and -datasource.showURL")
|
||||||
appendTypePrefix = flag.Bool("datasource.appendTypePrefix", false, "Whether to add type prefix to -datasource.url based on the query type. Set to true if sending different query types to the vmselect URL.")
|
appendTypePrefix = flag.Bool("datasource.appendTypePrefix", false, "Whether to add type prefix to -datasource.url based on the query type. Set to true if sending different query types to the vmselect URL.")
|
||||||
showDatasourceURL = flag.Bool("datasource.showURL", false, "Whether to avoid stripping sensitive information such as auth headers or passwords from URLs in log messages or UI and exported metrics. "+
|
showDatasourceURL = flag.Bool("datasource.showURL", false, "Whether to avoid stripping sensitive information such as auth headers or passwords from URLs in log messages or UI and exported metrics. "+
|
||||||
|
@ -99,7 +99,7 @@ func Init(extraParams url.Values) (QuerierBuilder, error) {
|
||||||
|
|
||||||
tr, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
tr, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create transport: %w", err)
|
return nil, fmt.Errorf("failed to create transport for -datasource.url=%q: %w", *addr, err)
|
||||||
}
|
}
|
||||||
tr.DialContext = netutil.NewStatDialFunc("vmalert_datasource")
|
tr.DialContext = netutil.NewStatDialFunc("vmalert_datasource")
|
||||||
tr.DisableKeepAlives = *disableKeepAlive
|
tr.DisableKeepAlives = *disableKeepAlive
|
||||||
|
|
|
@ -132,7 +132,8 @@ func NewAlertManager(alertManagerURL string, fn AlertURLGenerator, authCfg proma
|
||||||
}
|
}
|
||||||
tr, err := httputils.Transport(alertManagerURL, tls.CertFile, tls.KeyFile, tls.CAFile, tls.ServerName, tls.InsecureSkipVerify)
|
tr, err := httputils.Transport(alertManagerURL, tls.CertFile, tls.KeyFile, tls.CAFile, tls.ServerName, tls.InsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create transport: %w", err)
|
return nil, fmt.Errorf("failed to create transport for alertmanager URL=%q: %w", alertManagerURL, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ba := new(promauth.BasicAuthConfig)
|
ba := new(promauth.BasicAuthConfig)
|
||||||
|
|
|
@ -17,7 +17,7 @@ var (
|
||||||
addr = flag.String("remoteRead.url", "", "Optional URL to datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect."+
|
addr = flag.String("remoteRead.url", "", "Optional URL to datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect."+
|
||||||
"Remote read is used to restore alerts state."+
|
"Remote read is used to restore alerts state."+
|
||||||
"This configuration makes sense only if `vmalert` was configured with `remoteWrite.url` before and has been successfully persisted its state. "+
|
"This configuration makes sense only if `vmalert` was configured with `remoteWrite.url` before and has been successfully persisted its state. "+
|
||||||
"Supports address in the form of IP address with a port (e.g., 127.0.0.1:8428) or DNS SRV record. "+
|
"Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. "+
|
||||||
"See also '-remoteRead.disablePathAppend', '-remoteRead.showURL'.")
|
"See also '-remoteRead.disablePathAppend', '-remoteRead.showURL'.")
|
||||||
|
|
||||||
showRemoteReadURL = flag.Bool("remoteRead.showURL", false, "Whether to show -remoteRead.url in the exported metrics. "+
|
showRemoteReadURL = flag.Bool("remoteRead.showURL", false, "Whether to show -remoteRead.url in the exported metrics. "+
|
||||||
|
@ -68,7 +68,7 @@ func Init() (datasource.QuerierBuilder, error) {
|
||||||
}
|
}
|
||||||
tr, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
tr, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create transport: %w", err)
|
return nil, fmt.Errorf("failed to create transport for -remoteRead.url=%q: %w", *addr, err)
|
||||||
}
|
}
|
||||||
tr.IdleConnTimeout = *idleConnectionTimeout
|
tr.IdleConnTimeout = *idleConnectionTimeout
|
||||||
tr.DialContext = netutil.NewStatDialFunc("vmalert_remoteread")
|
tr.DialContext = netutil.NewStatDialFunc("vmalert_remoteread")
|
||||||
|
|
|
@ -32,7 +32,7 @@ func NewDebugClient() (*DebugClient, error) {
|
||||||
|
|
||||||
t, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
t, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create transport: %w", err)
|
return nil, fmt.Errorf("failed to create transport for -remoteWrite.url=%q: %w", *addr, err)
|
||||||
}
|
}
|
||||||
c := &DebugClient{
|
c := &DebugClient{
|
||||||
c: &http.Client{
|
c: &http.Client{
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
var (
|
var (
|
||||||
addr = flag.String("remoteWrite.url", "", "Optional URL to VictoriaMetrics or vminsert where to persist alerts state "+
|
addr = flag.String("remoteWrite.url", "", "Optional URL to VictoriaMetrics or vminsert where to persist alerts state "+
|
||||||
"and recording rules results in form of timeseries. "+
|
"and recording rules results in form of timeseries. "+
|
||||||
"Supports address in the form of IP address with a port (e.g., 127.0.0.1:8428) or DNS SRV record. "+
|
"Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. "+
|
||||||
"For example, if -remoteWrite.url=http://127.0.0.1:8428 is specified, "+
|
"For example, if -remoteWrite.url=http://127.0.0.1:8428 is specified, "+
|
||||||
"then the alerts state will be written to http://127.0.0.1:8428/api/v1/write . See also -remoteWrite.disablePathAppend, '-remoteWrite.showURL'.")
|
"then the alerts state will be written to http://127.0.0.1:8428/api/v1/write . See also -remoteWrite.disablePathAppend, '-remoteWrite.showURL'.")
|
||||||
showRemoteWriteURL = flag.Bool("remoteWrite.showURL", false, "Whether to show -remoteWrite.url in the exported metrics. "+
|
showRemoteWriteURL = flag.Bool("remoteWrite.showURL", false, "Whether to show -remoteWrite.url in the exported metrics. "+
|
||||||
|
@ -72,7 +72,7 @@ func Init(ctx context.Context) (*Client, error) {
|
||||||
|
|
||||||
t, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
t, err := httputils.Transport(*addr, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create transport: %w", err)
|
return nil, fmt.Errorf("failed to create transport for -remoteWrite.url=%q: %w", *addr, err)
|
||||||
}
|
}
|
||||||
t.IdleConnTimeout = *idleConnectionTimeout
|
t.IdleConnTimeout = *idleConnectionTimeout
|
||||||
t.DialContext = netutil.NewStatDialFunc("vmalert_remotewrite")
|
t.DialContext = netutil.NewStatDialFunc("vmalert_remotewrite")
|
||||||
|
|
|
@ -68,7 +68,7 @@ func main() {
|
||||||
|
|
||||||
tr, err := httputils.Transport(addr, certFile, keyFile, caFile, serverName, insecureSkipVerify)
|
tr, err := httputils.Transport(addr, certFile, keyFile, caFile, serverName, insecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create Transport: %s", err)
|
return fmt.Errorf("failed to create transport for -%s=%q: %s", otsdbAddr, addr, err)
|
||||||
}
|
}
|
||||||
oCfg := opentsdb.Config{
|
oCfg := opentsdb.Config{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
|
@ -180,7 +180,7 @@ func main() {
|
||||||
|
|
||||||
tr, err := httputils.Transport(addr, certFile, keyFile, caFile, serverName, insecureSkipVerify)
|
tr, err := httputils.Transport(addr, certFile, keyFile, caFile, serverName, insecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create transport: %s", err)
|
return fmt.Errorf("failed to create transport for -%s=%q: %s", remoteReadSrcAddr, addr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rr, err := remoteread.NewClient(remoteread.Config{
|
rr, err := remoteread.NewClient(remoteread.Config{
|
||||||
|
@ -438,7 +438,7 @@ func initConfigVM(c *cli.Context) (vm.Config, error) {
|
||||||
|
|
||||||
tr, err := httputils.Transport(addr, certFile, keyFile, caFile, serverName, insecureSkipVerify)
|
tr, err := httputils.Transport(addr, certFile, keyFile, caFile, serverName, insecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vm.Config{}, fmt.Errorf("failed to create Transport: %s", err)
|
return vm.Config{}, fmt.Errorf("failed to create transport for -%s=%q: %s", vmAddr, addr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bfRetries := c.Int(vmBackoffRetries)
|
bfRetries := c.Int(vmBackoffRetries)
|
||||||
|
|
|
@ -44,6 +44,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
||||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent/): account for `-usePromCompatibleNaming` cmd-line flag during when pushing data to remote storages. Thanks to @12345XXX for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6776).
|
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent/): account for `-usePromCompatibleNaming` cmd-line flag during when pushing data to remote storages. Thanks to @12345XXX for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6776).
|
||||||
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): reduce CPU usage by limiting the number of concurrently running inserts. The issue was introduced in [this commit](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/498fe1cfa523be5bfecaa372293c3cded85e75ab) starting from v1.101.0. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6733) issue for details.
|
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): reduce CPU usage by limiting the number of concurrently running inserts. The issue was introduced in [this commit](https://github.com/VictoriaMetrics/VictoriaMetrics/commit/498fe1cfa523be5bfecaa372293c3cded85e75ab) starting from v1.101.0. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6733) issue for details.
|
||||||
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/metricsql/): fix calculation [histogram_quantile](https://docs.victoriametrics.com/metricsql/#histogram_quantile) over Prometheus buckets with inconsistent values. It was producing incorrect results in case lower buckets. The issue was introduced in [v1.102.0](https://docs.victoriametrics.com/changelog/#v11020) release, see [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6714) for the details.
|
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/metricsql/): fix calculation [histogram_quantile](https://docs.victoriametrics.com/metricsql/#histogram_quantile) over Prometheus buckets with inconsistent values. It was producing incorrect results in case lower buckets. The issue was introduced in [v1.102.0](https://docs.victoriametrics.com/changelog/#v11020) release, see [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6714) for the details.
|
||||||
|
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/), [vmctl](https://docs.victoriametrics.com/vmctl/) and snapshot API: verify correctness of URLs provided via cmd-line flags before executing HTTP requests. See [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6740) issue for details.
|
||||||
|
|
||||||
## [v1.102.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.1)
|
## [v1.102.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.102.1)
|
||||||
|
|
||||||
|
|
|
@ -1075,7 +1075,7 @@ The shortlist of configuration flags is the following:
|
||||||
-datasource.tlsServerName string
|
-datasource.tlsServerName string
|
||||||
Optional TLS server name to use for connections to -datasource.url. By default, the server name from -datasource.url is used
|
Optional TLS server name to use for connections to -datasource.url. By default, the server name from -datasource.url is used
|
||||||
-datasource.url string
|
-datasource.url string
|
||||||
Datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect URL. Required parameter. Supports address in the form of IP address with a port (e.g., 127.0.0.1:8428) or DNS SRV record. See also -remoteRead.disablePathAppend and -datasource.showURL
|
Datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect URL. Required parameter. Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. See also -remoteRead.disablePathAppend and -datasource.showURL
|
||||||
-defaultTenant.graphite string
|
-defaultTenant.graphite string
|
||||||
Default tenant for Graphite alerting groups. See https://docs.victoriametrics.com/vmalert/#multitenancy .This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise/
|
Default tenant for Graphite alerting groups. See https://docs.victoriametrics.com/vmalert/#multitenancy .This flag is available only in Enterprise binaries. See https://docs.victoriametrics.com/enterprise/
|
||||||
-defaultTenant.prometheus string
|
-defaultTenant.prometheus string
|
||||||
|
@ -1341,7 +1341,7 @@ The shortlist of configuration flags is the following:
|
||||||
-remoteRead.tlsServerName string
|
-remoteRead.tlsServerName string
|
||||||
Optional TLS server name to use for connections to -remoteRead.url. By default, the server name from -remoteRead.url is used
|
Optional TLS server name to use for connections to -remoteRead.url. By default, the server name from -remoteRead.url is used
|
||||||
-remoteRead.url vmalert
|
-remoteRead.url vmalert
|
||||||
Optional URL to datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect.Remote read is used to restore alerts state.This configuration makes sense only if vmalert was configured with `remoteWrite.url` before and has been successfully persisted its state. Supports address in the form of IP address with a port (e.g., 127.0.0.1:8428) or DNS SRV record. See also '-remoteRead.disablePathAppend', '-remoteRead.showURL'.
|
Optional URL to datasource compatible with Prometheus HTTP API. It can be single node VictoriaMetrics or vmselect.Remote read is used to restore alerts state.This configuration makes sense only if vmalert was configured with `remoteWrite.url` before and has been successfully persisted its state. Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. See also '-remoteRead.disablePathAppend', '-remoteRead.showURL'.
|
||||||
-remoteWrite.basicAuth.password string
|
-remoteWrite.basicAuth.password string
|
||||||
Optional basic auth password for -remoteWrite.url
|
Optional basic auth password for -remoteWrite.url
|
||||||
-remoteWrite.basicAuth.passwordFile string
|
-remoteWrite.basicAuth.passwordFile string
|
||||||
|
@ -1397,7 +1397,7 @@ The shortlist of configuration flags is the following:
|
||||||
-remoteWrite.tlsServerName string
|
-remoteWrite.tlsServerName string
|
||||||
Optional TLS server name to use for connections to -remoteWrite.url. By default, the server name from -remoteWrite.url is used
|
Optional TLS server name to use for connections to -remoteWrite.url. By default, the server name from -remoteWrite.url is used
|
||||||
-remoteWrite.url string
|
-remoteWrite.url string
|
||||||
Optional URL to VictoriaMetrics or vminsert where to persist alerts state and recording rules results in form of timeseries. Supports address in the form of IP address with a port (e.g., 127.0.0.1:8428) or DNS SRV record. For example, if -remoteWrite.url=http://127.0.0.1:8428 is specified, then the alerts state will be written to http://127.0.0.1:8428/api/v1/write . See also -remoteWrite.disablePathAppend, '-remoteWrite.showURL'.
|
Optional URL to VictoriaMetrics or vminsert where to persist alerts state and recording rules results in form of timeseries. Supports address in the form of IP address with a port (e.g., http://127.0.0.1:8428) or DNS SRV record. For example, if -remoteWrite.url=http://127.0.0.1:8428 is specified, then the alerts state will be written to http://127.0.0.1:8428/api/v1/write . See also -remoteWrite.disablePathAppend, '-remoteWrite.showURL'.
|
||||||
-replay.disableProgressBar
|
-replay.disableProgressBar
|
||||||
Whether to disable rendering progress bars during the replay. Progress bar rendering might be verbose or break the logs parsing, so it is recommended to be disabled when not used in interactive mode.
|
Whether to disable rendering progress bars during the replay. Progress bar rendering might be verbose or break the logs parsing, so it is recommended to be disabled when not used in interactive mode.
|
||||||
-replay.maxDatapointsPerQuery /query_range
|
-replay.maxDatapointsPerQuery /query_range
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -12,6 +13,10 @@ import (
|
||||||
// Transport creates http.Transport object based on provided URL.
|
// Transport creates http.Transport object based on provided URL.
|
||||||
// Returns Transport with TLS configuration if URL contains `https` prefix
|
// Returns Transport with TLS configuration if URL contains `https` prefix
|
||||||
func Transport(URL, certFile, keyFile, caFile, serverName string, insecureSkipVerify bool) (*http.Transport, error) {
|
func Transport(URL, certFile, keyFile, caFile, serverName string, insecureSkipVerify bool) (*http.Transport, error) {
|
||||||
|
_, err := url.Parse(URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse URL: %w", err)
|
||||||
|
}
|
||||||
t := http.DefaultTransport.(*http.Transport).Clone()
|
t := http.DefaultTransport.(*http.Transport).Clone()
|
||||||
if !strings.HasPrefix(URL, "https") {
|
if !strings.HasPrefix(URL, "https") {
|
||||||
return t, nil
|
return t, nil
|
||||||
|
|
|
@ -49,4 +49,10 @@ func TestTransport(t *testing.T) {
|
||||||
if tr.TLSClientConfig == nil {
|
if tr.TLSClientConfig == nil {
|
||||||
t.Fatalf("expected TLSClientConfig to be set, got nil")
|
t.Fatalf("expected TLSClientConfig to be set, got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noSchemaURL := "127.0.0.1:8880"
|
||||||
|
_, err = Transport(noSchemaURL, certFile, keyFile, CAFile, serverName, insecureSkipVerify)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected to have parse error for URL without specified schema; got nil instead")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func Create(createSnapshotURL string) (string, error) {
|
||||||
// create Transport
|
// create Transport
|
||||||
tr, err := httputils.Transport(createSnapshotURL, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
tr, err := httputils.Transport(createSnapshotURL, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", fmt.Errorf("failed to create transport for createSnapshotURL=%q: %s", createSnapshotURL, err)
|
||||||
}
|
}
|
||||||
hc := &http.Client{Transport: tr}
|
hc := &http.Client{Transport: tr}
|
||||||
|
|
||||||
|
@ -83,7 +83,8 @@ func Delete(deleteSnapshotURL string, snapshotName string) error {
|
||||||
// create Transport
|
// create Transport
|
||||||
tr, err := httputils.Transport(deleteSnapshotURL, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
tr, err := httputils.Transport(deleteSnapshotURL, *tlsCertFile, *tlsKeyFile, *tlsCAFile, *tlsServerName, *tlsInsecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to create transport for deleteSnapshotURL=%q: %s", deleteSnapshotURL, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
hc := &http.Client{Transport: tr}
|
hc := &http.Client{Transport: tr}
|
||||||
resp, err := hc.PostForm(u.String(), formData)
|
resp, err := hc.PostForm(u.String(), formData)
|
||||||
|
|
Loading…
Reference in a new issue