133 lines
3.5 KiB
Go
133 lines
3.5 KiB
Go
package errutils
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
const legoDebugClientVerboseError = "LEGO_DEBUG_CLIENT_VERBOSE_ERROR"
|
|
|
|
// HTTPDoError uses with `(http.Client).Do` error.
|
|
type HTTPDoError struct {
|
|
req *http.Request
|
|
err error
|
|
}
|
|
|
|
// NewHTTPDoError creates a new HTTPDoError.
|
|
func NewHTTPDoError(req *http.Request, err error) *HTTPDoError {
|
|
return &HTTPDoError{req: req, err: err}
|
|
}
|
|
|
|
func (h HTTPDoError) Error() string {
|
|
msg := "unable to communicate with the API server:"
|
|
|
|
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
msg += fmt.Sprintf(" [request: %s %s]", h.req.Method, h.req.URL)
|
|
}
|
|
|
|
if h.err == nil {
|
|
return msg
|
|
}
|
|
|
|
return msg + fmt.Sprintf(" error: %v", h.err)
|
|
}
|
|
|
|
func (h HTTPDoError) Unwrap() error {
|
|
return h.err
|
|
}
|
|
|
|
// ReadResponseError use with `io.ReadAll` when reading response body.
|
|
type ReadResponseError struct {
|
|
req *http.Request
|
|
StatusCode int
|
|
err error
|
|
}
|
|
|
|
// NewReadResponseError creates a new ReadResponseError.
|
|
func NewReadResponseError(req *http.Request, statusCode int, err error) *ReadResponseError {
|
|
return &ReadResponseError{req: req, StatusCode: statusCode, err: err}
|
|
}
|
|
|
|
func (r ReadResponseError) Error() string {
|
|
msg := "unable to read response body:"
|
|
|
|
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
msg += fmt.Sprintf(" [request: %s %s]", r.req.Method, r.req.URL)
|
|
}
|
|
|
|
msg += fmt.Sprintf(" [status code: %d]", r.StatusCode)
|
|
|
|
if r.err == nil {
|
|
return msg
|
|
}
|
|
|
|
return msg + fmt.Sprintf(" error: %v", r.err)
|
|
}
|
|
|
|
func (r ReadResponseError) Unwrap() error {
|
|
return r.err
|
|
}
|
|
|
|
// UnmarshalError uses with `json.Unmarshal` or `xml.Unmarshal` when reading response body.
|
|
type UnmarshalError struct {
|
|
req *http.Request
|
|
StatusCode int
|
|
Body []byte
|
|
err error
|
|
}
|
|
|
|
// NewUnmarshalError creates a new UnmarshalError.
|
|
func NewUnmarshalError(req *http.Request, statusCode int, body []byte, err error) *UnmarshalError {
|
|
return &UnmarshalError{req: req, StatusCode: statusCode, Body: bytes.TrimSpace(body), err: err}
|
|
}
|
|
|
|
func (u UnmarshalError) Error() string {
|
|
msg := "unable to unmarshal response:"
|
|
|
|
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
msg += fmt.Sprintf(" [request: %s %s]", u.req.Method, u.req.URL)
|
|
}
|
|
|
|
msg += fmt.Sprintf(" [status code: %d] body: %s", u.StatusCode, string(u.Body))
|
|
|
|
if u.err == nil {
|
|
return msg
|
|
}
|
|
|
|
return msg + fmt.Sprintf(" error: %v", u.err)
|
|
}
|
|
|
|
func (u UnmarshalError) Unwrap() error {
|
|
return u.err
|
|
}
|
|
|
|
// UnexpectedStatusCodeError use when the status of the response is unexpected but there is no API error type.
|
|
type UnexpectedStatusCodeError struct {
|
|
req *http.Request
|
|
StatusCode int
|
|
Body []byte
|
|
}
|
|
|
|
// NewUnexpectedStatusCodeError creates a new UnexpectedStatusCodeError.
|
|
func NewUnexpectedStatusCodeError(req *http.Request, statusCode int, body []byte) *UnexpectedStatusCodeError {
|
|
return &UnexpectedStatusCodeError{req: req, StatusCode: statusCode, Body: bytes.TrimSpace(body)}
|
|
}
|
|
|
|
func NewUnexpectedResponseStatusCodeError(req *http.Request, resp *http.Response) *UnexpectedStatusCodeError {
|
|
raw, _ := io.ReadAll(resp.Body)
|
|
return &UnexpectedStatusCodeError{req: req, StatusCode: resp.StatusCode, Body: bytes.TrimSpace(raw)}
|
|
}
|
|
|
|
func (u UnexpectedStatusCodeError) Error() string {
|
|
msg := "unexpected status code:"
|
|
|
|
if ok, _ := strconv.ParseBool(os.Getenv(legoDebugClientVerboseError)); ok {
|
|
msg += fmt.Sprintf(" [request: %s %s]", u.req.Method, u.req.URL)
|
|
}
|
|
|
|
return msg + fmt.Sprintf(" [status code: %d] body: %s", u.StatusCode, string(u.Body))
|
|
}
|