]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add separate qparams module for handling query parameters.
authorRichard W.M. Jones <rjones@redhat.com>
Mon, 17 Dec 2007 10:07:56 +0000 (10:07 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Mon, 17 Dec 2007 10:07:56 +0000 (10:07 +0000)
* src/qparams.c, src/qparams.h, src/Makefile.am: Added a
  separate 'qparams' module for handling query parameters.
* src/remote_internal.c: Factor out query parameter code so
  it uses the 'qparams' module.

ChangeLog
src/Makefile.am
src/qparams.c [new file with mode: 0644]
src/qparams.h [new file with mode: 0644]
src/remote_internal.c

index 83612fdca837b6656643f9ffabbdb86893f81f3f..748fb68a28d28e0ba7c3aa096f48e5b58a5730c4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Dec 17 10:05:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
+
+       Add separate qparams module for handling query parameters.
+       * src/qparams.c, src/qparams.h, src/Makefile.am: Added a
+         separate 'qparams' module for handling query parameters.
+       * src/remote_internal.c: Factor out query parameter code so
+         it uses the 'qparams' module.
+
 Mon Dec 17 10:01:00 UTC 2007 Richard W.M. Jones <rjones@redhat.com>
 
        Add extra utility functions to buf.c
index 1979a194315e1f4f5ad1a186708e0c420991b0b1..82194485aba66e092afb874fb320f4ab68d141ac 100644 (file)
@@ -34,6 +34,7 @@ CLIENT_SOURCES =                                              \
                hash.c hash.h                                   \
                test.c test.h                                   \
                 buf.c buf.h                                    \
+               qparams.c qparams.h                             \
                xml.c xml.h                                     \
                event.c event.h                                 \
                xen_unified.c xen_unified.h                     \
diff --git a/src/qparams.c b/src/qparams.c
new file mode 100644 (file)
index 0000000..526c50e
--- /dev/null
@@ -0,0 +1,245 @@
+/* Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Authors:
+ *    Richard W.M. Jones <rjones@redhat.com>
+ *
+ * Utility functions to help parse and assemble query strings.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "buf.h"
+
+#include "qparams.h"
+
+struct qparam_set *
+new_qparam_set (int init_alloc, ...)
+{
+    va_list args;
+    struct qparam_set *ps;
+    const char *pname, *pvalue;
+
+    if (init_alloc <= 0) init_alloc = 1;
+
+    ps = malloc (sizeof (*ps));
+    if (!ps) return NULL;
+    ps->n = 0;
+    ps->alloc = init_alloc;
+    ps->p = malloc (init_alloc * sizeof (ps->p[0]));
+    if (!ps->p) {
+        free (ps);
+        return NULL;
+    }
+
+    va_start (args, init_alloc);
+    while ((pname = va_arg (args, char *)) != NULL) {
+        pvalue = va_arg (args, char *);
+
+        if (append_qparam (ps, pname, pvalue) == -1) {
+            free_qparam_set (ps);
+            return NULL;
+        }
+    }
+    va_end (args);
+
+    return ps;
+}
+
+int
+append_qparams (struct qparam_set *ps, ...)
+{
+    va_list args;
+    const char *pname, *pvalue;
+
+    va_start (args, ps);
+    while ((pname = va_arg (args, char *)) != NULL) {
+        pvalue = va_arg (args, char *);
+
+        if (append_qparam (ps, pname, pvalue) == -1)
+            return -1;
+    }
+    va_end (args);
+
+    return 0;
+}
+
+/* Ensure there is space to store at least one more parameter
+ * at the end of the set.
+ */
+static int
+grow_qparam_set (struct qparam_set *ps)
+{
+    struct qparam *old_p;
+
+    if (ps->n >= ps->alloc) {
+        old_p = ps->p;
+        ps->p = realloc (ps->p, 2 * ps->alloc * sizeof (ps->p[0]));
+        if (!ps->p) {
+            ps->p = old_p;
+            perror ("realloc");
+            return -1;
+        }
+        ps->alloc *= 2;
+    }
+
+    return 0;
+}
+
+int
+append_qparam (struct qparam_set *ps,
+               const char *name, const char *value)
+{
+    char *pname, *pvalue;
+
+    pname = strdup (name);
+    if (!pname)
+        return -1;
+
+    pvalue = strdup (value);
+    if (!pvalue) {
+        free (pname);
+        return -1;
+    }
+
+    if (grow_qparam_set (ps) == -1) {
+        free (pname);
+        free (pvalue);
+        return -1;
+    }
+
+    ps->p[ps->n].name = pname;
+    ps->p[ps->n].value = pvalue;
+    ps->p[ps->n].ignore = 0;
+    ps->n++;
+
+    return 0;
+}
+
+char *
+qparam_get_query (const struct qparam_set *ps)
+{
+    virBufferPtr buf;
+    int i, amp = 0;
+
+    buf = virBufferNew (100);
+    for (i = 0; i < ps->n; ++i) {
+        if (!ps->p[i].ignore) {
+            if (amp) virBufferAddChar (buf, '&');
+            virBufferStrcat (buf, ps->p[i].name, "=", NULL);
+            virBufferURIEncodeString (buf, ps->p[i].value);
+            amp = 1;
+        }
+    }
+
+    return virBufferContentAndFree (buf);
+}
+
+void
+free_qparam_set (struct qparam_set *ps)
+{
+    int i;
+
+    for (i = 0; i < ps->n; ++i) {
+        free (ps->p[i].name);
+        free (ps->p[i].value);
+    }
+    free (ps);
+}
+
+struct qparam_set *
+qparam_query_parse (const char *query)
+{
+    struct qparam_set *ps;
+    const char *name, *value, *end, *eq;
+
+    ps = new_qparam_set (0, NULL);
+    if (!ps) return NULL;
+
+    if (!query || query[0] == '\0') return ps;
+
+    while (*query) {
+        /* Find the next separator, or end of the string. */
+        end = strchr (query, '&');
+        if (!end) end = query + strlen (query);
+
+        /* Find the first '=' character between here and end. */
+        eq = strchr (query, '=');
+        if (eq && eq >= end) eq = NULL;
+
+        /* Empty section (eg. "&&"). */
+        if (end == query)
+            goto next;
+
+        /* If there is no '=' character, then we have just "name"
+         * and consistent with CGI.pm we assume value is "".
+         */
+        else if (!eq) {
+            name = xmlURIUnescapeString (query, end - query, NULL);
+            value = "";
+            if (!name) goto out_of_memory;
+        }
+        /* Or if we have "name=" here (works around annoying
+         * problem when calling xmlURIUnescapeString with len = 0).
+         */
+        else if (eq+1 == end) {
+            name = xmlURIUnescapeString (query, eq - query, NULL);
+            value = "";
+            if (!name) goto out_of_memory;
+        }
+        /* If the '=' character is at the beginning then we have
+         * "=value" and consistent with CGI.pm we _ignore_ this.
+         */
+        else if (query == eq)
+            goto next;
+
+        /* Otherwise it's "name=value". */
+        else {
+            name = xmlURIUnescapeString (query, eq - query, NULL);
+            value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
+            if (!name || !value) goto out_of_memory;
+        }
+
+        /* Append to the parameter set. */
+        if (append_qparam (ps, name, value) == -1) goto out_of_memory;
+
+    next:
+        query = end;
+        if (*query) query ++; /* skip '&' separator */
+    }
+
+    return ps;
+
+ out_of_memory:
+    free_qparam_set (ps);
+    return NULL;
+}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff --git a/src/qparams.h b/src/qparams.h
new file mode 100644 (file)
index 0000000..09b460a
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Authors:
+ *    Richard W.M. Jones <rjones@redhat.com>
+ *
+ * Utility functions to help parse and assemble query strings.
+ */
+
+#ifndef _QPARAMS_H_
+#define _QPARAMS_H_
+
+/* Single web service query parameter 'name=value'. */
+struct qparam {
+  char *name;                  /* Name (unescaped). */
+  char *value;                 /* Value (unescaped). */
+  int ignore;                  /* Ignore this field in qparam_get_query */
+};
+
+/* Set of parameters. */
+struct qparam_set {
+  int n;                       /* number of parameters used */
+  int alloc;                   /* allocated space */
+  struct qparam *p;            /* array of parameters */
+};
+
+/* New parameter set. */
+extern struct qparam_set *new_qparam_set (int init_alloc, ...);
+
+/* Appending parameters. */
+extern int append_qparams (struct qparam_set *ps, ...);
+extern int append_qparam (struct qparam_set *ps,
+                         const char *name, const char *value);
+
+/* Get a query string ("name=value&name=value&...") */
+extern char *qparam_get_query (const struct qparam_set *ps);
+
+/* Parse a query string into a parameter set. */
+extern struct qparam_set *qparam_query_parse (const char *query);
+
+extern void free_qparam_set (struct qparam_set *ps);
+
+#endif /* _QPARAMS_H_ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
index e0e735338a1b57c51cd9c040290b345ed7c5904d..4f5ca1ed456598fcc651ca4a2df8a41111b522b3 100644 (file)
 
 #include "internal.h"
 #include "driver.h"
+#include "buf.h"
+#include "qparams.h"
 #include "remote_internal.h"
 #include "remote_protocol.h"
 
-#define DEBUG 0                 /* Enable verbose messages on stderr. */
-
 /* Per-connection private data. */
 #define MAGIC 999               /* private_data->magic if OK */
 #define DEAD 998                /* private_data->magic if dead/closed */
@@ -152,22 +152,6 @@ static void make_nonnull_network (remote_nonnull_network *net_dst, virNetworkPtr
 /* Helper functions for remoteOpen. */
 static char *get_transport_from_scheme (char *scheme);
 
-/* Parse query string. */
-struct query_fields {
-    struct query_fields *next; /* Linked list chain. */
-    char *name;                        /* Field name (unescaped). */
-    char *value;               /* Field value (unescaped). */
-    int ignore;                        /* Ignore field in query_create. */
-};
-
-static int query_parse (const char *query,
-                        const char *separator,
-                        struct query_fields * *fields_out);
-static int query_create (const struct query_fields *fields,
-                         const char *separator,
-                         char **query_out);
-static void query_free (struct query_fields *fields);
-
 /* GnuTLS functions used by remoteOpen. */
 static int initialise_gnutls (virConnectPtr conn);
 static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, struct private_data *priv, int no_verify);
@@ -403,55 +387,59 @@ doRemoteOpen (virConnectPtr conn,
      * feasibly it might contain variables needed by the real driver,
      * although that won't be the case for now).
      */
-    struct query_fields *vars, *var;
+    struct qparam_set *vars;
+    struct qparam *var;
+    int i;
     char *query;
 #ifdef HAVE_XMLURI_QUERY_RAW
     query = uri->query_raw;
 #else
     query = uri->query;
 #endif
-    if (query_parse (query, NULL, &vars) != 0) goto failed;
+    vars = qparam_query_parse (query);
+    if (vars == NULL) goto failed;
 
-    for (var = vars; var; var = var->next) {
-        if (strcasecmp (var->name, "name") == 0) {
+    for (i = 0; i < vars->n; i++) {
+        var = &vars->p[i];
+        if (STRCASEEQ (var->name, "name")) {
             name = strdup (var->value);
             if (!name) goto out_of_memory;
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "command") == 0) {
+        } else if (STRCASEEQ (var->name, "command")) {
             command = strdup (var->value);
             if (!command) goto out_of_memory;
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "socket") == 0) {
+        } else if (STRCASEEQ (var->name, "socket")) {
             sockname = strdup (var->value);
             if (!sockname) goto out_of_memory;
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "auth") == 0) {
+        } else if (STRCASEEQ (var->name, "auth")) {
             authtype = strdup (var->value);
             if (!authtype) goto out_of_memory;
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "netcat") == 0) {
+        } else if (STRCASEEQ (var->name, "netcat")) {
             netcat = strdup (var->value);
             if (!netcat) goto out_of_memory;
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "no_verify") == 0) {
+        } else if (STRCASEEQ (var->name, "no_verify")) {
             no_verify = atoi (var->value);
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "no_tty") == 0) {
+        } else if (STRCASEEQ (var->name, "no_tty")) {
             no_tty = atoi (var->value);
             var->ignore = 1;
-        } else if (strcasecmp (var->name, "debug") == 0) {
+        } else if (STRCASEEQ (var->name, "debug")) {
             if (var->value &&
-                strcasecmp(var->value, "stdout") == 0)
+                STRCASEEQ (var->value, "stdout"))
                 priv->debugLog = stdout;
             else
                 priv->debugLog = stderr;
         }
-#if DEBUG
+#ifdef ENABLE_DEBUG
         else
             fprintf (stderr,
                      "remoteOpen: "
-                     "passing through variable '%s' to remote end\n",
-                     var->name);
+                     "passing through variable '%s' ('%s') to remote end\n",
+                     var->name, var->value);
 #endif
     }
 
@@ -461,14 +449,15 @@ doRemoteOpen (virConnectPtr conn,
     if (uri->query) xmlFree (uri->query);
 #endif
 
-    if (query_create (vars, NULL,
+    if ((
 #ifdef HAVE_XMLURI_QUERY_RAW
-                      &uri->query_raw
+         uri->query_raw =
 #else
-                      &uri->query
+         uri->query =
 #endif
-                      ) != 0) goto failed;
-    query_free (vars);
+         qparam_get_query (vars)) != 0) goto failed;
+
+    free_qparam_set (vars);
 
     /* For ext transport, command is required. */
     if (transport == trans_ext && !command) {
@@ -496,7 +485,7 @@ doRemoteOpen (virConnectPtr conn,
     }
 
     assert (name);
-#if DEBUG
+#ifdef ENABLE_DEBUG
     fprintf (stderr, "remoteOpen: proceeding with name = %s\n", name);
 #endif
 
@@ -882,179 +871,6 @@ get_transport_from_scheme (char *scheme)
     return p ? p+1 : 0;
 }
 
-static int
-query_create (const struct query_fields *fields,
-              const char *separator,
-              char **query_out)
-{
-    /* List of characters which are safe inside names or values,
-     * apart from '@', IS_MARK and IS_ALPHANUM.  Best to escape
-     * as much as possible.  Certainly '=', '&' and '#' must NEVER
-     * be added to this list.
-     */
-    static const xmlChar *special_chars = BAD_CAST "";
-
-    int append_sep = 0, sep_len;
-    xmlBufferPtr buf;
-    xmlChar *str;
-    int rv;
-
-    if (query_out) *query_out = NULL;
-    if (!fields) return 0;
-
-    if (separator == NULL) {
-       separator = "&";
-       sep_len = 1;
-    } else
-       sep_len = xmlStrlen (BAD_CAST separator);
-
-    buf = xmlBufferCreate ();
-    if (!buf) return -1;
-
-    rv = 0;
-    while (fields) {
-       if (!fields->ignore) {
-           if (append_sep) {
-               rv = xmlBufferAdd (buf, BAD_CAST separator, sep_len);
-               if (rv != 0) goto error;
-           }
-           append_sep = 1;
-
-           str = xmlURIEscapeStr (BAD_CAST fields->name, special_chars);
-           if (!str) { rv = XML_ERR_NO_MEMORY; goto error; }
-           rv = xmlBufferAdd (buf, str, xmlStrlen (str));
-           xmlFree (str);
-           if (rv != 0) goto error;
-
-           rv = xmlBufferAdd (buf, BAD_CAST "=", 1);
-           if (rv != 0) goto error;
-           str = xmlURIEscapeStr (BAD_CAST fields->value, special_chars);
-           if (!str) { rv = XML_ERR_NO_MEMORY; goto error; }
-           rv = xmlBufferAdd (buf, str, xmlStrlen (str));
-           xmlFree (str);
-           if (rv != 0) goto error;
-       }
-
-       fields = fields->next;
-    }
-
-    if (query_out && buf->content) {
-       *query_out = (char *) xmlStrdup (buf->content);
-       if (!*query_out) {
-           rv = XML_ERR_NO_MEMORY;
-           goto error;
-       }
-    }
-
- error:
-    if (buf)
-       xmlBufferFree (buf);
-    return rv;
-}
-
-static int
-query_parse (const char *query_,
-             const char *separator,
-             struct query_fields * *fields_out)
-{
-    struct query_fields *fields, *field, **prev;
-    int sep_len;
-    const xmlChar *query = BAD_CAST query_, *end, *eq;
-    char *name, *value;
-
-    if (fields_out) *fields_out = NULL;
-    if (!query || query[0] == '\0') return 0;
-
-    if (separator == NULL) {
-       separator = "&";
-       sep_len = 1;
-    } else
-       sep_len = xmlStrlen (BAD_CAST separator);
-
-    fields = NULL;
-    prev = &fields;
-
-    while (*query) {
-       /* Find the next separator, or end of the string. */
-       end = xmlStrstr (query, BAD_CAST separator);
-       if (!end) end = query + xmlStrlen (query);
-
-       /* Find the first '=' character between here and end. */
-       eq = xmlStrchr (query, '=');
-       if (eq && eq >= end) eq = NULL;
-
-       /* Empty section (eg. "?&"). */
-       if (end == query)
-           goto next;
-       /* If there is no '=' character, then we have just "name"
-        * and consistent with CGI.pm we assume value is "".
-        */
-       else if (!eq) {
-           name = xmlURIUnescapeString ((const char *) query,
-                                        end - query, NULL);
-           value = (char *) xmlStrdup (BAD_CAST "");
-           if (!name || !value) goto out_of_memory;
-       }
-       /* Or if we have "name=" here (works around annoying
-        * problem when calling xmlURIUnescapeString with len = 0).
-        */
-       else if (eq+1 == end) {
-           name = xmlURIUnescapeString ((const char *) query,
-                                        eq - query, NULL);
-           value = (char *) xmlStrdup (BAD_CAST "");
-           if (!name || !value) goto out_of_memory;
-       }
-       /* If the '=' character is at the beginning then we have
-        * "=value" and consistent with CGI.pm we _ignore_ this.
-        */
-       else if (query == eq)
-           goto next;
-       /* Otherwise it's "name=value". */
-       else {
-           name = xmlURIUnescapeString ((const char *) query,
-                                        eq - query, NULL);
-           value = xmlURIUnescapeString ((const char *) eq+1,
-                                         end - (eq+1), NULL);
-           if (!name || !value) goto out_of_memory;
-       }
-
-       /* Allocate this field and append to the list. */
-       field = xmlMalloc (sizeof *field);
-       if (!field) goto out_of_memory;
-       field->next = NULL;
-       field->name = name;
-       field->value = value;
-       field->ignore = 0;
-       *prev = field;
-       prev = &field->next;
-
-    next:
-       query = end;
-       if (*query) query += sep_len; /* skip separator */
-    }
-
-    if (fields_out) *fields_out = fields;
-    return 0;
-
- out_of_memory:
-    query_free (fields);
-    return XML_ERR_NO_MEMORY;
-}
-
-static void
-query_free (struct query_fields *fields)
-{
-    struct query_fields *t;
-
-    while (fields) {
-        if (fields->name) xmlFree (fields->name);
-        if (fields->value) xmlFree (fields->value);
-        t = fields;
-        fields = fields->next;
-        xmlFree (t);
-    }
-}
-
 /* GnuTLS functions used by remoteOpen. */
 static gnutls_certificate_credentials_t x509_cred;
 
@@ -1100,7 +916,7 @@ initialise_gnutls (virConnectPtr conn)
         return -1;
 
     /* Set the trusted CA cert. */
-#if DEBUG
+#ifdef ENABLE_DEBUG
     fprintf (stderr, "loading CA file %s\n", LIBVIRT_CACERT);
 #endif
     err =
@@ -1112,7 +928,7 @@ initialise_gnutls (virConnectPtr conn)
     }
 
     /* Set the client certificate and private key. */
-#if DEBUG
+#ifdef ENABLE_DEBUG
     fprintf (stderr, "loading client cert and key from files %s and %s\n",
              LIBVIRT_CLIENTCERT, LIBVIRT_CLIENTKEY);
 #endif