2010-02-18 19:27:22 +00:00
|
|
|
/* Copyright (C) 2007, 2009-2010 Red Hat, Inc.
|
2007-12-17 10:07:56 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2008-01-05 16:06:36 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
2007-12-17 10:07:56 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
2008-11-04 23:22:06 +00:00
|
|
|
#include <libxml/uri.h>
|
|
|
|
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
2007-12-17 10:07:56 +00:00
|
|
|
#include "buf.h"
|
2008-05-22 15:12:25 +00:00
|
|
|
#include "memory.h"
|
2007-12-17 10:07:56 +00:00
|
|
|
#include "qparams.h"
|
|
|
|
|
2009-01-28 16:13:46 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
2008-05-29 15:28:28 +00:00
|
|
|
|
2007-12-17 10:07:56 +00:00
|
|
|
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;
|
|
|
|
|
2008-05-29 15:28:28 +00:00
|
|
|
if (VIR_ALLOC(ps) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-05-22 15:12:25 +00:00
|
|
|
return NULL;
|
2008-05-29 15:28:28 +00:00
|
|
|
}
|
2007-12-17 10:07:56 +00:00
|
|
|
ps->n = 0;
|
|
|
|
ps->alloc = init_alloc;
|
2008-05-22 15:12:25 +00:00
|
|
|
if (VIR_ALLOC_N(ps->p, ps->alloc) < 0) {
|
|
|
|
VIR_FREE (ps);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-12-17 10:07:56 +00:00
|
|
|
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);
|
2010-02-18 19:27:22 +00:00
|
|
|
ps = NULL;
|
|
|
|
break;
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
return ps;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
append_qparams (struct qparam_set *ps, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
const char *pname, *pvalue;
|
2010-02-18 19:27:22 +00:00
|
|
|
int ret = 0;
|
2007-12-17 10:07:56 +00:00
|
|
|
|
|
|
|
va_start (args, ps);
|
|
|
|
while ((pname = va_arg (args, char *)) != NULL) {
|
|
|
|
pvalue = va_arg (args, char *);
|
|
|
|
|
2010-02-18 19:27:22 +00:00
|
|
|
if (append_qparam (ps, pname, pvalue) == -1) {
|
|
|
|
ret = -1;
|
|
|
|
break;
|
|
|
|
}
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
|
|
|
va_end (args);
|
|
|
|
|
2010-02-18 19:27:22 +00:00
|
|
|
return ret;
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
if (ps->n >= ps->alloc) {
|
2008-05-22 15:12:25 +00:00
|
|
|
if (VIR_REALLOC_N(ps->p, ps->alloc * 2) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-12-17 10:07:56 +00:00
|
|
|
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);
|
2008-05-29 15:28:28 +00:00
|
|
|
if (!pname) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-12-17 10:07:56 +00:00
|
|
|
return -1;
|
2008-05-29 15:28:28 +00:00
|
|
|
}
|
2007-12-17 10:07:56 +00:00
|
|
|
|
|
|
|
pvalue = strdup (value);
|
|
|
|
if (!pvalue) {
|
2008-05-22 15:12:25 +00:00
|
|
|
VIR_FREE (pname);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-12-17 10:07:56 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grow_qparam_set (ps) == -1) {
|
2008-05-22 15:12:25 +00:00
|
|
|
VIR_FREE (pname);
|
|
|
|
VIR_FREE (pvalue);
|
2007-12-17 10:07:56 +00:00
|
|
|
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)
|
|
|
|
{
|
2008-04-28 15:14:59 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2007-12-17 10:07:56 +00:00
|
|
|
int i, amp = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < ps->n; ++i) {
|
|
|
|
if (!ps->p[i].ignore) {
|
2008-04-28 15:14:59 +00:00
|
|
|
if (amp) virBufferAddChar (&buf, '&');
|
|
|
|
virBufferStrcat (&buf, ps->p[i].name, "=", NULL);
|
|
|
|
virBufferURIEncodeString (&buf, ps->p[i].value);
|
2007-12-17 10:07:56 +00:00
|
|
|
amp = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (virBufferError(&buf)) {
|
2009-12-09 23:00:50 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-04-28 15:14:59 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
free_qparam_set (struct qparam_set *ps)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ps->n; ++i) {
|
2008-05-22 15:12:25 +00:00
|
|
|
VIR_FREE (ps->p[i].name);
|
|
|
|
VIR_FREE (ps->p[i].value);
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
2008-05-22 15:12:25 +00:00
|
|
|
VIR_FREE (ps->p);
|
|
|
|
VIR_FREE (ps);
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct qparam_set *
|
|
|
|
qparam_query_parse (const char *query)
|
|
|
|
{
|
|
|
|
struct qparam_set *ps;
|
2008-05-22 23:49:36 +00:00
|
|
|
const char *end, *eq;
|
2007-12-17 10:07:56 +00:00
|
|
|
|
|
|
|
ps = new_qparam_set (0, NULL);
|
2008-05-29 15:28:28 +00:00
|
|
|
if (!ps) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-05-29 15:28:28 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-12-17 10:07:56 +00:00
|
|
|
|
|
|
|
if (!query || query[0] == '\0') return ps;
|
|
|
|
|
|
|
|
while (*query) {
|
2008-05-22 23:49:36 +00:00
|
|
|
char *name = NULL, *value = NULL;
|
|
|
|
|
2007-12-17 10:07:56 +00:00
|
|
|
/* Find the next separator, or end of the string. */
|
|
|
|
end = strchr (query, '&');
|
2008-05-22 23:49:36 +00:00
|
|
|
if (!end)
|
|
|
|
end = strchr (query, ';');
|
|
|
|
if (!end)
|
|
|
|
end = query + strlen (query);
|
2007-12-17 10:07:56 +00:00
|
|
|
|
|
|
|
/* 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 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);
|
|
|
|
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);
|
2008-05-22 23:49:36 +00:00
|
|
|
if (!name)
|
|
|
|
goto out_of_memory;
|
2007-12-17 10:07:56 +00:00
|
|
|
value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
|
2008-05-22 23:49:36 +00:00
|
|
|
if (!value) {
|
|
|
|
VIR_FREE(name);
|
|
|
|
goto out_of_memory;
|
|
|
|
}
|
2007-12-17 10:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Append to the parameter set. */
|
2008-05-22 23:49:36 +00:00
|
|
|
if (append_qparam (ps, name, value ? value : "") == -1) {
|
|
|
|
VIR_FREE(name);
|
|
|
|
VIR_FREE(value);
|
|
|
|
goto out_of_memory;
|
|
|
|
}
|
|
|
|
VIR_FREE(name);
|
|
|
|
VIR_FREE(value);
|
2007-12-17 10:07:56 +00:00
|
|
|
|
|
|
|
next:
|
|
|
|
query = end;
|
|
|
|
if (*query) query ++; /* skip '&' separator */
|
|
|
|
}
|
|
|
|
|
|
|
|
return ps;
|
|
|
|
|
|
|
|
out_of_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2007-12-17 10:07:56 +00:00
|
|
|
free_qparam_set (ps);
|
|
|
|
return NULL;
|
|
|
|
}
|