[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 *) &param.additional_header, 0},
+    {"basic-auth",   required_argument, (int *) &param.basic_auth_string, 0},
     {"burst-length", required_argument, &param.burst_len,		0},
     {"client",	     required_argument, (int *) &param.client,		0},
     {"close-with-reset", no_argument,	&param.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 == &param.additional_header)
 	    param.additional_header = optarg;
+	  else if (flag == &param.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 == &param.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