Skip to content

Commit 4accfa8

Browse files
author
Steffen Siering
authored
Introduce httpcommon package in libbeat (add support for Proxy) (#25219)
1 parent beaa972 commit 4accfa8

File tree

75 files changed

+1044
-738
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1044
-738
lines changed

CHANGELOG.next.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
598598
- Improve ES output error insights. {pull}25825[25825]
599599
- Add orchestrator.cluster.name/url fields as k8s metadata {pull}26056[26056]
600600
- Libbeat: report beat version to monitoring. {pull}26214[26214]
601+
- Ensure common proxy settings support in HTTP clients: proxy_disabled, proxy_url, proxy_headers and typical environment variables HTTP_PROXY, HTTPS_PROXY, NOPROXY. {pull}25219[25219]
601602

602603
*Auditbeat*
603604

@@ -845,6 +846,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
845846
*Heartbeat*
846847

847848
- Add mime type detection for http responses. {pull}22976[22976]
849+
- Add `proxy_headers` to HTTP monitor. {pull}25219[25219]
848850

849851
*Journalbeat*
850852

dev-tools/cmd/dashboards/export_dashboards.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929

3030
"github.com/pkg/errors"
3131

32+
"github.com/elastic/beats/v7/libbeat/common/transport/httpcommon"
3233
"github.com/elastic/beats/v7/libbeat/dashboards"
3334
"github.com/elastic/beats/v7/libbeat/kibana"
3435
)
@@ -64,14 +65,18 @@ func main() {
6465
user = u.User.Username()
6566
pass, _ = u.User.Password()
6667
}
68+
69+
transport := httpcommon.DefaultHTTPTransportSettings()
70+
transport.Timeout = kibanaTimeout
71+
6772
client, err := kibana.NewClientWithConfig(&kibana.ClientConfig{
68-
Protocol: u.Scheme,
69-
Host: u.Host,
70-
Username: user,
71-
Password: pass,
72-
Path: u.Path,
73-
SpaceID: *spaceID,
74-
Timeout: kibanaTimeout,
73+
Protocol: u.Scheme,
74+
Host: u.Host,
75+
Username: user,
76+
Password: pass,
77+
Path: u.Path,
78+
SpaceID: *spaceID,
79+
Transport: transport,
7580
})
7681
if err != nil {
7782
log.Fatalf("Error while connecting to Kibana: %v", err)

filebeat/fileset/modules_integration_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,7 @@ func TestLoadMultiplePipelinesWithRollback(t *testing.T) {
251251

252252
func getTestingElasticsearch(t eslegtest.TestLogger) *eslegclient.Connection {
253253
conn, err := eslegclient.NewConnection(eslegclient.ConnectionSettings{
254-
URL: eslegtest.GetURL(),
255-
Timeout: 0,
254+
URL: eslegtest.GetURL(),
256255
})
257256
if err != nil {
258257
t.Fatal(err)

filebeat/fileset/pipelines_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/stretchr/testify/assert"
2929
"github.com/stretchr/testify/require"
3030

31+
"github.com/elastic/beats/v7/libbeat/common/transport/httpcommon"
3132
"github.com/elastic/beats/v7/libbeat/esleg/eslegclient"
3233
"github.com/elastic/beats/v7/libbeat/logp"
3334
)
@@ -91,8 +92,10 @@ func TestLoadPipelinesWithMultiPipelineFileset(t *testing.T) {
9192
defer testESServer.Close()
9293

9394
testESClient, err := eslegclient.NewConnection(eslegclient.ConnectionSettings{
94-
URL: testESServer.URL,
95-
Timeout: 90 * time.Second,
95+
URL: testESServer.URL,
96+
Transport: httpcommon.HTTPTransportSettings{
97+
Timeout: 90 * time.Second,
98+
},
9699
})
97100
require.NoError(t, err)
98101

heartbeat/docs/monitors/monitor-http.asciidoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ that data will span multiple requests. Specifically the fields `http.rtt.content
4141

4242
The HTTP proxy URL. This setting is optional. Example `http://proxy.mydomain.com:3128`
4343

44+
[float]
45+
[[monitor-http-proxy-headers]]
46+
==== `proxy_headers`
47+
48+
Additional headers to send to proxies during CONNECT requests.
49+
4450
[float]
4551
[[monitor-http-username]]
4652
==== `username`

heartbeat/monitors/active/dialchain/tls.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,7 @@ func TLSLayer(cfg *tlscommon.TLSConfig, to time.Duration) Layer {
4040
// This gets us the timestamp for when the TLS layer will start the handshake.
4141
next = startTimerAfterDial(&timer, next)
4242

43-
dialer, err := transport.TLSDialer(next, cfg, to)
44-
if err != nil {
45-
return nil, err
46-
}
47-
43+
dialer := transport.TLSDialer(next, cfg, to)
4844
return afterDial(dialer, func(conn net.Conn) (net.Conn, error) {
4945
tlsConn, ok := conn.(*cryptoTLS.Conn)
5046
if !ok {

heartbeat/monitors/active/http/config.go

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,13 @@ import (
2424
"time"
2525

2626
"github.com/elastic/beats/v7/heartbeat/monitors"
27-
"github.com/elastic/beats/v7/libbeat/common/transport/tlscommon"
27+
"github.com/elastic/beats/v7/libbeat/common/transport/httpcommon"
2828
"github.com/elastic/beats/v7/libbeat/conditions"
2929
)
3030

3131
type Config struct {
3232
URLs []string `config:"urls"`
3333
Hosts []string `config:"hosts"`
34-
ProxyURL string `config:"proxy_url"`
35-
Timeout time.Duration `config:"timeout"`
3634
MaxRedirects int `config:"max_redirects"`
3735
Response responseConfig `config:"response"`
3836

@@ -42,11 +40,10 @@ type Config struct {
4240
Username string `config:"username"`
4341
Password string `config:"password"`
4442

45-
// configure tls (if not configured HTTPS will use system defaults)
46-
TLS *tlscommon.Config `config:"ssl"`
47-
4843
// http(s) ping validation
4944
Check checkConfig `config:"check"`
45+
46+
Transport httpcommon.HTTPTransportSettings `config:",inline"`
5047
}
5148

5249
type responseConfig struct {
@@ -90,27 +87,32 @@ type compressionConfig struct {
9087
Level int `config:"level"`
9188
}
9289

93-
var defaultConfig = Config{
94-
Timeout: 16 * time.Second,
95-
MaxRedirects: 0,
96-
Response: responseConfig{
97-
IncludeBody: "on_error",
98-
IncludeBodyMaxBytes: 2048,
99-
IncludeHeaders: true,
100-
},
101-
Mode: monitors.DefaultIPSettings,
102-
Check: checkConfig{
103-
Request: requestParameters{
104-
Method: "GET",
105-
SendHeaders: nil,
106-
SendBody: "",
90+
func defaultConfig() Config {
91+
cfg := Config{
92+
MaxRedirects: 0,
93+
Response: responseConfig{
94+
IncludeBody: "on_error",
95+
IncludeBodyMaxBytes: 2048,
96+
IncludeHeaders: true,
10797
},
108-
Response: responseParameters{
109-
RecvHeaders: nil,
110-
RecvBody: nil,
111-
RecvJSON: nil,
98+
Mode: monitors.DefaultIPSettings,
99+
Check: checkConfig{
100+
Request: requestParameters{
101+
Method: "GET",
102+
SendHeaders: nil,
103+
SendBody: "",
104+
},
105+
Response: responseParameters{
106+
RecvHeaders: nil,
107+
RecvBody: nil,
108+
RecvJSON: nil,
109+
},
112110
},
113-
},
111+
Transport: httpcommon.DefaultHTTPTransportSettings(),
112+
}
113+
cfg.Transport.Timeout = 16 * time.Second
114+
115+
return cfg
114116
}
115117

116118
// Validate validates of the responseConfig object is valid or not
@@ -169,7 +171,7 @@ func (c *Config) Validate() error {
169171

170172
// updateScheme looks at TLS config to decide if http or https should be used to update the host
171173
updateScheme := func(host string) string {
172-
if c.TLS != nil && *c.TLS.Enabled == true {
174+
if c.Transport.TLS != nil && c.Transport.TLS.IsEnabled() {
173175
return fmt.Sprint("https://", host)
174176
}
175177
return fmt.Sprint("http://", host)

heartbeat/monitors/active/http/http.go

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
"github.com/elastic/beats/v7/heartbeat/monitors/jobs"
2828
"github.com/elastic/beats/v7/heartbeat/monitors/wrappers"
2929
"github.com/elastic/beats/v7/libbeat/common"
30-
"github.com/elastic/beats/v7/libbeat/common/transport"
30+
"github.com/elastic/beats/v7/libbeat/common/transport/httpcommon"
3131
"github.com/elastic/beats/v7/libbeat/common/transport/tlscommon"
3232
"github.com/elastic/beats/v7/libbeat/logp"
3333
)
@@ -43,16 +43,11 @@ func create(
4343
name string,
4444
cfg *common.Config,
4545
) (p plugin.Plugin, err error) {
46-
config := defaultConfig
46+
config := defaultConfig()
4747
if err := cfg.Unpack(&config); err != nil {
4848
return plugin.Plugin{}, err
4949
}
5050

51-
tls, err := tlscommon.LoadTLSConfig(config.TLS)
52-
if err != nil {
53-
return plugin.Plugin{}, err
54-
}
55-
5651
var body []byte
5752
var enc contentEncoder
5853

@@ -84,8 +79,8 @@ func create(
8479
// In the event that a ProxyURL is present, or redirect support is enabled
8580
// we execute DNS resolution requests inline with the request, not running them as a separate job, and not returning
8681
// separate DNS rtt data.
87-
if config.ProxyURL != "" || config.MaxRedirects > 0 {
88-
transport, err := newRoundTripper(&config, tls)
82+
if (config.Transport.Proxy.URL != nil && !config.Transport.Proxy.Disable) || config.MaxRedirects > 0 {
83+
transport, err := newRoundTripper(&config)
8984
if err != nil {
9085
return plugin.Plugin{}, err
9186
}
@@ -94,6 +89,13 @@ func create(
9489
return newHTTPMonitorHostJob(urlStr, &config, transport, enc, body, validator)
9590
}
9691
} else {
92+
// preload TLS configuration
93+
tls, err := tlscommon.LoadTLSConfig(config.Transport.TLS)
94+
if err != nil {
95+
return plugin.Plugin{}, err
96+
}
97+
config.Transport.TLS = nil
98+
9799
makeJob = func(urlStr string) (jobs.Job, error) {
98100
return newHTTPMonitorIPsJob(&config, urlStr, tls, enc, body, validator)
99101
}
@@ -119,27 +121,12 @@ func create(
119121
return plugin.Plugin{Jobs: js, Close: nil, Endpoints: len(config.Hosts)}, nil
120122
}
121123

122-
func newRoundTripper(config *Config, tls *tlscommon.TLSConfig) (*http.Transport, error) {
123-
var proxy func(*http.Request) (*url.URL, error)
124-
if config.ProxyURL != "" {
125-
url, err := url.Parse(config.ProxyURL)
126-
if err != nil {
127-
return nil, err
128-
}
129-
proxy = http.ProxyURL(url)
130-
}
131-
132-
dialer := transport.NetDialer(config.Timeout)
133-
tlsDialer, err := transport.TLSDialer(dialer, tls, config.Timeout)
134-
if err != nil {
135-
return nil, err
136-
}
137-
138-
return &http.Transport{
139-
Proxy: proxy,
140-
Dial: dialer.Dial,
141-
DialTLS: tlsDialer.Dial,
142-
TLSClientConfig: tls.ToConfig(),
143-
DisableKeepAlives: true,
144-
}, nil
124+
func newRoundTripper(config *Config) (http.RoundTripper, error) {
125+
return config.Transport.RoundTripper(
126+
httpcommon.WithAPMHTTPInstrumentation(),
127+
httpcommon.WithoutProxyEnvironmentVariables(),
128+
httpcommon.WithKeepaliveSettings{
129+
Disable: true,
130+
},
131+
)
145132
}

heartbeat/monitors/active/http/http_test.go

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ import (
4545
"github.com/elastic/beats/v7/libbeat/beat"
4646
"github.com/elastic/beats/v7/libbeat/common"
4747
"github.com/elastic/beats/v7/libbeat/common/file"
48-
"github.com/elastic/beats/v7/libbeat/common/transport"
49-
"github.com/elastic/beats/v7/libbeat/common/transport/tlscommon"
5048
btesting "github.com/elastic/beats/v7/libbeat/testing"
5149
"github.com/elastic/go-lookslike"
5250
"github.com/elastic/go-lookslike/isdef"
@@ -408,7 +406,6 @@ func TestHTTPSServer(t *testing.T) {
408406
t.Skip("flaky test: https://github.com/elastic/beats/issues/25857")
409407
}
410408
server := httptest.NewTLSServer(hbtest.HelloWorldHandler(http.StatusOK))
411-
412409
runHTTPSServerCheck(t, server, nil)
413410
}
414411

@@ -613,39 +610,6 @@ func TestNoHeaders(t *testing.T) {
613610
)
614611
}
615612

616-
func TestNewRoundTripper(t *testing.T) {
617-
configs := map[string]Config{
618-
"Plain": {Timeout: time.Second},
619-
"With Proxy": {Timeout: time.Second, ProxyURL: "http://localhost:1234"},
620-
}
621-
622-
for name, config := range configs {
623-
t.Run(name, func(t *testing.T) {
624-
transp, err := newRoundTripper(&config, &tlscommon.TLSConfig{})
625-
require.NoError(t, err)
626-
627-
if config.ProxyURL == "" {
628-
require.Nil(t, transp.Proxy)
629-
} else {
630-
require.NotNil(t, transp.Proxy)
631-
}
632-
633-
// It's hard to compare func types in tests
634-
require.NotNil(t, transp.Dial)
635-
require.NotNil(t, transport.TLSDialer)
636-
637-
expected := (&tlscommon.TLSConfig{}).ToConfig()
638-
require.Equal(t, expected.InsecureSkipVerify, transp.TLSClientConfig.InsecureSkipVerify)
639-
// When we remove support for the legacy common name treatment
640-
// this test has to be adjusted, as we will not depend on our
641-
// VerifyConnection callback.
642-
require.NotNil(t, transp.TLSClientConfig.VerifyConnection)
643-
require.True(t, transp.DisableKeepAlives)
644-
})
645-
}
646-
647-
}
648-
649613
func TestProxy(t *testing.T) {
650614
if runtime.GOOS == "windows" && bits.UintSize == 32 {
651615
t.Skip("flaky test: https://github.com/elastic/beats/issues/25857")
@@ -705,3 +669,11 @@ func httpConnectTunnel(writer http.ResponseWriter, request *http.Request) {
705669
}()
706670
wg.Wait()
707671
}
672+
673+
func mustParseURL(t *testing.T, url string) *url.URL {
674+
parsed, err := common.ParseURL(url)
675+
if err != nil {
676+
t.Fatal(err)
677+
}
678+
return parsed
679+
}

heartbeat/monitors/active/http/task.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ var userAgent = useragent.UserAgent("Heartbeat")
5050
func newHTTPMonitorHostJob(
5151
addr string,
5252
config *Config,
53-
transport *http.Transport,
53+
transport http.RoundTripper,
5454
enc contentEncoder,
5555
body []byte,
5656
validator multiValidator,
@@ -61,17 +61,15 @@ func newHTTPMonitorHostJob(
6161
return nil, err
6262
}
6363

64-
timeout := config.Timeout
65-
6664
return jobs.MakeSimpleJob(func(event *beat.Event) error {
6765
var redirects []string
6866
client := &http.Client{
6967
// Trace visited URLs when redirects occur
7068
CheckRedirect: makeCheckRedirect(config.MaxRedirects, &redirects),
7169
Transport: transport,
72-
Timeout: config.Timeout,
70+
Timeout: config.Transport.Timeout,
7371
}
74-
_, _, err := execPing(event, client, request, body, timeout, validator, config.Response)
72+
_, _, err := execPing(event, client, request, body, config.Transport.Timeout, validator, config.Response)
7573
if len(redirects) > 0 {
7674
event.PutValue("http.response.redirects", redirects)
7775
}
@@ -112,7 +110,7 @@ func createPingFactory(
112110
body []byte,
113111
validator multiValidator,
114112
) func(*net.IPAddr) jobs.Job {
115-
timeout := config.Timeout
113+
timeout := config.Transport.Timeout
116114
isTLS := request.URL.Scheme == "https"
117115

118116
return monitors.MakePingIPFactory(func(event *beat.Event, ip *net.IPAddr) error {

0 commit comments

Comments
 (0)