On 2012年03月21日 01:33, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange(a)redhat.com>
Avoid the need for each driver to parse query parameters itself
by storing them directly in the virURIPtr struct. The parsing
code is a copy of that from src/util/qparams.c The latter will
be removed in a later patch
* src/util/viruri.h: Add query params to virURIPtr
* src/util/viruri.c: Parse query parameters when creating virURIPtr
* tests/viruritest.c: Expand test to cover params
---
src/libvirt_private.syms | 1 +
src/util/viruri.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/viruri.h | 15 +++++
tests/viruritest.c | 46 +++++++++++++---
4 files changed, 193 insertions(+), 8 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7cd6a96..49fb2ee 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1471,6 +1471,7 @@ virTypedParameterAssign;
# viruri.h
virURIFree;
virURIFormat;
+virURIFormatQuery;
virURIParse;
diff --git a/src/util/viruri.c b/src/util/viruri.c
index d8618d1..f5adca5 100644
--- a/src/util/viruri.c
+++ b/src/util/viruri.c
@@ -13,6 +13,7 @@
#include "memory.h"
#include "util.h"
#include "virterror_internal.h"
+#include "buf.h"
#define VIR_FROM_THIS VIR_FROM_URI
@@ -21,6 +22,117 @@
__FUNCTION__, __LINE__, __VA_ARGS__)
+static int
+virURIParamAppend(virURIPtr uri,
+ const char *name,
+ const char *value)
+{
+ char *pname = NULL;
+ char *pvalue = NULL;
+
+ if (!(pname = strdup(name)))
+ goto no_memory;
+ if (!(pvalue = strdup (value)))
+ goto no_memory;
+
+ if (VIR_RESIZE_N(uri->params, uri->paramsAlloc, uri->paramsCount, 1)<
0)
+ goto no_memory;
+
+ uri->params[uri->paramsCount].name = pname;
+ uri->params[uri->paramsCount].value = pvalue;
+ uri->params[uri->paramsCount].ignore = 0;
+ uri->paramsCount++;
+
+ return 0;
+
+no_memory:
+ VIR_FREE(pname);
+ VIR_FREE(pvalue);
+ virReportOOMError();
+ return -1;
+}
+
+
+static int
+virURIParseParams(virURIPtr uri)
+{
+ const char *end, *eq;
+ const char *query = uri->query;
+
+ if (!query || query[0] == '\0')
+ return 0;
+
+ while (*query) {
+ char *name = NULL, *value = NULL;
+
+ /* Find the next separator, or end of the string. */
+ end = strchr (query, '&');
+ if (!end)
+ 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);
+ if (!name) goto no_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);
+ if (!name) goto no_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);
+ if (!name)
+ goto no_memory;
+ value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
+ if (!value) {
+ VIR_FREE(name);
+ goto no_memory;
+ }
+ }
+
+ /* Append to the parameter set. */
+ if (virURIParamAppend(uri, name, value ? value : "")< 0) {
+ VIR_FREE(name);
+ VIR_FREE(value);
+ goto no_memory;
+ }
+ VIR_FREE(name);
+ VIR_FREE(value);
+
+ next:
+ query = end;
+ if (*query) query ++; /* skip '&' separator */
+ }
+
+ return 0;
+
+ no_memory:
+ virReportOOMError();
+ return -1;
+}
+
/**
* virURIParse:
* @uri: URI to parse
@@ -92,12 +204,16 @@ virURIParse(const char *uri)
* the uri with xmlFreeURI() */
}
+ if (virURIParseParams(ret)< 0)
+ goto error;
+
xmlFreeURI(xmluri);
return ret;
no_memory:
virReportOOMError();
+error:
xmlFreeURI(xmluri);
virURIFree(ret);
return NULL;
@@ -153,6 +269,29 @@ cleanup:
}
+char *virURIFormatQuery(virURIPtr uri)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int i, amp = 0;
+
+ for (i = 0; i< uri->paramsCount; ++i) {
+ if (!uri->params[i].ignore) {
+ if (amp) virBufferAddChar (&buf, '&');
+ virBufferStrcat (&buf, uri->params[i].name, "=", NULL);
+ virBufferURIEncodeString (&buf, uri->params[i].value);
+ amp = 1;
+ }
+ }
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
/**
* virURIFree:
* @uri: uri to free
diff --git a/src/util/viruri.h b/src/util/viruri.h
index dd270de..6fe0b2e 100644
--- a/src/util/viruri.h
+++ b/src/util/viruri.h
@@ -16,6 +16,15 @@
typedef struct _virURI virURI;
typedef virURI *virURIPtr;
+typedef struct _virURIParam virURIParam;
+typedef virURIParam *virURIParamPtr;
+
+struct _virURIParam {
+ char *name; /* Name (unescaped). */
+ char *value; /* Value (unescaped). */
+ bool ignore; /* Ignore this field in qparam_get_query */
+};
+
struct _virURI {
char *scheme; /* the URI scheme */
char *server; /* the server part */
@@ -24,6 +33,10 @@ struct _virURI {
char *path; /* the path string */
char *query; /* the query string */
char *fragment; /* the fragment string */
+
+ size_t paramsCount;
+ size_t paramsAlloc;
+ virURIParamPtr params;
};
virURIPtr virURIParse(const char *uri)
@@ -31,6 +44,8 @@ virURIPtr virURIParse(const char *uri)
char *virURIFormat(virURIPtr uri)
ATTRIBUTE_NONNULL(1);
+char *virURIFormatQuery(virURIPtr uri);
+
void virURIFree(virURIPtr uri);
Oh, the params array is not free()'ed in virURIFree()