github.com/cloudwego/hertz@v0.9.3/pkg/protocol/http1/client.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * The MIT License (MIT)
    17   *
    18   * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors
    19   *
    20   * Permission is hereby granted, free of charge, to any person obtaining a copy
    21   * of this software and associated documentation files (the "Software"), to deal
    22   * in the Software without restriction, including without limitation the rights
    23   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    24   * copies of the Software, and to permit persons to whom the Software is
    25   * furnished to do so, subject to the following conditions:
    26   *
    27   * The above copyright notice and this permission notice shall be included in
    28   * all copies or substantial portions of the Software.
    29   *
    30   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    31   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    32   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    33   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    34   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    35   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    36   * THE SOFTWARE.
    37   *
    38   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    39   * Modifications are Copyright 2022 CloudWeGo Authors.
    40   */
    41  
    42  package http1
    43  
    44  import (
    45  	"bytes"
    46  	"context"
    47  	"crypto/tls"
    48  	"errors"
    49  	"io"
    50  	"net"
    51  	"strings"
    52  	"sync"
    53  	"sync/atomic"
    54  	"syscall"
    55  	"time"
    56  
    57  	"github.com/cloudwego/hertz/internal/bytesconv"
    58  	"github.com/cloudwego/hertz/internal/bytestr"
    59  	"github.com/cloudwego/hertz/internal/nocopy"
    60  	"github.com/cloudwego/hertz/pkg/app/client/retry"
    61  	"github.com/cloudwego/hertz/pkg/common/config"
    62  	errs "github.com/cloudwego/hertz/pkg/common/errors"
    63  	"github.com/cloudwego/hertz/pkg/common/hlog"
    64  	"github.com/cloudwego/hertz/pkg/common/timer"
    65  	"github.com/cloudwego/hertz/pkg/network"
    66  	"github.com/cloudwego/hertz/pkg/network/dialer"
    67  	"github.com/cloudwego/hertz/pkg/protocol"
    68  	"github.com/cloudwego/hertz/pkg/protocol/client"
    69  	"github.com/cloudwego/hertz/pkg/protocol/consts"
    70  	"github.com/cloudwego/hertz/pkg/protocol/http1/proxy"
    71  	reqI "github.com/cloudwego/hertz/pkg/protocol/http1/req"
    72  	respI "github.com/cloudwego/hertz/pkg/protocol/http1/resp"
    73  )
    74  
    75  var (
    76  	errConnectionClosed = errs.NewPublic("the server closed connection before returning the first response byte. " +
    77  		"Make sure the server returns 'Connection: close' response header before closing the connection")
    78  
    79  	errTimeout = errs.New(errs.ErrTimeout, errs.ErrorTypePublic, "host client")
    80  )
    81  
    82  // HostClient balances http requests among hosts listed in Addr.
    83  //
    84  // HostClient may be used for balancing load among multiple upstream hosts.
    85  // While multiple addresses passed to HostClient.Addr may be used for balancing
    86  // load among them, it would be better using LBClient instead, since HostClient
    87  // may unevenly balance load among upstream hosts.
    88  //
    89  // It is forbidden copying HostClient instances. Create new instances instead.
    90  //
    91  // It is safe calling HostClient methods from concurrently running goroutines.
    92  type HostClient struct {
    93  	noCopy nocopy.NoCopy //lint:ignore U1000 until noCopy is used
    94  
    95  	*ClientOptions
    96  
    97  	// Comma-separated list of upstream HTTP server host addresses,
    98  	// which are passed to Dialer in a round-robin manner.
    99  	//
   100  	// Each address may contain port if default dialer is used.
   101  	// For example,
   102  	//
   103  	//    - foobar.com:80
   104  	//    - foobar.com:443
   105  	//    - foobar.com:8080
   106  	Addr     string
   107  	IsTLS    bool
   108  	ProxyURI *protocol.URI
   109  
   110  	clientName  atomic.Value
   111  	lastUseTime uint32
   112  
   113  	connsLock  sync.Mutex
   114  	connsCount int
   115  	conns      []*clientConn
   116  	connsWait  *wantConnQueue
   117  
   118  	addrsLock sync.Mutex
   119  	addrs     []string
   120  	addrIdx   uint32
   121  
   122  	tlsConfigMap     map[string]*tls.Config
   123  	tlsConfigMapLock sync.Mutex
   124  
   125  	pendingRequests int32
   126  
   127  	connsCleanerRun bool
   128  
   129  	closed chan struct{}
   130  }
   131  
   132  func (c *HostClient) SetDynamicConfig(dc *client.DynamicConfig) {
   133  	c.Addr = dc.Addr
   134  	c.ProxyURI = dc.ProxyURI
   135  	c.IsTLS = dc.IsTLS
   136  
   137  	// start observation after setting addr to avoid race
   138  	if c.StateObserve != nil {
   139  		go func() {
   140  			t := time.NewTicker(c.ObservationInterval)
   141  			for {
   142  				select {
   143  				case <-c.closed:
   144  					return
   145  				case <-t.C:
   146  					c.StateObserve(c)
   147  				}
   148  			}
   149  		}()
   150  	}
   151  }
   152  
   153  type clientConn struct {
   154  	c network.Conn
   155  
   156  	createdTime time.Time
   157  	lastUseTime time.Time
   158  }
   159  
   160  var startTimeUnix = time.Now().Unix()
   161  
   162  // LastUseTime returns time the client was last used
   163  func (c *HostClient) LastUseTime() time.Time {
   164  	n := atomic.LoadUint32(&c.lastUseTime)
   165  	return time.Unix(startTimeUnix+int64(n), 0)
   166  }
   167  
   168  // Get returns the status code and body of url.
   169  //
   170  // The contents of dst will be replaced by the body and returned, if the dst
   171  // is too small a new slice will be allocated.
   172  //
   173  // The function follows redirects. Use Do* for manually handling redirects.
   174  func (c *HostClient) Get(ctx context.Context, dst []byte, url string) (statusCode int, body []byte, err error) {
   175  	return client.GetURL(ctx, dst, url, c)
   176  }
   177  
   178  func (c *HostClient) ConnectionCount() (count int) {
   179  	c.connsLock.Lock()
   180  	count = len(c.conns)
   181  	c.connsLock.Unlock()
   182  	return
   183  }
   184  
   185  func (c *HostClient) WantConnectionCount() (count int) {
   186  	return c.connsWait.len()
   187  }
   188  
   189  func (c *HostClient) ConnPoolState() config.ConnPoolState {
   190  	c.connsLock.Lock()
   191  	defer c.connsLock.Unlock()
   192  	cps := config.ConnPoolState{
   193  		PoolConnNum:  len(c.conns),
   194  		TotalConnNum: c.connsCount,
   195  		Addr:         c.Addr,
   196  	}
   197  
   198  	if c.connsWait != nil {
   199  		cps.WaitConnNum = c.connsWait.len()
   200  	}
   201  	return cps
   202  }
   203  
   204  // GetTimeout returns the status code and body of url.
   205  //
   206  // The contents of dst will be replaced by the body and returned, if the dst
   207  // is too small a new slice will be allocated.
   208  //
   209  // The function follows redirects. Use Do* for manually handling redirects.
   210  //
   211  // errTimeout error is returned if url contents couldn't be fetched
   212  // during the given timeout.
   213  func (c *HostClient) GetTimeout(ctx context.Context, dst []byte, url string, timeout time.Duration) (statusCode int, body []byte, err error) {
   214  	return client.GetURLTimeout(ctx, dst, url, timeout, c)
   215  }
   216  
   217  // GetDeadline returns the status code and body of url.
   218  //
   219  // The contents of dst will be replaced by the body and returned, if the dst
   220  // is too small a new slice will be allocated.
   221  //
   222  // The function follows redirects. Use Do* for manually handling redirects.
   223  //
   224  // errTimeout error is returned if url contents couldn't be fetched
   225  // until the given deadline.
   226  func (c *HostClient) GetDeadline(ctx context.Context, dst []byte, url string, deadline time.Time) (statusCode int, body []byte, err error) {
   227  	return client.GetURLDeadline(ctx, dst, url, deadline, c)
   228  }
   229  
   230  // Post sends POST request to the given url with the given POST arguments.
   231  //
   232  // The contents of dst will be replaced by the body and returned, if the dst
   233  // is too small a new slice will be allocated.
   234  //
   235  // The function follows redirects. Use Do* for manually handling redirects.
   236  //
   237  // Empty POST body is sent if postArgs is nil.
   238  func (c *HostClient) Post(ctx context.Context, dst []byte, url string, postArgs *protocol.Args) (statusCode int, body []byte, err error) {
   239  	return client.PostURL(ctx, dst, url, postArgs, c)
   240  }
   241  
   242  // A wantConnQueue is a queue of wantConns.
   243  //
   244  // inspired by net/http/transport.go
   245  type wantConnQueue struct {
   246  	// This is a queue, not a deque.
   247  	// It is split into two stages - head[headPos:] and tail.
   248  	// popFront is trivial (headPos++) on the first stage, and
   249  	// pushBack is trivial (append) on the second stage.
   250  	// If the first stage is empty, popFront can swap the
   251  	// first and second stages to remedy the situation.
   252  	//
   253  	// This two-stage split is analogous to the use of two lists
   254  	// in Okasaki's purely functional queue but without the
   255  	// overhead of reversing the list when swapping stages.
   256  	head    []*wantConn
   257  	headPos int
   258  	tail    []*wantConn
   259  }
   260  
   261  // A wantConn records state about a wanted connection
   262  // (that is, an active call to getConn).
   263  // The conn may be gotten by dialing or by finding an idle connection,
   264  // or a cancellation may make the conn no longer wanted.
   265  // These three options are racing against each other and use
   266  // wantConn to coordinate and agree about the winning outcome.
   267  //
   268  // inspired by net/http/transport.go
   269  type wantConn struct {
   270  	ready chan struct{}
   271  	mu    sync.Mutex // protects conn, err, close(ready)
   272  	conn  *clientConn
   273  	err   error
   274  }
   275  
   276  // DoTimeout performs the given request and waits for response during
   277  // the given timeout duration.
   278  //
   279  // Request must contain at least non-zero RequestURI with full url (including
   280  // scheme and host) or non-zero Host header + RequestURI.
   281  //
   282  // The function doesn't follow redirects. Use Get* for following redirects.
   283  //
   284  // Response is ignored if resp is nil.
   285  //
   286  // errTimeout is returned if the response wasn't returned during
   287  // the given timeout.
   288  //
   289  // ErrNoFreeConns is returned if all HostClient.MaxConns connections
   290  // to the host are busy.
   291  //
   292  // It is recommended obtaining req and resp via AcquireRequest
   293  // and AcquireResponse in performance-critical code.
   294  //
   295  // Warning: DoTimeout does not terminate the request itself. The request will
   296  // continue in the background and the response will be discarded.
   297  // If requests take too long and the connection pool gets filled up please
   298  // try setting a ReadTimeout.
   299  func (c *HostClient) DoTimeout(ctx context.Context, req *protocol.Request, resp *protocol.Response, timeout time.Duration) error {
   300  	return client.DoTimeout(ctx, req, resp, timeout, c)
   301  }
   302  
   303  // DoDeadline performs the given request and waits for response until
   304  // the given deadline.
   305  //
   306  // Request must contain at least non-zero RequestURI with full url (including
   307  // scheme and host) or non-zero Host header + RequestURI.
   308  //
   309  // The function doesn't follow redirects. Use Get* for following redirects.
   310  //
   311  // Response is ignored if resp is nil.
   312  //
   313  // errTimeout is returned if the response wasn't returned until
   314  // the given deadline.
   315  //
   316  // ErrNoFreeConns is returned if all HostClient.MaxConns connections
   317  // to the host are busy.
   318  //
   319  // It is recommended obtaining req and resp via AcquireRequest
   320  // and AcquireResponse in performance-critical code.
   321  func (c *HostClient) DoDeadline(ctx context.Context, req *protocol.Request, resp *protocol.Response, deadline time.Time) error {
   322  	return client.DoDeadline(ctx, req, resp, deadline, c)
   323  }
   324  
   325  // DoRedirects performs the given http request and fills the given http response,
   326  // following up to maxRedirectsCount redirects. When the redirect count exceeds
   327  // maxRedirectsCount, ErrTooManyRedirects is returned.
   328  //
   329  // Request must contain at least non-zero RequestURI with full url (including
   330  // scheme and host) or non-zero Host header + RequestURI.
   331  //
   332  // Client determines the server to be requested in the following order:
   333  //
   334  //   - from RequestURI if it contains full url with scheme and host;
   335  //   - from Host header otherwise.
   336  //
   337  // Response is ignored if resp is nil.
   338  //
   339  // ErrNoFreeConns is returned if all DefaultMaxConnsPerHost connections
   340  // to the requested host are busy.
   341  //
   342  // It is recommended obtaining req and resp via AcquireRequest
   343  // and AcquireResponse in performance-critical code.
   344  func (c *HostClient) DoRedirects(ctx context.Context, req *protocol.Request, resp *protocol.Response, maxRedirectsCount int) error {
   345  	_, _, err := client.DoRequestFollowRedirects(ctx, req, resp, req.URI().String(), maxRedirectsCount, c)
   346  	return err
   347  }
   348  
   349  // Do performs the given http request and sets the corresponding response.
   350  //
   351  // Request must contain at least non-zero RequestURI with full url (including
   352  // scheme and host) or non-zero Host header + RequestURI.
   353  //
   354  // The function doesn't follow redirects. Use Get* for following redirects.
   355  //
   356  // Response is ignored if resp is nil.
   357  //
   358  // ErrNoFreeConns is returned if all HostClient.MaxConns connections
   359  // to the host are busy.
   360  //
   361  // It is recommended obtaining req and resp via AcquireRequest
   362  // and AcquireResponse in performance-critical code.
   363  func (c *HostClient) Do(ctx context.Context, req *protocol.Request, resp *protocol.Response) error {
   364  	var (
   365  		err                error
   366  		canIdempotentRetry bool
   367  		isDefaultRetryFunc                    = true
   368  		attempts           uint               = 0
   369  		connAttempts       uint               = 0
   370  		maxAttempts        uint               = 1
   371  		isRequestRetryable client.RetryIfFunc = client.DefaultRetryIf
   372  	)
   373  	retryCfg := c.ClientOptions.RetryConfig
   374  	if retryCfg != nil {
   375  		maxAttempts = retryCfg.MaxAttemptTimes
   376  	}
   377  
   378  	if c.ClientOptions.RetryIfFunc != nil {
   379  		isRequestRetryable = c.ClientOptions.RetryIfFunc
   380  		// if the user has provided a custom retry function, the canIdempotentRetry has no meaning anymore.
   381  		// User will have full control over the retry logic through the custom retry function.
   382  		isDefaultRetryFunc = false
   383  	}
   384  
   385  	atomic.AddInt32(&c.pendingRequests, 1)
   386  	req.Options().StartRequest()
   387  	for {
   388  		select {
   389  		case <-ctx.Done():
   390  			req.CloseBodyStream() //nolint:errcheck
   391  			return ctx.Err()
   392  		default:
   393  		}
   394  
   395  		canIdempotentRetry, err = c.do(req, resp)
   396  		// If there is no custom retry and err is equal to nil, the loop simply exits.
   397  		if err == nil && isDefaultRetryFunc {
   398  			if connAttempts != 0 {
   399  				hlog.SystemLogger().Warnf("Client connection attempt times: %d, url: %s. "+
   400  					"This is mainly because the connection in pool is closed by peer in advance. "+
   401  					"If this number is too high which indicates that long-connection are basically unavailable, "+
   402  					"try to change the request to short-connection.\n", connAttempts, req.URI().FullURI())
   403  			}
   404  			break
   405  		}
   406  
   407  		// This connection is closed by the peer when it is in the connection pool.
   408  		//
   409  		// This case is possible if the server closes the idle
   410  		// keep-alive connection on timeout.
   411  		//
   412  		// Apache and nginx usually do this.
   413  		if canIdempotentRetry && client.DefaultRetryIf(req, resp, err) && errors.Is(err, errs.ErrBadPoolConn) {
   414  			connAttempts++
   415  			continue
   416  		}
   417  
   418  		if isDefaultRetryFunc {
   419  			break
   420  		}
   421  
   422  		attempts++
   423  		if attempts >= maxAttempts {
   424  			break
   425  		}
   426  
   427  		// Check whether this request should be retried
   428  		if !isRequestRetryable(req, resp, err) {
   429  			break
   430  		}
   431  
   432  		wait := retry.Delay(attempts, err, retryCfg)
   433  		// Retry after wait time
   434  		time.Sleep(wait)
   435  	}
   436  	atomic.AddInt32(&c.pendingRequests, -1)
   437  
   438  	if err == io.EOF {
   439  		err = errConnectionClosed
   440  	}
   441  	return err
   442  }
   443  
   444  // PendingRequests returns the current number of requests the client
   445  // is executing.
   446  //
   447  // This function may be used for balancing load among multiple HostClient
   448  // instances.
   449  func (c *HostClient) PendingRequests() int {
   450  	return int(atomic.LoadInt32(&c.pendingRequests))
   451  }
   452  
   453  func (c *HostClient) do(req *protocol.Request, resp *protocol.Response) (bool, error) {
   454  	nilResp := false
   455  	if resp == nil {
   456  		nilResp = true
   457  		resp = protocol.AcquireResponse()
   458  	}
   459  
   460  	canIdempotentRetry, err := c.doNonNilReqResp(req, resp)
   461  
   462  	if nilResp {
   463  		protocol.ReleaseResponse(resp)
   464  	}
   465  
   466  	return canIdempotentRetry, err
   467  }
   468  
   469  type requestConfig struct {
   470  	dialTimeout  time.Duration
   471  	readTimeout  time.Duration
   472  	writeTimeout time.Duration
   473  }
   474  
   475  func (c *HostClient) preHandleConfig(o *config.RequestOptions) requestConfig {
   476  	rc := requestConfig{
   477  		dialTimeout:  c.DialTimeout,
   478  		readTimeout:  c.ReadTimeout,
   479  		writeTimeout: c.WriteTimeout,
   480  	}
   481  	if o.ReadTimeout() > 0 {
   482  		rc.readTimeout = o.ReadTimeout()
   483  	}
   484  
   485  	if o.WriteTimeout() > 0 {
   486  		rc.writeTimeout = o.WriteTimeout()
   487  	}
   488  
   489  	if o.DialTimeout() > 0 {
   490  		rc.dialTimeout = o.DialTimeout()
   491  	}
   492  
   493  	return rc
   494  }
   495  
   496  func updateReqTimeout(reqTimeout, compareTimeout time.Duration, before time.Time) (shouldCloseConn bool, timeout time.Duration) {
   497  	if reqTimeout <= 0 {
   498  		return false, compareTimeout
   499  	}
   500  	left := reqTimeout - time.Since(before)
   501  	if left <= 0 {
   502  		return true, 0
   503  	}
   504  
   505  	if compareTimeout <= 0 {
   506  		return false, left
   507  	}
   508  
   509  	if left > compareTimeout {
   510  		return false, compareTimeout
   511  	}
   512  
   513  	return false, left
   514  }
   515  
   516  func (c *HostClient) doNonNilReqResp(req *protocol.Request, resp *protocol.Response) (bool, error) {
   517  	if req == nil {
   518  		panic("BUG: req cannot be nil")
   519  	}
   520  	if resp == nil {
   521  		panic("BUG: resp cannot be nil")
   522  	}
   523  
   524  	atomic.StoreUint32(&c.lastUseTime, uint32(time.Now().Unix()-startTimeUnix))
   525  
   526  	rc := c.preHandleConfig(req.Options())
   527  
   528  	// Free up resources occupied by response before sending the request,
   529  	// so the GC may reclaim these resources (e.g. response body).
   530  	// backing up SkipBody in case it was set explicitly
   531  	customSkipBody := resp.SkipBody
   532  	resp.Reset()
   533  	resp.SkipBody = customSkipBody
   534  
   535  	if c.DisablePathNormalizing {
   536  		req.URI().DisablePathNormalizing = true
   537  	}
   538  	reqTimeout := req.Options().RequestTimeout()
   539  	begin := req.Options().StartTime()
   540  
   541  	dialTimeout := rc.dialTimeout
   542  	if (reqTimeout > 0 && reqTimeout < dialTimeout) || dialTimeout == 0 {
   543  		dialTimeout = reqTimeout
   544  	}
   545  	cc, inPool, err := c.acquireConn(dialTimeout)
   546  	// if getting connection error, fast fail
   547  	if err != nil {
   548  		return false, err
   549  	}
   550  	conn := cc.c
   551  
   552  	usingProxy := false
   553  	if c.ProxyURI != nil && bytes.Equal(req.Scheme(), bytestr.StrHTTP) {
   554  		usingProxy = true
   555  		proxy.SetProxyAuthHeader(&req.Header, c.ProxyURI)
   556  	}
   557  
   558  	resp.ParseNetAddr(conn)
   559  
   560  	shouldClose, timeout := updateReqTimeout(reqTimeout, rc.writeTimeout, begin)
   561  	if shouldClose {
   562  		c.closeConn(cc)
   563  		return false, errTimeout
   564  	}
   565  
   566  	if err = conn.SetWriteTimeout(timeout); err != nil {
   567  		c.closeConn(cc)
   568  		// try another connection if retry is enabled
   569  		return true, err
   570  	}
   571  
   572  	resetConnection := false
   573  	if c.MaxConnDuration > 0 && time.Since(cc.createdTime) > c.MaxConnDuration && !req.ConnectionClose() {
   574  		req.SetConnectionClose()
   575  		resetConnection = true
   576  	}
   577  
   578  	userAgentOld := req.Header.UserAgent()
   579  	if len(userAgentOld) == 0 {
   580  		req.Header.SetUserAgentBytes(c.getClientName())
   581  	}
   582  	zw := c.acquireWriter(conn)
   583  
   584  	if !usingProxy {
   585  		err = reqI.Write(req, zw)
   586  	} else {
   587  		err = reqI.ProxyWrite(req, zw)
   588  	}
   589  	if resetConnection {
   590  		req.Header.ResetConnectionClose()
   591  	}
   592  
   593  	if err == nil {
   594  		err = zw.Flush()
   595  	}
   596  	// error happened when writing request, close the connection, and try another connection if retry is enabled
   597  	if err != nil {
   598  		defer c.closeConn(cc)
   599  
   600  		errNorm, ok := conn.(network.ErrorNormalization)
   601  		if ok {
   602  			err = errNorm.ToHertzError(err)
   603  		}
   604  
   605  		if !errors.Is(err, errs.ErrConnectionClosed) {
   606  			return true, err
   607  		}
   608  
   609  		// set a protection timeout to avoid infinite loop.
   610  		if conn.SetReadTimeout(time.Second) != nil {
   611  			return true, err
   612  		}
   613  
   614  		// Only if the connection is closed while writing the request. Try to parse the response and return.
   615  		// In this case, the request/response is considered as successful.
   616  		// Otherwise, return the former error.
   617  		zr := c.acquireReader(conn)
   618  		defer zr.Release()
   619  		if respI.ReadHeaderAndLimitBody(resp, zr, c.MaxResponseBodySize) == nil {
   620  			return false, nil
   621  		}
   622  
   623  		if inPool {
   624  			err = errs.ErrBadPoolConn
   625  		}
   626  
   627  		return true, err
   628  	}
   629  
   630  	shouldClose, timeout = updateReqTimeout(reqTimeout, rc.readTimeout, begin)
   631  	if shouldClose {
   632  		c.closeConn(cc)
   633  		return false, errTimeout
   634  	}
   635  
   636  	// Set Deadline every time, since golang has fixed the performance issue
   637  	// See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details
   638  	if err = conn.SetReadTimeout(timeout); err != nil {
   639  		c.closeConn(cc)
   640  		// try another connection if retry is enabled
   641  		return true, err
   642  	}
   643  
   644  	if customSkipBody || req.Header.IsHead() || req.Header.IsConnect() {
   645  		resp.SkipBody = true
   646  	}
   647  	if c.DisableHeaderNamesNormalizing {
   648  		resp.Header.DisableNormalizing()
   649  	}
   650  	zr := c.acquireReader(conn)
   651  
   652  	// errs.ErrBadPoolConn error are returned when the
   653  	// 1 byte peek read fails, and we're actually anticipating a response.
   654  	// Usually this is just due to the inherent keep-alive shut down race,
   655  	// where the server closed the connection at the same time the client
   656  	// wrote. The underlying err field is usually io.EOF or some
   657  	// ECONNRESET sort of thing which varies by platform.
   658  	_, err = zr.Peek(1)
   659  	if err != nil {
   660  		zr.Release() //nolint:errcheck
   661  		c.closeConn(cc)
   662  		if inPool && (err == io.EOF || err == syscall.ECONNRESET) {
   663  			return true, errs.ErrBadPoolConn
   664  		}
   665  		// if this is not a pooled connection,
   666  		// we should not retry to avoid getting stuck in an endless retry loop.
   667  		errNorm, ok := conn.(network.ErrorNormalization)
   668  		if ok {
   669  			err = errNorm.ToHertzError(err)
   670  		}
   671  		return false, err
   672  	}
   673  
   674  	// init here for passing in ReadBodyStream's closure
   675  	// and this value will be assigned after reading Response's Header
   676  	//
   677  	// This is to solve the circular dependency problem of Response and BodyStream
   678  	shouldCloseConn := false
   679  
   680  	if !c.ResponseBodyStream {
   681  		err = respI.ReadHeaderAndLimitBody(resp, zr, c.MaxResponseBodySize)
   682  	} else {
   683  		err = respI.ReadBodyStream(resp, zr, c.MaxResponseBodySize, func(shouldClose bool) error {
   684  			if shouldCloseConn || shouldClose {
   685  				c.closeConn(cc)
   686  			} else {
   687  				c.releaseConn(cc)
   688  			}
   689  			return nil
   690  		})
   691  	}
   692  
   693  	if err != nil {
   694  		zr.Release() //nolint:errcheck
   695  		c.closeConn(cc)
   696  		// Don't retry in case of ErrBodyTooLarge since we will just get the same again.
   697  		retry := !errors.Is(err, errs.ErrBodyTooLarge)
   698  		return retry, err
   699  	}
   700  
   701  	zr.Release() //nolint:errcheck
   702  
   703  	shouldCloseConn = resetConnection || req.ConnectionClose() || resp.ConnectionClose()
   704  
   705  	// In stream mode, we still can close/release the connection immediately if there is no content on the wire.
   706  	if c.ResponseBodyStream && resp.BodyStream() != protocol.NoResponseBody {
   707  		return false, err
   708  	}
   709  
   710  	if shouldCloseConn {
   711  		c.closeConn(cc)
   712  	} else {
   713  		c.releaseConn(cc)
   714  	}
   715  
   716  	return false, err
   717  }
   718  
   719  func (c *HostClient) Close() error {
   720  	close(c.closed)
   721  	return nil
   722  }
   723  
   724  // SetMaxConns sets up the maximum number of connections which may be established to all hosts listed in Addr.
   725  func (c *HostClient) SetMaxConns(newMaxConns int) {
   726  	c.connsLock.Lock()
   727  	c.MaxConns = newMaxConns
   728  	c.connsLock.Unlock()
   729  }
   730  
   731  func (c *HostClient) acquireConn(dialTimeout time.Duration) (cc *clientConn, inPool bool, err error) {
   732  	createConn := false
   733  	startCleaner := false
   734  
   735  	var n int
   736  	c.connsLock.Lock()
   737  	n = len(c.conns)
   738  	if n == 0 {
   739  		maxConns := c.MaxConns
   740  		if maxConns <= 0 {
   741  			maxConns = consts.DefaultMaxConnsPerHost
   742  		}
   743  		if c.connsCount < maxConns {
   744  			c.connsCount++
   745  			createConn = true
   746  			if !c.connsCleanerRun {
   747  				startCleaner = true
   748  				c.connsCleanerRun = true
   749  			}
   750  		}
   751  	} else {
   752  		n--
   753  		cc = c.conns[n]
   754  		c.conns[n] = nil
   755  		c.conns = c.conns[:n]
   756  	}
   757  	c.connsLock.Unlock()
   758  
   759  	if cc != nil {
   760  		return cc, true, nil
   761  	}
   762  	if !createConn {
   763  		if c.MaxConnWaitTimeout <= 0 {
   764  			return nil, true, errs.ErrNoFreeConns
   765  		}
   766  
   767  		timeout := c.MaxConnWaitTimeout
   768  
   769  		// wait for a free connection
   770  		tc := timer.AcquireTimer(timeout)
   771  		defer timer.ReleaseTimer(tc)
   772  
   773  		w := &wantConn{
   774  			ready: make(chan struct{}, 1),
   775  		}
   776  		defer func() {
   777  			if err != nil {
   778  				w.cancel(c, err)
   779  			}
   780  		}()
   781  
   782  		// Note: In the case of setting MaxConnWaitTimeout, if the number
   783  		// of connections in the connection pool exceeds the maximum
   784  		// number of connections and needs to establish a connection while
   785  		// waiting, the dialtimeout on the hostclient is used instead of
   786  		// the dialtimeout in request options.
   787  		c.queueForIdle(w)
   788  
   789  		select {
   790  		case <-w.ready:
   791  			return w.conn, true, w.err
   792  		case <-tc.C:
   793  			return nil, true, errs.ErrNoFreeConns
   794  		}
   795  	}
   796  
   797  	if startCleaner {
   798  		go c.connsCleaner()
   799  	}
   800  
   801  	conn, err := c.dialHostHard(dialTimeout)
   802  	if err != nil {
   803  		c.decConnsCount()
   804  		return nil, false, err
   805  	}
   806  	cc = acquireClientConn(conn)
   807  
   808  	return cc, false, nil
   809  }
   810  
   811  func (c *HostClient) queueForIdle(w *wantConn) {
   812  	c.connsLock.Lock()
   813  	defer c.connsLock.Unlock()
   814  	if c.connsWait == nil {
   815  		c.connsWait = &wantConnQueue{}
   816  	}
   817  	c.connsWait.clearFront()
   818  	c.connsWait.pushBack(w)
   819  }
   820  
   821  func (c *HostClient) dialConnFor(w *wantConn) {
   822  	conn, err := c.dialHostHard(c.DialTimeout)
   823  	if err != nil {
   824  		w.tryDeliver(nil, err)
   825  		c.decConnsCount()
   826  		return
   827  	}
   828  
   829  	cc := acquireClientConn(conn)
   830  	delivered := w.tryDeliver(cc, nil)
   831  	if !delivered {
   832  		// not delivered, return idle connection
   833  		c.releaseConn(cc)
   834  	}
   835  }
   836  
   837  // CloseIdleConnections closes any connections which were previously
   838  // connected from previous requests but are now sitting idle in a
   839  // "keep-alive" state. It does not interrupt any connections currently
   840  // in use.
   841  func (c *HostClient) CloseIdleConnections() {
   842  	c.connsLock.Lock()
   843  	scratch := append([]*clientConn{}, c.conns...)
   844  	for i := range c.conns {
   845  		c.conns[i] = nil
   846  	}
   847  	c.conns = c.conns[:0]
   848  	c.connsLock.Unlock()
   849  
   850  	for _, cc := range scratch {
   851  		c.closeConn(cc)
   852  	}
   853  }
   854  
   855  func (c *HostClient) ShouldRemove() bool {
   856  	c.connsLock.Lock()
   857  	defer c.connsLock.Unlock()
   858  	return c.connsCount == 0
   859  }
   860  
   861  func (c *HostClient) connsCleaner() {
   862  	var (
   863  		scratch             []*clientConn
   864  		maxIdleConnDuration = c.MaxIdleConnDuration
   865  	)
   866  	if maxIdleConnDuration <= 0 {
   867  		maxIdleConnDuration = consts.DefaultMaxIdleConnDuration
   868  	}
   869  	for {
   870  		currentTime := time.Now()
   871  
   872  		// Determine idle connections to be closed.
   873  		c.connsLock.Lock()
   874  		conns := c.conns
   875  		n := len(conns)
   876  		i := 0
   877  
   878  		for i < n && currentTime.Sub(conns[i].lastUseTime) > maxIdleConnDuration {
   879  			i++
   880  		}
   881  		sleepFor := maxIdleConnDuration
   882  		if i < n {
   883  			// + 1 so we actually sleep past the expiration time and not up to it.
   884  			// Otherwise the > check above would still fail.
   885  			sleepFor = maxIdleConnDuration - currentTime.Sub(conns[i].lastUseTime) + 1
   886  		}
   887  		scratch = append(scratch[:0], conns[:i]...)
   888  		if i > 0 {
   889  			m := copy(conns, conns[i:])
   890  			for i = m; i < n; i++ {
   891  				conns[i] = nil
   892  			}
   893  			c.conns = conns[:m]
   894  		}
   895  		c.connsLock.Unlock()
   896  
   897  		// Close idle connections.
   898  		for i, cc := range scratch {
   899  			c.closeConn(cc)
   900  			scratch[i] = nil
   901  		}
   902  
   903  		// Determine whether to stop the connsCleaner.
   904  		c.connsLock.Lock()
   905  		mustStop := c.connsCount == 0
   906  		if mustStop {
   907  			c.connsCleanerRun = false
   908  		}
   909  		c.connsLock.Unlock()
   910  		if mustStop {
   911  			break
   912  		}
   913  
   914  		time.Sleep(sleepFor)
   915  	}
   916  }
   917  
   918  func (c *HostClient) closeConn(cc *clientConn) {
   919  	c.decConnsCount()
   920  	cc.c.Close()
   921  	releaseClientConn(cc)
   922  }
   923  
   924  func (c *HostClient) decConnsCount() {
   925  	if c.MaxConnWaitTimeout <= 0 {
   926  		c.connsLock.Lock()
   927  		c.connsCount--
   928  		c.connsLock.Unlock()
   929  		return
   930  	}
   931  
   932  	c.connsLock.Lock()
   933  	defer c.connsLock.Unlock()
   934  	dialed := false
   935  	if q := c.connsWait; q != nil && q.len() > 0 {
   936  		for q.len() > 0 {
   937  			w := q.popFront()
   938  			if w.waiting() {
   939  				go c.dialConnFor(w)
   940  				dialed = true
   941  				break
   942  			}
   943  		}
   944  	}
   945  	if !dialed {
   946  		c.connsCount--
   947  	}
   948  }
   949  
   950  func acquireClientConn(conn network.Conn) *clientConn {
   951  	v := clientConnPool.Get()
   952  	if v == nil {
   953  		v = &clientConn{}
   954  	}
   955  	cc := v.(*clientConn)
   956  	cc.c = conn
   957  	cc.createdTime = time.Now()
   958  	return cc
   959  }
   960  
   961  func releaseClientConn(cc *clientConn) {
   962  	// Reset all fields.
   963  	*cc = clientConn{}
   964  	clientConnPool.Put(cc)
   965  }
   966  
   967  var clientConnPool sync.Pool
   968  
   969  func (c *HostClient) releaseConn(cc *clientConn) {
   970  	cc.lastUseTime = time.Now()
   971  	if c.MaxConnWaitTimeout <= 0 {
   972  		c.connsLock.Lock()
   973  		c.conns = append(c.conns, cc)
   974  		c.connsLock.Unlock()
   975  		return
   976  	}
   977  
   978  	// try to deliver an idle connection to a *wantConn
   979  	c.connsLock.Lock()
   980  	defer c.connsLock.Unlock()
   981  	delivered := false
   982  	if q := c.connsWait; q != nil && q.len() > 0 {
   983  		for q.len() > 0 {
   984  			w := q.popFront()
   985  			if w.waiting() {
   986  				delivered = w.tryDeliver(cc, nil)
   987  				break
   988  			}
   989  		}
   990  	}
   991  	if !delivered {
   992  		c.conns = append(c.conns, cc)
   993  	}
   994  }
   995  
   996  func (c *HostClient) acquireWriter(conn network.Conn) network.Writer {
   997  	return conn
   998  }
   999  
  1000  func (c *HostClient) acquireReader(conn network.Conn) network.Reader {
  1001  	return conn
  1002  }
  1003  
  1004  func newClientTLSConfig(c *tls.Config, addr string) *tls.Config {
  1005  	if c == nil {
  1006  		c = &tls.Config{}
  1007  	} else {
  1008  		c = c.Clone()
  1009  	}
  1010  
  1011  	if c.ClientSessionCache == nil {
  1012  		c.ClientSessionCache = tls.NewLRUClientSessionCache(0)
  1013  	}
  1014  
  1015  	if len(c.ServerName) == 0 {
  1016  		serverName := tlsServerName(addr)
  1017  		if serverName == "*" {
  1018  			c.InsecureSkipVerify = true
  1019  		} else {
  1020  			c.ServerName = serverName
  1021  		}
  1022  	}
  1023  	return c
  1024  }
  1025  
  1026  func tlsServerName(addr string) string {
  1027  	if !strings.Contains(addr, ":") {
  1028  		return addr
  1029  	}
  1030  	host, _, err := net.SplitHostPort(addr)
  1031  	if err != nil {
  1032  		return "*"
  1033  	}
  1034  	return host
  1035  }
  1036  
  1037  func (c *HostClient) nextAddr() string {
  1038  	c.addrsLock.Lock()
  1039  	if c.addrs == nil {
  1040  		c.addrs = strings.Split(c.Addr, ",")
  1041  	}
  1042  	addr := c.addrs[0]
  1043  	if len(c.addrs) > 1 {
  1044  		addr = c.addrs[c.addrIdx%uint32(len(c.addrs))]
  1045  		c.addrIdx++
  1046  	}
  1047  	c.addrsLock.Unlock()
  1048  	return addr
  1049  }
  1050  
  1051  func (c *HostClient) dialHostHard(dialTimeout time.Duration) (conn network.Conn, err error) {
  1052  	// attempt to dial all the available hosts before giving up.
  1053  
  1054  	c.addrsLock.Lock()
  1055  	n := len(c.addrs)
  1056  	c.addrsLock.Unlock()
  1057  
  1058  	if n == 0 {
  1059  		// It looks like c.addrs isn't initialized yet.
  1060  		n = 1
  1061  	}
  1062  
  1063  	deadline := time.Now().Add(dialTimeout)
  1064  	for n > 0 {
  1065  		addr := c.nextAddr()
  1066  		tlsConfig := c.cachedTLSConfig(addr)
  1067  		conn, err = dialAddr(addr, c.Dialer, c.DialDualStack, tlsConfig, dialTimeout, c.ProxyURI, c.IsTLS)
  1068  		if err == nil {
  1069  			return conn, nil
  1070  		}
  1071  		if time.Since(deadline) >= 0 {
  1072  			break
  1073  		}
  1074  		n--
  1075  	}
  1076  	return nil, err
  1077  }
  1078  
  1079  func (c *HostClient) cachedTLSConfig(addr string) *tls.Config {
  1080  	var cfgAddr string
  1081  	if c.ProxyURI != nil && bytes.Equal(c.ProxyURI.Scheme(), bytestr.StrHTTPS) {
  1082  		cfgAddr = bytesconv.B2s(c.ProxyURI.Host())
  1083  	}
  1084  
  1085  	if c.IsTLS && cfgAddr == "" {
  1086  		cfgAddr = addr
  1087  	}
  1088  
  1089  	if cfgAddr == "" {
  1090  		return nil
  1091  	}
  1092  
  1093  	c.tlsConfigMapLock.Lock()
  1094  	if c.tlsConfigMap == nil {
  1095  		c.tlsConfigMap = make(map[string]*tls.Config)
  1096  	}
  1097  	cfg := c.tlsConfigMap[cfgAddr]
  1098  	if cfg == nil {
  1099  		cfg = newClientTLSConfig(c.TLSConfig, cfgAddr)
  1100  		c.tlsConfigMap[cfgAddr] = cfg
  1101  	}
  1102  	c.tlsConfigMapLock.Unlock()
  1103  
  1104  	return cfg
  1105  }
  1106  
  1107  func dialAddr(addr string, dial network.Dialer, dialDualStack bool, tlsConfig *tls.Config, timeout time.Duration, proxyURI *protocol.URI, isTLS bool) (network.Conn, error) {
  1108  	var conn network.Conn
  1109  	var err error
  1110  	if dial == nil {
  1111  		hlog.SystemLogger().Warn("HostClient: no dialer specified, trying to use default dialer")
  1112  		dial = dialer.DefaultDialer()
  1113  	}
  1114  	dialFunc := dial.DialConnection
  1115  
  1116  	// addr has already been added port, no need to do it here
  1117  	if proxyURI != nil {
  1118  		// use tcp connection first, proxy will AddTLS to it
  1119  		conn, err = dialFunc("tcp", string(proxyURI.Host()), timeout, nil)
  1120  	} else {
  1121  		conn, err = dialFunc("tcp", addr, timeout, tlsConfig)
  1122  	}
  1123  
  1124  	if err != nil {
  1125  		return nil, err
  1126  	}
  1127  	if conn == nil {
  1128  		panic("BUG: dial.DialConnection returned (nil, nil)")
  1129  	}
  1130  
  1131  	if proxyURI != nil {
  1132  		conn, err = proxy.SetupProxy(conn, addr, proxyURI, tlsConfig, isTLS, dial)
  1133  	}
  1134  
  1135  	// conn must be nil when got error, so doesn't need to close it
  1136  	if err != nil {
  1137  		return nil, err
  1138  	}
  1139  	return conn, nil
  1140  }
  1141  
  1142  func (c *HostClient) getClientName() []byte {
  1143  	v := c.clientName.Load()
  1144  	var clientName []byte
  1145  	if v == nil {
  1146  		clientName = []byte(c.Name)
  1147  		if len(clientName) == 0 && !c.NoDefaultUserAgentHeader {
  1148  			clientName = bytestr.DefaultUserAgent
  1149  		}
  1150  		c.clientName.Store(clientName)
  1151  	} else {
  1152  		clientName = v.([]byte)
  1153  	}
  1154  	return clientName
  1155  }
  1156  
  1157  // waiting reports whether w is still waiting for an answer (connection or error).
  1158  func (w *wantConn) waiting() bool {
  1159  	select {
  1160  	case <-w.ready:
  1161  		return false
  1162  	default:
  1163  		return true
  1164  	}
  1165  }
  1166  
  1167  // tryDeliver attempts to deliver conn, err to w and reports whether it succeeded.
  1168  func (w *wantConn) tryDeliver(conn *clientConn, err error) bool {
  1169  	w.mu.Lock()
  1170  	defer w.mu.Unlock()
  1171  
  1172  	if w.conn != nil || w.err != nil {
  1173  		return false
  1174  	}
  1175  	w.conn = conn
  1176  	w.err = err
  1177  	if w.conn == nil && w.err == nil {
  1178  		panic("hertz: internal error: misuse of tryDeliver")
  1179  	}
  1180  	close(w.ready)
  1181  	return true
  1182  }
  1183  
  1184  // cancel marks w as no longer wanting a result (for example, due to cancellation).
  1185  // If a connection has been delivered already, cancel returns it with c.releaseConn.
  1186  func (w *wantConn) cancel(c *HostClient, err error) {
  1187  	w.mu.Lock()
  1188  	if w.conn == nil && w.err == nil {
  1189  		close(w.ready) // catch misbehavior in future delivery
  1190  	}
  1191  
  1192  	conn := w.conn
  1193  	w.conn = nil
  1194  	w.err = err
  1195  	w.mu.Unlock()
  1196  
  1197  	if conn != nil {
  1198  		c.releaseConn(conn)
  1199  	}
  1200  }
  1201  
  1202  // len returns the number of items in the queue.
  1203  func (q *wantConnQueue) len() int {
  1204  	return len(q.head) - q.headPos + len(q.tail)
  1205  }
  1206  
  1207  // pushBack adds w to the back of the queue.
  1208  func (q *wantConnQueue) pushBack(w *wantConn) {
  1209  	q.tail = append(q.tail, w)
  1210  }
  1211  
  1212  // popFront removes and returns the wantConn at the front of the queue.
  1213  func (q *wantConnQueue) popFront() *wantConn {
  1214  	if q.headPos >= len(q.head) {
  1215  		if len(q.tail) == 0 {
  1216  			return nil
  1217  		}
  1218  		// Pick up tail as new head, clear tail.
  1219  		q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
  1220  	}
  1221  
  1222  	w := q.head[q.headPos]
  1223  	q.head[q.headPos] = nil
  1224  	q.headPos++
  1225  	return w
  1226  }
  1227  
  1228  // peekFront returns the wantConn at the front of the queue without removing it.
  1229  func (q *wantConnQueue) peekFront() *wantConn {
  1230  	if q.headPos < len(q.head) {
  1231  		return q.head[q.headPos]
  1232  	}
  1233  	if len(q.tail) > 0 {
  1234  		return q.tail[0]
  1235  	}
  1236  	return nil
  1237  }
  1238  
  1239  // cleanFront pops any wantConns that are no longer waiting from the head of the
  1240  // queue, reporting whether any were popped.
  1241  func (q *wantConnQueue) clearFront() (cleaned bool) {
  1242  	for {
  1243  		w := q.peekFront()
  1244  		if w == nil || w.waiting() {
  1245  			return cleaned
  1246  		}
  1247  		q.popFront()
  1248  		cleaned = true
  1249  	}
  1250  }
  1251  
  1252  func NewHostClient(c *ClientOptions) client.HostClient {
  1253  	hc := &HostClient{
  1254  		ClientOptions: c,
  1255  		closed:        make(chan struct{}),
  1256  	}
  1257  
  1258  	return hc
  1259  }
  1260  
  1261  type ClientOptions struct {
  1262  	// Client name. Used in User-Agent request header.
  1263  	Name string
  1264  
  1265  	// NoDefaultUserAgentHeader when set to true, causes the default
  1266  	// User-Agent header to be excluded from the Request.
  1267  	NoDefaultUserAgentHeader bool
  1268  
  1269  	// Callback for establishing new connection to the host.
  1270  	//
  1271  	// Default Dialer is used if not set.
  1272  	Dialer network.Dialer
  1273  
  1274  	// Timeout for establishing new connections to hosts.
  1275  	//
  1276  	// Default DialTimeout is used if not set.
  1277  	DialTimeout time.Duration
  1278  
  1279  	// Attempt to connect to both ipv4 and ipv6 host addresses
  1280  	// if set to true.
  1281  	//
  1282  	// This option is used only if default TCP dialer is used,
  1283  	// i.e. if Dialer is blank.
  1284  	//
  1285  	// By default client connects only to ipv4 addresses,
  1286  	// since unfortunately ipv6 remains broken in many networks worldwide :)
  1287  	DialDualStack bool
  1288  
  1289  	// Whether to use TLS (aka SSL or HTTPS) for host connections.
  1290  	// Optional TLS config.
  1291  	TLSConfig *tls.Config
  1292  
  1293  	// Maximum number of connections which may be established to all hosts
  1294  	// listed in Addr.
  1295  	//
  1296  	// You can change this value while the HostClient is being used
  1297  	// using HostClient.SetMaxConns(value)
  1298  	//
  1299  	// DefaultMaxConnsPerHost is used if not set.
  1300  	MaxConns int
  1301  
  1302  	// Keep-alive connections are closed after this duration.
  1303  	//
  1304  	// By default connection duration is unlimited.
  1305  	MaxConnDuration time.Duration
  1306  
  1307  	// Idle keep-alive connections are closed after this duration.
  1308  	//
  1309  	// By default idle connections are closed
  1310  	// after DefaultMaxIdleConnDuration.
  1311  	MaxIdleConnDuration time.Duration
  1312  
  1313  	// Maximum duration for full response reading (including body).
  1314  	//
  1315  	// By default response read timeout is unlimited.
  1316  	ReadTimeout time.Duration
  1317  
  1318  	// Maximum duration for full request writing (including body).
  1319  	//
  1320  	// By default request write timeout is unlimited.
  1321  	WriteTimeout time.Duration
  1322  
  1323  	// Maximum response body size.
  1324  	//
  1325  	// The client returns errBodyTooLarge if this limit is greater than 0
  1326  	// and response body is greater than the limit.
  1327  	//
  1328  	// By default response body size is unlimited.
  1329  	MaxResponseBodySize int
  1330  
  1331  	// Header names are passed as-is without normalization
  1332  	// if this option is set.
  1333  	//
  1334  	// Disabled header names' normalization may be useful only for proxying
  1335  	// responses to other clients expecting case-sensitive header names.
  1336  	//
  1337  	// By default request and response header names are normalized, i.e.
  1338  	// The first letter and the first letters following dashes
  1339  	// are uppercased, while all the other letters are lowercased.
  1340  	// Examples:
  1341  	//
  1342  	//     * HOST -> Host
  1343  	//     * content-type -> Content-Type
  1344  	//     * cONTENT-lenGTH -> Content-Length
  1345  	DisableHeaderNamesNormalizing bool
  1346  
  1347  	// Path values are sent as-is without normalization
  1348  	//
  1349  	// Disabled path normalization may be useful for proxying incoming requests
  1350  	// to servers that are expecting paths to be forwarded as-is.
  1351  	//
  1352  	// By default path values are normalized, i.e.
  1353  	// extra slashes are removed, special characters are encoded.
  1354  	DisablePathNormalizing bool
  1355  
  1356  	// Maximum duration for waiting for a free connection.
  1357  	//
  1358  	// By default will not wait, return ErrNoFreeConns immediately
  1359  	MaxConnWaitTimeout time.Duration
  1360  
  1361  	// ResponseBodyStream enables response body streaming
  1362  	ResponseBodyStream bool
  1363  
  1364  	// All configurations related to retry
  1365  	RetryConfig *retry.Config
  1366  
  1367  	RetryIfFunc client.RetryIfFunc
  1368  
  1369  	// Observe hostclient state
  1370  	StateObserve config.HostClientStateFunc
  1371  
  1372  	// StateObserve execution interval
  1373  	ObservationInterval time.Duration
  1374  }