Client should return ErrTimeout on timeout (#736)

Not ErrConnectionClosed which is incorrect.

Fixes: https://github.com/valyala/fasthttp/issues/355
This commit is contained in:
Erik Dubbelboer
2020-01-31 22:21:00 +01:00
committed by GitHub
parent 38e068a51c
commit 69d5c3721a
4 changed files with 46 additions and 6 deletions
+20 -3
View File
@@ -1284,9 +1284,6 @@ var (
// see this error.
ErrNoFreeConns = errors.New("no free connections available to host")
// ErrTimeout is returned from timed out calls.
ErrTimeout = errors.New("timeout")
// ErrConnectionClosed may be returned from client methods if the server
// closes connection before returning the first response byte.
//
@@ -1298,6 +1295,26 @@ var (
"Make sure the server returns 'Connection: close' response header before closing the connection")
)
type timeoutError struct {
}
func (e *timeoutError) Error() string {
return "timeout"
}
// Only implement the Timeout() function of the net.Error interface.
// This allows for checks like:
//
// if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
func (e *timeoutError) Timeout() bool {
return true
}
var (
// ErrTimeout is returned from timed out calls.
ErrTimeout = &timeoutError{}
)
// SetMaxConns sets up the maximum number of connections which may be established to all hosts listed in Addr.
func (c *HostClient) SetMaxConns(newMaxConns int) {
c.connsLock.Lock()
+3 -1
View File
@@ -436,7 +436,9 @@ func TestClientReadTimeout(t *testing.T) {
req.SetRequestURI("http://localhost")
req.SetConnectionClose()
c.Do(req, res) //nolint:errcheck
if err := c.Do(req, res); err != ErrTimeout {
t.Errorf("expected ErrTimeout got %#v", err)
}
ReleaseRequest(req)
ReleaseResponse(res)
+18 -1
View File
@@ -197,9 +197,26 @@ func (c *pipeConn) readNextByteBuffer(mayBlock bool) error {
var (
errWouldBlock = errors.New("would block")
errConnectionClosed = errors.New("connection closed")
)
type timeoutError struct {
}
func (e *timeoutError) Error() string {
return "timeout"
}
// Only implement the Timeout() function of the net.Error interface.
// This allows for checks like:
//
// if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
func (e *timeoutError) Timeout() bool {
return true
}
var (
// ErrTimeout is returned from Read() or Write() on timeout.
ErrTimeout = errors.New("timeout")
ErrTimeout = &timeoutError{}
)
func (c *pipeConn) Close() error {
+5 -1
View File
@@ -1307,7 +1307,11 @@ func (h *ResponseHeader) tryRead(r *bufio.Reader, n int) error {
h.resetSkipNormalize()
b, err := r.Peek(n)
if len(b) == 0 {
// treat all errors on the first byte read as EOF
// Return ErrTimeout on any timeout.
if x, ok := err.(interface{ Timeout() bool }); ok && x.Timeout() {
return ErrTimeout
}
// treat all other errors on the first byte read as EOF
if n == 1 || err == io.EOF {
return io.EOF
}