Skip to content

Commit

Permalink
Skip decoding if Content-Length is zero (#63)
Browse files Browse the repository at this point in the history
* Some servers send a 0 length response, without a 204 StatusNoContent. Skip decoding these responses, as if they're 204s

Co-authored-by: Dalton Hubble <dghubble@gmail.com>
  • Loading branch information
perigrin and dghubble committed Oct 29, 2020
1 parent ccc28dc commit cb0cde7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
15 changes: 8 additions & 7 deletions sling.go
Expand Up @@ -360,9 +360,9 @@ func (s *Sling) ReceiveSuccess(successV interface{}) (*http.Response, error) {
// Receive creates a new HTTP request and returns the response. Success
// responses (2XX) are JSON decoded into the value pointed to by successV and
// other responses are JSON decoded into the value pointed to by failureV.
// If the status code of response is 204(no content), decoding is skipped.
// Any error creating the request, sending it, or decoding the response is
// returned.
// If the status code of response is 204(no content) or the Content-Lenght is 0,
// decoding is skipped. Any error creating the request, sending it, or decoding
// the response is returned.
// Receive is shorthand for calling Request and Do.
func (s *Sling) Receive(successV, failureV interface{}) (*http.Response, error) {
req, err := s.Request()
Expand All @@ -375,8 +375,9 @@ func (s *Sling) Receive(successV, failureV interface{}) (*http.Response, error)
// Do sends an HTTP request and returns the response. Success responses (2XX)
// are JSON decoded into the value pointed to by successV and other responses
// are JSON decoded into the value pointed to by failureV.
// If the status code of response is 204(no content), decoding is skipped.
// Any error sending the request or decoding the response is returned.
// If the status code of response is 204(no content) or the Content-Length is 0,
// decoding is skipped. Any error sending the request or decoding the response
// is returned.
func (s *Sling) Do(req *http.Request, successV, failureV interface{}) (*http.Response, error) {
resp, err := s.httpClient.Do(req)
if err != nil {
Expand All @@ -391,8 +392,8 @@ func (s *Sling) Do(req *http.Request, successV, failureV interface{}) (*http.Res
// 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 {
// Don't try to decode on 204s or Content-Length is 0
if resp.StatusCode == http.StatusNoContent || resp.ContentLength == 0 {
return resp, nil
}

Expand Down
32 changes: 32 additions & 0 deletions sling_test.go
Expand Up @@ -828,6 +828,38 @@ func TestReceive_success(t *testing.T) {
}
}

func TestReceive_StatusOKNoContent(t *testing.T) {
client, mux, server := testServer()
defer server.Close()
mux.HandleFunc("/foo/submit", func(w http.ResponseWriter, r *http.Request) {
assertMethod(t, "POST", r)
w.WriteHeader(201)
w.Header().Set("Location", "/foo/latest")
})

endpoint := New().Client(client).Base("http://example.com/").Path("foo/").Post("submit")
// fake a post response for testing purposes, checking that it's valid happens in other tests
params := FakeParams{}
model := new(FakeModel)
apiError := new(APIError)
resp, err := endpoint.New().BodyForm(params).Receive(model, apiError)

if err != nil {
t.Errorf("expected nil, got %v", err)
}
if resp.StatusCode != 201 {
t.Errorf("expected %d, got %d", 201, resp.StatusCode)
}
expectedModel := &FakeModel{}
if !reflect.DeepEqual(expectedModel, model) {
t.Errorf("expected %v, got %v", expectedModel, model)
}
expectedAPIError := &APIError{}
if !reflect.DeepEqual(expectedAPIError, apiError) {
t.Errorf("failureV should be zero valued, exepcted %v, got %v", expectedAPIError, apiError)
}
}

func TestReceive_failure(t *testing.T) {
client, mux, server := testServer()
defer server.Close()
Expand Down

0 comments on commit cb0cde7

Please sign in to comment.