summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Veillard <veillard@redhat.com>2014-10-03 19:22:39 +0800
committerDaniel Veillard <veillard@redhat.com>2014-10-03 19:22:39 +0800
commitbeb7281055dbf0ed4d041022a67c6c5cfd126f25 (patch)
tree3bb80c7254a7306a883601d7a84f7ae540f20e41
parentb3e488b0d90d5b0dbebf02cbd20894367f728d3e (diff)
downloadlibxml2-beb7281055dbf0ed4d041022a67c6c5cfd126f25.tar.gz
Fix a problem properly saving URIs
As written by Martin Kletzander <mkletzan@redhat.com>: Since commit 8eb55d782a2b9afacc7938694891cc6fad7b42a5, when you parse and save an URI that has no server (or similar) part, two slashes after the 'schema:' get lost. It means 'uri:///noserver' is turned into 'uri:/noserver'. basically foo:///only/path means a host of "" while foo:/only/path means no host at all So the best fix IMHO is to fix the URI parser to record the first case and an empty host string and the second case as a NULL host string I would not revert the initial patch, we should not 'invent' those slash, but we should instead when parsing keep the information that it's a host based path and that foo:/// means the presence of a host but an empty one. Once applied the resulting patch below, all cases seems to be saved properly: thinkpad:~/XML -> ./testURI uri:/noserver uri:/noserver thinkpad:~/XML -> ./testURI uri:///noserver uri:///noserver thinkpad:~/XML -> ./testURI uri://server/foo uri://server/foo thinkpad:~/XML -> ./testURI uri:/noserver/foo uri:/noserver/foo thinkpad:~/XML -> ./testURI uri:/// uri:/// thinkpad:~/XML -> ./testURI uri:// uri:// thinkpad:~/XML -> ./testURI uri:/ uri:/ thinkpad:~/XML -> If you revert the initial patch that last case fails The problem is that I don't want to change the xmlURI structure to minimize ABI breakage, so I could not extend the field. The natural solution is to denote that uri:/// has an empty host by making the uri server field an empty string which works very well but breaks applications (like libvirt ;-) who blindly look at uri->server not being NULL to try to reach it ! Simplest was to stick the port to -1 in that case, instead of 0 application don't bother looking at the port of there is no server string, this makes the patch more complex than a 1 liner, but is better for ABI.
-rw-r--r--uri.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/uri.c b/uri.c
index d4dcd2fe..ff47abbe 100644
--- a/uri.c
+++ b/uri.c
@@ -759,6 +759,8 @@ xmlParse3986HierPart(xmlURIPtr uri, const char **str)
cur += 2;
ret = xmlParse3986Authority(uri, &cur);
if (ret != 0) return(ret);
+ if (uri->server == NULL)
+ uri->port = -1;
ret = xmlParse3986PathAbEmpty(uri, &cur);
if (ret != 0) return(ret);
*str = cur;
@@ -1106,7 +1108,7 @@ xmlSaveUri(xmlURIPtr uri) {
}
}
} else {
- if (uri->server != NULL) {
+ if ((uri->server != NULL) || (uri->port == -1)) {
if (len + 3 >= max) {
temp = xmlSaveUriRealloc(ret, &max);
if (temp == NULL) goto mem_error;
@@ -1143,22 +1145,24 @@ xmlSaveUri(xmlURIPtr uri) {
}
ret[len++] = '@';
}
- p = uri->server;
- while (*p != 0) {
- if (len >= max) {
- temp = xmlSaveUriRealloc(ret, &max);
- if (temp == NULL) goto mem_error;
- ret = temp;
+ if (uri->server != NULL) {
+ p = uri->server;
+ while (*p != 0) {
+ if (len >= max) {
+ temp = xmlSaveUriRealloc(ret, &max);
+ if (temp == NULL) goto mem_error;
+ ret = temp;
+ }
+ ret[len++] = *p++;
}
- ret[len++] = *p++;
- }
- if (uri->port > 0) {
- if (len + 10 >= max) {
- temp = xmlSaveUriRealloc(ret, &max);
- if (temp == NULL) goto mem_error;
- ret = temp;
+ if (uri->port > 0) {
+ if (len + 10 >= max) {
+ temp = xmlSaveUriRealloc(ret, &max);
+ if (temp == NULL) goto mem_error;
+ ret = temp;
+ }
+ len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
}
- len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
}
} else if (uri->authority != NULL) {
if (len + 3 >= max) {