forked from tcnksm/go-httpstat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpre_go18.go
128 lines (108 loc) · 2.9 KB
/
pre_go18.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
// +build !go1.8
package httpstat
import (
"context"
"net"
"net/http/httptrace"
"time"
)
// End sets the time when reading response is done.
// This must be called after reading response body.
func (r *Result) End(t time.Time) {
r.t5 = t
// This means result is empty (it does nothing).
// Skip setting value(contentTransfer and total will be zero).
if r.t0.IsZero() {
return
}
r.contentTransfer = r.t5.Sub(r.t4)
r.total = r.t5.Sub(r.t0)
}
// ContentTransfer returns the duration of content transfer time.
// It is from first response byte to the given time. The time must
// be time after read body (go-httpstat can not detect that time).
func (r *Result) ContentTransfer(t time.Time) time.Duration {
return t.Sub(r.t4)
}
// Total returns the duration of total http request.
// It is from dns lookup start time to the given time. The
// time must be time after read body (go-httpstat can not detect that time).
func (r *Result) Total(t time.Time) time.Duration {
return t.Sub(r.t0)
}
func withClientTrace(ctx context.Context, r *Result) context.Context {
return httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
GetConn: func(hostPort string) {
_, port, err := net.SplitHostPort(hostPort)
if err != nil {
return
}
// Heuristic way to detect
if port == "443" {
r.isTLS = true
}
},
DNSStart: func(i httptrace.DNSStartInfo) {
r.t0 = time.Now()
},
DNSDone: func(i httptrace.DNSDoneInfo) {
r.t1 = time.Now()
r.DNSLookup = r.t1.Sub(r.t0)
r.NameLookup = r.t1.Sub(r.t0)
},
ConnectStart: func(_, _ string) {
// When connecting to IP
if r.t0.IsZero() {
r.t0 = time.Now()
r.t1 = r.t0
}
},
ConnectDone: func(network, addr string, err error) {
r.t2 = time.Now()
if r.isTLS {
r.TCPConnection = r.t2.Sub(r.t1)
r.Connect = r.t2.Sub(r.t0)
}
},
GotConn: func(i httptrace.GotConnInfo) {
// Handle when keep alive is enabled and connection is reused.
// DNSStart(Done) and ConnectStart(Done) is skipped
if i.Reused {
r.t0 = time.Now()
r.t1 = r.t0
r.t2 = r.t0
r.isReused = true
}
},
WroteRequest: func(info httptrace.WroteRequestInfo) {
r.t3 = time.Now()
// This means DNSStart, Done and ConnectStart is not
// called. This happens if client doesn't use DialContext
// or using net package before go1.7.
if r.t0.IsZero() && r.t1.IsZero() && r.t2.IsZero() {
r.t0 = time.Now()
r.t1 = r.t0
r.t2 = r.t0
r.t3 = r.t0
}
// When connection is reused, TLS handshake is skipped.
if r.isReused {
r.t3 = r.t0
}
if r.isTLS {
r.TLSHandshake = r.t3.Sub(r.t2)
r.Pretransfer = r.t3.Sub(r.t0)
return
}
r.TCPConnection = r.t3.Sub(r.t1)
r.Connect = r.t3.Sub(r.t0)
r.TLSHandshake = r.t3.Sub(r.t3)
r.Pretransfer = r.Connect
},
GotFirstResponseByte: func() {
r.t4 = time.Now()
r.ServerProcessing = r.t4.Sub(r.t3)
r.StartTransfer = r.t4.Sub(r.t0)
},
})
}