/
http.go
118 lines (105 loc) · 2.45 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
package lib
import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/url"
"strconv"
"strings"
"time"
"github.com/kffl/gocannon/common"
"github.com/valyala/fasthttp"
)
var (
ErrWrongTarget = errors.New("wrong target URL")
ErrUnsupportedProtocol = errors.New("unsupported target protocol")
ErrMissingPort = errors.New("missing target port")
)
func parseTarget(target string) (scheme string, host string, err error) {
u, err := url.ParseRequestURI(target)
if err != nil {
err = ErrWrongTarget
return
}
if u.Scheme != "http" && u.Scheme != "https" {
err = ErrUnsupportedProtocol
return
}
tokenizedHost := strings.Split(u.Host, ":")
port := tokenizedHost[len(tokenizedHost)-1]
if _, err = strconv.Atoi(port); err != nil {
err = ErrMissingPort
return
}
return u.Scheme, u.Host, nil
}
func dialHost(host string, timeout time.Duration) error {
conn, err := fasthttp.DialTimeout(host, timeout)
if err != nil {
return fmt.Errorf("dialing host failed (%w)", err)
}
conn.Close()
return nil
}
func newHTTPClient(
target string,
timeout time.Duration,
connections int,
trustAll bool,
checkHost bool,
) (*fasthttp.HostClient, error) {
scheme, host, err := parseTarget(target)
if err != nil {
return nil, err
}
c := &fasthttp.HostClient{
Addr: host,
MaxConns: int(connections),
ReadTimeout: timeout,
WriteTimeout: timeout,
DisableHeaderNamesNormalizing: true,
Dial: func(addr string) (net.Conn, error) {
return fasthttp.DialTimeout(addr, timeout)
},
IsTLS: scheme == "https",
TLSConfig: &tls.Config{
InsecureSkipVerify: trustAll,
},
}
if checkHost {
err = dialHost(host, timeout)
if err != nil {
return nil, err
}
}
return c, nil
}
func performRequest(c *fasthttp.HostClient, target string, method string, body []byte, headers common.RequestHeaders) (
code int, start int64, end int64,
) {
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
if strings.HasPrefix(target, "https") {
req.URI().SetScheme("https")
} else {
req.URI().SetScheme("http")
}
req.Header.SetMethod(method)
req.SetRequestURI(target)
req.SetBodyRaw(body)
for _, h := range headers {
req.Header.Add(h.Key, h.Value)
}
start = makeTimestamp()
err := c.Do(req, resp)
if err != nil {
code = 0
} else {
code = resp.StatusCode()
}
end = makeTimestamp()
fasthttp.ReleaseRequest(req)
fasthttp.ReleaseResponse(resp)
return
}