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
9 changes: 6 additions & 3 deletions github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,9 +723,8 @@ func (e *Error) Error() string {
// CheckResponse checks the API response for errors, and returns them if
// present. A response is considered an error if it has a status code outside
// the 200 range or equal to 202 Accepted.
// API error responses are expected to have either no response
// body, or a JSON response body that maps to ErrorResponse. Any other
// response body will be silently ignored.
// API error responses are expected to have response
// body, and a JSON response body that maps to ErrorResponse.
//
// The error type will be *RateLimitError for rate limit exceeded errors,
// *AcceptedError for 202 Accepted status codes,
Expand All @@ -742,6 +741,10 @@ func CheckResponse(r *http.Response) error {
if err == nil && data != nil {
json.Unmarshal(data, errorResponse)
}
// Re-populate error response body because GitHub error responses are often
// undocumented and inconsistent.
// Issue #1136, #540.
r.Body = ioutil.NopCloser(bytes.NewBuffer(data))
switch {
case r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required"):
return (*TwoFactorAuthError)(errorResponse)
Expand Down
30 changes: 30 additions & 0 deletions github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,36 @@ func TestCheckResponse_noBody(t *testing.T) {
}
}

func TestCheckResponse_unexpectedErrorStructure(t *testing.T) {
httpBody := `{"message":"m", "errors": ["error 1"]}`
res := &http.Response{
Request: &http.Request{},
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(strings.NewReader(httpBody)),
}
err := CheckResponse(res).(*ErrorResponse)

if err == nil {
t.Errorf("Expected error response.")
}

want := &ErrorResponse{
Response: res,
Message: "m",
Errors: []Error{{}},
}
if !reflect.DeepEqual(err, want) {
t.Errorf("Error = %#v, want %#v", err, want)
}
data, err2 := ioutil.ReadAll(err.Response.Body)
if err2 != nil {
t.Fatalf("failed to read response body: %v", err)
}
if got := string(data); got != httpBody {
t.Errorf("ErrorResponse.Response.Body = %q, want %q", got, httpBody)
}
}

func TestParseBooleanResponse_true(t *testing.T) {
result, err := parseBoolResponse(nil)
if err != nil {
Expand Down