func WrapRoundTripper(f func(http.RoundTripper) http.RoundTripper) ConfigOpt {
	return func(c *Config) {
		if f != nil {
			if rt := f(c.client.Transport); rt != nil {
				c.client.Transport = rt
			}
		}
	}
}
WrapRoundTripper allows a caller to customize a configuration's HTTP exchanger. Useful
for authentication protocols that operate over stock HTTP.
package httpcli
import (
	"bytes"
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"sync"
	"time"
	"github.com/mesos/mesos-go/api/v1/lib"
	"github.com/mesos/mesos-go/api/v1/lib/client"
	logger "github.com/mesos/mesos-go/api/v1/lib/debug"
	"github.com/mesos/mesos-go/api/v1/lib/encoding"
	"github.com/mesos/mesos-go/api/v1/lib/encoding/codecs"
	"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
	"github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors"
	"github.com/mesos/mesos-go/api/v1/lib/recordio"
)
func noRedirect(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }
type ProtocolError string
func (pe ProtocolError) Error() string { return string(pe) }
const (
	debug             = logger.Logger(false)
	mediaTypeRecordIO = encoding.MediaType("application/recordio")
)
type DoFunc func(*http.Request) (*http.Response, error)
type Response struct {
	io.Closer
	encoding.Decoder
	Header http.Header
}
type ErrorMapperFunc func(*http.Response) error
type ResponseHandler func(*http.Response, client.ResponseClass, error) (mesos.Response, error)
type Client struct {
	url              string
	do               DoFunc
	header           http.Header
	codec            encoding.Codec
	errorMapper      ErrorMapperFunc
	requestOpts      []RequestOpt
	buildRequestFunc func(client.Request, client.ResponseClass, ...RequestOpt) (*http.Request, error)
	handleResponse   ResponseHandler
}
var (
	DefaultCodec   = codecs.ByMediaType[codecs.MediaTypeProtobuf]
	DefaultHeaders = http.Header{}
	DefaultConfigOpt = []ConfigOpt{
		Transport(func(t *http.Transport) {
			t.ResponseHeaderTimeout = 15 * time.Second
			t.MaxIdleConnsPerHost = 2  
		}),
	}
	DefaultErrorMapper = ErrorMapperFunc(apierrors.FromResponse)
)
func New(opts ...Opt) *Client {
	c := &Client{
		codec:       DefaultCodec,
		do:          With(DefaultConfigOpt...),
		header:      cloneHeaders(DefaultHeaders),
		errorMapper: DefaultErrorMapper,
	}
	c.buildRequestFunc = c.buildRequest
	c.handleResponse = c.HandleResponse
	c.With(opts...)
	return c
}
func cloneHeaders(hs http.Header) http.Header {
	result := make(http.Header)
	for k, v := range hs {
		cloned := make([]string, len(v))
		copy(cloned, v)
		result[k] = cloned
	}
	return result
}
func (c *Client) Endpoint() string {
	return c.url
}
type RequestOpt func(*http.Request)
type RequestOpts []RequestOpt
func (opts RequestOpts) Apply(req *http.Request) {
	for _, o := range opts {
		if o != nil {
			o(req)
		}
	}
}
func (c *Client) With(opts ...Opt) Opt {
	return Opts(opts).Merged().Apply(c)
}
func (c *Client) WithTemporary(opt Opt, f func() error) error {
	if opt != nil {
		undo := c.With(opt)
		defer c.With(undo)
	}
	return f()
}
func (c *Client) Mesos(opts ...RequestOpt) mesos.Client {
	return mesos.ClientFunc(func(m encoding.Marshaler) (mesos.Response, error) {
		return c.Do(m, opts...)
	})
}
func prepareForResponse(rc client.ResponseClass, codec encoding.Codec) (RequestOpts, error) {
	var accept RequestOpts
	switch rc {
	case client.ResponseClassSingleton, client.ResponseClassAuto, client.ResponseClassNoData:
		accept = append(accept, Header("Accept", codec.Type.ContentType()))
	case client.ResponseClassStreaming:
		accept = append(accept, Header("Accept", mediaTypeRecordIO.ContentType()))
		accept = append(accept, Header("Message-Accept", codec.Type.ContentType()))
	default:
		return nil, ProtocolError(fmt.Sprintf("illegal response class requested: %v", rc))
	}
	return accept, nil
}
func (c *Client) buildRequest(cr client.Request, rc client.ResponseClass, opt ...RequestOpt) (*http.Request, error) {
	if crs, ok := cr.(client.RequestStreaming); ok {
		return c.buildRequestStream(crs.Marshaler, rc, opt...)
	}
	accept, err := prepareForResponse(rc, c.codec)
	if err != nil {
		return nil, err
	}
	var body bytes.Buffer
	if err := c.codec.NewEncoder(encoding.SinkWriter(&body)).Encode(cr.Marshaler()); err != nil {
		return nil, err
	}
	req, err := http.NewRequest("POST", c.url, &body)
	if err != nil {
		return nil, err
	}
	helper := HTTPRequestHelper{req}
	return helper.
		withOptions(c.requestOpts, opt).
		withHeaders(c.header).
		withHeader("Content-Type", c.codec.Type.ContentType()).
		withHeader("Accept", c.codec.Type.ContentType()).
		withOptions(accept).
		Request, nil
}
func (c *Client) buildRequestStream(f func() encoding.Marshaler, rc client.ResponseClass, opt ...RequestOpt) (*http.Request, error) {
	accept, err := prepareForResponse(rc, c.codec)
	if err != nil {
		return nil, err
	}
	var (
		pr, pw = io.Pipe()
		enc    = c.codec.NewEncoder(func() framing.Writer { return recordio.NewWriter(pw) })
	)
	req, err := http.NewRequest("POST", c.url, pr)
	if err != nil {
		pw.Close()  
		return nil, err
	}
	go func() {
		var closeOnce sync.Once
		defer closeOnce.Do(func() {
			pw.Close()
		})
		for {
			m := f()
			if m == nil {
				break
			}
			err := enc.Encode(m)
			if err != nil {
				closeOnce.Do(func() {
					pw.CloseWithError(err)
				})
				break
			}
		}
	}()
	helper := HTTPRequestHelper{req}
	return helper.
		withOptions(c.requestOpts, opt).
		withHeaders(c.header).
		withHeader("Content-Type", mediaTypeRecordIO.ContentType()).
		withHeader("Message-Content-Type", c.codec.Type.ContentType()).
		withOptions(accept).
		Request, nil
}
func validateSuccessfulResponse(codec encoding.Codec, res *http.Response, rc client.ResponseClass) error {
	switch res.StatusCode {
	case http.StatusOK:
		ct := res.Header.Get("Content-Type")
		switch rc {
		case client.ResponseClassNoData:
			if ct != "" {
				return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
			}
		case client.ResponseClassSingleton, client.ResponseClassAuto:
			if ct != codec.Type.ContentType() {
				return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
			}
		case client.ResponseClassStreaming:
			if ct != mediaTypeRecordIO.ContentType() {
				return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
			}
			ct = res.Header.Get("Message-Content-Type")
			if ct != codec.Type.ContentType() {
				return ProtocolError(fmt.Sprintf("unexpected message content type: %q", ct))
			}
		default:
			return ProtocolError(fmt.Sprintf("unsupported response-class: %q", rc))
		}
	case http.StatusAccepted:
	}
	return nil
}
func newSourceFactory(rc client.ResponseClass, knownLen bool) encoding.SourceFactoryFunc {
	switch rc {
	case client.ResponseClassNoData:
		return nil
	case client.ResponseClassSingleton:
		return encoding.SourceReader
	case client.ResponseClassStreaming:
		return recordIOSourceFactory
	case client.ResponseClassAuto:
		if knownLen {
			return encoding.SourceReader
		}
		return recordIOSourceFactory
	default:
		panic(fmt.Sprintf("unsupported response-class: %q", rc))
	}
}
func recordIOSourceFactory(r io.Reader) encoding.Source {
	return func() framing.Reader { return recordio.NewReader(r) }
}
func (c *Client) HandleResponse(res *http.Response, rc client.ResponseClass, err error) (mesos.Response, error) {
	if err != nil {
		if res != nil && res.Body != nil {
			res.Body.Close()
		}
		return nil, err
	}
	result := &Response{
		Closer: res.Body,
		Header: res.Header,
	}
	if err = c.errorMapper(res); err != nil {
		return result, err
	}
	err = validateSuccessfulResponse(c.codec, res, rc)
	if err != nil {
		res.Body.Close()
		return nil, err
	}
	switch res.StatusCode {
	case http.StatusOK:
		debug.Log("request OK, decoding response")
		sf := newSourceFactory(rc, res.ContentLength > -1)
		if sf == nil {
			if rc != client.ResponseClassNoData {
				panic("nil Source for response that expected data")
			}
			defer res.Body.Close()
			_, err = io.Copy(ioutil.Discard, res.Body)
			return nil, err
		}
		result.Decoder = c.codec.NewDecoder(sf.NewSource(res.Body))
	case http.StatusAccepted:
		debug.Log("request Accepted")
		defer res.Body.Close()
		_, err = io.Copy(ioutil.Discard, res.Body)
		return nil, err
	default:
		debug.Log("unexpected HTTP status", res.StatusCode)
		defer res.Body.Close()
		io.Copy(ioutil.Discard, res.Body)  
		return nil, ProtocolError(fmt.Sprintf("unexpected mesos HTTP response code: %d", res.StatusCode))
	}
	return result, nil
}
func (c *Client) Do(m encoding.Marshaler, opt ...RequestOpt) (res mesos.Response, err error) {
	return c.Send(client.RequestSingleton(m), client.ResponseClassAuto, opt...)
}
func (c *Client) Send(cr client.Request, rc client.ResponseClass, opt ...RequestOpt) (res mesos.Response, err error) {
	var (
		hreq *http.Request
		hres *http.Response
	)
	hreq, err = c.buildRequestFunc(cr, rc, opt...)
	if err == nil {
		hres, err = c.do(hreq)
		res, err = c.handleResponse(hres, rc, err)
	}
	return
}
func ErrorMapper(em ErrorMapperFunc) Opt {
	return func(c *Client) Opt {
		old := c.errorMapper
		c.errorMapper = em
		return ErrorMapper(old)
	}
}
func Endpoint(rawurl string) Opt {
	return func(c *Client) Opt {
		old := c.url
		c.url = rawurl
		return Endpoint(old)
	}
}
func WrapDoer(f func(DoFunc) DoFunc) Opt {
	return func(c *Client) Opt {
		old := c.do
		c.do = f(c.do)
		return Do(old)
	}
}
func Do(do DoFunc) Opt {
	return func(c *Client) Opt {
		old := c.do
		c.do = do
		return Do(old)
	}
}
func Codec(codec encoding.Codec) Opt {
	return func(c *Client) Opt {
		old := c.codec
		c.codec = codec
		return Codec(old)
	}
}
func DefaultHeader(k, v string) Opt {
	return func(c *Client) Opt {
		old, found := c.header[k]
		old = append([]string{}, old...)  
		c.header.Add(k, v)
		return func(c *Client) Opt {
			if found {
				c.header[k] = old
			} else {
				c.header.Del(k)
			}
			return DefaultHeader(k, v)
		}
	}
}
func HandleResponse(f ResponseHandler) Opt {
	return func(c *Client) Opt {
		old := c.handleResponse
		c.handleResponse = f
		return HandleResponse(old)
	}
}
func RequestOptions(opts ...RequestOpt) Opt {
	if len(opts) == 0 {
		return nil
	}
	return func(c *Client) Opt {
		old := append([]RequestOpt{}, c.requestOpts...)
		c.requestOpts = opts
		return RequestOptions(old...)
	}
}
func Header(k, v string) RequestOpt { return func(r *http.Request) { r.Header.Add(k, v) } }
func Close(b bool) RequestOpt { return func(r *http.Request) { r.Close = b } }
func Context(ctx context.Context) RequestOpt {
	return func(r *http.Request) {
		r2 := r.WithContext(ctx)
		*r = *r2
	}
}
type Config struct {
	client    *http.Client
	dialer    *net.Dialer
	transport *http.Transport
}
type ConfigOpt func(*Config)
func With(opt ...ConfigOpt) DoFunc {
	var (
		dialer = &net.Dialer{
			LocalAddr: &net.TCPAddr{IP: net.IPv4zero},
			KeepAlive: 30 * time.Second,
			Timeout:   5 * time.Second,
		}
		transport = &http.Transport{
			Proxy:                 http.ProxyFromEnvironment,
			Dial:                  dialer.Dial,
			ResponseHeaderTimeout: 5 * time.Second,
			TLSClientConfig:       &tls.Config{InsecureSkipVerify: false},
			TLSHandshakeTimeout:   5 * time.Second,
		}
		config = &Config{
			dialer:    dialer,
			transport: transport,
			client: &http.Client{
				Transport:     transport,
				CheckRedirect: noRedirect,  
			},
		}
	)
	for _, o := range opt {
		if o != nil {
			o(config)
		}
	}
	return config.client.Do
}
func Timeout(d time.Duration) ConfigOpt {
	return func(c *Config) {
		c.transport.ResponseHeaderTimeout = d
		c.transport.TLSHandshakeTimeout = d
		c.dialer.Timeout = d
	}
}
func RoundTripper(rt http.RoundTripper) ConfigOpt {
	return func(c *Config) {
		c.client.Transport = rt
	}
}
func TLSConfig(tc *tls.Config) ConfigOpt {
	return func(c *Config) {
		c.transport.TLSClientConfig = tc
	}
}
func Transport(modifyTransport func(*http.Transport)) ConfigOpt {
	return func(c *Config) {
		if modifyTransport != nil {
			modifyTransport(c.transport)
		}
	}
}