Imported Upstream version 2.5.1
[scm/test.git] / lfsapi / errors.go
1 package lfsapi
2
3 import (
4         "fmt"
5         "net/http"
6         "strings"
7
8         "github.com/git-lfs/git-lfs/errors"
9 )
10
11 type httpError interface {
12         Error() string
13         HTTPResponse() *http.Response
14 }
15
16 func IsHTTP(err error) (*http.Response, bool) {
17         if httpErr, ok := err.(httpError); ok {
18                 return httpErr.HTTPResponse(), true
19         }
20         return nil, false
21 }
22
23 type ClientError struct {
24         Message          string `json:"message"`
25         DocumentationUrl string `json:"documentation_url,omitempty"`
26         RequestId        string `json:"request_id,omitempty"`
27         response         *http.Response
28 }
29
30 func (e *ClientError) HTTPResponse() *http.Response {
31         return e.response
32 }
33
34 func (e *ClientError) Error() string {
35         return e.Message
36 }
37
38 func (c *Client) handleResponse(res *http.Response) error {
39         if res.StatusCode < 400 {
40                 return nil
41         }
42
43         cliErr := &ClientError{response: res}
44         err := DecodeJSON(res, cliErr)
45         if IsDecodeTypeError(err) {
46                 err = nil
47         }
48
49         if err == nil {
50                 if len(cliErr.Message) == 0 {
51                         err = defaultError(res)
52                 } else {
53                         err = cliErr
54                 }
55         }
56
57         if res.StatusCode == 401 {
58                 return errors.NewAuthError(err)
59         }
60
61         if res.StatusCode == 422 {
62                 return errors.NewUnprocessableEntityError(err)
63         }
64
65         if res.StatusCode > 499 && res.StatusCode != 501 && res.StatusCode != 507 && res.StatusCode != 509 {
66                 return errors.NewFatalError(err)
67         }
68
69         return err
70 }
71
72 type statusCodeError struct {
73         response *http.Response
74 }
75
76 func NewStatusCodeError(res *http.Response) error {
77         return &statusCodeError{response: res}
78 }
79
80 func (e *statusCodeError) Error() string {
81         req := e.response.Request
82         return fmt.Sprintf("Invalid HTTP status for %s %s: %d",
83                 req.Method,
84                 strings.SplitN(req.URL.String(), "?", 2)[0],
85                 e.response.StatusCode,
86         )
87 }
88
89 func (e *statusCodeError) HTTPResponse() *http.Response {
90         return e.response
91 }
92
93 var (
94         defaultErrors = map[int]string{
95                 400: "Client error: %s",
96                 401: "Authorization error: %s\nCheck that you have proper access to the repository",
97                 403: "Authorization error: %s\nCheck that you have proper access to the repository",
98                 404: "Repository or object not found: %s\nCheck that it exists and that you have proper access to it",
99                 422: "Unprocessable entity: %s",
100                 429: "Rate limit exceeded: %s",
101                 500: "Server error: %s",
102                 501: "Not Implemented: %s",
103                 507: "Insufficient server storage: %s",
104                 509: "Bandwidth limit exceeded: %s",
105         }
106 )
107
108 func defaultError(res *http.Response) error {
109         var msgFmt string
110
111         if f, ok := defaultErrors[res.StatusCode]; ok {
112                 msgFmt = f
113         } else if res.StatusCode < 500 {
114                 msgFmt = defaultErrors[400] + fmt.Sprintf(" from HTTP %d", res.StatusCode)
115         } else {
116                 msgFmt = defaultErrors[500] + fmt.Sprintf(" from HTTP %d", res.StatusCode)
117         }
118
119         return errors.Errorf(msgFmt, res.Request.URL)
120 }