client.go raw
1 package errutils
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "net/http"
8 "os"
9 "strconv"
10 )
11
12 const legoDebugClientVerboseError = "LEGO_DEBUG_CLIENT_VERBOSE_ERROR"
13
14 // HTTPDoError uses with `(http.Client).Do` error.
15 type HTTPDoError struct {
16 req *http.Request
17 err error
18 }
19
20 // NewHTTPDoError creates a new HTTPDoError.
21 func NewHTTPDoError(req *http.Request, err error) *HTTPDoError {
22 return &HTTPDoError{req: req, err: err}
23 }
24
25 func (h HTTPDoError) Error() string {
26 msg := "unable to communicate with the API server:"
27
28 if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
29 msg += fmt.Sprintf(" [request: %s %s]", h.req.Method, h.req.URL)
30 }
31
32 if h.err == nil {
33 return msg
34 }
35
36 return msg + fmt.Sprintf(" error: %v", h.err)
37 }
38
39 func (h HTTPDoError) Unwrap() error {
40 return h.err
41 }
42
43 // ReadResponseError use with `io.ReadAll` when reading response body.
44 type ReadResponseError struct {
45 req *http.Request
46 StatusCode int
47 err error
48 }
49
50 // NewReadResponseError creates a new ReadResponseError.
51 func NewReadResponseError(req *http.Request, statusCode int, err error) *ReadResponseError {
52 return &ReadResponseError{req: req, StatusCode: statusCode, err: err}
53 }
54
55 func (r ReadResponseError) Error() string {
56 msg := "unable to read response body:"
57
58 if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
59 msg += fmt.Sprintf(" [request: %s %s]", r.req.Method, r.req.URL)
60 }
61
62 msg += fmt.Sprintf(" [status code: %d]", r.StatusCode)
63
64 if r.err == nil {
65 return msg
66 }
67
68 return msg + fmt.Sprintf(" error: %v", r.err)
69 }
70
71 func (r ReadResponseError) Unwrap() error {
72 return r.err
73 }
74
75 // UnmarshalError uses with `json.Unmarshal` or `xml.Unmarshal` when reading response body.
76 type UnmarshalError struct {
77 req *http.Request
78 StatusCode int
79 Body []byte
80 err error
81 }
82
83 // NewUnmarshalError creates a new UnmarshalError.
84 func NewUnmarshalError(req *http.Request, statusCode int, body []byte, err error) *UnmarshalError {
85 return &UnmarshalError{req: req, StatusCode: statusCode, Body: bytes.TrimSpace(body), err: err}
86 }
87
88 func (u UnmarshalError) Error() string {
89 msg := "unable to unmarshal response:"
90
91 if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
92 msg += fmt.Sprintf(" [request: %s %s]", u.req.Method, u.req.URL)
93 }
94
95 msg += fmt.Sprintf(" [status code: %d] body: %s", u.StatusCode, string(u.Body))
96
97 if u.err == nil {
98 return msg
99 }
100
101 return msg + fmt.Sprintf(" error: %v", u.err)
102 }
103
104 func (u UnmarshalError) Unwrap() error {
105 return u.err
106 }
107
108 // UnexpectedStatusCodeError use when the status of the response is unexpected but there is no API error type.
109 type UnexpectedStatusCodeError struct {
110 req *http.Request
111 StatusCode int
112 Body []byte
113 }
114
115 // NewUnexpectedStatusCodeError creates a new UnexpectedStatusCodeError.
116 func NewUnexpectedStatusCodeError(req *http.Request, statusCode int, body []byte) *UnexpectedStatusCodeError {
117 return &UnexpectedStatusCodeError{req: req, StatusCode: statusCode, Body: bytes.TrimSpace(body)}
118 }
119
120 func NewUnexpectedResponseStatusCodeError(req *http.Request, resp *http.Response) *UnexpectedStatusCodeError {
121 raw, _ := io.ReadAll(resp.Body)
122 return &UnexpectedStatusCodeError{req: req, StatusCode: resp.StatusCode, Body: bytes.TrimSpace(raw)}
123 }
124
125 func (u UnexpectedStatusCodeError) Error() string {
126 msg := "unexpected status code:"
127
128 if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
129 msg += fmt.Sprintf(" [request: %s %s]", u.req.Method, u.req.URL)
130 }
131
132 return msg + fmt.Sprintf(" [status code: %d] body: %s", u.StatusCode, string(u.Body))
133 }
134