diff --git a/client.go b/client.go index 42f0bce54a..4315f3a23a 100644 --- a/client.go +++ b/client.go @@ -930,6 +930,7 @@ func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c clientDo go func() { req := AcquireRequest() + req.Timeout = timeout statusCodeCopy, bodyCopy, errCopy := doRequestFollowRedirectsBuffer(req, dst, url, c) mu.Lock() @@ -1241,7 +1242,7 @@ func clientDoDeadline(req *Request, resp *Response, deadline time.Time, c client var timedout, responded bool go func() { - reqCopy.timeout = timeout + reqCopy.Timeout = timeout errDo := c.Do(reqCopy, respCopy) mu.Lock() { @@ -1419,11 +1420,11 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) } var deadline time.Time - if req.timeout > 0 { - deadline = time.Now().Add(req.timeout) + if req.Timeout > 0 { + deadline = time.Now().Add(req.Timeout) } - cc, err := c.acquireConn(req.timeout, req.ConnectionClose()) + cc, err := c.acquireConn(req.Timeout, req.ConnectionClose()) if err != nil { return false, err } @@ -2455,6 +2456,7 @@ func (c *pipelineConnClient) DoDeadline(req *Request, resp *Response, deadline t w := acquirePipelineWork(&c.workPool, timeout) w.respCopy.Header.disableNormalizing = c.DisableHeaderNamesNormalizing w.req = &w.reqCopy + w.req.Timeout = timeout w.resp = &w.respCopy // Make a copy of the request in order to avoid data races on timeouts @@ -2733,7 +2735,6 @@ func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error defer bw.Flush() chR := c.chR chW := c.chW - writeTimeout := c.WriteTimeout maxIdleConnDuration := c.MaxIdleConnDuration if maxIdleConnDuration <= 0 { @@ -2782,11 +2783,17 @@ func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error w.resp.parseNetConn(conn) - if writeTimeout > 0 { + writeDeadline := w.deadline + if c.WriteTimeout > 0 { + tmpWriteDeadline := time.Now().Add(c.WriteTimeout) + if writeDeadline.IsZero() || tmpWriteDeadline.Before(writeDeadline) { + writeDeadline = tmpWriteDeadline + } + } + if !writeDeadline.IsZero() { // Set Deadline every time, since golang has fixed the performance issue // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details - currentTime := time.Now() - if err = conn.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil { + if err = conn.SetWriteDeadline(writeDeadline); err != nil { w.err = err w.done <- struct{}{} return err @@ -2838,7 +2845,6 @@ func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error } br := bufio.NewReaderSize(conn, readBufferSize) chR := c.chR - readTimeout := c.ReadTimeout var ( w *pipelineWork @@ -2857,11 +2863,17 @@ func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error } } - if readTimeout > 0 { + readDeadline := w.deadline + if c.ReadTimeout > 0 { + tmpReadDeadline := time.Now().Add(c.ReadTimeout) + if readDeadline.IsZero() || tmpReadDeadline.Before(readDeadline) { + readDeadline = tmpReadDeadline + } + } + if !readDeadline.IsZero() { // Set Deadline every time, since golang has fixed the performance issue // See https://github.com/golang/go/issues/15133#issuecomment-271571395 for details - currentTime := time.Now() - if err = conn.SetReadDeadline(currentTime.Add(readTimeout)); err != nil { + if err = conn.SetReadDeadline(readDeadline); err != nil { w.err = err w.done <- struct{}{} return err diff --git a/http.go b/http.go index 0cf1bfed1f..ca012c3680 100644 --- a/http.go +++ b/http.go @@ -67,7 +67,7 @@ type Request struct { // Request timeout. Usually set by DoDeadline or DoTimeout // if <= 0, means not set - timeout time.Duration + Timeout time.Duration // Use Host header (request.Header.SetHost) instead of the host from SetRequestURI, SetHost, or URI().SetHost UseHostHeader bool @@ -1030,7 +1030,7 @@ func (req *Request) Reset() { } req.Header.Reset() req.resetSkipHeader() - req.timeout = 0 + req.Timeout = 0 req.UseHostHeader = false }