Skip to content

Commit

Permalink
Read body to completion before close
Browse files Browse the repository at this point in the history
The default HTTP client's Transport may not
reuse HTTP/1.x "keep-alive" TCP connections if the Body is
not read to completion and closed.
See: https://golang.org/pkg/net/http/#Response
  • Loading branch information
bigflood committed Mar 18, 2020
1 parent 0997dd0 commit 97842f8
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
7 changes: 7 additions & 0 deletions sling.go
Expand Up @@ -3,6 +3,7 @@ package sling
import (
"encoding/base64"
"io"
"io/ioutil"
"net/http"
"net/url"

Expand Down Expand Up @@ -384,6 +385,12 @@ func (s *Sling) Do(req *http.Request, successV, failureV interface{}) (*http.Res
// when err is nil, resp contains a non-nil resp.Body which must be closed
defer resp.Body.Close()

// The default HTTP client's Transport may not
// reuse HTTP/1.x "keep-alive" TCP connections if the Body is
// not read to completion and closed.
// See: https://golang.org/pkg/net/http/#Response
defer io.Copy(ioutil.Discard, resp.Body)

// Don't try to decode on 204s
if resp.StatusCode == http.StatusNoContent {
return resp, nil
Expand Down
42 changes: 42 additions & 0 deletions sling_test.go
Expand Up @@ -2,17 +2,20 @@ package sling

import (
"bytes"
"context"
"encoding/xml"
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"net"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"sync/atomic"
"testing"
)

Expand Down Expand Up @@ -890,6 +893,45 @@ func TestReceive_errorCreatingRequest(t *testing.T) {
}
}

func TestReuseTcpConnections(t *testing.T) {
var connCount int32

ln, _ := net.Listen("tcp", ":0")
rawURL := fmt.Sprintf("http://%s/", ln.Addr())

server := http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "GET", r)
fmt.Fprintf(w, `{"text": "Some text"}`)
}),
ConnState: func(conn net.Conn, state http.ConnState) {
if state == http.StateNew {
atomic.AddInt32(&connCount, 1)
}
},
}

go server.Serve(ln)

endpoint := New().Client(http.DefaultClient).Base(rawURL).Path("foo/").Get("get")

for i := 0; i < 10; i++ {
resp, err := endpoint.New().Receive(nil, nil)
if err != nil {
t.Errorf("expected nil, got %v", err)
}
if resp.StatusCode != 200 {
t.Errorf("expected %d, got %d", 200, resp.StatusCode)
}
}

server.Shutdown(context.Background())

if connCount != 1 {
t.Errorf("expected 1, got %v", atomic.LoadInt32(&connCount))
}
}

// Testing Utils

// testServer returns an http Client, ServeMux, and Server. The client proxies
Expand Down

0 comments on commit 97842f8

Please sign in to comment.