/
http.go
129 lines (122 loc) · 3.16 KB
/
http.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
package executor
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
. "github.com/spyzhov/healthy/executor/internal/args"
http2 "github.com/spyzhov/healthy/executor/internal/net/http"
"github.com/spyzhov/healthy/step"
"github.com/spyzhov/safe"
)
type HttpArgs struct {
// region Request
Method string `json:"method"`
Url string `json:"url"`
Payload *ReachText `json:"payload"`
Form HttpArgsForm `json:"form"`
Headers map[string]string `json:"headers"`
Timeout Duration `json:"timeout"`
Redirect bool `json:"redirect"`
BasicAuth *HttpArgsBasicAuth `json:"basic_auth"`
// endregion
// region Response
Require HttArgsRequire `json:"require"`
// endregion
}
func (e *Executor) Http(args *HttpArgs) (step.Function, error) {
if err := args.Validate(); err != nil {
return nil, safe.Wrap(err, "http")
}
if args.Timeout.Duration == 0 {
args.Timeout.Duration = 30 * time.Second
}
client := func() *http.Client {
result := http2.GetClient(args.Timeout.Duration, e.version)
if args.Redirect {
return result
}
result.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
return result
}
return func() (*step.Result, error) {
// region Request
contentType, body, err := args.body()
if err != nil {
return nil, fmt.Errorf("http: %w", err)
}
defer safe.Close(body, "request body")
request, err := http.NewRequest(args.method(), args.Url, body)
if err != nil {
return nil, fmt.Errorf("http: %w", err)
}
if contentType != "" {
request.Header.Add("Content-Type", contentType)
}
for key, value := range args.Headers {
request.Header.Set(key, value)
}
if args.BasicAuth != nil {
request.SetBasicAuth(args.BasicAuth.Username, args.BasicAuth.Password)
}
// endregion
// region Response
var response *http.Response
response, err = client().Do(request.WithContext(e.ctx))
if err != nil {
return nil, fmt.Errorf("http: %w", err)
}
defer safe.Close(response.Body, "http:response.body")
// endregion
// region Match
if err = args.Require.Match(response); err != nil {
return nil, fmt.Errorf("http: %w", err)
}
// endregion
return step.NewResultSuccess("OK"), nil
}, nil
}
func (a *HttpArgs) Validate() (err error) {
if err = a.Timeout.Validate(); err != nil {
return err
}
if err = a.Payload.Validate(); err != nil {
return err
}
if err = a.Form.Validate(); err != nil {
return err
}
if err = a.Require.Validate(); err != nil {
return err
}
if a.Payload != nil && (len(a.Form.Files)+len(a.Form.Values) != 0) {
return fmt.Errorf("body: http.payload and http.form set in the same time")
}
return
}
func (a *HttpArgs) method() string {
if a.Method == "" {
return "GET"
}
return a.Method
}
func (a *HttpArgs) body() (contentType string, r io.ReadCloser, err error) {
if a.Payload != nil {
r, err = a.Payload.Value()
if err != nil {
return "", nil, safe.Wrap(err, "payload")
}
} else {
b := new(bytes.Buffer)
contentType, err = a.Form.SubmitForm(b)
if err != nil {
return "", nil, err
}
r = ioutil.NopCloser(b)
}
return contentType, r, err
}