Skip to content

Commit

Permalink
Read body to completion before close (#59)
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 May 13, 2020
1 parent 0997dd0 commit 2f3bcb6
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 count := atomic.LoadInt32(&connCount); count != 1 {
t.Errorf("expected 1, got %v", count)
}
}

// Testing Utils

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

0 comments on commit 2f3bcb6

Please sign in to comment.