Skip to content

Commit 7d4df58

Browse files
committed
uri: Fix handling of Windows drive letters
Allow drive letters in URI paths. Technically, these should be treated as URI schemes, but this is not what users expect. This also makes sure that paths with drive letters are resolved as filesystem paths and unescaped, for example when used in libxslt's document() function. Should fix #832.
1 parent 5396636 commit 7d4df58

File tree

2 files changed

+115
-1
lines changed

2 files changed

+115
-1
lines changed

testparser.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,81 @@ testBuildRelativeUri(void) {
683683
return err;
684684
}
685685

686+
#if defined(_WIN32) || defined(__CYGWIN__)
687+
static int
688+
testWindowsUri(void) {
689+
const char *url = "c:/a%20b/file.txt";
690+
xmlURIPtr uri;
691+
xmlChar *res;
692+
int err = 0;
693+
int i;
694+
695+
static const xmlRelativeUriTest tests[] = {
696+
{
697+
"c:/a%20b/file.txt",
698+
"base.xml",
699+
"c:/a b/file.txt"
700+
}, {
701+
"file:///c:/a%20b/file.txt",
702+
"base.xml",
703+
"file:///c:/a%20b/file.txt"
704+
}, {
705+
"Z:/a%20b/file.txt",
706+
"http://example.com/",
707+
"Z:/a b/file.txt"
708+
}, {
709+
"a%20b/b1/c1",
710+
"C:/a/b2/c2",
711+
"C:/a/b2/a b/b1/c1"
712+
}, {
713+
"a%20b/b1/c1",
714+
"\\a\\b2\\c2",
715+
"/a/b2/a b/b1/c1"
716+
}, {
717+
"a%20b/b1/c1",
718+
"\\\\?\\a\\b2\\c2",
719+
"//?/a/b2/a b/b1/c1"
720+
}, {
721+
"a%20b/b1/c1",
722+
"\\\\\\\\server\\b2\\c2",
723+
"//server/b2/a b/b1/c1"
724+
}
725+
};
726+
727+
uri = xmlParseURI(url);
728+
if (uri == NULL) {
729+
fprintf(stderr, "xmlParseURI failed\n");
730+
err = 1;
731+
} else {
732+
if (uri->scheme != NULL) {
733+
fprintf(stderr, "invalid scheme: %s\n", uri->scheme);
734+
err = 1;
735+
}
736+
if (uri->path == NULL || strcmp(uri->path, "c:/a b/file.txt") != 0) {
737+
fprintf(stderr, "invalid path: %s\n", uri->path);
738+
err = 1;
739+
}
740+
741+
xmlFreeURI(uri);
742+
}
743+
744+
for (i = 0; (size_t) i < sizeof(tests) / sizeof(tests[0]); i++) {
745+
const xmlRelativeUriTest *test = tests + i;
746+
747+
res = xmlBuildURI(BAD_CAST test->uri, BAD_CAST test->base);
748+
if (res == NULL || !xmlStrEqual(res, BAD_CAST test->result)) {
749+
fprintf(stderr, "xmlBuildURI failed uri=%s base=%s "
750+
"result=%s expected=%s\n", test->uri, test->base,
751+
res, test->result);
752+
err = 1;
753+
}
754+
xmlFree(res);
755+
}
756+
757+
return err;
758+
}
759+
#endif /* WIN32 */
760+
686761
int
687762
main(void) {
688763
int err = 0;
@@ -717,6 +792,9 @@ main(void) {
717792
err |= testWriterClose();
718793
#endif
719794
err |= testBuildRelativeUri();
795+
#if defined(_WIN32) || defined(__CYGWIN__)
796+
err |= testWindowsUri();
797+
#endif
720798

721799
return err;
722800
}

uri.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,15 @@ xmlParse3986Scheme(xmlURIPtr uri, const char **str) {
231231
if (!ISA_ALPHA(cur))
232232
return(1);
233233
cur++;
234+
235+
#if defined(_WIN32) || defined(__CYGWIN__)
236+
/*
237+
* Don't treat Windows drive letters as scheme.
238+
*/
239+
if (*cur == ':')
240+
return(1);
241+
#endif
242+
234243
while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
235244
(*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
236245
if (uri != NULL) {
@@ -582,11 +591,21 @@ xmlParse3986Segment(xmlURIPtr uri, const char **str, char forbid, int empty)
582591
const char *cur;
583592

584593
cur = *str;
585-
if (!ISA_PCHAR(uri, cur)) {
594+
if (!ISA_PCHAR(uri, cur) || (*cur == forbid)) {
586595
if (empty)
587596
return(0);
588597
return(1);
589598
}
599+
NEXT(cur);
600+
601+
#if defined(_WIN32) || defined(__CYGWIN__)
602+
/*
603+
* Allow Windows drive letters.
604+
*/
605+
if ((forbid == ':') && (*cur == forbid))
606+
NEXT(cur);
607+
#endif
608+
590609
while (ISA_PCHAR(uri, cur) && (*cur != forbid))
591610
NEXT(cur);
592611
*str = cur;
@@ -2064,6 +2083,23 @@ xmlBuildURISafe(const xmlChar *URI, const xmlChar *base, xmlChar **valPtr) {
20642083
return(xmlResolvePath(URI, base, valPtr));
20652084
}
20662085

2086+
#if defined(_WIN32) || defined(__CYGWIN__)
2087+
/*
2088+
* Resolve paths with a Windows drive letter as filesystem path
2089+
* even if base has a scheme.
2090+
*/
2091+
if ((ref != NULL) && (ref->path != NULL)) {
2092+
int c = ref->path[0];
2093+
2094+
if ((((c >= 'A') && (c <= 'Z')) ||
2095+
((c >= 'a') && (c <= 'z'))) &&
2096+
(ref->path[1] == ':')) {
2097+
xmlFreeURI(ref);
2098+
return(xmlResolvePath(URI, base, valPtr));
2099+
}
2100+
}
2101+
#endif
2102+
20672103
ret = xmlParseURISafe((const char *) base, &bas);
20682104
if (ret < 0)
20692105
goto done;

0 commit comments

Comments
 (0)