diff --git a/args_parser.go b/args_parser.go index 11c7684..d686f0c 100644 --- a/args_parser.go +++ b/args_parser.go @@ -36,6 +36,7 @@ type kingpinParser struct { stream bool certPath string keyPath string + proxyUrl string rate *nullableUint64 clientType clientTyp @@ -59,6 +60,7 @@ func newKingpinParser() argsParser { stream: false, certPath: "", keyPath: "", + proxyUrl: "", insecure: false, url: "", rate: new(nullableUint64), @@ -104,6 +106,9 @@ func newKingpinParser() argsParser { app.Flag("key", "Path to the client's TLS Certificate Private Key"). Default(""). StringVar(&kparser.keyPath) + app.Flag("proxy", "URL of the HTTP proxy"). + Default(""). + StringVar(&kparser.proxyUrl) app.Flag("insecure", "Controls whether a client verifies the server's certificate"+ " chain and host name"). @@ -224,6 +229,7 @@ func (k *kingpinParser) parse(args []string) (config, error) { bodyFilePath: k.bodyFilePath, stream: k.stream, keyPath: k.keyPath, + proxyUrl: k.proxyUrl, certPath: k.certPath, printLatencies: k.latencies, insecure: k.insecure, diff --git a/bombardier.go b/bombardier.go index 5efe68e..b6803f1 100644 --- a/bombardier.go +++ b/bombardier.go @@ -135,6 +135,7 @@ func newBombardier(c config) (*bombardier, error) { headers: c.headers, url: c.url, + proxyUrl: c.proxyUrl, method: c.method, body: pbody, bodProd: bsp, @@ -346,6 +347,7 @@ func (b *bombardier) bombard() { } func (b *bombardier) printIntro() { + if b.conf.testType() == counted { fmt.Fprintf(b.out, "Bombarding %v with %v request(s) using %v connection(s)\n", diff --git a/clients.go b/clients.go index 3de0030..958c989 100644 --- a/clients.go +++ b/clients.go @@ -2,6 +2,7 @@ package main import ( "crypto/tls" + "github.com/valyala/fasthttp/fasthttpproxy" "io" "io/ioutil" "net/http" @@ -27,8 +28,8 @@ type clientOpts struct { tlsConfig *tls.Config disableKeepAlives bool - headers *headersList - url, method string + headers *headersList + url, method, proxyUrl string body *string bodProd bodyStreamProducer @@ -47,6 +48,8 @@ type fasthttpClient struct { } func newFastHTTPClient(opts *clientOpts) client { + var dial fasthttp.DialFunc + c := new(fasthttpClient) u, err := url.Parse(opts.url) if err != nil { @@ -55,7 +58,22 @@ func newFastHTTPClient(opts *clientOpts) client { } c.host = u.Host c.requestURI = u.RequestURI() + + if opts.proxyUrl != "" { + if strings.Contains(opts.proxyUrl, "socks5") { + urlProxy := strings.Replace(opts.proxyUrl, "socks5://", "", 1) + dial = fasthttpproxy.FasthttpSocksDialer(urlProxy) + } else { + urlProxy := strings.Replace(opts.proxyUrl, "https://", "", 1) + urlProxy = strings.Replace(urlProxy, "http://", "", 1) + dial = fasthttpproxy.FasthttpHTTPDialer(urlProxy) + } + } else { + dial = fasthttpDialFunc(opts.bytesRead, opts.bytesWritten) + } + c.client = &fasthttp.HostClient{ + Addr: u.Host, IsTLS: u.Scheme == "https", MaxConns: int(opts.maxConns), @@ -63,10 +81,9 @@ func newFastHTTPClient(opts *clientOpts) client { WriteTimeout: opts.timeout, DisableHeaderNamesNormalizing: true, TLSConfig: opts.tlsConfig, - Dial: fasthttpDialFunc( - opts.bytesRead, opts.bytesWritten, - ), + Dial: dial, } + c.headers = headersToFastHTTPHeaders(opts.headers) c.method, c.body = opts.method, opts.body c.bodProd = opts.bodProd @@ -131,12 +148,21 @@ type httpClient struct { } func newHTTPClient(opts *clientOpts) client { + var err error + c := new(httpClient) tr := &http.Transport{ TLSClientConfig: opts.tlsConfig, MaxIdleConnsPerHost: int(opts.maxConns), DisableKeepAlives: opts.disableKeepAlives, } + + if opts.proxyUrl != "" { + urlObj := url.URL{} + urlProxy, _ := urlObj.Parse(opts.proxyUrl) + tr.Proxy = http.ProxyURL(urlProxy) + } + tr.DialContext = httpDialContextFunc(opts.bytesRead, opts.bytesWritten) if opts.HTTP2 { _ = http2.ConfigureTransport(tr) @@ -157,7 +183,7 @@ func newHTTPClient(opts *clientOpts) client { c.headers = headersToHTTPHeaders(opts.headers) c.method, c.body, c.bodProd = opts.method, opts.body, opts.bodProd - var err error + c.url, err = url.Parse(opts.url) if err != nil { // opts.url guaranteed to be valid at this point diff --git a/config.go b/config.go index 20fbac5..5e233d8 100644 --- a/config.go +++ b/config.go @@ -8,15 +8,15 @@ import ( ) type config struct { - numConns uint64 - numReqs *uint64 - disableKeepAlives bool - duration *time.Duration - url, method, certPath, keyPath string - body, bodyFilePath string - stream bool - headers *headersList - timeout time.Duration + numConns uint64 + numReqs *uint64 + disableKeepAlives bool + duration *time.Duration + url, method, certPath, keyPath, proxyUrl string + body, bodyFilePath string + stream bool + headers *headersList + timeout time.Duration // TODO(codesenberg): printLatencies should probably be // re(named&maked) into printPercentiles or even let // users provide their own percentiles and not just