5252 // Command line flags.
5353 httpMethod string
5454 postBody string
55+ repeat int
5556 followRedirects bool
5657 onlyHeader bool
5758 insecure bool
@@ -72,6 +73,7 @@ const maxRedirects = 10
7273func init () {
7374 flag .StringVar (& httpMethod , "X" , "GET" , "HTTP method to use" )
7475 flag .StringVar (& postBody , "d" , "" , "the body of a POST or PUT request; from file use @filename" )
76+ flag .IntVar (& repeat , "r" , 0 , "Repeat the same request N times on the same connection" )
7577 flag .BoolVar (& followRedirects , "L" , false , "follow 30x redirects" )
7678 flag .BoolVar (& onlyHeader , "I" , false , "don't read body of request" )
7779 flag .BoolVar (& insecure , "k" , false , "allow insecure SSL connections" )
@@ -127,8 +129,11 @@ func main() {
127129 }
128130
129131 url := parseURL (args [0 ])
132+ tr := newTransport (url )
130133
131- visit (url )
134+ for i := repeat + 1 ; i > 0 ; i -- {
135+ visit (tr , url )
136+ }
132137}
133138
134139// readClientCert - helper function to read client certificate
@@ -197,9 +202,42 @@ func headerKeyValue(h string) (string, string) {
197202 return strings .TrimRight (h [:i ], " " ), strings .TrimLeft (h [i :], " :" )
198203}
199204
205+ func newTransport (url * url.URL ) * http.Transport {
206+ tr := & http.Transport {
207+ Proxy : http .ProxyFromEnvironment ,
208+ MaxIdleConns : 100 ,
209+ IdleConnTimeout : 90 * time .Second ,
210+ TLSHandshakeTimeout : 10 * time .Second ,
211+ ExpectContinueTimeout : 1 * time .Second ,
212+ }
213+
214+ switch url .Scheme {
215+ case "https" :
216+ host , _ , err := net .SplitHostPort (url .Host )
217+ if err != nil {
218+ host = url .Host
219+ }
220+
221+ tr .TLSClientConfig = & tls.Config {
222+ ServerName : host ,
223+ InsecureSkipVerify : insecure ,
224+ Certificates : readClientCert (clientCertFile ),
225+ }
226+
227+ // Because we create a custom TLSClientConfig, we have to opt-in to HTTP/2.
228+ // See https://github.com/golang/go/issues/14275
229+ err = http2 .ConfigureTransport (tr )
230+ if err != nil {
231+ log .Fatalf ("failed to prepare transport for HTTP/2: %v" , err )
232+ }
233+ }
234+
235+ return tr
236+ }
237+
200238// visit visits a url and times the interaction.
201239// If the response is a 30x, visit follows the redirect.
202- func visit (url * url.URL ) {
240+ func visit (tr * http. Transport , url * url.URL ) {
203241 req := newRequest (httpMethod , url , postBody )
204242
205243 var tStart , tDNSStart , tDNSEnd , tConnectStart , tConnectEnd , tTLSStart , tTLSEnd , tConnected , tTTBF , tDone time.Time
@@ -229,35 +267,6 @@ func visit(url *url.URL) {
229267 }
230268 req = req .WithContext (httptrace .WithClientTrace (context .Background (), trace ))
231269
232- tr := & http.Transport {
233- Proxy : http .ProxyFromEnvironment ,
234- MaxIdleConns : 100 ,
235- IdleConnTimeout : 90 * time .Second ,
236- TLSHandshakeTimeout : 10 * time .Second ,
237- ExpectContinueTimeout : 1 * time .Second ,
238- }
239-
240- switch url .Scheme {
241- case "https" :
242- host , _ , err := net .SplitHostPort (req .Host )
243- if err != nil {
244- host = req .Host
245- }
246-
247- tr .TLSClientConfig = & tls.Config {
248- ServerName : host ,
249- InsecureSkipVerify : insecure ,
250- Certificates : readClientCert (clientCertFile ),
251- }
252-
253- // Because we create a custom TLSClientConfig, we have to opt-in to HTTP/2.
254- // See https://github.com/golang/go/issues/14275
255- err = http2 .ConfigureTransport (tr )
256- if err != nil {
257- log .Fatalf ("failed to prepare transport for HTTP/2: %v" , err )
258- }
259- }
260-
261270 client := & http.Client {
262271 Transport : tr ,
263272 CheckRedirect : func (req * http.Request , via []* http.Request ) error {
@@ -363,7 +372,7 @@ func visit(url *url.URL) {
363372 log .Fatalf ("maximum number of redirects (%d) followed" , maxRedirects )
364373 }
365374
366- visit (loc )
375+ visit (tr , loc )
367376 }
368377}
369378
0 commit comments