ab.c revision 19894e85591f45980c8002507cbd99d071415c85
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht/* Licensed to the Apache Software Foundation (ASF) under one or more
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * contributor license agreements. See the NOTICE file distributed with
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * this work for additional information regarding copyright ownership.
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * The ASF licenses this file to You under the Apache License, Version 2.0
98890889ffb2e8f6f722b00e265a211f13b5a861Corneliu-Claudiu Prodescu * (the "License"); you may not use this file except in compliance with
2643008447e30b6025f742eb6a661f38be756b1eSimon Ulbricht * the License. You may obtain a copy of the License at
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * Unless required by applicable law or agreed to in writing, software
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * distributed under the License is distributed on an "AS IS" BASIS,
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0b152383e04dbeb10dba29bcdfaa0981e4d9df27Simon Ulbricht * See the License for the specific language governing permissions and
2643008447e30b6025f742eb6a661f38be756b1eSimon Ulbricht * limitations under the License.
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** This program is based on ZeusBench V1.0 written by Adam Twiss
d815d2b83e945875100ceca322ebd50d96714206Simon Ulbricht ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** This software is provided "as is" and any express or implied waranties,
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** including but not limited to, the implied warranties of merchantability and
abea93ed557b22ea833e1524ee5ca11afc12208aSimon Ulbricht ** fitness for a particular purpose are disclaimed. In no event shall
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special,
d815d2b83e945875100ceca322ebd50d96714206Simon Ulbricht ** exemplary, or consequential damaged (including, but not limited to,
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht ** procurement of substitute good or services; loss of use, data, or profits;
6150196e8d99f7161a622fdc1a872fecd378195fSimon Ulbricht ** or business interruption) however caused and on theory of liability. Whether
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** in contract, strict liability or tort (including negligence or otherwise)
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** arising in any way out of the use of this software, even if advised of the
abea93ed557b22ea833e1524ee5ca11afc12208aSimon Ulbricht ** possibility of such damage.
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht ** - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht ** with input from Mike Belshe <mbelshe@netscape.com> and
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** Michael Campanella <campanella@stevms.enet.dec.com>
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** Version 1.3d
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - Increased version number - as some of the socket/error handling has
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** fundamentally changed - and will give fundamentally different results
abea93ed557b22ea833e1524ee5ca11afc12208aSimon Ulbricht ** in situations where a server is dropping requests. Therefore you can
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** no longer compare results of AB as easily. Hence the inc of the version.
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** They should be closer to the truth though. Sander & <dirkx@covalent.net>, End 2000.
9da6e0cb2ea6e43f5b09dcd2a9af5468a5d0fcf4Christian Maeder ** - Fixed proxy functionality, added median/mean statistics, added gnuplot
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** output option, added _experimental/rudimentary_ SSL support. Added
6150196e8d99f7161a622fdc1a872fecd378195fSimon Ulbricht ** confidence guestimators and warnings. Sander & <dirkx@covalent.net>, End 2000
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** - Fixed serious int overflow issues which would cause realistic (longer
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht ** than a few minutes) run's to have wrong (but believable) results. Added
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** trapping of connection errors which influenced measurements.
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** Contributed by Sander Temme, Early 2001
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** Version 1.3e
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** - Changed timeout behavour during write to work whilst the sockets
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht ** are filling up and apr_write() does writes a few - but not all.
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** This will potentially change results. <dirkx@webweaving.org>, April 2001
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Version 2.0.36-dev
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Improvements to concurrent processing:
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** - Enabled non-blocking connect()s.
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** - Prevent blocking calls to apr_socket_recv() (thereby allowing AB to
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** manage its entire set of socket descriptors).
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** - Any error returned from apr_socket_recv() that is not EAGAIN or EOF
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** is now treated as fatal.
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Contributed by Aaron Bannert, April 24, 2002
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Version 2.0.36-2
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Internalized the version string - this string is part
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** of the Agent: header and the result output.
d8623e217fff016f9e1759b5603fc06b29fda62cChristian Maeder ** Version 2.0.37-dev
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Adopted SSL code by Madhu Mathihalli <madhusudan_mathihalli@hp.com>
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** [PATCH] ab with SSL support Posted Wed, 15 Aug 2001 20:55:06 GMT
d8623e217fff016f9e1759b5603fc06b29fda62cChristian Maeder ** Introduces four 'if (int == value)' tests per non-ssl request.
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** Version 2.0.40-dev
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Switched to the new abstract pollset API, allowing ab to
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** take advantage of future apr_pollset_t scalability improvements.
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Contributed by Brian Pane, August 31, 2002
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** Version 2.3
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht ** SIGINT now triggers output_results().
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder ** Contributed by colm, March 30, 2006
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder/* Note: this version string should start with \d+[\d\.]* and be a valid
432ac7c08e2592af0660e026051ffb052e88a100Simon Ulbricht * string for an HTTP Agent: header when prefixed with 'ApacheBench/'.
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht * It should reflect the version of AB - and not that of the apache server
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht * it happens to accompany. And it should be updated or changed whenever
432ac7c08e2592af0660e026051ffb052e88a100Simon Ulbricht * the results are no longer fundamentally comparable to the results of
432ac7c08e2592af0660e026051ffb052e88a100Simon Ulbricht * a previous version of ab. Either due to a change in the logic of
432ac7c08e2592af0660e026051ffb052e88a100Simon Ulbricht * ab - or to due to a change in the distribution it is compiled with
432ac7c08e2592af0660e026051ffb052e88a100Simon Ulbricht * (such as an APR change in for example blocking).
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder * - has various other poor buffer attacks related to the lazy parsing of
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht * response headers from the server
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht * - doesn't implement much of HTTP/1.x, only accepts certain forms of
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht * - (performance problem) heavy use of strstr shows up top in profile
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder * only an issue for loopback usage
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht/* -------------------------------------------------------------------- */
e9a1a4d5820d527a6800d524ebaf29fbad6196c6Simon Ulbricht/* Hmmm... This source code isn't being compiled in ASCII.
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder * In order for data that flows over the network to make
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder * sense, we need to translate to/from ASCII.
abea93ed557b22ea833e1524ee5ca11afc12208aSimon Ulbricht/* affects include files on Solaris */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht/* Libraries for RSA SSL-C */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht/* Libraries on most systems.. */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht/* ------------------- DEFINITIONS -------------------------- */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht#define AB_MAX APR_INT64_C(0x7fffffffffffffff)
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht/* maximum number of requests on a time limited test */
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht#define MAX_REQUESTS (INT_MAX > 50000 ? 50000 : INT_MAX)
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht/* connection state
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht * don't add enums or rearrange or otherwise change values without
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder * visiting set_conn_state()
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbrichttypedef enum {
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht STATE_CONNECTING, /* TCP connect initiated, but we don't
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht * know if it worked yet
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht STATE_CONNECTED, /* we know TCP connect completed */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht apr_size_t rwrite, rwrote; /* keep pointers in what we write - across
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht apr_size_t length; /* Content-Length value used for keep-alive */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht char cbuff[CBUFFSIZE]; /* a buffer to store server response header */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht int keepalive; /* non-zero if a keep-alive request */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht int gotheader; /* non-zero if we have the entire header in
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder apr_time_t start, /* Start of connection */
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht apr_time_t starttime; /* start time of connection */
a210c2e5add831cd438183c8602ed8e610922beaSimon Ulbricht apr_interval_time_t waittime; /* between request and reading response */
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht apr_interval_time_t ctime; /* time to connect */
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbricht apr_interval_time_t time; /* time for connection */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbricht#define ap_min(a,b) (((a)<(b))?(a):(b))
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder#define ap_max(a,b) (((a)>(b))?(a):(b))
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder#define ap_round_ms(a) ((apr_time_t)((a) + 500)/1000)
65660c22133e6de16f9ece7b36ac6423014b20aaChristian Maeder#define ap_double_ms(a) ((double)(a)/1000.0)
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbricht/* --------------------- GLOBALS ---------------------------- */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint verbosity = 0; /* no verbosity by default */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint recverrok = 0; /* ok to proceed after socket receive errors */
3ac14720aa7f1e0715311bd1598e7d78c37dd3c6Simon Ulbrichtenum {NO_METH = 0, GET, HEAD, PUT, POST} method = NO_METH;
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtconst char *method_str[] = {"bug", "GET", "HEAD", "PUT", "POST"};
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint send_body = 0; /* non-zero if sending body with request */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint requests = 1; /* Number of requests to make */
7c84f8fd92ed59eb2b9a674e6b1ea93c0f945006Simon Ulbrichtint heartbeatres = 100; /* How often do we say we're alive */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint concurrency = 1; /* Number of multiple requests to make */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint percentile = 1; /* Show percentile served */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint confidence = 1; /* Show confidence estimator and warnings */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint keepalive = 0; /* try and do keepalive connections */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtint windowsize = 0; /* we use the OS default window size */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtchar servername[1024]; /* name that server reports */
53d3b5d18cae658f0e54872ade90ab5259b52b95Simon Ulbrichtconst char *host_field; /* value of "Host:" header field */
1651c7f5055453e18a8c34f96c333e2aa702a34eSimon Ulbrichtchar postfile[1024]; /* name of file containing post data */
369771f5d48a40eda134026b1f45f63b2c00bdb8Simon Ulbrichtchar *postdata; /* *buffer containing data from postfile */
const char *connecthost;
const char *fullurl;
const char *colonhost;
int isproxy = 0;
const char *tablestring;
const char *trstring;
const char *tdstring;
#ifdef USE_SSL
int is_ssl;
#ifdef NOT_ASCII
static void err(const char *s)
if (done)
if (done)
if (new_reqevents != 0) {
#ifdef USE_SSL
return(ret);
return ret;
if (w & SSL_CB_ALERT) {
} else if (w & SSL_CB_LOOP) {
#ifndef RAND_MAX
static int ssl_rand_choosenum(int l, int h)
static void ssl_rand_seed(void)
int nDone = 0;
time_t t;
l = sizeof(time_t);
RAND_seed((unsigned char *)&t, l);
nDone += l;
l = sizeof(pid_t);
nDone += l;
int count;
while (do_next) {
switch (ecode) {
case SSL_ERROR_NONE:
ssl_print_info(c);
if (cert)
write_request(c);
do_next = 0;
case SSL_ERROR_WANT_READ:
do_next = 0;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_CONNECT:
case SSL_ERROR_SSL:
case SSL_ERROR_SYSCALL:
close_connection(c);
do_next = 0;
if (c->rwrite == 0) {
c->rwrote = 0;
if (send_body)
close_connection(c);
#ifdef USE_SSL
if (c->ssl) {
if (e_ssl != l) {
close_connection (c);
l = e_ssl;
e = APR_SUCCESS;
epipe++;
close_connection(c);
totalposted += l;
c->rwrote += l;
c->rwrite -= l;
} while (c->rwrite);
started++;
double timetaken;
if (sig) {
#ifdef USE_SSL
if (bad)
if (err_response)
if (keepalive)
if (send_body)
if (send_body) {
if (done > 0) {
for (i = 0; i < done; i++) {
for (i = 0; i < done; i++) {
sdtot += a * a;
sdcon += a * a;
sdd += a * a;
sdwait += a * a;
(int (*) (const void *, const void *)) compradre);
(int (*) (const void *, const void *)) compri);
(int (*) (const void *, const void *)) compwait);
(int (*) (const void *, const void *)) comprando);
if (confidence) {
#define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %4" APR_TIME_T_FMT " %5.1f %6" APR_TIME_T_FMT " %7" APR_TIME_T_FMT "\n"
else if (d > sd ) \
for (i = 0; i < sizeof(percs) / sizeof(int); i++) {
if (percs[i] <= 0)
if (csvperc) {
if (!out) {
if (gnuplot) {
if (!out) {
for (i = 0; i < done; i++) {
if (sig) {
static void output_html_results(void)
if (bad)
if (err_response)
if (keepalive)
if (send_body)
if (timetaken) {
if (send_body) {
for (i = 0; i < done; i++) {
c->read = 0;
c->bread = 0;
c->keepalive = 0;
c->cbx = 0;
c->gotheader = 0;
c->rwrite = 0;
if (c->ctx)
!= APR_SUCCESS) {
if (windowsize != 0) {
#ifdef USE_SSL
if (is_ssl) {
c->rwrite = 0;
err_conn++;
start_connect(c);
#ifdef USE_SSL
if (c->ssl) {
write_request(c);
if (good)
bad++;
err_length++;
#ifdef USE_SSL
if (c->ssl) {
start_connect(c);
apr_size_t r;
char *part;
r = sizeof(buffer);
#ifdef USE_SSL
if (c->ssl) {
if (status <= 0) {
good++;
close_connection(c);
c->read = 0;
close_connection(c);
r = status;
good++;
close_connection(c);
err_recv++;
if (recverrok) {
bad++;
close_connection(c);
totalread += r;
if (c->read == 0) {
c->read += r;
if (!c->gotheader) {
#ifdef NOT_ASCII
if (space) {
err_response++;
start_connect(c);
if (!good) {
q = servername;
err_response++;
if (keepalive &&
char *cl;
if (!cl)
if (cl) {
if (!cl) {
c->length = 0;
c->bread += r;
totalbread += r;
good++;
bad++;
err_length++;
doneka++;
c->keepalive = 0;
c->length = 0;
c->gotheader = 0;
c->cbx = 0;
write_request(c);
static void test(void)
int snprintf_res = 0;
#ifdef NOT_ASCII
if (isproxy) {
if (!use_html) {
if (isproxy)
if (!opt_host) {
if (!opt_useragent) {
if (!opt_accept) {
if (!send_body) {
if (send_body) {
if (!buff) {
#ifdef NOT_ASCII
!= APR_SUCCESS) {
#ifdef SIGINT
for (i = 0; i < concurrency; i++) {
apr_int32_t n;
n = concurrency;
struct connection *c;
#ifdef USE_SSL
read_connection(c);
bad++;
err_except++;
/* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */
read_connection(c);
start_connect(c);
err_conn++;
start_connect(c);
#ifdef USE_SSL
if (c->ssl)
write_request(c);
write_request(c);
if (heartbeatres)
if (use_html)
output_results(0);
static void copyright(void)
if (!use_html) {
printf(" This is ApacheBench, Version %s <i><%s></i><br>\n", AP_AB_BASEREVISION, "$Revision$");
#ifdef USE_SSL
/* 80 column ruler: ********************************************************************************
#ifdef USE_SSL
char *cp;
char *scope_id;
#ifdef USE_SSL
is_ssl = 0;
#ifdef USE_SSL
#ifdef USE_SSL
if (is_ssl)
#ifdef USE_SSL
return rv;
return rv;
if (!postdata) {
return APR_ENOMEM;
return rv;
return APR_SUCCESS;
const char *optarg;
#ifdef USE_SSL
#ifdef NOT_ASCII
if (status) {
if (status) {
if (status) {
#ifdef USE_SSL
if (requests <= 0) {
heartbeatres = 0;
percentile = 0;
confidence = 0;
optarg++;
optarg++;
copyright();
#ifdef USE_SSL
heartbeatres = 0;
#ifdef USE_SSL
#ifdef RSAREF
#ifdef SIGPIPE
copyright();
test();