Skip to content

Commit

Permalink
*: drain http.Response.Body before closing
Browse files Browse the repository at this point in the history
Draining the body prevents the TCP/TLS connection from closing
and makes the connection available for reuse.
  • Loading branch information
gyuho committed Mar 28, 2016
1 parent 83ada72 commit b49a6d7
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 1 deletion.
2 changes: 2 additions & 0 deletions etcdserver/cluster_util.go
Expand Up @@ -17,6 +17,7 @@ package etcdserver
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"sort"
Expand Down Expand Up @@ -231,6 +232,7 @@ func getVersion(m *Member, rt http.RoundTripper) (*version.Versions, error) {
}
// etcd 2.0 does not have version endpoint on peer url.
if resp.StatusCode == http.StatusNotFound {
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
return &version.Versions{
Server: "2.0.0",
Expand Down
7 changes: 6 additions & 1 deletion rafthttp/snapshot_sender.go
Expand Up @@ -124,7 +124,12 @@ func (s *snapshotSender) post(req *http.Request) (err error) {
// close the response body when timeouts.
// prevents from reading the body forever when the other side dies right after
// successfully receives the request body.
time.AfterFunc(snapResponseReadTimeout, func() { resp.Body.Close() })
time.AfterFunc(snapResponseReadTimeout, func() {
// Draining the body prevents the TCP/TLS connection from closing
// and makes the connection available for reuse
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
})
body, err := ioutil.ReadAll(resp.Body)
result <- responseAndError{resp, body, err}
}()
Expand Down
5 changes: 5 additions & 0 deletions rafthttp/stream.go
Expand Up @@ -417,13 +417,15 @@ func (cr *streamReader) dial(t streamType) (io.ReadCloser, error) {
rv := serverVersion(resp.Header)
lv := semver.Must(semver.NewVersion(version.Version))
if compareMajorMinorVersion(rv, lv) == -1 && !checkStreamSupport(rv, t) {
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
cr.picker.unreachable(u)
return nil, errUnsupportedStreamType
}

switch resp.StatusCode {
case http.StatusGone:
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
cr.picker.unreachable(u)
err := fmt.Errorf("the member has been permanently removed from the cluster")
Expand All @@ -435,6 +437,7 @@ func (cr *streamReader) dial(t streamType) (io.ReadCloser, error) {
case http.StatusOK:
return resp.Body, nil
case http.StatusNotFound:
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
cr.picker.unreachable(u)
return nil, fmt.Errorf("remote member %s could not recognize local member", cr.remote)
Expand All @@ -444,6 +447,7 @@ func (cr *streamReader) dial(t streamType) (io.ReadCloser, error) {
cr.picker.unreachable(u)
return nil, err
}
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
cr.picker.unreachable(u)

Expand All @@ -459,6 +463,7 @@ func (cr *streamReader) dial(t streamType) (io.ReadCloser, error) {
return nil, fmt.Errorf("unhandled error %q when precondition failed", string(b))
}
default:
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
cr.picker.unreachable(u)
return nil, fmt.Errorf("unhandled http status %d", resp.StatusCode)
Expand Down

0 comments on commit b49a6d7

Please sign in to comment.