From: Peter Krempa Date: Tue, 9 May 2017 12:52:40 +0000 (+0200) Subject: conf: Add support for cookies for HTTP based disks X-Git-Tag: v6.2.0-rc1~192 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b076391befc3fe72deb0c244ac6c2b4c100b410;p=thirdparty%2Flibvirt.git conf: Add support for cookies for HTTP based disks Add possibility to specify one or more cookies for http based disks. This patch adds the config parser, storage and validation of the cookies. Signed-off-by: Peter Krempa Reviewed-by: Ján Tomko --- diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index bc34aef605..9430ccdee1 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2849,6 +2849,9 @@ <driver name='qemu' type='raw'/> <source protocol="http" name="url_path"> <host name="hostname" port="80"/> + <cookies> + <cookie name="test">somevalue</cookie> + </cookies> </source> <target dev='hde' bus='ide' tray='open'/> <readonly/> @@ -3392,6 +3395,13 @@ certificate validation. Supported values are yes and no. Since 6.2.0 +
cookies
+
+ For http and https accessed storage it's + possible to pass one or more cookies. The cookie name and value + must conform to the HTTP specification. + Since 6.2.0 +

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d179a25ee6..85d6484dbd 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1817,6 +1817,24 @@ + + + + + + + [!#$%&'*+\-.0-9A-Z\^_`a-z|~]+ + + + + [!#$%&'()*+\-./0-9:>=<?@A-Z\^_`\[\]a-z|~]+ + + + + + + + @@ -1833,6 +1851,9 @@ + + + @@ -1849,6 +1870,9 @@ + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 50646fc440..f3de76efe4 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9340,6 +9340,62 @@ virDomainDiskSourcePoolDefParse(xmlNodePtr node, } +static virStorageNetCookieDefPtr +virDomainStorageNetCookieParse(xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + g_autoptr(virStorageNetCookieDef) cookie = NULL; + + ctxt->node = node; + + cookie = g_new0(virStorageNetCookieDef, 1); + + if (!(cookie->name = virXPathString("string(./@name)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", _("missing cookie name")); + return NULL; + } + + if (!(cookie->value = virXPathString("string(.)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, _("missing value for cookie '%s'"), + cookie->name); + return NULL; + } + + return g_steal_pointer(&cookie); +} + + +static int +virDomainStorageNetCookiesParse(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virStorageSourcePtr src) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + g_autofree xmlNodePtr *nodes = NULL; + ssize_t nnodes; + size_t i; + + ctxt->node = node; + + if ((nnodes = virXPathNodeSet("./cookie", ctxt, &nodes)) < 0) + return -1; + + src->cookies = g_new0(virStorageNetCookieDefPtr, nnodes); + src->ncookies = nnodes; + + for (i = 0; i < nnodes; i++) { + if (!(src->cookies[i] = virDomainStorageNetCookieParse(nodes[i], ctxt))) + return -1; + } + + if (virStorageSourceNetCookiesValidate(src) < 0) + return -1; + + return 0; +} + + static int virDomainDiskSourceNetworkParse(xmlNodePtr node, xmlXPathContextPtr ctxt, @@ -9351,6 +9407,7 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node, g_autofree char *haveTLS = NULL; g_autofree char *tlsCfg = NULL; g_autofree char *sslverifystr = NULL; + xmlNodePtr tmpnode; if (!(protocol = virXMLPropString(node, "protocol"))) { virReportError(VIR_ERR_XML_ERROR, "%s", @@ -9436,6 +9493,13 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node, src->sslverify = verify; } + if ((src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTP || + src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS) && + (tmpnode = virXPathNode("./cookies", ctxt))) { + if (virDomainStorageNetCookiesParse(tmpnode, ctxt, src) < 0) + return -1; + } + return 0; } @@ -24500,6 +24564,22 @@ virDomainSourceDefFormatSeclabel(virBufferPtr buf, } +static void +virDomainDiskSourceFormatNetworkCookies(virBufferPtr buf, + virStorageSourcePtr src) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + size_t i; + + for (i = 0; i < src->ncookies; i++) { + virBufferEscapeString(&childBuf, "", src->cookies[i]->name); + virBufferEscapeString(&childBuf, "%s\n", src->cookies[i]->value); + } + + virXMLFormatElement(buf, "cookies", NULL, &childBuf); +} + + static int virDomainDiskSourceFormatNetwork(virBufferPtr attrBuf, virBufferPtr childBuf, @@ -24550,6 +24630,8 @@ virDomainDiskSourceFormatNetwork(virBufferPtr attrBuf, virTristateBoolTypeToString(src->sslverify)); } + virDomainDiskSourceFormatNetworkCookies(childBuf, src); + return 0; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c140164cdd..6b305bdd0e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3147,6 +3147,7 @@ virStorageSourceIsEmpty; virStorageSourceIsLocalStorage; virStorageSourceIsRelative; virStorageSourceIsSameLocation; +virStorageSourceNetCookiesValidate; virStorageSourceNetworkAssignDefaultPorts; virStorageSourceNew; virStorageSourceNewFromBacking; diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index ca91fc65ba..266e9c489e 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -2157,6 +2157,118 @@ virStorageSourceSeclabelsCopy(virStorageSourcePtr to, } +void +virStorageNetCookieDefFree(virStorageNetCookieDefPtr def) +{ + if (!def) + return; + + g_free(def->name); + g_free(def->value); + + g_free(def); +} + + +static void +virStorageSourceNetCookiesClear(virStorageSourcePtr src) +{ + size_t i; + + if (!src || !src->cookies) + return; + + for (i = 0; i < src->ncookies; i++) + virStorageNetCookieDefFree(src->cookies[i]); + + g_clear_pointer(&src->cookies, g_free); + src->ncookies = 0; +} + + +static void +virStorageSourceNetCookiesCopy(virStorageSourcePtr to, + const virStorageSource *from) +{ + size_t i; + + if (from->ncookies == 0) + return; + + to->cookies = g_new0(virStorageNetCookieDefPtr, from->ncookies); + to->ncookies = from->ncookies; + + for (i = 0; i < from->ncookies; i++) { + to->cookies[i]->name = g_strdup(from->cookies[i]->name); + to->cookies[i]->value = g_strdup(from->cookies[i]->value); + } +} + + +/* see https://tools.ietf.org/html/rfc6265#section-4.1.1 */ +static const char virStorageSourceCookieValueInvalidChars[] = + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + " \",;\\"; + +/* in addition cookie name can't contain these */ +static const char virStorageSourceCookieNameInvalidChars[] = + "()<>@:/[]?={}"; + +static int +virStorageSourceNetCookieValidate(virStorageNetCookieDefPtr def) +{ + /* name must have at least 1 character */ + if (*(def->name) == '\0') { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("cookie name must not be empty")); + return -1; + } + + /* check invalid characters in name */ + if (virStringHasChars(def->name, virStorageSourceCookieValueInvalidChars) || + virStringHasChars(def->name, virStorageSourceCookieNameInvalidChars)) { + virReportError(VIR_ERR_XML_ERROR, + _("cookie name '%s' contains invalid characters"), + def->name); + return -1; + } + + /* check invalid characters in value */ + if (virStringHasChars(def->value, virStorageSourceCookieValueInvalidChars)) { + virReportError(VIR_ERR_XML_ERROR, + _("value of cookie '%s' contains invalid characters"), + def->name); + return -1; + } + + return 0; +} + + +int +virStorageSourceNetCookiesValidate(virStorageSourcePtr src) +{ + size_t i; + size_t j; + + for (i = 0; i < src->ncookies; i++) { + if (virStorageSourceNetCookieValidate(src->cookies[i]) < 0) + return -1; + + for (j = i + 1; j < src->ncookies; j++) { + if (STREQ(src->cookies[i]->name, src->cookies[j]->name)) { + virReportError(VIR_ERR_XML_ERROR, _("duplicate cookie '%s'"), + src->cookies[i]->name); + return -1; + } + } + } + + return 0; +} + + static virStorageTimestampsPtr virStorageTimestampsCopy(const virStorageTimestamps *src) { @@ -2299,6 +2411,8 @@ virStorageSourceCopy(const virStorageSource *src, def->nhosts = src->nhosts; } + virStorageSourceNetCookiesCopy(def, src); + if (src->srcpool && !(def->srcpool = virStorageSourcePoolDefCopy(src->srcpool))) return NULL; @@ -2560,6 +2674,7 @@ virStorageSourceClear(virStorageSourcePtr def) VIR_FREE(def->volume); VIR_FREE(def->snapshot); VIR_FREE(def->configFile); + virStorageSourceNetCookiesClear(def); virStorageSourcePoolDefFree(def->srcpool); virBitmapFree(def->features); VIR_FREE(def->compat); diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 49718b51d8..95d9501dd8 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -161,6 +161,17 @@ struct _virStorageNetHostDef { char *socket; /* path to unix socket */ }; +typedef struct _virStorageNetCookieDef virStorageNetCookieDef; +typedef virStorageNetCookieDef *virStorageNetCookieDefPtr; +struct _virStorageNetCookieDef { + char *name; + char *value; +}; + +void virStorageNetCookieDefFree(virStorageNetCookieDefPtr def); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageNetCookieDef, virStorageNetCookieDefFree); + /* Information for a storage volume from a virStoragePool */ /* @@ -275,6 +286,8 @@ struct _virStorageSource { the source definition */ size_t nhosts; virStorageNetHostDefPtr hosts; + size_t ncookies; + virStorageNetCookieDefPtr *cookies; virStorageSourcePoolDefPtr srcpool; virStorageAuthDefPtr auth; bool authInherited; @@ -476,6 +489,8 @@ int virStorageSourceUpdateCapacity(virStorageSourcePtr src, int virStorageSourceNewFromBacking(virStorageSourcePtr parent, virStorageSourcePtr *backing); +int virStorageSourceNetCookiesValidate(virStorageSourcePtr src); + virStorageSourcePtr virStorageSourceCopy(const virStorageSource *src, bool backingChain) ATTRIBUTE_NONNULL(1); diff --git a/tests/genericxml2xmlindata/disk-network-http.xml b/tests/genericxml2xmlindata/disk-network-http.xml index bdcc1977f2..bafb77c8ec 100644 --- a/tests/genericxml2xmlindata/disk-network-http.xml +++ b/tests/genericxml2xmlindata/disk-network-http.xml @@ -33,6 +33,10 @@ + + testcookievalue + blurb + @@ -41,6 +45,10 @@ + + testcookievalue + blurb +