/
http_post.go
167 lines (147 loc) · 3.66 KB
/
http_post.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
package httppost
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/cofxlabs/cofx/functiondriver/go/spec"
"github.com/cofxlabs/cofx/manifest"
"github.com/tidwall/gjson"
)
var (
urlArg = manifest.UsageDesc{
Name: "url",
Desc: "Specify the url address to access",
}
pathArg = manifest.UsageDesc{
Name: "query_json_path",
Desc: "Specify the path to get values from json document, the path is provided with GJSON Syntax:\nhttps://github.com/tidwall/gjson/blob/master/SYNTAX.md",
}
headersArg = manifest.UsageDesc{
Name: "set_headers",
Desc: "Set some headers that you want to send to the server",
}
cookiesArg = manifest.UsageDesc{
Name: "set_cookies",
Desc: "Set some cookies that you want to send to the server",
}
jsonBodyArg = manifest.UsageDesc{
Name: "json_file_path",
Desc: "Specify the json file path to read as the http POST request body",
}
)
var (
statuscodeRet = manifest.UsageDesc{
Name: "status_code",
Desc: "Returns the status code of the http response",
}
)
var _manifest = manifest.Manifest{
Category: "http",
Name: "http_post",
Description: "Send a http POST request to a service, and then handle the response",
Driver: "go",
Args: map[string]string{},
RetryOnFailure: 0,
Usage: manifest.Usage{
Args: []manifest.UsageDesc{urlArg, pathArg, headersArg, cookiesArg, jsonBodyArg},
ReturnValues: []manifest.UsageDesc{statuscodeRet},
},
}
type Custom struct {
BodyReader io.Reader
// for testing
client *http.Client
}
func (c *Custom) Close() error {
if c.BodyReader != nil {
v, ok := c.BodyReader.(io.Closer)
if ok {
return v.Close()
}
}
c.client = nil
return nil
}
func New() (*manifest.Manifest, spec.EntrypointFunc, spec.CreateCustomFunc) {
return &_manifest, Entrypoint, func() spec.Customer {
return &Custom{}
}
}
func Entrypoint(ctx context.Context, bundle spec.EntrypointBundle, args spec.EntrypointArgs) (map[string]string, error) {
url, err := args.GetURL(urlArg.Name)
if err != nil {
return nil, err
}
headers := args.GetStringSlice(headersArg.Name)
br, err := args.GetReader(jsonBodyArg.Name)
if err != nil {
return nil, err
}
if br == nil {
br = bundle.Custom.(*Custom).BodyReader
}
defer func() {
if br != nil {
c, ok := br.(io.Closer)
if ok {
c.Close()
}
}
}()
tr := &http.Transport{
MaxIdleConns: 5,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
}
client := &http.Client{Transport: tr}
// Used to unit test
if bundle.Custom.(*Custom).client != nil {
client = bundle.Custom.(*Custom).client
}
req, err := http.NewRequestWithContext(ctx, "POST", url, br)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
for _, s := range headers {
fields := strings.Split(s, ":")
if len(fields) == 2 {
k := strings.TrimSpace(fields[0])
v := strings.TrimSpace(fields[1])
req.Header.Set(k, v)
}
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// read body
var buff bytes.Buffer
io.Copy(&buff, resp.Body)
// handle error
if resp.StatusCode-200 >= 100 {
return nil, fmt.Errorf("status code not 2xx: %d: %s", resp.StatusCode, buff.String())
}
// success
returns := make(map[string]string)
returns["status_code"] = strconv.Itoa(resp.StatusCode)
paths := args.GetStringSlice(pathArg.Name)
if len(paths) != 0 {
ct := resp.Header.Get("Content-Type")
if strings.Contains(ct, "application/json") {
results := gjson.GetManyBytes(buff.Bytes(), paths...)
for i, res := range results {
k := paths[i]
v := res.String()
returns[k] = v
}
}
}
return returns, nil
}