Code

src/utils_cgi.[ch]: Basically a rewrite of the parameter handling functions.
authorFlorian Forster <ff@octo.it>
Wed, 23 Jun 2010 15:54:48 +0000 (17:54 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Wed, 23 Jun 2010 15:54:48 +0000 (17:54 +0200)
src/utils_cgi.c
src/utils_cgi.h

index 97dfc7c60b9a9bdd6e8b588d7645fcd9a8ea63c4..b96e15aeb53340c14918184cbfe1bdfd26d0ea5d 100644 (file)
@@ -4,8 +4,10 @@
 #include <ctype.h>
 #include <errno.h>
 #include <time.h>
+#include <assert.h>
 
 #include "utils_cgi.h"
+#include "common.h"
 
 #include <fcgiapp.h>
 #include <fcgi_stdio.h>
@@ -17,87 +19,45 @@ struct parameter_s
 };
 typedef struct parameter_s parameter_t;
 
-static parameter_t *parameters = NULL;
-static size_t parameters_num = 0;
-static _Bool parameters_init = 0;
-
-static int parameter_add (const char *key, const char *value) /* {{{ */
+struct param_list_s
 {
-  parameter_t *ptr;
-
-  if (value == NULL)
-    return (EINVAL);
-
-  ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
-  if (ptr == NULL)
-    return (ENOMEM);
-  parameters = ptr;
-
-  ptr = parameters + parameters_num;
-  if (key == NULL)
-  {
-    ptr->key = NULL;
-  }
-  else
-  {
-    ptr->key = strdup (key);
-    if (ptr->key == NULL)
-      return (ENOMEM);
-  }
-
-  ptr->value = strdup (value);
-  if (ptr->value == NULL)
-  {
-    free (ptr->key);
-    return (ENOMEM);
-  }
-
-  parameters_num++;
-  return (0);
-} /* }}} int parameter_add */
-
-static char *parameter_lookup (const char *key) /* {{{ */
-{
-  size_t i;
-
-  for (i = 0; i < parameters_num; i++)
-  {
-    if ((key == NULL) && (parameters[i].key == NULL))
-      return (parameters[i].value);
-    else if ((key != NULL) && (parameters[i].key != NULL)
-        && (strcmp (key, parameters[i].key) == 0))
-      return (parameters[i].value);
-  }
+  parameter_t *parameters;
+  size_t parameters_num;
+};
 
-  return (NULL);
-} /* }}} char *parameter_lookup */
+static param_list_t *pl_global = NULL;
 
-static char *uri_unescape (char *string) /* {{{ */
+static char *uri_unescape_copy (char *dest, const char *src, size_t n) /* {{{ */
 {
-  char *in;
-  char *out;
+  const char *src_ptr;
+  char *dest_ptr;
 
-  if (string == NULL)
+  if ((dest == NULL) || (src == NULL) || (n < 1))
     return (NULL);
 
-  in = string;
-  out = string;
+  src_ptr = src;
+  dest_ptr = dest;
+
+  *dest_ptr = 0;
 
-  while (*in != 0)
+  while (*src_ptr != 0)
   {
-    if (*in == '+')
+    if (n < 2)
+      break;
+
+    if (*src_ptr == '+')
     {
-      *out = ' ';
+      *dest_ptr = ' ';
     }
-    else if ((in[0] == '%')
-        && isxdigit ((int) in[1]) && isxdigit ((int) in[2]))
+    else if ((src_ptr[0] == '%')
+        && isxdigit ((int) src_ptr[1]) && isxdigit ((int) src_ptr[2]))
     {
       char tmpstr[3];
       char *endptr;
       long value;
 
-      tmpstr[0] = in[1];
-      tmpstr[1] = in[2];
+      tmpstr[0] = src_ptr[1];
+      tmpstr[1] = src_ptr[2];
       tmpstr[2] = 0;
 
       errno = 0;
@@ -105,64 +65,88 @@ static char *uri_unescape (char *string) /* {{{ */
       value = strtol (tmpstr, &endptr, /* base = */ 16);
       if ((endptr == tmpstr) || (errno != 0))
       {
-        *out = '?';
+        *dest_ptr = '?';
       }
       else
       {
-        *out = (char) value;
+        *dest_ptr = (char) value;
       }
 
-      in += 2;
+      src_ptr += 2;
     }
     else
     {
-      *out = *in;
+      *dest_ptr = *src_ptr;
     }
 
-    in++;
-    out++;
-  } /* while (*in != 0) */
+    src_ptr++;
+    dest_ptr++;
+    *dest_ptr = 0;
+  } /* while (*src_ptr != 0) */
+
+  assert (*dest_ptr == 0);
+  return (dest);
+} /* }}} char *uri_unescape */
+
+static char *uri_unescape (const char *string) /* {{{ */
+{
+  char buffer[4096];
 
-  *out = 0;
-  return (string);
+  if (string == NULL)
+    return (NULL);
+
+  uri_unescape_copy (buffer, string, sizeof (buffer));
+  
+  return (strdup (buffer));
 } /* }}} char *uri_unescape */
 
-static int parse_keyval (char *keyval) /* {{{ */
+static int param_parse_keyval (param_list_t *pl, char *keyval) /* {{{ */
 {
+  char *key_raw;
+  char *value_raw;
   char *key;
-  char *val;
+  char *value;
 
-  val = strchr (keyval, '=');
-  if (val == NULL)
-  {
-    key = NULL;
-    val = keyval;
-  }
-  else
+  key_raw = keyval;
+  value_raw = strchr (key_raw, '=');
+  if (value_raw == NULL)
+    return (EINVAL);
+  *value_raw = 0;
+  value_raw++;
+
+  key = uri_unescape (key_raw);
+  if (key == NULL)
+    return (ENOMEM);
+
+  value = uri_unescape (value_raw);
+  if (value == NULL)
   {
-    key = keyval;
-    *val = 0;
-    val++;
+    free (key);
+    return (ENOMEM);
   }
+  
+  param_set (pl, key, value);
 
-  parameter_add (uri_unescape (key), uri_unescape (val));
+  free (key);
+  free (value);
 
   return (0);
-} /* }}} int parse_keyval */
+} /* }}} int param_parse_keyval */
 
-static int parse_query_string (char *query_string) /* {{{ */
+static int parse_query_string (param_list_t *pl, /* {{{ */
+    char *query_string)
 {
   char *dummy;
   char *keyval;
 
-  if (query_string == NULL)
+  if ((pl == NULL) || (query_string == NULL))
     return (EINVAL);
 
   dummy = query_string;
   while ((keyval = strtok (dummy, ";&")) != NULL)
   {
     dummy = NULL;
-    parse_keyval (keyval);
+    param_parse_keyval (pl, keyval);
   }
 
   return (0);
@@ -170,56 +154,244 @@ static int parse_query_string (char *query_string) /* {{{ */
 
 int param_init (void) /* {{{ */
 {
-  const char *query_string;
-  char *copy;
-  int status;
-
-  if (parameters_init)
+  if (pl_global != NULL)
     return (0);
 
-  query_string = getenv ("QUERY_STRING");
+  pl_global = param_create (/* query string = */ NULL);
+  if (pl_global == NULL)
+    return (ENOMEM);
+
+  return (0);
+} /* }}} int param_init */
+
+void param_finish (void) /* {{{ */
+{
+  param_destroy (pl_global);
+  pl_global = NULL;
+} /* }}} void param_finish */
+
+const char *param (const char *key) /* {{{ */
+{
+  param_init ();
+
+  return (param_get (pl_global, key));
+} /* }}} const char *param */
+
+param_list_t *param_create (const char *query_string) /* {{{ */
+{
+  char *tmp;
+  param_list_t *pl;
+
   if (query_string == NULL)
-    return (ENOENT);
+    query_string = getenv ("QUERY_STRING");
 
-  copy = strdup (query_string);
-  if (copy == NULL)
-    return (ENOMEM);
+  if (query_string == NULL)
+    return (NULL);
+
+  tmp = strdup (query_string);
+  if (tmp == NULL)
+    return (NULL);
+  
+  pl = malloc (sizeof (*pl));
+  if (pl == NULL)
+  {
+    free (tmp);
+    return (NULL);
+  }
+  memset (pl, 0, sizeof (*pl));
 
-  status = parse_query_string (copy);
-  free (copy);
+  parse_query_string (pl, tmp);
 
-  parameters_init = 1;
+  free (tmp);
+  return (pl);
+} /* }}} param_list_t *param_create */
 
-  return (status);
-} /* }}} int param_init */
+  param_list_t *param_clone (__attribute__((unused)) param_list_t *pl) /* {{{ */
+{
+  /* FIXME: To be implemented. */
+  assert (23 == 42);
+  return (NULL);
+} /* }}} param_list_t *param_clone */
 
-void param_finish (void) /* {{{ */
+void param_destroy (param_list_t *pl) /* {{{ */
 {
   size_t i;
 
-  if (!parameters_init)
+  if (pl == NULL)
     return;
 
-  for (i = 0; i < parameters_num; i++)
+  for (i = 0; i < pl->parameters_num; i++)
   {
-    free (parameters[i].key);
-    free (parameters[i].value);
+    free (pl->parameters[i].key);
+    free (pl->parameters[i].value);
   }
-  free (parameters);
+  free (pl->parameters);
+  free (pl);
+} /* }}} void param_destroy */
 
-  parameters = NULL;
-  parameters_num = 0;
-  parameters_init = 0;
-} /* }}} void param_finish */
+const char *param_get (param_list_t *pl, const char *name) /* {{{ */
+{
+  size_t i;
 
-const char *param (const char *key) /* {{{ */
+  if ((pl == NULL) || (name == NULL))
+    return (NULL);
+
+  for (i = 0; i < pl->parameters_num; i++)
+  {
+    if ((name == NULL) && (pl->parameters[i].key == NULL))
+      return (pl->parameters[i].value);
+    else if ((name != NULL) && (pl->parameters[i].key != NULL)
+        && (strcmp (name, pl->parameters[i].key) == 0))
+      return (pl->parameters[i].value);
+  }
+
+  return (NULL);
+} /* }}} char *param_get */
+
+static int param_add (param_list_t *pl, /* {{{ */
+    const char *key, const char *value)
 {
-  param_init ();
+  parameter_t *tmp;
 
-  return (parameter_lookup (key));
-} /* }}} const char *param */
+  tmp = realloc (pl->parameters,
+      sizeof (*pl->parameters) * (pl->parameters_num + 1));
+  if (tmp == NULL)
+    return (ENOMEM);
+  pl->parameters = tmp;
+  tmp = pl->parameters + pl->parameters_num;
+
+  memset (tmp, 0, sizeof (*tmp));
+  tmp->key = strdup (key);
+  if (tmp->key == NULL)
+    return (ENOMEM);
+
+  tmp->value = strdup (value);
+  if (tmp->value == NULL)
+  {
+    free (tmp->key);
+    return (ENOMEM);
+  }
+
+  pl->parameters_num++;
+
+  return (0);
+} /* }}} int param_add */
+
+static int param_delete (param_list_t *pl, /* {{{ */
+    const char *name)
+{
+  size_t i;
+
+  if ((pl == NULL) || (name == NULL))
+    return (EINVAL);
+
+  for (i = 0; i < pl->parameters_num; i++)
+    if (strcasecmp (pl->parameters[i].key, name) == 0)
+      break;
+
+  if (i >= pl->parameters_num)
+    return (ENOENT);
+
+  if (i < (pl->parameters_num - 1))
+  {
+    parameter_t p;
+
+    p = pl->parameters[i];
+    pl->parameters[i] = pl->parameters[pl->parameters_num - 1];
+    pl->parameters[pl->parameters_num - 1] = p;
+  }
+
+  pl->parameters_num--;
+  free (pl->parameters[pl->parameters_num].key);
+  free (pl->parameters[pl->parameters_num].value);
+
+  return (0);
+} /* }}} int param_delete */
+
+int param_set (param_list_t *pl, const char *name, /* {{{ */
+    const char *value)
+{
+  parameter_t *p;
+  char *value_copy;
+  size_t i;
+
+  if ((pl == NULL) || (name == NULL))
+    return (EINVAL);
+
+  if (value == NULL)
+    return (param_delete (pl, name));
+
+  p = NULL;
+  for (i = 0; i < pl->parameters_num; i++)
+  {
+    if (strcasecmp (pl->parameters[i].key, name) == 0)
+    {
+      p = pl->parameters + i;
+      break;
+    }
+  }
+
+  if (p == NULL)
+    return (param_add (pl, name, value));
+
+  value_copy = strdup (value);
+  if (value_copy == NULL)
+    return (ENOMEM);
+
+  free (p->value);
+  p->value = value_copy;
+
+  return (0);
+} /* }}} int param_set */
+
+const char *param_as_string (param_list_t *pl) /* {{{ */
+{
+  char buffer[4096];
+  char key[2048];
+  char value[2048];
+  size_t i;
+
+  if (pl == NULL)
+    return (NULL);
+
+  buffer[0] = 0;
+  for (i = 0; i < pl->parameters_num; i++)
+  {
+    uri_escape_copy (key, pl->parameters[i].key, sizeof (key));
+    uri_escape_copy (value, pl->parameters[i].value, sizeof (value));
+
+    if (i != 0)
+      strlcat (buffer, ";", sizeof (buffer));
+    strlcat (buffer, key, sizeof (buffer));
+    strlcat (buffer, "=", sizeof (buffer));
+    strlcat (buffer, value, sizeof (buffer));
+  }
+
+  return (strdup (buffer));
+} /* }}} char *param_as_string */
 
-int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
+int param_print_hidden (param_list_t *pl) /* {{{ */
+{
+  char key[2048];
+  char value[2048];
+  size_t i;
+
+  if (pl == NULL)
+    return (EINVAL);
+
+  for (i = 0; i < pl->parameters_num; i++)
+  {
+    html_escape_copy (key, pl->parameters[i].key, sizeof (key));
+    html_escape_copy (value, pl->parameters[i].value, sizeof (value));
+
+    printf ("  <input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
+        key, value);
+  }
+
+  return (0);
+} /* }}} int param_print_hidden */
+
+char *uri_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
 {
   size_t in;
   size_t out;
@@ -230,37 +402,51 @@ int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
   {
     if (src[in] == 0)
     {
-      dst[out] = 0;
-      return (0);
+      dest[out] = 0;
+      return (dest);
     }
-    else if ((src[in] < 32)
+    else if ((((unsigned char) src[in]) < 32)
         || (src[in] == '&')
         || (src[in] == ';')
+        || (src[in] == '?')
+        || (src[in] == '/')
         || (((unsigned char) src[in]) >= 128))
     {
       char esc[4];
 
-      if ((size - out) < 4)
+      if ((n - out) < 4)
         break;
       
       snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
-      dst[out] = esc[0];
-      dst[out+1] = esc[1];
-      dst[out+2] = esc[2];
+      dest[out] = esc[0];
+      dest[out+1] = esc[1];
+      dest[out+2] = esc[2];
 
       out += 3;
       in++;
     }
     else
     {
-      dst[out] = src[in];
+      dest[out] = src[in];
       out++;
       in++;
     }
   } /* while (42) */
 
-  return (0);
-} /* }}} int uri_escape */
+  return (dest);
+} /* }}} char *uri_escape_copy */
+
+char *uri_escape (const char *string) /* {{{ */
+{
+  char buffer[4096];
+
+  if (string == NULL)
+    return (NULL);
+
+  uri_escape_copy (buffer, string, sizeof (buffer));
+
+  return (strdup (buffer));
+} /* }}} char *uri_escape */
 
 const char *script_name (void) /* {{{ */
 {
index e8e847ec430e39f4e0748c42c0c6235ed2aed4e9..973d3f36c5822c230d3f6c0e8c7ab930dca75f25 100644 (file)
@@ -19,6 +19,9 @@ struct page_callbacks_s
 };
 typedef struct page_callbacks_s page_callbacks_t;
 
+struct param_list_s;
+typedef struct param_list_s param_list_t;
+
 #define PAGE_CALLBACKS_INIT \
 { NULL, NULL, NULL, \
   NULL, NULL, NULL, \
@@ -29,7 +32,20 @@ void param_finish (void);
 
 const char *param (const char *key);
 
-int uri_escape (char *dst, const char *src, size_t size);
+/* Create a new parameter list from "query_string". If "query_string" is NULL,
+ * the "QUERY_STRING" will be used. */
+param_list_t *param_create (const char *query_string);
+param_list_t *param_clone (param_list_t *pl);
+void param_destroy (param_list_t *pl);
+const char *param_get (param_list_t *pl, const char *name);
+int param_set (param_list_t *pl,
+    const char *name, const char *value);
+const char *param_as_string (param_list_t *pl);
+int param_print_hidden (param_list_t *pl);
+
+char *uri_escape (const char *string);
+char *uri_escape_buffer (char *buffer, size_t buffer_size);
+char *uri_escape_copy (char *dest, const char *src, size_t n);
 
 const char *script_name (void);