func (h HTTPTransport) TLSEnabled() bool {
	return h.TLS != nil
}
TLSEnabled returns true if TLS is enabled.
package reverseproxy
import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"encoding/base64"
	"fmt"
	weakrand "math/rand"
	"net"
	"net/http"
	"os"
	"reflect"
	"time"
	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddytls"
	"golang.org/x/net/http2"
)
func init() {
	caddy.RegisterModule(HTTPTransport{})
}
type HTTPTransport struct {
	Resolver *UpstreamResolver `json:"resolver,omitempty"`
	TLS *TLSConfig `json:"tls,omitempty"`
	KeepAlive *KeepAlive `json:"keep_alive,omitempty"`
	Compression *bool `json:"compression,omitempty"`
	MaxConnsPerHost int `json:"max_conns_per_host,omitempty"`
	DialTimeout caddy.Duration `json:"dial_timeout,omitempty"`
	FallbackDelay caddy.Duration `json:"dial_fallback_delay,omitempty"`
	ResponseHeaderTimeout caddy.Duration `json:"response_header_timeout,omitempty"`
	ExpectContinueTimeout caddy.Duration `json:"expect_continue_timeout,omitempty"`
	MaxResponseHeaderSize int64 `json:"max_response_header_size,omitempty"`
	WriteBufferSize int `json:"write_buffer_size,omitempty"`
	ReadBufferSize int `json:"read_buffer_size,omitempty"`
	Versions []string `json:"versions,omitempty"`
	Transport *http.Transport `json:"-"`
	h2cTransport *http2.Transport
}
func (HTTPTransport) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "http.reverse_proxy.transport.http",
		New: func() caddy.Module { return new(HTTPTransport) },
	}
}
func (h *HTTPTransport) Provision(ctx caddy.Context) error {
	if len(h.Versions) == 0 {
		h.Versions = []string{"1.1", "2"}
	}
	rt, err := h.NewTransport(ctx)
	if err != nil {
		return err
	}
	h.Transport = rt
	if sliceContains(h.Versions, "h2c") {
		h2t := &http2.Transport{
			DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) {
				return net.Dial(network, addr)
			},
			AllowHTTP: true,
		}
		if h.Compression != nil {
			h2t.DisableCompression = !*h.Compression
		}
		h.h2cTransport = h2t
	}
	return nil
}
func (h *HTTPTransport) NewTransport(ctx caddy.Context) (*http.Transport, error) {
	dialer := &net.Dialer{
		Timeout:       time.Duration(h.DialTimeout),
		FallbackDelay: time.Duration(h.FallbackDelay),
	}
	if h.Resolver != nil {
		for _, v := range h.Resolver.Addresses {
			addr, err := caddy.ParseNetworkAddress(v)
			if err != nil {
				return nil, err
			}
			if addr.PortRangeSize() != 1 {
				return nil, fmt.Errorf("resolver address must have exactly one address; cannot call %v", addr)
			}
			h.Resolver.netAddrs = append(h.Resolver.netAddrs, addr)
		}
		d := &net.Dialer{
			Timeout:       time.Duration(h.DialTimeout),
			FallbackDelay: time.Duration(h.FallbackDelay),
		}
		dialer.Resolver = &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
				addr := h.Resolver.netAddrs[weakrand.Intn(len(h.Resolver.netAddrs))]
				return d.DialContext(ctx, addr.Network, addr.JoinHostPort(0))
			},
		}
	}
	rt := &http.Transport{
		DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
			if dialInfo, ok := GetDialInfo(ctx); ok {
				network = dialInfo.Network
				address = dialInfo.Address
			}
			conn, err := dialer.DialContext(ctx, network, address)
			if err != nil {
				return nil, DialError{err}
			}
			return conn, nil
		},
		MaxConnsPerHost:        h.MaxConnsPerHost,
		ResponseHeaderTimeout:  time.Duration(h.ResponseHeaderTimeout),
		ExpectContinueTimeout:  time.Duration(h.ExpectContinueTimeout),
		MaxResponseHeaderBytes: h.MaxResponseHeaderSize,
		WriteBufferSize:        h.WriteBufferSize,
		ReadBufferSize:         h.ReadBufferSize,
	}
	if h.TLS != nil {
		rt.TLSHandshakeTimeout = time.Duration(h.TLS.HandshakeTimeout)
		var err error
		rt.TLSClientConfig, err = h.TLS.MakeTLSClientConfig(ctx)
		if err != nil {
			return nil, fmt.Errorf("making TLS client config: %v", err)
		}
	}
	if h.KeepAlive != nil {
		dialer.KeepAlive = time.Duration(h.KeepAlive.ProbeInterval)
		if h.KeepAlive.Enabled != nil {
			rt.DisableKeepAlives = !*h.KeepAlive.Enabled
		}
		rt.MaxIdleConns = h.KeepAlive.MaxIdleConns
		rt.MaxIdleConnsPerHost = h.KeepAlive.MaxIdleConnsPerHost
		rt.IdleConnTimeout = time.Duration(h.KeepAlive.IdleConnTimeout)
	}
	if h.Compression != nil {
		rt.DisableCompression = !*h.Compression
	}
	if sliceContains(h.Versions, "2") {
		if err := http2.ConfigureTransport(rt); err != nil {
			return nil, err
		}
	}
	return rt, nil
}
func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	h.SetScheme(req)
	if req.ProtoMajor == 2 && req.URL.Scheme == "http" && h.h2cTransport != nil {
		return h.h2cTransport.RoundTrip(req)
	}
	return h.Transport.RoundTrip(req)
}
func (h *HTTPTransport) SetScheme(req *http.Request) {
	if req.URL.Scheme == "" {
		req.URL.Scheme = "http"
		if h.TLS != nil {
			req.URL.Scheme = "https"
		}
	}
}