diff --git a/args_parser.go b/args_parser.go index eddea8e..e4f0597 100644 --- a/args_parser.go +++ b/args_parser.go @@ -28,6 +28,7 @@ type kingpinParser struct { latencies bool insecure bool disableKeepAlives bool + allowRedirects bool method string body string bodyFilePath string @@ -111,6 +112,10 @@ func newKingpinParser() argsParser { "Disable HTTP keep-alive. For fasthttp use -H 'Connection: close'"). Short('a'). BoolVar(&kparser.disableKeepAlives) + app.Flag("allowRedirects", + "Allow the client to follow HTTP redirects"). + Short('R'). + BoolVar(&kparser.allowRedirects) app.Flag("header", "HTTP headers to use(can be repeated)"). PlaceHolder("\"K: V\""). @@ -226,6 +231,7 @@ func (k *kingpinParser) parse(args []string) (config, error) { printLatencies: k.latencies, insecure: k.insecure, disableKeepAlives: k.disableKeepAlives, + allowRedirects: k.allowRedirects, rate: k.rate.val, clientType: k.clientType, printIntro: pi, diff --git a/args_parser_test.go b/args_parser_test.go index 9ba6513..2bec2cf 100644 --- a/args_parser_test.go +++ b/args_parser_test.go @@ -711,6 +711,27 @@ func TestArgsParsing(t *testing.T) { format: userDefinedTemplate("/path/to/tmpl.txt"), }, }, + { + [][]string{ + { + programName, + "localhost:8080", + "-R", + }, + }, + config{ + numConns: defaultNumberOfConns, + timeout: defaultTimeout, + headers: new(headersList), + method: "GET", + url: "http://localhost:8080", + printIntro: true, + printProgress: true, + printResult: true, + format: knownFormat("plain-text"), + allowRedirects: true, + }, + }, } for _, e := range expectations { for _, args := range e.in { diff --git a/bombardier.go b/bombardier.go index d966116..3840ec7 100644 --- a/bombardier.go +++ b/bombardier.go @@ -132,6 +132,7 @@ func newBombardier(c config) (*bombardier, error) { timeout: c.timeout, tlsConfig: tlsConfig, disableKeepAlives: c.disableKeepAlives, + allowRedirects: c.allowRedirects, headers: c.headers, url: c.url, diff --git a/bombardier_test.go b/bombardier_test.go index 335ddc1..14fc8dc 100644 --- a/bombardier_test.go +++ b/bombardier_test.go @@ -727,3 +727,47 @@ func testBombardierShouldSendCustomHostHeader( b.disableOutput() b.bombard() } + +func TestBombardierFollowRedirects(t *testing.T) { + testAllClients(t, testBombardierFollowRedirects) +} + +func testBombardierFollowRedirects( + clientType clientTyp, t *testing.T, +) { + var numFollowRedirects uint64 + s := httptest.NewServer( + http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + http.Redirect(rw, r, "/foo", http.StatusFound) + } else { + rw.WriteHeader(http.StatusOK) + numFollowRedirects++ + } + }), + ) + defer s.Close() + numReqs := uint64(100) + b, e := newBombardier(config{ + numConns: defaultNumberOfConns, + numReqs: &numReqs, + url: s.URL, + headers: new(headersList), + timeout: defaultTimeout, + method: "GET", + body: "", + clientType: clientType, + format: knownFormat("plain-text"), + allowRedirects: true, + }) + if e != nil { + t.Error(e) + return + } + b.disableOutput() + b.bombard() + + if numFollowRedirects != numReqs { + t.Errorf("Bombardier does not follow HTTP redirects: expected %v, got %v", numReqs, numFollowRedirects) + } +} diff --git a/clients.go b/clients.go index 5835c1a..a9b0ee4 100644 --- a/clients.go +++ b/clients.go @@ -26,6 +26,7 @@ type clientOpts struct { timeout time.Duration tlsConfig *tls.Config disableKeepAlives bool + allowRedirects bool headers *headersList url, method string @@ -44,6 +45,8 @@ type fasthttpClient struct { body *string bodProd bodyStreamProducer + + allowRedirects bool } func newFastHTTPClient(opts *clientOpts) client { @@ -69,6 +72,7 @@ func newFastHTTPClient(opts *clientOpts) client { c.headers = headersToFastHTTPHeaders(opts.headers) c.method, c.body = opts.method, opts.body c.bodProd = opts.bodProd + c.allowRedirects = opts.allowRedirects return client(c) } @@ -97,7 +101,12 @@ func (c *fasthttpClient) do() ( // fire the request start := time.Now() - err = c.client.Do(req, resp) + if c.allowRedirects { + // stop after 10 consecutive redirects + err = c.client.DoRedirects(req, resp, 10) + } else { + err = c.client.Do(req, resp) + } if err != nil { code = -1 } else { @@ -136,9 +145,11 @@ func newHTTPClient(opts *clientOpts) client { cl := &http.Client{ Transport: tr, Timeout: opts.timeout, - CheckRedirect: func(req *http.Request, via []*http.Request) error { + } + if !opts.allowRedirects { + cl.CheckRedirect = func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse - }, + } } c.client = cl diff --git a/config.go b/config.go index 123c5c2..b2deae7 100644 --- a/config.go +++ b/config.go @@ -11,6 +11,7 @@ type config struct { numConns uint64 numReqs *uint64 disableKeepAlives bool + allowRedirects bool duration *time.Duration url, method, certPath, keyPath string body, bodyFilePath string