Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 40 additions & 26 deletions github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,16 +512,15 @@ func parseRate(r *http.Response) Rate {
return rate
}

// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. If v implements the io.Writer
// interface, the raw response body will be written to v, without attempting to
// first decode it. If rate limit is exceeded and reset time is in the future,
// Do returns *RateLimitError immediately without making a network API call.
// BareDo sends an API request and lets you handle the api response. If an error
// or API Error occurs, the error will contain more information. Otherwise you
// are supposed to read and close the response's Body. If rate limit is exceeded
// and reset time is in the future, BareDo returns *RateLimitError immediately
// without making a network API call.
//
// The provided ctx must be non-nil, if it is nil an error is returned. If it is canceled or times out,
// ctx.Err() will be returned.
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
// The provided ctx must be non-nil, if it is nil an error is returned. If it is
// canceled or times out, ctx.Err() will be returned.
func (c *Client) BareDo(ctx context.Context, req *http.Request) (*Response, error) {
if ctx == nil {
return nil, errors.New("context must be non-nil")
}
Expand Down Expand Up @@ -558,8 +557,6 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
return nil, err
}

defer resp.Body.Close()

response := newResponse(resp)

c.rateMu.Lock()
Expand All @@ -568,6 +565,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res

err = CheckResponse(resp)
if err != nil {
defer resp.Body.Close()
// Special case for AcceptedErrors. If an AcceptedError
// has been encountered, the response's payload will be
// added to the AcceptedError and returned.
Expand All @@ -581,27 +579,43 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
}

aerr.Raw = b
return response, aerr
err = aerr
}
}
return response, err
}

return response, err
// Do sends an API request and returns the API response. The API response is
// JSON decoded and stored in the value pointed to by v, or returned as an
// error if an API error has occurred. If v implements the io.Writer interface,
// the raw response body will be written to v, without attempting to first
// decode it. If v is nil, and no error hapens, the response is returned as is.
// If rate limit is exceeded and reset time is in the future, Do returns
// *RateLimitError immediately without making a network API call.
//
// The provided ctx must be non-nil, if it is nil an error is returned. If it
// is canceled or times out, ctx.Err() will be returned.
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
resp, err := c.BareDo(ctx, req)
if err != nil {
return resp, err
}
defer resp.Body.Close()

if v != nil {
if w, ok := v.(io.Writer); ok {
io.Copy(w, resp.Body)
} else {
decErr := json.NewDecoder(resp.Body).Decode(v)
if decErr == io.EOF {
decErr = nil // ignore EOF errors caused by empty response body
}
if decErr != nil {
err = decErr
}
switch v := v.(type) {
case nil:
case io.Writer:
_, err = io.Copy(v, resp.Body)
default:
decErr := json.NewDecoder(resp.Body).Decode(v)
if decErr == io.EOF {
decErr = nil // ignore EOF errors caused by empty response body
}
if decErr != nil {
err = decErr
}
}

return response, err
return resp, err
}

// checkRateLimitBeforeDo does not make any network calls, but uses existing knowledge from
Expand Down
35 changes: 35 additions & 0 deletions github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1560,3 +1560,38 @@ func TestAddOptions_QueryValues(t *testing.T) {
t.Error("addOptions err = nil, want error")
}
}

func TestBareDo_returnsOpenBody(t *testing.T) {

client, mux, _, teardown := setup()
defer teardown()

expectedBody := "Hello from the other side !"

mux.HandleFunc("/test-url", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, expectedBody)
})

ctx := context.Background()
req, err := client.NewRequest("GET", "test-url", nil)
if err != nil {
t.Fatalf("client.NewRequest returned error: %v", err)
}

resp, err := client.BareDo(ctx, req)
if err != nil {
t.Fatalf("client.BareDo returned error: %v", err)
}

got, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("ioutil.ReadAll returned error: %v", err)
}
if string(got) != expectedBody {
t.Fatalf("Expected %q, got %q", expectedBody, string(got))
}
if err := resp.Body.Close(); err != nil {
t.Fatalf("resp.Body.Close() returned error: %v", err)
}
}