#include "memory.h"
#include "util.h"
#include "virterror_internal.h"
+#include "buf.h"
#define VIR_FROM_THIS VIR_FROM_URI
__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
* the uri with xmlFreeURI() */
}
+ if (virURIParseParams(ret) < 0)
+ goto error;
+
xmlFreeURI(xmluri);
return ret;
no_memory:
virReportOOMError();
+error:
xmlFreeURI(xmluri);
virURIFree(ret);
return NULL;
}
+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
*/
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);
}
const char *path;
const char *query;
const char *fragment;
+ virURIParamPtr params;
};
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;
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);
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);
}