[httperf] reading request body and headers from a file

Steffen Kiefer steffen.kiefer at webde.de
Wed Jan 23 07:27:36 PST 2008


Ted Bullock schrieb:
> Can you please send this patch against the most recent CVS version.

Sure, i'm sorry.
Attached you will find the patch against the most recent CVS version.

Steffen
-------------- next part --------------
--- httperf-cvs-head/httperf/src/gen/misc.c	2007-07-16 02:59:57.000000000 +0200
+++ httperf-cvs-head_patched/httperf/src/gen/misc.c	2008-01-23 15:56:54.404135467 +0100
@@ -56,11 +56,23 @@
 #include <call.h>
 #include <localevent.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 static const char *extra;
 static size_t extra_len;
 
 static size_t method_len;
 
+static size_t body_len;
+static const char *body;
+
+static const char *request_file_header;
+static size_t request_file_header_len;
+
 /* A simple module that collects cookies from the server responses and
    includes them in future calls to the server.  */
 
@@ -124,16 +136,87 @@
   if (method_len > 0)
     call_set_method (c, param.method, method_len);
 
+  if (body_len > 0)
+  {
+    call_set_contents (c, body, body_len);
+    char content_length_header[50];
+    snprintf(content_length_header, 50, "Content-length: %d\r\n", body_len);
+    call_append_request_header (c, strdup(content_length_header), strlen(content_length_header));
+  }
+
   if (extra_len > 0)
     call_append_request_header (c, extra, extra_len);
+
+  if (request_file_header_len > 0)
+    call_append_request_header (c, request_file_header, request_file_header_len);
 }
 
+static void
+parse_request_header_and_body(const char* request_file)
+{
+  // read headers & body from request_file
+  int fd = open(request_file, O_RDONLY);
+  if (fd < 0)
+    panic ("%s: can't open given request file '%s'.\n", prog_name, request_file);
+
+  struct stat statbuf;
+  if (fstat(fd, &statbuf) < 0)
+    panic ("%s: can't determine filesize of file %s.\n", prog_name, request_file);
+
+  off_t filesize = statbuf.st_size;
+  body = (char*) malloc(filesize);
+  if (filesize > 0)
+    body = mmap(0, filesize, PROT_READ, MAP_SHARED, fd, 0);
+
+  // parse & set request headers
+  int headerlen = 0;
+  int newblankline = 1;
+  char* headersbuf = malloc(filesize);
+  for (;;)
+  {
+    headerlen++;
+    if (*body == 0)
+    {
+      // no headers given
+      body = headersbuf;
+      request_file_header_len = 0;
+      body_len = filesize;
+      break;
+    }
+    else if (*body == '\n')
+    {
+      if (newblankline == 1)
+      {
+        // finished parsing headers
+        body++;
+        headersbuf[headerlen] = '\0';
+        request_file_header_len = headerlen;
+        request_file_header = unescape (headersbuf, &request_file_header_len);
+        body_len = filesize - headerlen;
+        break;
+      }
+      else
+      {
+        newblankline = 1;
+      }
+    }
+    else if (isspace(*body) == 0)
+    {
+      newblankline = 0;
+    }
+    headersbuf[headerlen - 1] = *body;
+    body++;
+  }
+}
 
 static void
 init (void)
 {
   Any_Type arg;
 
+  if (param.request_file)
+    parse_request_header_and_body(param.request_file);
+
   if (param.additional_header)
     extra = unescape (param.additional_header, &extra_len);
 
@@ -144,10 +227,18 @@
   event_register_handler (EV_CALL_NEW, call_created, arg);
 }
 
+static void
+stop (void)
+{
+  if (body_len > 0 && body != 0)
+    munmap(body, body_len);
+}
+
+
 Load_Generator misc =
   {
     "Miscellaneous command line options",
     init,
     no_op,
-    no_op
+    stop 
   };
--- httperf-cvs-head/httperf/src/gen/wsesslog.c	2007-09-12 06:47:27.000000000 +0200
+++ httperf-cvs-head_patched/httperf/src/gen/wsesslog.c	2008-01-23 16:04:18.346220578 +0100
@@ -81,6 +81,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include <generic_types.h>
 #include <object.h>
@@ -93,6 +97,7 @@
 #include <rate.h>
 #include <session.h>
 
+
 /* Maximum number of sessions that can be defined in the configuration
    file.  */
 #define MAX_SESSION_TEMPLATES	1000
@@ -116,7 +121,9 @@
     int uri_len;
     char *contents;
     int contents_len;
-    char extra_hdrs[50];	/* plenty for "Content-length: 1234567890" */
+    char *request_file;
+    int request_filelen;
+    char extra_hdrs[50000];
     int extra_hdrs_len;
   };
 
@@ -393,6 +400,7 @@
   char method_str[1000];
   char this_arg[10000];
   char contents[10000];
+  char request_file[10000];
   double think_time;
   int bytes_read;
   REQ *reqptr;
@@ -566,6 +574,160 @@
 		    strlen (sptr->current_req->extra_hdrs);
 		}
 	    }
+      else if (sscanf (this_arg, "request-file=%s", request_file) == 1)
+       {
+         /* this is tricky since request-file might be a quoted
+        string with embedded spaces or escaped quotes.  We
+        should parse this carefully from parsed_so_far */
+         from = strchr (parsed_so_far, '=') + 1;
+         to = request_file;
+         single_quoted = FALSE;
+         double_quoted = FALSE;
+         escaped = FALSE;
+         done = FALSE;
+         while ((ch = *from++) != '\0' && !done)
+       {
+         if (escaped == TRUE)
+           {
+             switch (ch)
+           {
+           case 'n':
+             *to++ = '\n';
+             break;
+           case 'r':
+             *to++ = '\r';
+             break;
+           case 't':
+             *to++ = '\t';
+             break;
+           case '\n':
+             *to++ = '\n';
+             /* this allows an escaped newline to
+                continue the parsing to the next line. */
+             if (fgets(line,sizeof(line),fp) == NULL)
+               {
+                 lineno++;
+                 panic ("%s: premature EOF seen in '%s'\n",
+                   prog_name, param.wsesslog.file);
+               }
+             parsed_so_far = from = line;
+             break;
+           default:
+             *to++ = ch;
+             break;
+           }
+             escaped = FALSE;
+           }
+         else if (ch == '"' && double_quoted)
+           {
+             double_quoted = FALSE;
+           }
+         else if (ch == '\'' && single_quoted)
+           {
+             single_quoted = FALSE;
+           }
+         else
+           {
+             switch (ch)
+           {
+           case '\t':
+           case '\n':
+           case ' ':
+             if (single_quoted == FALSE &&
+                 double_quoted == FALSE)
+               done = TRUE;    /* we are done */
+             else
+               *to++ = ch;
+             break;
+           case '\\':      /* backslash */
+             escaped = TRUE;
+             break;
+           case '"':       /* double quote */
+             if (single_quoted)
+               *to++ = ch;
+             else
+               double_quoted = TRUE;
+             break;
+           case '\'':      /* single quote */
+             if (double_quoted)
+               *to++ = ch;
+             else
+               single_quoted = TRUE;
+             break;
+           default:
+             *to++ = ch;
+             break;
+           }
+           }
+       }
+         *to = '\0';
+         from--;       /* back up 'from' to '\0' or white-space */
+         bytes_read = from - parsed_so_far;
+         if (strlen (request_file) > 0)
+         {
+            sptr->current_req->request_file = strdup (request_file);
+
+            // read headers & body from request_file
+            int fd = open(sptr->current_req->request_file, O_RDONLY);
+            if (fd < 0)
+              panic ("%s: can't open given request file '%s' from wsesslog.\n", prog_name, sptr->current_req->request_file);
+
+            struct stat statbuf;
+            if (fstat(fd, &statbuf) < 0)
+              panic ("%s: can't determine filesize of file %s.\n", prog_name, sptr->current_req->request_file);
+
+            off_t filesize = statbuf.st_size;
+            sptr->current_req->request_filelen = filesize;
+            sptr->current_req->contents = (char*) malloc(filesize);
+            if (filesize > 0)
+              sptr->current_req->contents = mmap(0, filesize, PROT_READ, MAP_SHARED, fd, 0);
+
+            // parse & set request headers
+            int headerlen = 0;
+            int newblankline = 1;
+            char* headersbuf = malloc(filesize);
+            for (;;)
+            {
+              headerlen++;
+              if (*sptr->current_req->contents == 0)
+                // no headers given
+                sptr->current_req->contents = headersbuf;
+                sptr->current_req->contents_len = filesize;
+                break;
+              }
+              else if (*sptr->current_req->contents == '\n')
+              {
+                if (newblankline == 1)
+                {
+                  // finished parsing headers
+                  sptr->current_req->contents++;
+                  headersbuf[headerlen] = '\0';
+                  strncat(sptr->current_req->extra_hdrs, strdup(headersbuf), strlen(headersbuf));
+                  sptr->current_req->extra_hdrs_len = strlen(sptr->current_req->extra_hdrs);
+                  sptr->current_req->contents_len = filesize - headerlen;
+                  break;
+                }
+                else
+                {
+                  newblankline = 1;
+                }
+              }
+              else if (isspace(*sptr->current_req->contents) == 0)
+              {
+                newblankline = 0;
+              }
+              headersbuf[headerlen - 1] = *sptr->current_req->contents;
+              sptr->current_req->contents++;
+            }
+
+            char content_length_header[50];
+            snprintf(content_length_header, 50, "Content-length: %d\r\n", sptr->current_req->contents_len);
+            strncat(sptr->current_req->extra_hdrs,
+               content_length_header, strlen(content_length_header));
+            sptr->current_req->extra_hdrs_len =
+                strlen (sptr->current_req->extra_hdrs);
+          }
+        }
 	  else
 	    {
 	      /* do not recognize this arg */
@@ -644,10 +806,36 @@
   rate_generator_start (&rg_sess, EV_SESS_DESTROYED);
 }
 
+static void
+stop (void)
+{
+  Sess_Private_Data *priv;
+  int i = 0;
+  for ( ; i < num_templates; i++)
+  {
+    priv = &session_templates[i];
+    if (priv != 0)
+    {
+      BURST* firstb = priv->current_burst;
+      BURST* currb;
+      for (currb = firstb; currb != 0; currb = currb->next)
+      {
+        REQ* firstreq = currb->req_list;
+        REQ* curreq;
+        for (curreq = firstreq; curreq != 0; curreq = curreq->next )
+        {
+          if (curreq->request_file != 0)
+              munmap(curreq->contents, curreq->request_filelen);
+        }
+      }
+    }
+  }
+}
+
 Load_Generator wsesslog =
   {
     "creates log-based session workload",
     init,
     start,
-    no_op
+    stop 
   };
--- httperf-cvs-head/httperf/src/httperf.c	2007-11-17 01:50:56.000000000 +0100
+++ httperf-cvs-head_patched/httperf/src/httperf.c	2008-01-23 16:07:15.017150968 +0100
@@ -129,6 +129,7 @@
 	{"print-request", optional_argument, &param.print_request, 0},
 	{"rate", required_argument, (int *) &param.rate, 0},
 	{"recv-buffer", required_argument, (int *) &param.recv_buffer_size, 0},
+    {"request-file",  required_argument, (int *) &param.request_file, 0},
 	{"retry-on-failure", no_argument, &param.retry_on_failure, 1},
 	{"send-buffer", required_argument, (int *) &param.send_buffer_size, 0},
 	{"server", required_argument, (int *) &param.server, 0},
@@ -164,7 +165,7 @@
 	       "\t[--num-calls N] [--num-conns N] [--period [d|u|e]T1[,T2]]\n"
 	       "\t[--port N] "
 	       "[--print-reply [header|body]] [--print-request [header|body]]\n"
-	       "\t[--rate X] [--recv-buffer N] [--retry-on-failure] "
+           "\t[--rate X] [--recv-buffer N] [--request-file file] [--retry-on-failure] "
 	       "[--send-buffer N]\n"
 	       "\t[--server S] [--server-name S] [--session-cookies]\n"
 #ifdef HAVE_SSL
@@ -633,6 +634,8 @@
 #endif
 			else if (flag == &param.uri)
 				param.uri = optarg;
+            else if (flag == &param.request_file)
+                param.request_file = optarg;
 			else if (flag == &param.think_timeout) {
 				errno = 0;
 				param.think_timeout = strtod(optarg, &end);
@@ -957,7 +960,7 @@
 		gen[num_gen++] = &sess_cookie;
 	}
 
-	if (param.additional_header || param.method)
+	if (param.additional_header || param.method || param.request_file)
 		gen[num_gen++] = &misc;
 
 	/*
--- httperf-cvs-head/httperf/src/httperf.h	2007-07-15 23:14:20.000000000 +0200
+++ httperf-cvs-head_patched/httperf/src/httperf.h	2008-01-23 16:07:57.903008020 +0100
@@ -122,6 +122,7 @@
     int use_timer_cache;
     const char *additional_header;	/* additional request header(s) */
     const char *method;	/* default call method */
+    const char *request_file;  /* name of the file where entries are */
     struct
       {
 	u_int id;


More information about the httperf mailing list