@@ -21,215 +21,11 @@ package httpcommon
2121
2222import (
2323 "net/http"
24- "time"
2524
26- "go.elastic.co/apm/module/apmhttp"
27- "golang.org/x/net/http2"
28-
29- "github.com/elastic/beats/v7/libbeat/common"
3025 "github.com/elastic/beats/v7/libbeat/common/transport"
3126 "github.com/elastic/beats/v7/libbeat/common/transport/tlscommon"
32- "github.com/elastic/beats/v7/libbeat/logp"
33- )
34-
35- // HTTPTransportSettings provides common HTTP settings for HTTP clients.
36- type HTTPTransportSettings struct {
37- // TLS provides ssl/tls setup settings
38- TLS * tlscommon.Config `config:"ssl" yaml:"ssl,omitempty" json:"ssl,omitempty"`
39-
40- // Timeout configures the `(http.Transport).Timeout`.
41- Timeout time.Duration `config:"timeout" yaml:"timeout,omitempty" json:"timeout,omitempty"`
42-
43- Proxy HTTPClientProxySettings `config:",inline" yaml:",inline"`
44-
45- // TODO: Add more settings:
46- // - DisableKeepAlive
47- // - MaxIdleConns
48- // - IdleConnTimeout
49- // - ResponseHeaderTimeout
50- // - ConnectionTimeout (currently 'Timeout' is used for both)
51- }
52-
53- // WithKeepaliveSettings options can be used to modify the Keepalive
54- type WithKeepaliveSettings struct {
55- Disable bool
56- MaxIdleConns int
57- MaxIdleConnsPerHost int
58- IdleConnTimeout time.Duration
59- }
60-
61- var _ httpTransportOption = WithKeepaliveSettings {}
62-
63- const defaultHTTPTimeout = 90 * time .Second
64-
65- type (
66- // TransportOption are applied to the http.RoundTripper to be build
67- // from HTTPTransportSettings.
68- TransportOption interface { sealTransportOption () }
69-
70- extraSettings struct {
71- logger * logp.Logger
72- http2 bool
73- }
74-
75- dialerOption interface {
76- TransportOption
77- baseDialer () transport.Dialer
78- }
79- dialerModOption interface {
80- TransportOption
81- applyDialer (* HTTPTransportSettings , transport.Dialer ) transport.Dialer
82- }
83- httpTransportOption interface {
84- TransportOption
85- applyTransport (* HTTPTransportSettings , * http.Transport )
86- }
87- roundTripperOption interface {
88- TransportOption
89- applyRoundTripper (* HTTPTransportSettings , http.RoundTripper ) http.RoundTripper
90- }
91- extraOption interface {
92- TransportOption
93- applyExtra (* extraSettings )
94- }
9527)
9628
97- type baseDialerFunc func () transport.Dialer
98-
99- var _ dialerOption = baseDialerFunc (nil )
100-
101- func (baseDialerFunc ) sealTransportOption () {}
102- func (fn baseDialerFunc ) baseDialer () transport.Dialer {
103- return fn ()
104- }
105-
106- type dialerOptFunc func (transport.Dialer ) transport.Dialer
107-
108- var _ dialerModOption = dialerOptFunc (nil )
109-
110- func (dialerOptFunc ) sealTransportOption () {}
111- func (fn dialerOptFunc ) applyDialer (_ * HTTPTransportSettings , d transport.Dialer ) transport.Dialer {
112- return fn (d )
113-
114- }
115-
116- type transportOptFunc func (* HTTPTransportSettings , * http.Transport )
117-
118- var _ httpTransportOption = transportOptFunc (nil )
119-
120- func (transportOptFunc ) sealTransportOption () {}
121- func (fn transportOptFunc ) applyTransport (s * HTTPTransportSettings , t * http.Transport ) {
122- fn (s , t )
123- }
124-
125- type rtOptFunc func (http.RoundTripper ) http.RoundTripper
126-
127- var _ roundTripperOption = rtOptFunc (nil )
128-
129- func (rtOptFunc ) sealTransportOption () {}
130- func (fn rtOptFunc ) applyRoundTripper (_ * HTTPTransportSettings , rt http.RoundTripper ) http.RoundTripper {
131- return fn (rt )
132- }
133-
134- type extraOptionFunc func (* extraSettings )
135-
136- func (extraOptionFunc ) sealTransportOption () {}
137- func (fn extraOptionFunc ) applyExtra (s * extraSettings ) { fn (s ) }
138-
139- // DefaultHTTPTransportSettings returns the default HTTP transport setting.
140- func DefaultHTTPTransportSettings () HTTPTransportSettings {
141- return HTTPTransportSettings {
142- Proxy : DefaultHTTPClientProxySettings (),
143- Timeout : defaultHTTPTimeout ,
144- }
145- }
146-
147- // Unpack reads a config object into the settings.
148- func (settings * HTTPTransportSettings ) Unpack (cfg * common.Config ) error {
149- tmp := struct {
150- TLS * tlscommon.Config `config:"ssl"`
151- Timeout time.Duration `config:"timeout"`
152- }{Timeout : settings .Timeout }
153-
154- if err := cfg .Unpack (& tmp ); err != nil {
155- return err
156- }
157-
158- var proxy HTTPClientProxySettings
159- if err := cfg .Unpack (& proxy ); err != nil {
160- return err
161- }
162-
163- _ , err := tlscommon .LoadTLSConfig (tmp .TLS )
164- if err != nil {
165- return err
166- }
167-
168- * settings = HTTPTransportSettings {
169- TLS : tmp .TLS ,
170- Timeout : tmp .Timeout ,
171- Proxy : proxy ,
172- }
173- return nil
174- }
175-
176- // RoundTripper creates a http.RoundTripper for use with http.Client.
177- //
178- // The dialers will registers with stats if given. Stats is used to collect metrics for io errors,
179- // bytes in, and bytes out.
180- func (settings * HTTPTransportSettings ) RoundTripper (opts ... TransportOption ) (http.RoundTripper , error ) {
181- var dialer transport.Dialer
182-
183- var extra extraSettings
184- for _ , opt := range opts {
185- if opt , ok := opt .(extraOption ); ok {
186- opt .applyExtra (& extra )
187- }
188- }
189-
190- for _ , opt := range opts {
191- if dialOpt , ok := opt .(dialerOption ); ok {
192- dialer = dialOpt .baseDialer ()
193- }
194- }
195-
196- if dialer == nil {
197- dialer = transport .NetDialer (settings .Timeout )
198- }
199-
200- tls , err := tlscommon .LoadTLSConfig (settings .TLS )
201- if err != nil {
202- return nil , err
203- }
204-
205- tlsDialer := transport .TLSDialer (dialer , tls , settings .Timeout )
206- for _ , opt := range opts {
207- if dialOpt , ok := opt .(dialerModOption ); ok {
208- dialer = dialOpt .applyDialer (settings , dialer )
209- tlsDialer = dialOpt .applyDialer (settings , tlsDialer )
210- }
211- }
212-
213- if logger := extra .logger ; logger != nil {
214- dialer = transport .LoggingDialer (dialer , logger )
215- tlsDialer = transport .LoggingDialer (tlsDialer , logger )
216- }
217-
218- var rt http.RoundTripper
219- if extra .http2 {
220- rt , err = settings .http2RoundTripper (tls , dialer , tlsDialer , opts ... )
221- } else {
222- rt , err = settings .httpRoundTripper (tls , dialer , tlsDialer , opts ... )
223- }
224-
225- for _ , opt := range opts {
226- if rtOpt , ok := opt .(roundTripperOption ); ok {
227- rt = rtOpt .applyRoundTripper (settings , rt )
228- }
229- }
230- return rt , nil
231- }
232-
23329func (settings * HTTPTransportSettings ) httpRoundTripper (
23430 tls * tlscommon.TLSConfig ,
23531 dialer , tlsDialer transport.Dialer ,
@@ -257,128 +53,3 @@ func (settings *HTTPTransportSettings) httpRoundTripper(
25753
25854 return t , nil
25955}
260-
261- func (settings * HTTPTransportSettings ) http2RoundTripper (
262- tls * tlscommon.TLSConfig ,
263- dialer , tlsDialer transport.Dialer ,
264- opts ... TransportOption ,
265- ) (* http2.Transport , error ) {
266- t1 , err := settings .httpRoundTripper (tls , dialer , tlsDialer , opts ... )
267- if err != nil {
268- return nil , err
269- }
270-
271- t2 , err := http2 .ConfigureTransports (t1 )
272- if err != nil {
273- return nil , err
274- }
275-
276- t2 .AllowHTTP = true
277- return t2 , nil
278- }
279-
280- // Client creates a new http.Client with configured Transport. The transport is
281- // instrumented using apmhttp.WrapRoundTripper.
282- func (settings HTTPTransportSettings ) Client (opts ... TransportOption ) (* http.Client , error ) {
283- rt , err := settings .RoundTripper (opts ... )
284- if err != nil {
285- return nil , err
286- }
287-
288- return & http.Client {Transport : rt , Timeout : settings .Timeout }, nil
289- }
290-
291- func (opts WithKeepaliveSettings ) sealTransportOption () {}
292- func (opts WithKeepaliveSettings ) applyTransport (_ * HTTPTransportSettings , t * http.Transport ) {
293- t .DisableKeepAlives = opts .Disable
294- if opts .IdleConnTimeout != 0 {
295- t .IdleConnTimeout = opts .IdleConnTimeout
296- }
297- if opts .MaxIdleConns != 0 {
298- t .MaxIdleConns = opts .MaxIdleConns
299- }
300- if opts .MaxIdleConnsPerHost != 0 {
301- t .MaxIdleConnsPerHost = opts .MaxIdleConnsPerHost
302- }
303- }
304-
305- // WithBaseDialer configures the dialer used for TCP and TLS connections.
306- func WithBaseDialer (d transport.Dialer ) TransportOption {
307- return baseDialerFunc (func () transport.Dialer {
308- return d
309- })
310- }
311-
312- // WithIOStats instruments the RoundTripper dialers with the given statser, such
313- // that bytes in, bytes out, and errors can be monitored.
314- func WithIOStats (stats transport.IOStatser ) TransportOption {
315- return dialerOptFunc (func (d transport.Dialer ) transport.Dialer {
316- if stats == nil {
317- return d
318- }
319- return transport .StatsDialer (d , stats )
320- })
321- }
322-
323- // WithTransportFunc register a custom function that is used to apply
324- // custom changes to the net.Transport, when the Client is build.
325- func WithTransportFunc (fn func (* http.Transport )) TransportOption {
326- return transportOptFunc (func (_ * HTTPTransportSettings , t * http.Transport ) {
327- fn (t )
328- })
329- }
330-
331- // WithHTTP2Only will ensure that a HTTP 2 only roundtripper is created.
332- func WithHTTP2Only (b bool ) TransportOption {
333- return extraOptionFunc (func (settings * extraSettings ) {
334- settings .http2 = b
335- })
336- }
337-
338- // WithForceAttemptHTTP2 sets the `http.Tansport.ForceAttemptHTTP2` field.
339- func WithForceAttemptHTTP2 (b bool ) TransportOption {
340- return transportOptFunc (func (settings * HTTPTransportSettings , t * http.Transport ) {
341- t .ForceAttemptHTTP2 = b
342- })
343- }
344-
345- // WithNOProxy disables the configured proxy. Proxy environment variables
346- // like HTTP_PROXY and HTTPS_PROXY will have no affect.
347- func WithNOProxy () TransportOption {
348- return transportOptFunc (func (s * HTTPTransportSettings , t * http.Transport ) {
349- t .Proxy = nil
350- })
351- }
352-
353- // WithoutProxyEnvironmentVariables disables support for the HTTP_PROXY, HTTPS_PROXY and
354- // NO_PROXY envionrment variables. Explicitely configured proxy URLs will still applied.
355- func WithoutProxyEnvironmentVariables () TransportOption {
356- return transportOptFunc (func (settings * HTTPTransportSettings , t * http.Transport ) {
357- if settings .Proxy .Disable || settings .Proxy .URL == nil {
358- t .Proxy = nil
359- }
360- })
361- }
362-
363- // WithModRoundtripper allows customization of the roundtipper.
364- func WithModRoundtripper (w func (http.RoundTripper ) http.RoundTripper ) TransportOption {
365- return rtOptFunc (w )
366- }
367-
368- var withAPMHTTPRountTripper = WithModRoundtripper (func (rt http.RoundTripper ) http.RoundTripper {
369- return apmhttp .WrapRoundTripper (rt )
370- })
371-
372- // WithAPMHTTPInstrumentation insruments the HTTP client via apmhttp.WrapRoundTripper.
373- // Custom APM round tripper wrappers can be configured via WithModRoundtripper.
374- func WithAPMHTTPInstrumentation () TransportOption {
375- return withAPMHTTPRountTripper
376- }
377-
378- // WithLogger sets the internal logger that will be used to log dial or TCP level errors.
379- // Logging at the connection level will only happen if the logger has been set.
380- func WithLogger (logger * logp.Logger ) TransportOption {
381- return extraOptionFunc (func (s * extraSettings ) {
382- s .logger = logger
383- })
384- }
0 commit comments