mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 03:25:20 +00:00
Store parsed query parameters directly in the virURIPtr struct
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 Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
300e60e15b
commit
4ae4ae4ba4
@ -1472,6 +1472,7 @@ virTypedParameterAssign;
|
||||
|
||||
# viruri.h
|
||||
virURIFormat;
|
||||
virURIFormatParams;
|
||||
virURIFree;
|
||||
virURIParse;
|
||||
|
||||
|
@ -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 *virURIFormatParams(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
|
||||
@ -161,12 +300,23 @@ cleanup:
|
||||
*/
|
||||
void virURIFree(virURIPtr uri)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!uri)
|
||||
return;
|
||||
|
||||
VIR_FREE(uri->scheme);
|
||||
VIR_FREE(uri->server);
|
||||
VIR_FREE(uri->user);
|
||||
VIR_FREE(uri->path);
|
||||
VIR_FREE(uri->query);
|
||||
VIR_FREE(uri->fragment);
|
||||
|
||||
for (i = 0 ; i < uri->paramsCount ; i++) {
|
||||
VIR_FREE(uri->params[i].name);
|
||||
VIR_FREE(uri->params[i].value);
|
||||
}
|
||||
VIR_FREE(uri->params);
|
||||
|
||||
VIR_FREE(uri);
|
||||
}
|
||||
|
@ -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 virURIFormatParams */
|
||||
};
|
||||
|
||||
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 *virURIFormatParams(virURIPtr uri);
|
||||
|
||||
void virURIFree(virURIPtr uri);
|
||||
|
||||
#endif /* __VIR_URI_H__ */
|
||||
|
@ -41,6 +41,7 @@ struct URIParseData {
|
||||
const char *path;
|
||||
const char *query;
|
||||
const char *fragment;
|
||||
virURIParamPtr params;
|
||||
};
|
||||
|
||||
static int testURIParse(const void *args)
|
||||
@ -49,6 +50,7 @@ static int testURIParse(const void *args)
|
||||
virURIPtr uri = NULL;
|
||||
const struct URIParseData *data = args;
|
||||
char *uristr;
|
||||
size_t i;
|
||||
|
||||
if (!(uri = virURIParse(data->uri)))
|
||||
goto cleanup;
|
||||
@ -98,6 +100,29 @@ static int testURIParse(const void *args)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0 ; data->params && data->params[i].name && i < uri->paramsCount ; i++) {
|
||||
if (!STREQ_NULLABLE(data->params[i].name, uri->params[i].name)) {
|
||||
VIR_DEBUG("Expected param name %zu '%s', actual '%s'",
|
||||
i, data->params[i].name, uri->params[i].name);
|
||||
goto cleanup;
|
||||
}
|
||||
if (!STREQ_NULLABLE(data->params[i].value, uri->params[i].value)) {
|
||||
VIR_DEBUG("Expected param value %zu '%s', actual '%s'",
|
||||
i, data->params[i].value, uri->params[i].value);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
if (data->params && data->params[i].name) {
|
||||
VIR_DEBUG("Missing parameter %zu %s=%s",
|
||||
i, data->params[i].name, data->params[i].value);
|
||||
goto cleanup;
|
||||
}
|
||||
if (i != uri->paramsCount) {
|
||||
VIR_DEBUG("Unexpected parameter %zu %s=%s",
|
||||
i, uri->params[i].name, uri->params[i].value);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(uristr);
|
||||
@ -113,21 +138,26 @@ mymain(void)
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
#define TEST_PARSE(uri, scheme, server, port, path, query, fragment) \
|
||||
#define TEST_PARSE(uri, scheme, server, port, path, query, fragment, params) \
|
||||
do { \
|
||||
const struct URIParseData data = { \
|
||||
uri, scheme, server, port, path, query, fragment \
|
||||
uri, scheme, server, port, path, query, fragment, params \
|
||||
}; \
|
||||
if (virtTestRun("Test IPv6 " # uri, 1, testURIParse, &data) < 0) \
|
||||
ret = -1; \
|
||||
} while (0)
|
||||
|
||||
TEST_PARSE("test://example.com", "test", "example.com", 0, NULL, NULL, NULL);
|
||||
TEST_PARSE("test://example.com:123", "test", "example.com", 123, NULL, NULL, NULL);
|
||||
TEST_PARSE("test://example.com:123/system?name=value#foo", "test", "example.com", 123, "/system", "name=value", "foo");
|
||||
TEST_PARSE("test://127.0.0.1:123/system", "test", "127.0.0.1", 123, "/system", NULL, NULL);
|
||||
TEST_PARSE("test://[::1]:123/system", "test", "::1", 123, "/system", NULL, NULL);
|
||||
TEST_PARSE("test://[2001:41c8:1:4fd4::2]:123/system", "test", "2001:41c8:1:4fd4::2", 123, "/system", NULL, NULL);
|
||||
virURIParam params[] = {
|
||||
{ (char*)"name", (char*)"value" },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
TEST_PARSE("test://example.com", "test", "example.com", 0, NULL, NULL, NULL, NULL);
|
||||
TEST_PARSE("test://example.com:123", "test", "example.com", 123, NULL, NULL, NULL, NULL);
|
||||
TEST_PARSE("test://example.com:123/system?name=value#foo", "test", "example.com", 123, "/system", "name=value", "foo", params);
|
||||
TEST_PARSE("test://127.0.0.1:123/system", "test", "127.0.0.1", 123, "/system", NULL, NULL, NULL);
|
||||
TEST_PARSE("test://[::1]:123/system", "test", "::1", 123, "/system", NULL, NULL, NULL);
|
||||
TEST_PARSE("test://[2001:41c8:1:4fd4::2]:123/system", "test", "2001:41c8:1:4fd4::2", 123, "/system", NULL, NULL, NULL);
|
||||
|
||||
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user