-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreq_body.go
More file actions
147 lines (123 loc) · 3.14 KB
/
req_body.go
File metadata and controls
147 lines (123 loc) · 3.14 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
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
package greq
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/gookit/goutil/netutil/httpctype"
)
// BodyProvider provides Body content for http.Request attachment.
type BodyProvider interface {
// ContentType returns the Content-Type of the body.
ContentType() string
// Body returns the io.Reader body.
Body() (io.Reader, error)
}
// bodyProvider provides the wrapped body value as a Body for reqests.
type bodyProvider struct {
body io.Reader
}
// ContentType value
func (p bodyProvider) ContentType() string {
return ""
}
// Body get body reader
func (p bodyProvider) Body() (io.Reader, error) {
return p.body, nil
}
// jsonBodyProvider encodes a JSON tagged struct value as a Body for requests.
type jsonBodyProvider struct {
payload any
}
// ContentType value
func (p jsonBodyProvider) ContentType() string {
return httpctype.JSON
}
// Body get body reader
func (p jsonBodyProvider) Body() (io.Reader, error) {
buf := &bytes.Buffer{}
err := json.NewEncoder(buf).Encode(p.payload)
if err != nil {
return nil, err
}
return buf, nil
}
// formBodyProvider encodes a url tagged struct value as Body for requests.
type formBodyProvider struct {
// allow type: string, url.Values
payload any
}
// ContentType value
func (p formBodyProvider) ContentType() string {
return httpctype.Form
}
// Body get body reader
func (p formBodyProvider) Body() (io.Reader, error) {
values, ok := p.payload.(url.Values)
if ok {
return strings.NewReader(values.Encode()), nil
}
mps, ok := p.payload.(map[string][]string)
if ok {
return strings.NewReader(url.Values(mps).Encode()), nil
}
if str, ok := p.payload.(string); ok {
return strings.NewReader(str), nil
}
return nil, fmt.Errorf("formBodyProvider: invalid form data type: %T", p.payload)
}
type multipartBodyProvider struct {
files map[string]string
fields map[string]string
contentType string
body *bytes.Buffer
}
// ContentType value
func (p *multipartBodyProvider) ContentType() string {
return p.contentType
}
// Body data build
func (p *multipartBodyProvider) Body() (io.Reader, error) {
if p.body == nil {
if err := p.build(); err != nil {
return nil, err
}
}
return p.body, nil
}
func (p *multipartBodyProvider) build() error {
buf := &bytes.Buffer{}
writer := multipart.NewWriter(buf)
for fieldName, filePath := range p.files {
file, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("open file %s failed: %w", filePath, err)
}
part, err := writer.CreateFormFile(fieldName, filepath.Base(filePath))
if err != nil {
file.Close()
return fmt.Errorf("create form file %s failed: %w", fieldName, err)
}
_, err = io.Copy(part, file)
file.Close()
if err != nil {
return fmt.Errorf("copy file %s failed: %w", filePath, err)
}
}
for key, value := range p.fields {
if err := writer.WriteField(key, value); err != nil {
return fmt.Errorf("write field %s failed: %w", key, err)
}
}
if err := writer.Close(); err != nil {
return fmt.Errorf("close multipart writer failed: %w", err)
}
p.contentType = writer.FormDataContentType()
p.body = buf
return nil
}