/
options.go
252 lines (223 loc) · 6.28 KB
/
options.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
package requests
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/url"
"os"
"path/filepath"
"strings"
"time"
)
// RequestOptions is a collection of request options.
type RequestOptions struct {
Headers map[string]interface{}
Queries url.Values
Cookies map[string]string
Body io.Reader
Deadline time.Time
multipartWriter *multipart.Writer
Err error
}
func (o *RequestOptions) getMultipartWriter() *multipart.Writer {
if o.multipartWriter == nil {
Body(new(bytes.Buffer))(o)
o.multipartWriter = multipart.NewWriter(o.Body.(*bytes.Buffer))
}
return o.multipartWriter
}
// NewOptions return a new *RequestOptions.
func NewOptions() *RequestOptions {
return &RequestOptions{
Headers: map[string]interface{}{},
Queries: url.Values{},
Cookies: map[string]string{},
}
}
// RequestOption is used to update the fields in RequestOptions.
type RequestOption func(o *RequestOptions)
// Deadline set the deadline of this request.
func Deadline(t time.Time) RequestOption {
return func(o *RequestOptions) {
o.Deadline = t
}
}
// Timeout set the timeout of this request.
func Timeout(d time.Duration) RequestOption {
return func(o *RequestOptions) {
o.Deadline = time.Now().Add(d)
}
}
// Header sets the request's header, v can be a string, fmt.Stringer or nil,
// when v is nil this header will be removed.
func Header(k string, v interface{}) RequestOption {
return func(o *RequestOptions) {
o.Headers[k] = v
}
}
// Headers sets the request's headers, value of map be a string, fmt.Stringer or nil,
// when v is nil this header will be removed.
// If the replace flag is true, the existing header will be removed.
func Headers(m map[string]interface{}, replace ...bool) RequestOption {
return func(o *RequestOptions) {
if len(replace) == 1 && replace[0] {
o.Headers = m
return
}
for k, v := range m {
Header(k, v)(o)
}
}
}
// UserAgent sets the request's UserAgent header.
func UserAgent(ua string) RequestOption {
return func(o *RequestOptions) {
Header(HeaderUserAgent, ua)(o)
}
}
// ContentType sets the request's ContentType header.
func ContentType(ct string) RequestOption {
return func(o *RequestOptions) {
Header(HeaderContentType, ct)(o)
}
}
// Referer sets the request's Referer header.
func Referer(r string) RequestOption {
return func(o *RequestOptions) {
Header(HeaderReferer, r)(o)
}
}
// Authorization sets the request's Authorization header.
func Authorization(a string) RequestOption {
return func(o *RequestOptions) {
Header(HeaderAuthorization, a)(o)
}
}
// BasicAuth sets the request's Authorization header to use HTTP
// Basic Authentication with the provided username and password.
func BasicAuth(username, password string) RequestOption {
return func(o *RequestOptions) {
Authorization("Basic " + base64.StdEncoding.EncodeToString(
[]byte(fmt.Sprintf("%s:%s", username, password))))(o)
}
}
// Cookie sets the request's cookie.
func Cookie(k, v string) RequestOption {
return func(o *RequestOptions) {
o.Cookies[k] = v
}
}
// Cookies sets the request's cookies,
// if the replace flag is true, the existing cookies will be removed.
func Cookies(m map[string]string, replace ...bool) RequestOption {
return func(o *RequestOptions) {
if len(replace) == 1 && replace[0] {
o.Cookies = m
return
}
for k, v := range m {
o.Cookies[k] = v
}
}
}
// Query sets the request's query.
func Query(k, v string) RequestOption {
return func(o *RequestOptions) {
o.Queries.Set(k, v)
}
}
// Queries sets the request's queries.
func Queries(m map[string]string, replace ...bool) RequestOption {
return func(o *RequestOptions) {
if len(replace) == 1 && replace[0] {
o.Queries = url.Values{}
}
for k, v := range m {
o.Queries.Set(k, v)
}
}
}
// QueriesFromValue sets the request's queries.
func QueriesFromValue(v url.Values) RequestOption {
return func(o *RequestOptions) {
o.Queries = v
}
}
// Body sets the request's body.
func Body(r io.Reader) RequestOption {
return func(o *RequestOptions) {
o.Body = r
}
}
// JSON marshal i to JSON format and sets it to request's body.
// ContentType will set to ContentTypeJSON.
func JSON(i interface{}) RequestOption {
return func(o *RequestOptions) {
ContentType(ContentTypeJSON)(o)
Body(new(bytes.Buffer))(o)
if err := json.NewEncoder(o.Body.(*bytes.Buffer)).Encode(i); err != nil {
o.Err = fmt.Errorf("json option error %w", err)
}
}
}
// Form sets m as form format of request's body.
// ContentType will set to ContentTypeForm.
func Form(m map[string]string) RequestOption {
return func(o *RequestOptions) {
ContentType(ContentTypeForm)(o)
value := url.Values{}
for k, v := range m {
value.Set(k, v)
}
Body(strings.NewReader(value.Encode()))(o)
}
}
// FileFromReader build the body for a multipart/form-data request.
func FileFromReader(fieldName, fileName string, r io.Reader) RequestOption {
return func(o *RequestOptions) {
mw := o.getMultipartWriter()
w, err := mw.CreateFormFile(fieldName, fileName)
if err != nil {
o.Err = fmt.Errorf("fileFromReader option error %w", err)
return
}
_, err = io.Copy(w, r)
if err != nil {
o.Err = fmt.Errorf("fileFromReader option error %w", err)
return
}
ContentType(mw.FormDataContentType())(o)
}
}
// File build the body for a multipart/form-data request.
func File(fieldName string, file *os.File) RequestOption {
return FileFromReader(fieldName, filepath.Base(file.Name()), file)
}
// MultipartField build the body for a multipart/form-data request.
func MultipartField(fieldName string, r io.Reader) RequestOption {
return func(o *RequestOptions) {
mw := o.getMultipartWriter()
w, err := mw.CreateFormField(fieldName)
if err != nil {
o.Err = fmt.Errorf("multipartField option error %w", err)
return
}
_, err = io.Copy(w, r)
if err != nil {
o.Err = fmt.Errorf("file option error %w", err)
return
}
ContentType(mw.FormDataContentType())(o)
}
}
// MultipartFieldString build the body for a multipart/form-data request.
func MultipartFieldString(fieldName, value string) RequestOption {
return MultipartField(fieldName, strings.NewReader(value))
}
// MultipartFieldBytes build the body for a multipart/form-data request.
func MultipartFieldBytes(fieldName string, value []byte) RequestOption {
return MultipartField(fieldName, bytes.NewReader(value))
}