Skip to content

Commit

Permalink
Fix read timeout with nothing read
Browse files Browse the repository at this point in the history
Fixes #605
  • Loading branch information
erikdubbelboer committed Jul 11, 2019
1 parent 1bd0404 commit a0248ed
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 13 deletions.
8 changes: 6 additions & 2 deletions header.go
Original file line number Diff line number Diff line change
Expand Up @@ -1395,9 +1395,10 @@ func (h *RequestHeader) tryRead(r *bufio.Reader, n int) error {
}
}

// n == 1 on the first read for the request.
if n == 1 {
// We didn't read a single byte.
return errNothingRead
return errNothingRead{err}
}

return fmt.Errorf("error when reading request headers: %s", err)
Expand Down Expand Up @@ -2172,9 +2173,12 @@ func AppendNormalizedHeaderKeyBytes(dst, key []byte) []byte {
var (
errNeedMore = errors.New("need more data: cannot find trailing lf")
errSmallBuffer = errors.New("small read buffer. Increase ReadBufferSize")
errNothingRead = errors.New("read timeout with nothing read")
)

type errNothingRead struct {
error
}

// ErrSmallBuffer is returned when the provided buffer size is too small
// for reading request and/or response headers.
//
Expand Down
30 changes: 19 additions & 11 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,10 @@ type Server struct {
// msg to the client if there are more than Server.Concurrency concurrent
// handlers h are running at the moment.
func TimeoutHandler(h RequestHandler, timeout time.Duration, msg string) RequestHandler {
return TimeoutWithCodeHandler(h,timeout,msg, StatusRequestTimeout)
return TimeoutWithCodeHandler(h, timeout, msg, StatusRequestTimeout)
}

// TimeoutWithCodeHandler creates RequestHandler, which returns an error with
// TimeoutWithCodeHandler creates RequestHandler, which returns an error with
// the given msg and status code to the client if h didn't return during
// the given duration.
//
Expand Down Expand Up @@ -1876,7 +1876,9 @@ func (s *Server) serveConn(c net.Conn) error {
if len(b) == 0 {
// If reading from a keep-alive connection returns nothing it means
// the connection was closed (either timeout or from the other side).
err = errNothingRead
if err != io.EOF {
err = errNothingRead{err}
}
}
}
} else {
Expand Down Expand Up @@ -1914,14 +1916,20 @@ func (s *Server) serveConn(c net.Conn) error {
if err != nil {
if err == io.EOF {
err = nil
} else if connRequestNum > 1 && err == errNothingRead {
// This is not the first request and we haven't read a single byte
// of a new request yet. This means it's just a keep-alive connection
// closing down either because the remote closed it or because
// or a read timeout on our side. Either way just close the connection
// and don't return any error response.
err = nil
} else {
} else if nr, ok := err.(errNothingRead); ok {
if connRequestNum > 1 {
// This is not the first request and we haven't read a single byte
// of a new request yet. This means it's just a keep-alive connection
// closing down either because the remote closed it or because
// or a read timeout on our side. Either way just close the connection
// and don't return any error response.
err = nil
} else {
err = nr.error
}
}

if err != nil {
bw = s.writeErrorResponse(bw, ctx, serverName, err)
}
break
Expand Down

0 comments on commit a0248ed

Please sign in to comment.