dirkx 99/04/05 06:52:21
Modified: src/support ab.8 ab.c Added: src/support README Log: Added Basic Auth, Cookies and arbitrary headers to ab.c/ab.8. Sorry for the diff; ident seemed to have mangled some lines with the current .indedent.pro. Sneaked in a write() to writev() replacement which at least on FreeBSD makes a POST significantly 2-5% faster. Added a README file. To make it even more obvious that there are usefull things such as rotate_log, split_log and the likes. Revision Changes Path 1.5 +47 -0 apache-1.3/src/support/ab.8 Index: ab.8 =================================================================== RCS file: /x3/home/cvs/apache-1.3/src/support/ab.8,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- ab.8 1999/02/19 16:25:35 1.4 +++ ab.8 1999/04/05 13:52:20 1.5 @@ -1,4 +1,5 @@ .TH ab 1 "March 1998" +.\" $Id: ab.8,v 1.5 1999/04/05 13:52:20 dirkx Exp $ .\" Copyright (c) 1998-1999 The Apache Group. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -66,6 +67,14 @@ ] [ .BI \-p " POST file" ] [ +.BI \-A " Authenticate username:password" +] [ +.BI \-P " Proxy Authenticate username:password" +] [ +.BI \-H " Custom header" +] [ +.BI \-C " Cookie name=value" +] [ .BI \-T " content-type" ] [ .BI \-v " verbosity" @@ -126,6 +135,31 @@ File containing data to POST. .TP 12 +.BI \-A " Authorization username:password" +Supply BASIC Authentification credentials to the server. The username +and password are separated by a single ':' and send on the wire uuencoded. +The string is send regardless of wether the server needs it; (i.e. has +send an 401. Authentifcation needed). + +.TP 12 +.BI \-p " Proxy-Authorization username:password" +Supply BASIC Authentification credentials to a proxy en-route. The username +and password are separated by a single ':' and send on the wire uuencoded. +The string is send regardless of wether the proxy needs it; (i.e. has +send an 407 Proxy authentifcation needed). + +.TP 12 +.BI \-C " Cookie name=value" +Add a 'Cookie:' line to the request. The argument is typically in the form +of a 'name=value' pair. This field is repeatable. + +.TP 12 +.BI \-p " Header string" +Postfix extra headers to the request. The argument is typically in the form +of a valid header line; containing a colon separated field value pair. (i.e. +'Accept-Encoding: zip/zop;8bit'). + +.TP 12 .BI \-T " content-type" Content-type header to use for POST data. @@ -158,6 +192,19 @@ .B \-h Display usage information. .PD +.SH BUGS +There are various statically declared buffers of fixed length. Combined +with the lazy parsing of the command line arguments, the response headers +from the server and other external inputs this might bite you. +.P +It does not implment HTTP/1.x fully; only accepts some 'expected' forms +of responses. The rather heavy use of +.BR strstr(3) +shows up top in profile, +which might indicate a performance problem; i.e. you would measure the +.BR ab +performance rather than the server's. + .SH SEE ALSO .BR httpd(8) . 1.21 +130 -30 apache-1.3/src/support/ab.c Index: ab.c =================================================================== RCS file: /x3/home/cvs/apache-1.3/src/support/ab.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- ab.c 1999/02/19 16:25:35 1.20 +++ ab.c 1999/04/05 13:52:21 1.21 @@ -81,6 +81,7 @@ ** - Cleaned up by Ralf S. Engelschall <[EMAIL PROTECTED]>, March 1998 ** - POST and verbosity by Kurt Sussman <[EMAIL PROTECTED]>, August 1998 ** - HTML table output added by David N. Welton <[EMAIL PROTECTED]>, January 1999 + ** - Added Cookie, Arbitrary header and auth support. <[EMAIL PROTECTED]>, April 199 ** */ @@ -120,11 +121,17 @@ #include <string.h> #define ap_select select -#else /* (!)NO_APACHE_INCLUDES */ +#else /* (!)NO_APACHE_INCLUDES */ #include "ap_config.h" #include <fcntl.h> #include <sys/time.h> -#endif /* NO_APACHE_INCLUDES */ + +#ifndef NO_WRITEV +#include <sys/types.h> +#include <sys/uio.h> +#endif + +#endif /* NO_APACHE_INCLUDES */ /* ------------------- DEFINITIONS -------------------------- */ /* maximum number of requests on a time limited test */ @@ -146,7 +153,8 @@ char cbuff[CBUFFSIZE]; /* a buffer to store server response header */ int cbx; /* offset in cbuffer */ int keepalive; /* non-zero if a keep-alive request */ - int gotheader; /* non-zero if we have the entire header in cbuff */ + int gotheader; /* non-zero if we have the entire header in + * cbuff */ struct timeval start, connect, done; }; @@ -174,6 +182,10 @@ char *postdata; /* *buffer containing data from postfile */ int postlen = 0; /* length of data to be POSTed */ char content_type[1024]; /* content type to put in POST header */ +char cookie[1024], /* optional cookie line */ + auth[1024], /* optional (basic/uuencoded) + * authentification */ + hdrs[4096]; /* optional arbitrary headers */ int port = 80; /* port number */ int use_html = 0; /* use html in the report */ @@ -223,20 +235,63 @@ exit(errno); } +/* -- simple uuencode, lifted from main/util.c which + * needed the pool, so duplicated here with normal + * malloc. + */ +static const char basis_64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static char *uuencode(char *string) +{ + int i, len = strlen(string); + char *p; + char *encoded = (char *) malloc((len + 2) / 3 * 4 + 1); + p = encoded; + for (i = 0; i < len; i += 3) { + *p++ = basis_64[string[i] >> 2]; + *p++ = basis_64[((string[i] & 0x3) << 4) | + ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2) | + ((int) (string[i + 2] & 0xC0) >> 6)]; + *p++ = basis_64[string[i + 2] & 0x3F]; + }; + *p-- = '\0'; + *p-- = '='; + *p-- = '='; + return encoded; +} + + /* --------------------------------------------------------- */ /* write out request to a connection - assumes we can write (small) request out in one go into our new socket buffer */ -static void write_request(struct connection *c) +static void write_request(struct connection * c) { +#ifndef NO_WRITEV + struct iovec out[2]; int outcnt = 1; +#endif gettimeofday(&c->connect, 0); - /* XXX: this could use writev for posting -- more efficient -djg */ - write(c->fd, request, reqlen); +#ifndef NO_WRITEV + out[0].iov_base = request; + out[0].iov_len = reqlen; + if (posting) { - write(c->fd, postdata, postlen); + out[1].iov_base = postdata; + out[1].iov_len = postlen; + outcnt = 2; totalposted += (reqlen + postlen); } + writev(c->fd,out, outcnt); +#else + write(c->fd,request,reqlen); + if (posting) { + write(c->fd,postdata,postlen); + totalposted += (reqlen + postlen); + } +#endif c->state = STATE_READ; FD_SET(c->fd, &readbits); @@ -469,7 +524,7 @@ /* start asnchronous non-blocking connection */ -static void start_connect(struct connection *c) +static void start_connect(struct connection * c) { c->read = 0; c->bread = 0; @@ -484,7 +539,7 @@ nonblock(c->fd); gettimeofday(&c->start, 0); - if (connect(c->fd, (struct sockaddr *) &server, sizeof(server)) < 0) { + if (connect(c->fd, (struct sockaddr *) & server, sizeof(server)) < 0) { if (errno == EINPROGRESS) { c->state = STATE_CONNECTING; FD_SET(c->fd, &writebits); @@ -508,7 +563,7 @@ /* close down connection and save stats */ -static void close_connection(struct connection *c) +static void close_connection(struct connection * c) { if (c->read == 0 && c->keepalive) { /* server has legitimately shut down an idle keep alive request */ @@ -548,7 +603,7 @@ /* read data from connection */ -static void read_connection(struct connection *c) +static void read_connection(struct connection * c) { int r; char *part; @@ -570,13 +625,14 @@ if (!c->gotheader) { char *s; int l = 4; - int space = CBUFFSIZE - c->cbx - 1; /* -1 to allow for 0 terminator */ + int space = CBUFFSIZE - c->cbx - 1; /* -1 to allow for 0 + * terminator */ int tocopy = (space < r) ? space : r; #ifndef CHARSET_EBCDIC memcpy(c->cbuff + c->cbx, buffer, space); -#else /*CHARSET_EBCDIC */ +#else /* CHARSET_EBCDIC */ ascii2ebcdic(c->cbuff + c->cbx, buffer, space); -#endif /*CHARSET_EBCDIC */ +#endif /* CHARSET_EBCDIC */ c->cbx += tocopy; space -= tocopy; c->cbuff[c->cbx] = 0; /* terminate for benefit of strstr */ @@ -584,8 +640,10 @@ printf("LOG: header received:\n%s\n", c->cbuff); } s = strstr(c->cbuff, "\r\n\r\n"); - /* this next line is so that we talk to NCSA 1.5 which blatantly breaks - the http specifaction */ + /* + * this next line is so that we talk to NCSA 1.5 which blatantly + * breaks the http specifaction + */ if (!s) { s = strstr(c->cbuff, "\n\n"); l = 2; @@ -620,10 +678,12 @@ *q = 0; } - /* XXX: this parsing isn't even remotely HTTP compliant... - * but in the interest of speed it doesn't totally have to be, - * it just needs to be extended to handle whatever servers - * folks want to test against. -djg */ + /* + * XXX: this parsing isn't even remotely HTTP compliant... but in + * the interest of speed it doesn't totally have to be, it just + * needs to be extended to handle whatever servers folks want to + * test against. -djg + */ /* check response code */ part = strstr(c->cbuff, "HTTP"); /* really HTTP/1.x_ */ @@ -732,29 +792,31 @@ if (!posting) { sprintf(request, "GET %s HTTP/1.0\r\n" "User-Agent: ApacheBench/%s\r\n" - "%s" + "%s" "%s" "%s" "Host: %s\r\n" "Accept: */*\r\n" - "\r\n", + "\r\n" "%s", path, VERSION, keepalive ? "Connection: Keep-Alive\r\n" : "", - hostname); + cookie, auth, hostname, hdrs); } else { sprintf(request, "POST %s HTTP/1.0\r\n" "User-Agent: ApacheBench/%s\r\n" - "%s" + "%s" "%s" "%s" "Host: %s\r\n" "Accept: */*\r\n" "Content-length: %d\r\n" "Content-type: %s\r\n" + "%s" "\r\n", path, VERSION, keepalive ? "Connection: Keep-Alive\r\n" : "", + cookie, auth, hostname, postlen, - (content_type[0]) ? content_type : "text/plain"); + (content_type[0]) ? content_type : "text/plain", hdrs); } if (verbosity >= 2) @@ -764,7 +826,7 @@ #ifdef CHARSET_EBCDIC ebcdic2ascii(request, request, reqlen); -#endif /*CHARSET_EBCDIC */ +#endif /* CHARSET_EBCDIC */ /* ok - lets start */ gettimeofday(&start, 0); @@ -851,6 +913,13 @@ fprintf(stderr, " -x attributes String to insert as table attributes\n"); fprintf(stderr, " -y attributes String to insert as tr attributes\n"); fprintf(stderr, " -z attributes String to insert as td or th attributes\n"); + fprintf(stderr, " -C attribute Add cookie, eg. 'Apache=1234. (repeatable)\n"); + fprintf(stderr, " -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: zop'\n"); + fprintf(stderr, " Inserted after all normal header lines. (repeatable)\n"); + fprintf(stderr, " -A attribute Add Basic WWW Authentication, the attributes\n"); + fprintf(stderr, " are a colon separated username and password.\n"); + fprintf(stderr, " -p attribute Add Basic Proxy Authentication, the attributes\n"); + fprintf(stderr, " are a colon separated username and password.\n"); fprintf(stderr, " -V Print version number and exit\n"); fprintf(stderr, " -k Use HTTP KeepAlive feature\n"); fprintf(stderr, " -h Display usage information (this message)\n"); @@ -929,9 +998,11 @@ tablestring = ""; trstring = ""; tdstring = "bgcolor=white"; - + cookie[0] = '\0'; + auth[0] = '\0'; + hdrs[0] = '\0'; optind = 1; - while ((c = getopt(argc, argv, "n:c:t:T:p:v:kVhwx:y:z:")) > 0) { + while ((c = getopt(argc, argv, "n:c:t:T:p:v:kVhwx:y:z:C:H:P:A:")) > 0) { switch (c) { case 'n': requests = atoi(optarg); @@ -958,11 +1029,37 @@ break; case 't': tlimit = atoi(optarg); - requests = MAX_REQUESTS; /* need to size data array on something */ + requests = MAX_REQUESTS; /* need to size data array on + * something */ break; case 'T': strcpy(content_type, optarg); break; + case 'C': + strncat(cookie, "Cookie: ", sizeof(cookie)); + strncat(cookie, optarg, sizeof(cookie)); + strncat(cookie, "\r\n", sizeof(cookie)); + break; + case 'A': + /* + * assume username passwd already to be in colon separated form. + */ + strncat(auth, "Authorization: basic ", sizeof(auth)); + strncat(auth, uuencode(optarg), sizeof(auth)); + strncat(auth, "\r\n", sizeof(auth)); + break; + case 'P': + /* + * assume username passwd already to be in colon separated form. + */ + strncat(auth, "Proxy-Authorization: basic ", sizeof(auth)); + strncat(auth, uuencode(optarg), sizeof(auth)); + strncat(auth, "\r\n", sizeof(auth)); + break; + case 'H': + strncat(hdrs, optarg, sizeof(hdrs)); + strncat(hdrs, "\r\n", sizeof(hdrs)); + break; case 'V': copyright(); exit(0); @@ -970,7 +1067,10 @@ case 'w': use_html = 1; break; - /* if any of the following three are used, turn on html output automatically */ + /* + * if any of the following three are used, turn on html output + * automatically + */ case 'x': use_html = 1; tablestring = optarg; 1.1 apache-1.3/src/support/README Index: README =================================================================== Support files: ab ABuse your server with this benchmarker. Rudimentary command line testing tool. apachectl Apache run-time Control script. To facilitate the administrator and/or your rc.d scripts to control the functioning of the Apache httpd daemon. apxs APache eXtenSion tool. Eases building and installing DSO style modules. dbmmanage Create and update user authentication files in the faster DBM format used by mod_auth_db. htdigest Create and update user authentication files used in DIGEST authentification. See mod_auth_digest. htpasswd Create and update user authentication files used in BASIC authentification. I.e. the htpasswd files. See mod_auth. httpd.8 General apache man page. log_server_status This script is designed to be run at a frequent interval by something like cron. It connects to the server and downloads the status information. It reformats the information to a single line and logs it to a file. logresolve resolve hostnames for IP-adresses in Apache logfiles phf_abuse_log.cgi This script can be used to detect people trying to abuse an ancient and long plugged security hole which existed in a CGI script distributed with Apache 1.0.3 and earlier versions. rotatelogs rotate Apache logs without having to kill the server. split-logfile This script will take a combined virtual hosts access log file and break its contents into separate files. suexec Switch User For Exec. Used internally by apache, see the document `Apache suEXEC Support' under http://www.apache.org/docs/suexec.html .