[httperf] Patch to add HTTP Basic Authentication
Durval Menezes
httperf@napali.hpl.hp.com
Mon, 13 Nov 2000 20:42:43 -0200
On Wed, Nov 08, 2000 at 07:45:09AM -0200, Durval Menezes wrote:
> Hello,
>
> On Tue, Nov 07, 2000 at 06:27:39PM -0800, David Mosberger wrote:
> > That's unfortunately a problem, since the advertising clause is
> > incompatible with GPL. Can you replace it with some other code?
>
> Sure. Will do, probably with code from GNU sharutils.
> Expect it done around next monday (I usually hack code in the weekends).
Here it goes. In fact, I used code from GNU's wget (it's *much* better
written). The resulting httperf has been tested and is working in my
setup.
Best Regards,
--
Durval Menezes (durval@tmp.com.br, http://www.amcham.com.br/~durval)
# patch-httperf-0.8-basic_auth
# 2000/11/12 Durval Menezes <durval@tmp.com.br>
#
# This patch adds HTTP Basic Authentication command-line option to httperf-0.8
#
# Apply with
# tar xzf httperf-0.8.tar.gz
# cd httperf-0.8
# patch -p1 <../patch-httperf-0.8-basic_auth
#
diff -ru httperf-0.8/gen/misc.c httperf-0.8-basic-auth/gen/misc.c
--- httperf-0.8/gen/misc.c Wed Oct 11 21:37:05 2000
+++ httperf-0.8-basic-auth/gen/misc.c Sun Nov 12 16:16:07 2000
@@ -28,6 +28,16 @@
--add-header Adds one or more command-line specified header(s)
to each call request.
+ --basic-auth Adds a Basic Authentication header to each call
+ request.
+
+ Note that a browser would first send the request
+ without the Authentication Header, get a 401
+ error from the server, prompt the user for his/her
+ username and password and ONLY THEN send a new
+ request with the Authentication Header in it; this
+ isn't what we do here.
+
--method Sets the method to be used when performing a
call. */
@@ -45,6 +55,9 @@
static const char *extra;
static size_t extra_len;
+static const char *basic_auth;
+static size_t basic_auth_len;
+
static size_t method_len;
/* A simple module that collects cookies from the server responses and
@@ -100,6 +113,79 @@
return dst;
}
+/* ----------------------------------------------------------------------------- */
+/* the following code was extracted from GNU wget version 1.5.3, file src/http.c */
+/* ----------------------------------------------------------------------------- */
+
+/* How many bytes it will take to store LEN bytes in base64. */
+#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
+
+/* Encode the string S of length LENGTH to base64 format and place it
+ to STORE. STORE will be 0-terminated, and must point to a writable
+ buffer of at least 1+BASE64_LENGTH(length) bytes. */
+static void
+base64_encode (const char *s, char *store, int length)
+{
+ /* Conversion table. */
+ static char tbl[64] = {
+ 'A','B','C','D','E','F','G','H',
+ 'I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X',
+ 'Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n',
+ 'o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3',
+ '4','5','6','7','8','9','+','/'
+ };
+ int i;
+ unsigned char *p = (unsigned char *)store;
+
+ /* Transform the 3x8 bits to 4x6 bits, as required by base64. */
+ for (i = 0; i < length; i += 3)
+ {
+ *p++ = tbl[s[0] >> 2];
+ *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
+ *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
+ *p++ = tbl[s[2] & 0x3f];
+ s += 3;
+ }
+ /* Pad the result if necessary... */
+ if (i == length + 1)
+ *(p - 1) = '=';
+ else if (i == length + 2)
+ *(p - 1) = *(p - 2) = '=';
+ /* ...and zero-terminate it. */
+ *p = '\0';
+}
+
+/* ----------------------------------------------------------------------------- */
+/* end of code extracted from GNU wget 1.5.3, file src/http.c */
+/* ----------------------------------------------------------------------------- */
+
+static const char *
+basic_auth_encode (const char *str, size_t *len)
+{
+ static char *prefix = "Authorization: basic ";
+ int maxuulen=BASE64_LENGTH(strlen(str));
+ char *uu = malloc(maxuulen+1);
+ int maxdstlen=strlen(prefix)+maxuulen+3;
+ char *dst = malloc(maxdstlen+1);
+
+ if (!uu || !dst)
+ panic ("%s: malloc() failed: %s\n", prog_name, strerror (errno));
+
+ base64_encode(str, uu, strlen(str));
+
+ strncat(dst, prefix, maxdstlen);
+ strncat(dst, uu, maxdstlen);
+ strncat(dst, "\r\n", maxdstlen);
+
+ free(uu);
+
+ *len = strlen(dst);
+ return dst;
+}
+
static void
call_created (Event_Type et, Object *obj, Any_Type reg_arg, Any_Type arg)
{
@@ -112,6 +198,9 @@
if (extra_len > 0)
call_append_request_header (c, extra, extra_len);
+
+ if (basic_auth_len > 0)
+ call_append_request_header (c, basic_auth, basic_auth_len);
}
@@ -122,6 +211,9 @@
if (param.additional_header)
extra = unescape (param.additional_header, &extra_len);
+
+ if (param.basic_auth_string)
+ basic_auth = basic_auth_encode (param.basic_auth_string, &basic_auth_len);
if (param.method)
method_len = strlen (param.method);
diff -ru httperf-0.8/httperf.c httperf-0.8-basic-auth/httperf.c
--- httperf-0.8/httperf.c Tue Oct 31 18:20:00 2000
+++ httperf-0.8-basic-auth/httperf.c Sun Nov 12 16:08:59 2000
@@ -96,6 +96,7 @@
static struct option longopts[] =
{
{"add-header", required_argument, (int *) ¶m.additional_header, 0},
+ {"basic-auth", required_argument, (int *) ¶m.basic_auth_string, 0},
{"burst-length", required_argument, ¶m.burst_len, 0},
{"client", required_argument, (int *) ¶m.client, 0},
{"close-with-reset", no_argument, ¶m.close_with_reset, 1},
@@ -144,6 +145,7 @@
{
printf ("Usage: %s "
"[-hdvV] [--add-header S] [--burst-length N] [--client N/N]\n"
+ "\t[--basic-auth \"username:password\"]\n"
"\t[--close-with-reset] [--debug N] [--failure-status N]\n"
"\t[--help] [--hog] [--http-version S] [--max-connections N]\n"
"\t[--max-piped-calls N] [--method S] [--no-host-hdr]\n"
@@ -267,6 +269,19 @@
param.method = optarg;
else if (flag == ¶m.additional_header)
param.additional_header = optarg;
+ else if (flag == ¶m.basic_auth_string)
+ {
+ char *p;
+ if ((p=strchr(optarg,':')) == NULL ||
+ (p-optarg) == 0 ||
+ (p-optarg) == strlen(optarg)-1)
+ {
+ fprintf(stderr, "%s: invalid string for --basic-auth '%s'\n", prog_name, optarg);
+ exit(-1);
+ }
+ else
+ param.basic_auth_string = optarg;
+ }
else if (flag == ¶m.num_calls)
{
errno = 0;
@@ -826,7 +841,7 @@
gen[num_gen++] = &sess_cookie;
}
- if (param.additional_header || param.method)
+ if (param.additional_header || param.basic_auth_string || param.method)
gen[num_gen++] = &misc;
/* echo command invocation for logging purposes: */
@@ -900,6 +915,8 @@
#endif
if (param.additional_header)
printf (" --add-header='%s'", param.additional_header);
+ if (param.basic_auth_string)
+ printf (" --basic-auth='%s'", param.basic_auth_string);
if (param.method) printf (" --method=%s", param.method);
if (param.wsesslog.num_sessions)
{
diff -ru httperf-0.8/httperf.h httperf-0.8-basic-auth/httperf.h
--- httperf-0.8/httperf.h Tue Oct 31 18:32:09 2000
+++ httperf-0.8-basic-auth/httperf.h Sun Nov 12 16:08:59 2000
@@ -127,6 +127,7 @@
const char *ssl_cipher_list; /* client's list of SSL cipher suites */
#endif
const char *additional_header; /* additional request header(s) */
+ const char *basic_auth_string; /* Basic Authentication string (username:password) */
const char *method; /* default call method */
struct
{
diff -ru httperf-0.8/httperf.man httperf-0.8-basic-auth/httperf.man
--- httperf-0.8/httperf.man Tue Oct 31 18:17:15 2000
+++ httperf-0.8-basic-auth/httperf.man Sun Nov 12 16:08:59 2000
@@ -6,6 +6,8 @@
.B httperf
.RB [ --add-header
.IR S ]
+.RB [ --basic-auth
+.IR username : password ]
.RB [ --burst-length
.IR N ]
.RB [ --client
@@ -151,6 +153,17 @@
sequences are ``\\r'' (carriage-return), ``\\a'' (line-feed), ``\\\\''
(backslash), and ``\\N'' where N is the code the character to be
inserted (in octal).
+.TP
+.BI --basic-auth= "username:password"
+Specifies to include an HTTP Basic Authentication header in every
+request, with the
+.I username
+and
+.I password
+as given (separated by ``:''). Note that a browser would first send the request
+without the Authentication Header, get a 401 error from the server, prompt the
+user for his/her username and password and ONLY THEN send a new request with
+the Authentication Header in it; this isn't what we do here.
.TP
.BI --burst-length= N
Specifies the length of bursts. Each burst consists of
--
To unsubscribe: echo unsubscribe httperf | mail majordomo@linux.hpl.hp.com