forked from go-kivik/couchdb
/
errors.go
108 lines (92 loc) · 2.55 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package chttp
import (
"encoding/json"
"fmt"
"mime"
"net/http"
)
// HTTPError is an error that represents an HTTP transport error.
type HTTPError struct {
// Response is the HTTP response received by the client. Typically the
// response body has already been consumed, but the response and request
// headers and other metadata will typically be in tact for debugging
// purposes.
Response *http.Response `json:"-"`
// Reason is the server-supplied error reason.
Reason string `json:"reason"`
exitStatus int
}
func (e *HTTPError) Error() string {
if e.Reason == "" {
return http.StatusText(e.StatusCode())
}
if statusText := http.StatusText(e.StatusCode()); statusText != "" {
return fmt.Sprintf("%s: %s", statusText, e.Reason)
}
return e.Reason
}
// StatusCode returns the embedded status code.
func (e *HTTPError) StatusCode() int {
return e.Response.StatusCode
}
// ExitStatus returns the embedded exit status.
func (e *HTTPError) ExitStatus() int {
return e.exitStatus
}
// Format implements fmt.Formatter
func (e *HTTPError) Format(f fmt.State, c rune) {
formatError(e, f, c)
}
// FormatError satisfies the Go 1.13 errors.Formatter interface
// (golang.org/x/xerrors.Formatter for older versions of Go).
func (e *HTTPError) FormatError(p printer) error {
p.Print(e.Error())
if p.Detail() {
p.Printf("REQUEST: %s %s (%d bytes)", e.Response.Request.Method, e.Response.Request.URL.String(), e.Response.Request.ContentLength)
p.Printf("\nRESPONSE: %d / %s (%d bytes)\n", e.Response.StatusCode, http.StatusText(e.Response.StatusCode), e.Response.ContentLength)
}
return nil
}
// ResponseError returns an error from an *http.Response.
func ResponseError(resp *http.Response) error {
if resp.StatusCode < 400 {
return nil
}
if resp.Body != nil {
defer resp.Body.Close() // nolint: errcheck
}
httpErr := &HTTPError{
Response: resp,
exitStatus: ExitNotRetrieved,
}
if resp.Request.Method != "HEAD" && resp.ContentLength != 0 {
if ct, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type")); ct == typeJSON {
_ = json.NewDecoder(resp.Body).Decode(httpErr)
}
}
return httpErr
}
type curlError struct {
curlStatus int
httpStatus int
error
}
func (e *curlError) ExitStatus() int {
return e.curlStatus
}
func (e *curlError) StatusCode() int {
return e.httpStatus
}
func fullError(httpStatus, curlStatus int, err error) error {
return &curlError{
curlStatus: curlStatus,
httpStatus: httpStatus,
error: err,
}
}
func (e *curlError) Cause() error {
return e.error
}
func (e *curlError) Unwrap() error {
return e.error
}