mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-03-19 14:50:07 +03:00
uri: Handle filesystem paths in xmlBuildRelativeURISafe
This mainly fixes issues on Windows but should also fix a few general corner cases. Should fix #745.
This commit is contained in:
parent
7655ed2cc0
commit
2ce70cde46
131
testparser.c
131
testparser.c
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "libxml.h"
|
#include "libxml.h"
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/uri.h>
|
||||||
#include <libxml/xmlreader.h>
|
#include <libxml/xmlreader.h>
|
||||||
#include <libxml/xmlwriter.h>
|
#include <libxml/xmlwriter.h>
|
||||||
#include <libxml/HTMLparser.h>
|
#include <libxml/HTMLparser.h>
|
||||||
@ -387,6 +388,135 @@ testWriterClose(void){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *uri;
|
||||||
|
const char *base;
|
||||||
|
const char *result;
|
||||||
|
} xmlRelativeUriTest;
|
||||||
|
|
||||||
|
static int
|
||||||
|
testBuildRelativeUri(void) {
|
||||||
|
xmlChar *res;
|
||||||
|
int err = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
static const xmlRelativeUriTest tests[] = {
|
||||||
|
{
|
||||||
|
"/a/b1/c1",
|
||||||
|
"/a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"a/b1/c1",
|
||||||
|
"a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"a/././b1/x/y/../z/../.././c1",
|
||||||
|
"./a/./b2/././b2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"file:///a/b1/c1",
|
||||||
|
"/a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"/a/b1/c1",
|
||||||
|
"file:///a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"a/b1/c1",
|
||||||
|
"/a/b2/c2",
|
||||||
|
NULL
|
||||||
|
}, {
|
||||||
|
"/a/b1/c1",
|
||||||
|
"a/b2/c2",
|
||||||
|
"file:///a/b1/c1"
|
||||||
|
}, {
|
||||||
|
"http://example.org/a/b1/c1",
|
||||||
|
"http://example.org/a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"http://example.org/a/b1/c1",
|
||||||
|
"https://example.org/a/b2/c2",
|
||||||
|
NULL
|
||||||
|
}, {
|
||||||
|
"http://example.org/a/b1/c1",
|
||||||
|
"http://localhost/a/b2/c2",
|
||||||
|
NULL
|
||||||
|
}, {
|
||||||
|
"with space/x x/y y",
|
||||||
|
"with space/b2/c2",
|
||||||
|
"../x%20x/y%20y"
|
||||||
|
}, {
|
||||||
|
"with space/x x/y y",
|
||||||
|
"/b2/c2",
|
||||||
|
"with%20space/x%20x/y%20y"
|
||||||
|
}
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
, {
|
||||||
|
"\\a\\b1\\c1",
|
||||||
|
"\\a\\b2\\c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"\\a\\b1\\c1",
|
||||||
|
"/a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"a\\b1\\c1",
|
||||||
|
"a/b2/c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"file://server/a/b1/c1",
|
||||||
|
"\\\\?\\UNC\\server\\a\\b2\\c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"file://server/a/b1/c1",
|
||||||
|
"\\\\server\\a\\b2\\c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"file:///x:/a/b1/c1",
|
||||||
|
"x:\\a\\b2\\c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"file:///x:/a/b1/c1",
|
||||||
|
"\\\\?\\x:\\a\\b2\\c2",
|
||||||
|
"../b1/c1"
|
||||||
|
}, {
|
||||||
|
"file:///x:/a/b1/c1",
|
||||||
|
"file:///y:/a/b2/c2",
|
||||||
|
NULL
|
||||||
|
}, {
|
||||||
|
"x:/a/b1/c1",
|
||||||
|
"y:/a/b2/c2",
|
||||||
|
"file:///x:/a/b1/c1"
|
||||||
|
}, {
|
||||||
|
"/a/b1/c1",
|
||||||
|
"y:/a/b2/c2",
|
||||||
|
"file:///a/b1/c1"
|
||||||
|
}, {
|
||||||
|
"\\server\\a\\b1\\c1",
|
||||||
|
"a/b2/c2",
|
||||||
|
"file:///server/a/b1/c1"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; (size_t) i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||||
|
const xmlRelativeUriTest *test = tests + i;
|
||||||
|
const char *expect;
|
||||||
|
|
||||||
|
res = xmlBuildRelativeURI(BAD_CAST test->uri, BAD_CAST test->base);
|
||||||
|
expect = test->result ? test->result : test->uri;
|
||||||
|
if (!xmlStrEqual(res, BAD_CAST expect)) {
|
||||||
|
fprintf(stderr, "xmlBuildRelativeURI failed uri=%s base=%s "
|
||||||
|
"result=%s expected=%s\n", test->uri, test->base,
|
||||||
|
res, expect);
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
xmlFree(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void) {
|
main(void) {
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@ -414,6 +544,7 @@ main(void) {
|
|||||||
#ifdef LIBXML_WRITER_ENABLED
|
#ifdef LIBXML_WRITER_ENABLED
|
||||||
err |= testWriterClose();
|
err |= testWriterClose();
|
||||||
#endif
|
#endif
|
||||||
|
err |= testBuildRelativeUri();
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
224
uri.c
224
uri.c
@ -2365,6 +2365,121 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
|
|||||||
return(out);
|
return(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xmlParseUriOrPath(const char *str, xmlURIPtr *out, int *drive) {
|
||||||
|
xmlURIPtr uri;
|
||||||
|
char *buf = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
*out = NULL;
|
||||||
|
*drive = 0;
|
||||||
|
|
||||||
|
uri = xmlCreateURI();
|
||||||
|
if (uri == NULL) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmlStrstr(BAD_CAST str, BAD_CAST "://") == NULL) {
|
||||||
|
const char *path;
|
||||||
|
size_t pathSize;
|
||||||
|
int prependSlash = 0;
|
||||||
|
|
||||||
|
buf = xmlMemStrdup(str);
|
||||||
|
if (buf == NULL) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xmlNormalizePath(buf, /* isFile */ 1);
|
||||||
|
|
||||||
|
path = buf;
|
||||||
|
|
||||||
|
if (xmlIsAbsolutePath(BAD_CAST buf)) {
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
const char *server = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uri->scheme = (char *) xmlStrdup(BAD_CAST "file");
|
||||||
|
if (uri->scheme == NULL) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
if (strncmp(buf, "//?/UNC/", 8) == 0) {
|
||||||
|
server = buf + 8;
|
||||||
|
} else if (strncmp(buf, "//?/", 4) == 0) {
|
||||||
|
path = buf + 3;
|
||||||
|
} else if (strncmp(buf, "//", 2) == 0) {
|
||||||
|
server = buf + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server != NULL) {
|
||||||
|
const char *end = strchr(server, '/');
|
||||||
|
|
||||||
|
if (end == NULL) {
|
||||||
|
uri->server = xmlMemStrdup(server);
|
||||||
|
path = "/";
|
||||||
|
} else {
|
||||||
|
uri->server = (char *) xmlStrndup(BAD_CAST server,
|
||||||
|
end - server);
|
||||||
|
path = end;
|
||||||
|
}
|
||||||
|
if (uri->server == NULL) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((path[0] >= 'A') && (path[0] <= 'Z')) ||
|
||||||
|
((path[0] >= 'a') && (path[0] <= 'z'))) &&
|
||||||
|
(path[1] == ':'))
|
||||||
|
prependSlash = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (uri->server == NULL)
|
||||||
|
uri->port = PORT_EMPTY_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathSize = strlen(path);
|
||||||
|
uri->path = xmlMalloc(pathSize + prependSlash + 1);
|
||||||
|
if (uri->path == NULL) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (prependSlash) {
|
||||||
|
uri->path[0] = '/';
|
||||||
|
memcpy(uri->path + 1, path, pathSize + 1);
|
||||||
|
} else {
|
||||||
|
memcpy(uri->path, path, pathSize + 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = xmlParseURIReference(uri, str);
|
||||||
|
if (ret != 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
xmlNormalizePath(uri->path, /* isFile */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
|
if ((uri->path[0] == '/') &&
|
||||||
|
(((uri->path[1] >= 'A') && (uri->path[1] <= 'Z')) ||
|
||||||
|
((uri->path[1] >= 'a') && (uri->path[1] <= 'z'))) &&
|
||||||
|
(uri->path[2] == ':'))
|
||||||
|
*drive = uri->path[1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*out = uri;
|
||||||
|
uri = NULL;
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
xmlFreeURI(uri);
|
||||||
|
xmlFree(buf);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlBuildRelativeURISafe:
|
* xmlBuildRelativeURISafe:
|
||||||
* @URI: the URI reference under consideration
|
* @URI: the URI reference under consideration
|
||||||
@ -2411,8 +2526,10 @@ xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base,
|
|||||||
int len;
|
int len;
|
||||||
xmlURIPtr ref = NULL;
|
xmlURIPtr ref = NULL;
|
||||||
xmlURIPtr bas = NULL;
|
xmlURIPtr bas = NULL;
|
||||||
xmlChar *bptr, *uptr, *vptr;
|
const xmlChar *bptr, *uptr, *rptr;
|
||||||
|
xmlChar *vptr;
|
||||||
int remove_path = 0;
|
int remove_path = 0;
|
||||||
|
int refDrive, baseDrive;
|
||||||
|
|
||||||
if (valPtr == NULL)
|
if (valPtr == NULL)
|
||||||
return(1);
|
return(1);
|
||||||
@ -2420,65 +2537,39 @@ xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base,
|
|||||||
if ((URI == NULL) || (*URI == 0))
|
if ((URI == NULL) || (*URI == 0))
|
||||||
return(1);
|
return(1);
|
||||||
|
|
||||||
/*
|
ret = xmlParseUriOrPath((char *) URI, &ref, &refDrive);
|
||||||
* First parse URI into a standard form
|
if (ret < 0)
|
||||||
*/
|
goto done;
|
||||||
ref = xmlCreateURI ();
|
if (ret != 0) {
|
||||||
if (ref == NULL) {
|
/* Return URI if URI is invalid */
|
||||||
ret = -1;
|
ret = 0;
|
||||||
goto done;
|
val = xmlStrdup(URI);
|
||||||
}
|
|
||||||
/* If URI not already in "relative" form */
|
|
||||||
if (URI[0] != '.') {
|
|
||||||
ret = xmlParseURIReference (ref, (const char *) URI);
|
|
||||||
if (ret != 0)
|
|
||||||
goto done; /* Error in URI, return NULL */
|
|
||||||
} else {
|
|
||||||
ref->path = (char *)xmlStrdup(URI);
|
|
||||||
if (ref->path == NULL) {
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Next parse base into the same standard form
|
|
||||||
*/
|
|
||||||
if ((base == NULL) || (*base == 0)) {
|
|
||||||
val = xmlStrdup (URI);
|
|
||||||
if (val == NULL)
|
if (val == NULL)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
bas = xmlCreateURI ();
|
|
||||||
if (bas == NULL) {
|
/* Return URI if base is empty */
|
||||||
ret = -1;
|
if ((base == NULL) || (*base == 0))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
if (base[0] != '.') {
|
ret = xmlParseUriOrPath((char *) base, &bas, &baseDrive);
|
||||||
ret = xmlParseURIReference (bas, (const char *) base);
|
if (ret < 0)
|
||||||
if (ret != 0)
|
goto done;
|
||||||
goto done; /* Error in base, return NULL */
|
if (ret != 0) {
|
||||||
} else {
|
/* Return URI if base is invalid */
|
||||||
bas->path = (char *)xmlStrdup(base);
|
ret = 0;
|
||||||
if (bas->path == NULL) {
|
goto done;
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the scheme / server on the URI differs from the base,
|
* If the scheme / server on the URI differs from the base,
|
||||||
* just return the URI
|
* just return the URI
|
||||||
*/
|
*/
|
||||||
if ((ref->scheme != NULL) &&
|
if ((xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
|
||||||
((bas->scheme == NULL) ||
|
(xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)) ||
|
||||||
(xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
|
(bas->port != ref->port) ||
|
||||||
(xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)) ||
|
(baseDrive != refDrive)) {
|
||||||
(bas->port != ref->port))) {
|
|
||||||
val = xmlStrdup (URI);
|
|
||||||
if (val == NULL)
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
|
if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
|
||||||
@ -2489,9 +2580,11 @@ xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base,
|
|||||||
}
|
}
|
||||||
if (bas->path == NULL) {
|
if (bas->path == NULL) {
|
||||||
val = xmlStrdup((xmlChar *)ref->path);
|
val = xmlStrdup((xmlChar *)ref->path);
|
||||||
if (val == NULL)
|
if (val == NULL) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
goto escape;
|
||||||
}
|
}
|
||||||
if (ref->path == NULL) {
|
if (ref->path == NULL) {
|
||||||
ref->path = (char *) "/";
|
ref->path = (char *) "/";
|
||||||
@ -2499,25 +2592,17 @@ xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point (at last!) we can compare the two paths
|
* At this point we can compare the two paths
|
||||||
*
|
|
||||||
* First we take care of the special case where either of the
|
|
||||||
* two path components may be missing (bug 316224)
|
|
||||||
*/
|
*/
|
||||||
bptr = (xmlChar *)bas->path;
|
|
||||||
{
|
{
|
||||||
xmlChar *rptr = (xmlChar *) ref->path;
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
|
bptr = (xmlChar *) bas->path;
|
||||||
|
rptr = (xmlChar *) ref->path;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next we compare the two strings and find where they first differ
|
* Next we compare the two strings and find where they first differ
|
||||||
*/
|
*/
|
||||||
if ((*rptr == '.') && (rptr[1] == '/'))
|
|
||||||
rptr += 2;
|
|
||||||
if ((*bptr == '.') && (bptr[1] == '/'))
|
|
||||||
bptr += 2;
|
|
||||||
else if ((*bptr == '/') && (*rptr != '/'))
|
|
||||||
bptr++;
|
|
||||||
while ((bptr[pos] == rptr[pos]) && (bptr[pos] != 0))
|
while ((bptr[pos] == rptr[pos]) && (bptr[pos] != 0))
|
||||||
pos++;
|
pos++;
|
||||||
|
|
||||||
@ -2605,9 +2690,10 @@ xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base,
|
|||||||
vptr[len - 1] = 0;
|
vptr[len - 1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
escape:
|
||||||
/* escape the freshly-built path */
|
/* escape the freshly-built path */
|
||||||
vptr = val;
|
vptr = val;
|
||||||
/* exception characters from xmlSaveUri */
|
/* exception characters from xmlSaveUri */
|
||||||
val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
|
val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
|
||||||
if (val == NULL)
|
if (val == NULL)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@ -2616,6 +2702,12 @@ xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base,
|
|||||||
xmlFree(vptr);
|
xmlFree(vptr);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if ((ret == 0) && (val == NULL)) {
|
||||||
|
val = xmlSaveUri(ref);
|
||||||
|
if (val == NULL)
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the working variables
|
* Free the working variables
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user