-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp.go
More file actions
129 lines (113 loc) · 3.63 KB
/
Copy pathhttp.go
File metadata and controls
129 lines (113 loc) · 3.63 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
package main
import (
"bytes"
"crypto/tls"
"fmt"
"io"
"net/http"
"net/http/httptrace"
"os"
"time"
)
var (
authorization string = os.Getenv("AUTHORIZATION")
)
// RequestTrace aggregates timing information
type RequestTrace struct {
StatusCode int
DNSLookup time.Duration // Time spent performing DNS lookup
Connection time.Duration // Time spent establishing the connection
TLSHandshake time.Duration // Time spent performing the TLS handshake
ServerProcessing time.Duration // Time spent by the server processing the request
FirstResponseByteStart time.Time
TimeToFirstResponseByte time.Duration
TotalResponseTime time.Duration
DownloadTime time.Duration
ResponseSize int
}
func (c *Config) sendGet(path string) (*RequestTrace, error) {
t, err := c.sendRequest(path, "", http.MethodGet)
if err != nil {
return nil, err
}
return t, nil
}
func (c *Config) sendPost(path, body string) (*RequestTrace, error) {
t, err := c.sendRequest(path, body, http.MethodPost)
if err != nil {
return nil, err
}
return t, nil
}
func (c *Config) sendRequest(path, body, method string) (*RequestTrace, error) {
// Create a new HTTP client
client := &http.Client{
Timeout: time.Duration(30 * time.Second), // Adding long timeout given potential for long-running requests
}
// Construct full url
url := c.BaseURL + path
// Create a new HTTP request
req, err := http.NewRequest(method, url, bytes.NewReader([]byte(body)))
if err != nil {
return nil, fmt.Errorf("error creating request:%s", err)
}
// Create a RequestTrace struct to aggregate timing information
var RequestTrace RequestTrace
var dnsStart time.Time
var connStart time.Time
var tlsStart time.Time
// Attach a httptrace.ClientTrace to the request
trace := &httptrace.ClientTrace{
DNSStart: func(_ httptrace.DNSStartInfo) {
dnsStart = time.Now()
},
DNSDone: func(_ httptrace.DNSDoneInfo) {
RequestTrace.DNSLookup = time.Since(dnsStart)
},
ConnectStart: func(_, _ string) {
connStart = time.Now()
},
ConnectDone: func(_, _ string, _ error) {
RequestTrace.Connection = time.Since(connStart)
},
TLSHandshakeStart: func() {
tlsStart = time.Now()
},
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) {
RequestTrace.TLSHandshake = time.Since(tlsStart)
},
GotFirstResponseByte: func() {
RequestTrace.FirstResponseByteStart = time.Now()
},
}
// Attach the trace to the request's context
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
// Add headers
req.Header.Add("authorization", authorization)
req.Header.Add("content-type", "application/json")
// Perform the HTTP request
reqStart := time.Now()
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error performing request:%s", err)
}
// Capture end of response time
reqEnd := time.Now()
// Read response body and calculate its size
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body:%s", err)
}
respSize := len(respBody)
// Set fields associated with response data
RequestTrace.StatusCode = resp.StatusCode
RequestTrace.TotalResponseTime = reqEnd.Sub(reqStart)
RequestTrace.ServerProcessing = RequestTrace.FirstResponseByteStart.Sub(reqStart) -
RequestTrace.Connection - RequestTrace.TLSHandshake - RequestTrace.DNSLookup
RequestTrace.TimeToFirstResponseByte = RequestTrace.FirstResponseByteStart.Sub(reqStart)
RequestTrace.DownloadTime = reqEnd.Sub(RequestTrace.FirstResponseByteStart)
RequestTrace.ResponseSize = respSize
// Return request trace
return &RequestTrace, nil
}