-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathresponse.go
More file actions
118 lines (105 loc) · 2.99 KB
/
response.go
File metadata and controls
118 lines (105 loc) · 2.99 KB
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
109
110
111
112
113
114
115
116
117
118
package requests
import (
"encoding/json"
"errors"
"io"
"net/http"
)
// Response is a wrapper of http.Response.
type Response struct {
*http.Response
body []byte // auto filled from Response.Body
}
// newResponse reads and closes Response.Body. Then check the HTTP status
// in Response.StatusCode. It will return an error with status and text
// body embedded if status code is not 2xx, and none-nil response is also
// returned.
func newResponse(resp *http.Response, opts *Options) (*Response, error) {
r := &Response{
Response: resp,
}
if err := r.readAndCloseBody(); err != nil {
return nil, err
}
// return error with status and text body embedded if status code
// is not 2xx, and response is also returned.
if resp.StatusCode < 200 || resp.StatusCode > 299 {
// TODO: only extracts 128 bytes from body.
return r, errors.New(resp.Status + " " + r.Text())
}
if opts.ToText != nil {
*opts.ToText = r.Text()
}
if opts.ToJSON != nil {
if err := r.JSON(opts.ToJSON); err != nil {
return r, err
}
}
return r, nil
}
// readAndCloseBody drains all the HTTP response body stream and then closes it.
func (r *Response) readAndCloseBody() (err error) {
defer func() {
err1 := r.Response.Body.Close()
err = errors.Join(err, err1)
}()
r.body, err = io.ReadAll(r.Response.Body)
return err
}
// StatusCode returns status code of HTTP response.
//
// NOTE: It returns -1 if response is nil.
func (r *Response) StatusCode() int {
if r == nil || r.Response == nil {
// return special status code -1 which is not registered with IANA.
return -1
}
return r.Response.StatusCode
}
// StatusText returns a text for the HTTP status code.
//
// NOTE:
// - It returns "<nil>" if response is nil.
// - It returns the empty string if the code is unknown.
//
// e.g. "OK"
func (r *Response) StatusText() string {
if r == nil || r.Response == nil {
// return special status code -1 which is not registered with IANA.
return "<nil>"
}
return r.Response.Status
}
// Bytes returns the HTTP response body as []byte.
func (r *Response) Bytes() []byte {
return r.body
}
// Text parses the HTTP response body as string.
func (r *Response) Text() string {
return string(r.body)
}
// JSON decodes the HTTP response body as JSON format.
func (r *Response) JSON(v any) error {
return json.Unmarshal(r.body, v)
}
// Method returns the HTTP request method.
func (r *Response) Method() string {
return r.Response.Request.Method
}
// URL returns the HTTP request URL string.
func (r *Response) URL() string {
return r.Response.Request.URL.String()
}
// Headers maps header keys to values. If the response had multiple headers
// with the same key, they may be concatenated, with comma delimiters.
func (r *Response) Headers() http.Header {
return r.Response.Header
}
// Cookies parses and returns the cookies set in the Set-Cookie headers.
func (r *Response) Cookies() map[string]*http.Cookie {
cookies := make(map[string]*http.Cookie)
for _, c := range r.Response.Cookies() {
cookies[c.Name] = c
}
return cookies
}