diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | include/libxml/uri.h | 36 | ||||
-rw-r--r-- | result/errors/webdav.xml | 8 | ||||
-rw-r--r-- | result/errors/webdav.xml.err | 15 | ||||
-rw-r--r-- | result/errors/webdav.xml.str | 16 | ||||
-rw-r--r-- | test/errors/webdav.xml | 9 | ||||
-rw-r--r-- | testapi.c | 2 | ||||
-rw-r--r-- | uri.c | 1699 |
9 files changed, 863 insertions, 932 deletions
@@ -1,3 +1,11 @@ +Mon Aug 4 17:27:27 CEST 2008 Daniel Veillard <daniel@veillard.com> + + * uri.c include/libxml/uri.h: rewrite the URI parser to update to + rfc3986 (from 2396) + * test/errors/webdav.xml result/errors/webdav.xml*: removed the + error test, 'DAV:' is a correct URI under 3986 + * Makefile.am: small cleanup in make check + Thu Jul 31 21:49:45 CEST 2008 Daniel Veillard <daniel@veillard.com> * runxmlconf.c: more progresses against the official regression tests diff --git a/Makefile.am b/Makefile.am index b42abef1..591bd6cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -167,7 +167,7 @@ runxmlconf_LDADD= $(LDADDS) #testOOM_LDADD= $(LDADDS) runtests: - runtest$(EXEEXT) && testapi$(EXEEXT) && runxmlconf$(EXEEXT) + ./runtest$(EXEEXT) && ./testapi$(EXEEXT) && ./runxmlconf$(EXEEXT) check: all runtests diff --git a/include/libxml/uri.h b/include/libxml/uri.h index 49ed105e..db48262b 100644 --- a/include/libxml/uri.h +++ b/include/libxml/uri.h @@ -49,43 +49,43 @@ struct _xmlURI { * xmlChar * xmlNodeGetBase (xmlDocPtr doc, * xmlNodePtr cur); */ -XMLPUBFUN xmlURIPtr XMLCALL +XMLPUBFUN xmlURIPtr XMLCALL xmlCreateURI (void); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * XMLCALL xmlBuildURI (const xmlChar *URI, - const xmlChar *base); -XMLPUBFUN xmlChar * XMLCALL + const xmlChar *base); +XMLPUBFUN xmlChar * XMLCALL xmlBuildRelativeURI (const xmlChar *URI, - const xmlChar *base); -XMLPUBFUN xmlURIPtr XMLCALL + const xmlChar *base); +XMLPUBFUN xmlURIPtr XMLCALL xmlParseURI (const char *str); -XMLPUBFUN xmlURIPtr XMLCALL +XMLPUBFUN xmlURIPtr XMLCALL xmlParseURIRaw (const char *str, int raw); -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlParseURIReference (xmlURIPtr uri, const char *str); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * XMLCALL xmlSaveUri (xmlURIPtr uri); -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL xmlPrintURI (FILE *stream, xmlURIPtr uri); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * XMLCALL xmlURIEscapeStr (const xmlChar *str, - const xmlChar *list); -XMLPUBFUN char * XMLCALL + const xmlChar *list); +XMLPUBFUN char * XMLCALL xmlURIUnescapeString (const char *str, int len, char *target); -XMLPUBFUN int XMLCALL +XMLPUBFUN int XMLCALL xmlNormalizeURIPath (char *path); -XMLPUBFUN xmlChar * XMLCALL +XMLPUBFUN xmlChar * XMLCALL xmlURIEscape (const xmlChar *str); -XMLPUBFUN void XMLCALL +XMLPUBFUN void XMLCALL xmlFreeURI (xmlURIPtr uri); -XMLPUBFUN xmlChar* XMLCALL +XMLPUBFUN xmlChar* XMLCALL xmlCanonicPath (const xmlChar *path); -XMLPUBFUN xmlChar* XMLCALL +XMLPUBFUN xmlChar* XMLCALL xmlPathToURI (const xmlChar *path); #ifdef __cplusplus diff --git a/result/errors/webdav.xml b/result/errors/webdav.xml deleted file mode 100644 index 26462196..00000000 --- a/result/errors/webdav.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<propfind xmlns="DAV:"><prop> -<getcontentlength xmlns="DAV:"/> -<getlastmodified xmlns="DAV:"/> -<displayname xmlns="DAV:"/> -<executable xmlns="http://apache.org/dav/props/"/> -<resourcetype xmlns="DAV:"/> -</prop></propfind> diff --git a/result/errors/webdav.xml.err b/result/errors/webdav.xml.err deleted file mode 100644 index 34bc8714..00000000 --- a/result/errors/webdav.xml.err +++ /dev/null @@ -1,15 +0,0 @@ -./test/errors/webdav.xml:2: namespace error : xmlns: 'DAV:' is not a valid URI -<propfind xmlns="DAV:"><prop> - ^ -./test/errors/webdav.xml:3: namespace error : xmlns: 'DAV:' is not a valid URI -<getcontentlength xmlns="DAV:"/> - ^ -./test/errors/webdav.xml:4: namespace error : xmlns: 'DAV:' is not a valid URI -<getlastmodified xmlns="DAV:"/> - ^ -./test/errors/webdav.xml:5: namespace error : xmlns: 'DAV:' is not a valid URI -<displayname xmlns="DAV:"/> - ^ -./test/errors/webdav.xml:7: namespace error : xmlns: 'DAV:' is not a valid URI -<resourcetype xmlns="DAV:"/> - ^ diff --git a/result/errors/webdav.xml.str b/result/errors/webdav.xml.str deleted file mode 100644 index 15eed0aa..00000000 --- a/result/errors/webdav.xml.str +++ /dev/null @@ -1,16 +0,0 @@ -./test/errors/webdav.xml:2: namespace error : xmlns: 'DAV:' is not a valid URI -<propfind xmlns="DAV:"><prop> - ^ -./test/errors/webdav.xml:3: namespace error : xmlns: 'DAV:' is not a valid URI -<getcontentlength xmlns="DAV:"/> - ^ -./test/errors/webdav.xml:4: namespace error : xmlns: 'DAV:' is not a valid URI -<getlastmodified xmlns="DAV:"/> - ^ -./test/errors/webdav.xml:5: namespace error : xmlns: 'DAV:' is not a valid URI -<displayname xmlns="DAV:"/> - ^ -./test/errors/webdav.xml:7: namespace error : xmlns: 'DAV:' is not a valid URI -<resourcetype xmlns="DAV:"/> - ^ -./test/errors/webdav.xml : failed to parse diff --git a/test/errors/webdav.xml b/test/errors/webdav.xml deleted file mode 100644 index 981c7c99..00000000 --- a/test/errors/webdav.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<propfind xmlns="DAV:"><prop> -<getcontentlength xmlns="DAV:"/> -<getlastmodified xmlns="DAV:"/> -<displayname xmlns="DAV:"/> -<executable xmlns="http://apache.org/dav/props/"/> -<resourcetype xmlns="DAV:"/> -</prop></propfind> - @@ -212,7 +212,7 @@ void xmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra); name resolution delays, so we use these */ #define REMOTE1GOOD "http://localhost/" -#define REMOTE1BAD "http://missing. example.org/" +#define REMOTE1BAD "http:http://http" #define REMOTE2GOOD "ftp://localhost/foo" #define gen_nb_void_ptr 2 @@ -1,7 +1,7 @@ /** * uri.c: set of generic URI related routines * - * Reference: RFCs 2396, 2732 and 2373 + * Reference: RFCs 3986, 2732 and 2373 * * See Copyright for the status of this software. * @@ -18,14 +18,10 @@ #include <libxml/globals.h> #include <libxml/xmlerror.h> -/************************************************************************ - * * - * Macros to differentiate various character type * - * directly extracted from RFC 2396 * - * * - ************************************************************************/ +static void xmlCleanURI(xmlURIPtr uri); /* + * Old rule from 2396 used in legacy handling code * alpha = lowalpha | upalpha */ #define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x)) @@ -61,31 +57,30 @@ #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x)) /* - * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | - * "a" | "b" | "c" | "d" | "e" | "f" - */ - -#define IS_HEX(x) ((IS_DIGIT(x)) || (((x) >= 'a') && ((x) <= 'f')) || \ - (((x) >= 'A') && ((x) <= 'F'))) - -/* * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" */ -#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \ - ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \ +#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \ + ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \ ((x) == '(') || ((x) == ')')) +/* + * unwise = "{" | "}" | "|" | "\" | "^" | "`" + */ +#define IS_UNWISE(p) \ + (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \ + ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \ + ((*(p) == ']')) || ((*(p) == '`'))) /* * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," | - * "[" | "]" + * "[" | "]" */ -#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \ - ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \ - ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \ - ((x) == ']')) +#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \ + ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \ + ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \ + ((x) == ']')) /* * unreserved = alphanum | mark @@ -94,98 +89,855 @@ #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x)) /* - * escaped = "%" hex hex + * Skip to next pointer char, handle escaped sequences */ -#define IS_ESCAPED(p) ((*(p) == '%') && (IS_HEX((p)[1])) && \ - (IS_HEX((p)[2]))) +#define NEXT(p) ((*p == '%')? p += 3 : p++) /* - * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | - * "&" | "=" | "+" | "$" | "," + * Productions from the spec. + * + * authority = server | reg_name + * reg_name = 1*( unreserved | escaped | "$" | "," | + * ";" | ":" | "@" | "&" | "=" | "+" ) + * + * path = [ abs_path | opaque_part ] */ -#define IS_URIC_NO_SLASH(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||\ - ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||\ - ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||\ - ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ','))) + +#define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n)) + +/************************************************************************ + * * + * RFC 3986 parser * + * * + ************************************************************************/ + +#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9')) +#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \ + ((*(p) >= 'A') && (*(p) <= 'Z'))) +#define ISA_HEXDIG(p) \ + (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \ + ((*(p) >= 'A') && (*(p) <= 'F'))) /* - * pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | "," + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" */ -#define IS_PCHAR(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \ - ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||\ - ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||\ - ((*(p) == ','))) +#define ISA_SUB_DELIM(p) \ + (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \ + ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \ + ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \ + ((*(p) == '='))) /* - * rel_segment = 1*( unreserved | escaped | - * ";" | "@" | "&" | "=" | "+" | "$" | "," ) + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" */ +#define ISA_GEN_DELIM(p) \ + (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \ + ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \ + ((*(p) == '@'))) -#define IS_SEGMENT(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \ - ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) || \ - ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) || \ - ((*(p) == ','))) +/* + * reserved = gen-delims / sub-delims + */ +#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p))) /* - * scheme = alpha *( alpha | digit | "+" | "-" | "." ) + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" */ +#define ISA_UNRESERVED(p) \ + ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \ + ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~'))) -#define IS_SCHEME(x) ((IS_ALPHA(x)) || (IS_DIGIT(x)) || \ - ((x) == '+') || ((x) == '-') || ((x) == '.')) +/* + * pct-encoded = "%" HEXDIG HEXDIG + */ +#define ISA_PCT_ENCODED(p) \ + ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2))) /* - * reg_name = 1*( unreserved | escaped | "$" | "," | - * ";" | ":" | "@" | "&" | "=" | "+" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */ +#define ISA_PCHAR(p) \ + (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \ + ((*(p) == ':')) || ((*(p) == '@'))) -#define IS_REG_NAME(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \ - ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) || \ - ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) || \ - ((*(p) == '=')) || ((*(p) == '+'))) +/** + * xmlParse3986Scheme: + * @uri: pointer to an URI structure + * @str: pointer to the string to analyze + * + * Parse an URI scheme + * + * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986Scheme(xmlURIPtr uri, const char **str) { + const char *cur; -/* - * userinfo = *( unreserved | escaped | ";" | ":" | "&" | "=" | - * "+" | "$" | "," ) + if (str == NULL) + return(-1); + + cur = *str; + if (!ISA_ALPHA(cur)) + return(2); + cur++; + while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || + (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++; + if (uri != NULL) { + if (uri->scheme != NULL) xmlFree(uri->scheme); + uri->scheme = STRNDUP(*str, cur - *str); + } + *str = cur; + return(0); +} + +/** + * xmlParse3986Fragment: + * @uri: pointer to an URI structure + * @str: pointer to the string to analyze + * + * Parse the query part of an URI + * + * query = *uric + * + * Returns 0 or the error code */ -#define IS_USERINFO(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \ - ((*(p) == ';')) || ((*(p) == ':')) || ((*(p) == '&')) || \ - ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) || \ - ((*(p) == ','))) +static int +xmlParse3986Fragment(xmlURIPtr uri, const char **str) +{ + const char *cur; -/* - * uric = reserved | unreserved | escaped + if (str == NULL) + return (-1); + + cur = *str; + + while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') || + ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) + NEXT(cur); + if (uri != NULL) { + if (uri->fragment != NULL) + xmlFree(uri->fragment); + if (uri->cleanup & 2) + uri->fragment = STRNDUP(*str, cur - *str); + else + uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986Query: + * @uri: pointer to an URI structure + * @str: pointer to the string to analyze + * + * Parse the query part of an URI + * + * query = *uric + * + * Returns 0 or the error code */ +static int +xmlParse3986Query(xmlURIPtr uri, const char **str) +{ + const char *cur; -#define IS_URIC(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \ - (IS_RESERVED(*(p)))) + if (str == NULL) + return (-1); -/* -* unwise = "{" | "}" | "|" | "\" | "^" | "`" -*/ + cur = *str; -#define IS_UNWISE(p) \ - (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \ - ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \ - ((*(p) == ']')) || ((*(p) == '`'))) + while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') || + ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) + NEXT(cur); + if (uri != NULL) { + if (uri->query != NULL) + xmlFree(uri->query); + if (uri->cleanup & 2) + uri->query = STRNDUP(*str, cur - *str); + else + uri->query = xmlURIUnescapeString(*str, cur - *str, NULL); -/* - * Skip to next pointer char, handle escaped sequences + /* Save the raw bytes of the query as well. + * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114 + */ + if (uri->query_raw != NULL) + xmlFree (uri->query_raw); + uri->query_raw = STRNDUP (*str, cur - *str); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986Port: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse a port part and fills in the appropriate fields + * of the @uri structure + * + * port = *DIGIT + * + * Returns 0 or the error code */ +static int +xmlParse3986Port(xmlURIPtr uri, const char **str) +{ + const char *cur = *str; -#define NEXT(p) ((*p == '%')? p += 3 : p++) + if (ISA_DIGIT(cur)) { + if (uri != NULL) + uri->port = 0; + while (ISA_DIGIT(cur)) { + if (uri != NULL) + uri->port = uri->port * 10 + (*cur - '0'); + cur++; + } + *str = cur; + return(0); + } + return(1); +} -/* - * Productions from the spec. +/** + * xmlParse3986Userinfo: + * @uri: pointer to an URI structure + * @str: the string to analyze * - * authority = server | reg_name - * reg_name = 1*( unreserved | escaped | "$" | "," | - * ";" | ":" | "@" | "&" | "=" | "+" ) + * Parse an user informations part and fills in the appropriate fields + * of the @uri structure * - * path = [ abs_path | opaque_part ] + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * + * Returns 0 or the error code */ +static int +xmlParse3986Userinfo(xmlURIPtr uri, const char **str) +{ + const char *cur; -#define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n)) + cur = *str; + while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || + ISA_SUB_DELIM(cur) || (*cur == ':')) + NEXT(cur); + if (*cur == '@') { + if (uri != NULL) { + if (uri->user != NULL) xmlFree(uri->user); + if (uri->cleanup & 2) + uri->user = STRNDUP(*str, cur - *str); + else + uri->user = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return(0); + } + return(1); +} + +/** + * xmlParse3986DecOctet: + * @str: the string to analyze + * + * dec-octet = DIGIT ; 0-9 + * / %x31-39 DIGIT ; 10-99 + * / "1" 2DIGIT ; 100-199 + * / "2" %x30-34 DIGIT ; 200-249 + * / "25" %x30-35 ; 250-255 + * + * Skip a dec-octet. + * + * Returns 0 if found and skipped, 1 otherwise + */ +static int +xmlParse3986DecOctet(const char **str) { + const char *cur = *str; + + if (!(ISA_DIGIT(cur))) + return(1); + if (!ISA_DIGIT(cur+1)) + cur++; + else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2))) + cur += 2; + else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2))) + cur += 3; + else if ((*cur == '2') && (*(cur + 1) >= '0') && + (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2))) + cur += 3; + else if ((*cur == '2') && (*(cur + 1) == '5') && + (*(cur + 2) >= '0') && (*(cur + 1) <= '5')) + cur += 3; + else + return(1); + *str = cur; + return(0); +} +/** + * xmlParse3986Host: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an host part and fills in the appropriate fields + * of the @uri structure + * + * host = IP-literal / IPv4address / reg-name + * IP-literal = "[" ( IPv6address / IPvFuture ) "]" + * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + * reg-name = *( unreserved / pct-encoded / sub-delims ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986Host(xmlURIPtr uri, const char **str) +{ + const char *cur = *str; + const char *host; + + host = cur; + /* + * IPv6 and future adressing scheme are enclosed between brackets + */ + if (*cur == '[') { + cur++; + while ((*cur != ']') && (*cur != 0)) + cur++; + if (*cur != ']') + return(1); + cur++; + goto found; + } + /* + * try to parse an IPv4 + */ + if (ISA_DIGIT(cur)) { + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + if (*cur != '.') + goto not_ipv4; + cur++; + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + if (*cur != '.') + goto not_ipv4; + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + if (*cur != '.') + goto not_ipv4; + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + goto found; +not_ipv4: + cur = *str; + } + /* + * then this should be a hostname which can be empty + */ + while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) + NEXT(cur); +found: + if (uri != NULL) { + if (uri->authority != NULL) xmlFree(uri->authority); + uri->authority = NULL; + if (uri->server != NULL) xmlFree(uri->server); + if (cur != host) { + if (uri->cleanup & 2) + uri->server = STRNDUP(host, cur - host); + else + uri->server = xmlURIUnescapeString(host, cur - host, NULL); + } else + uri->server = NULL; + } + *str = cur; + return(0); +} + +/** + * xmlParse3986Authority: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an authority part and fills in the appropriate fields + * of the @uri structure + * + * authority = [ userinfo "@" ] host [ ":" port ] + * + * Returns 0 or the error code + */ +static int +xmlParse3986Authority(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + /* + * try to parse an userinfo and check for the trailing @ + */ + ret = xmlParse3986Userinfo(uri, &cur); + if ((ret != 0) || (*cur != '@')) + cur = *str; + else + cur++; + ret = xmlParse3986Host(uri, &cur); + if (ret != 0) return(ret); + if (*cur == ':') { + ret = xmlParse3986Port(uri, &cur); + if (ret != 0) return(ret); + } + *str = cur; + return(0); +} + +/** + * xmlParse3986Segment: + * @str: the string to analyze + * @forbid: an optional forbidden character + * @empty: allow an empty segment + * + * Parse a segment and fills in the appropriate fields + * of the @uri structure + * + * segment = *pchar + * segment-nz = 1*pchar + * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + * ; non-zero-length segment without any colon ":" + * + * Returns 0 or the error code + */ +static int +xmlParse3986Segment(const char **str, char forbid, int empty) +{ + const char *cur; + + cur = *str; + if (!ISA_PCHAR(cur)) { + if (empty) + return(0); + return(1); + } + while (ISA_PCHAR(cur) && (*cur != forbid)) + NEXT(cur); + *str = cur; + return (0); +} + +/** + * xmlParse3986PathAbEmpty: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path absolute or empty and fills in the appropriate fields + * of the @uri structure + * + * path-abempty = *( "/" segment ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&cur, 0, 1); + if (ret != 0) return(ret); + } + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + if (uri->cleanup & 2) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986PathAbsolute: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path absolute and fills in the appropriate fields + * of the @uri structure + * + * path-absolute = "/" [ segment-nz *( "/" segment ) ] + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + if (*cur != '/') + return(1); + cur++; + ret = xmlParse3986Segment(&cur, 0, 0); + if (ret == 0) { + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&cur, 0, 1); + if (ret != 0) return(ret); + } + } + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + if (uri->cleanup & 2) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986PathRootless: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path without root and fills in the appropriate fields + * of the @uri structure + * + * path-rootless = segment-nz *( "/" segment ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathRootless(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + ret = xmlParse3986Segment(&cur, 0, 0); + if (ret != 0) return(ret); + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&cur, 0, 1); + if (ret != 0) return(ret); + } + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + if (uri->cleanup & 2) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986PathNoScheme: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path which is not a scheme and fills in the appropriate fields + * of the @uri structure + * + * path-noscheme = segment-nz-nc *( "/" segment ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + ret = xmlParse3986Segment(&cur, ':', 0); + if (ret != 0) return(ret); + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&cur, 0, 1); + if (ret != 0) return(ret); + } + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + if (uri->cleanup & 2) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986HierPart: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an hierarchical part and fills in the appropriate fields + * of the @uri structure + * + * hier-part = "//" authority path-abempty + * / path-absolute + * / path-rootless + * / path-empty + * + * Returns 0 or the error code + */ +static int +xmlParse3986HierPart(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + if ((*cur == '/') && (*(cur + 1) == '/')) { + cur += 2; + ret = xmlParse3986Authority(uri, &cur); + if (ret != 0) return(ret); + ret = xmlParse3986PathAbEmpty(uri, &cur); + if (ret != 0) return(ret); + *str = cur; + return(0); + } else if (*cur == '/') { + ret = xmlParse3986PathAbsolute(uri, &cur); + if (ret != 0) return(ret); + } else if (ISA_PCHAR(cur)) { + ret = xmlParse3986PathRootless(uri, &cur); + if (ret != 0) return(ret); + } else { + /* path-empty is effectively empty */ + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + uri->path = NULL; + } + } + *str = cur; + return (0); +} + +/** + * xmlParse3986RelativeRef: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI string and fills in the appropriate fields + * of the @uri structure + * + * relative-ref = relative-part [ "?" query ] [ "#" fragment ] + * relative-part = "//" authority path-abempty + * / path-absolute + * / path-noscheme + * / path-empty + * + * Returns 0 or the error code + */ +static int +xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) { + int ret; + + if ((*str == '/') && (*(str + 1) == '/')) { + str += 2; + ret = xmlParse3986Authority(uri, &str); + if (ret != 0) return(ret); + ret = xmlParse3986PathAbEmpty(uri, &str); + if (ret != 0) return(ret); + } else if (*str == '/') { + ret = xmlParse3986PathAbsolute(uri, &str); + if (ret != 0) return(ret); + } else if (ISA_PCHAR(str)) { + ret = xmlParse3986PathNoScheme(uri, &str); + if (ret != 0) return(ret); + } else { + /* path-empty is effectively empty */ + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + uri->path = NULL; + } + } + + if (*str == '?') { + str++; + ret = xmlParse3986Query(uri, &str); + if (ret != 0) return(ret); + } + if (*str == '#') { + str++; + ret = xmlParse3986Fragment(uri, &str); + if (ret != 0) return(ret); + } + if (*str != 0) { + xmlCleanURI(uri); + return(1); + } + return(0); +} + + +/** + * xmlParse3986URI: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI string and fills in the appropriate fields + * of the @uri structure + * + * scheme ":" hier-part [ "?" query ] [ "#" fragment ] + * + * Returns 0 or the error code + */ +static int +xmlParse3986URI(xmlURIPtr uri, const char *str) { + int ret; + + ret = xmlParse3986Scheme(uri, &str); + if (ret != 0) return(ret); + if (*str != ':') { + return(1); + } + str++; + ret = xmlParse3986HierPart(uri, &str); + if (ret != 0) return(ret); + if (*str == '?') { + str++; + ret = xmlParse3986Query(uri, &str); + if (ret != 0) return(ret); + } + if (*str == '#') { + str++; + ret = xmlParse3986Fragment(uri, &str); + if (ret != 0) return(ret); + } + if (*str != 0) { + xmlCleanURI(uri); + return(1); + } + return(0); +} + +/** + * xmlParse3986URIReference: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI reference string and fills in the appropriate fields + * of the @uri structure + * + * URI-reference = URI / relative-ref + * + * Returns 0 or the error code + */ +static int +xmlParse3986URIReference(xmlURIPtr uri, const char *str) { + int ret; + + if (str == NULL) + return(-1); + xmlCleanURI(uri); + + /* + * Try first to parse absolute refs, then fallback to relative if + * it fails. + */ + ret = xmlParse3986URI(uri, str); + if (ret != 0) { + xmlCleanURI(uri); + ret = xmlParse3986RelativeRef(uri, str); + if (ret != 0) { + xmlCleanURI(uri); + return(ret); + } + } + return(0); +} + +/** + * xmlParseURI: + * @str: the URI string to analyze + * + * Parse an URI based on RFC 3986 + * + * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] + * + * Returns a newly built xmlURIPtr or NULL in case of error + */ +xmlURIPtr +xmlParseURI(const char *str) { + xmlURIPtr uri; + int ret; + + if (str == NULL) + return(NULL); + uri = xmlCreateURI(); + if (uri != NULL) { + ret = xmlParse3986URIReference(uri, str); + if (ret) { + xmlFreeURI(uri); + return(NULL); + } + } + return(uri); +} + +/** + * xmlParseURIReference: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI reference string based on RFC 3986 and fills in the + * appropriate fields of the @uri structure + * + * URI-reference = URI / relative-ref + * + * Returns 0 or the error code + */ +int +xmlParseURIReference(xmlURIPtr uri, const char *str) { + return(xmlParse3986URIReference(uri, str)); +} + +/** + * xmlParseURIRaw: + * @str: the URI string to analyze + * @raw: if 1 unescaping of URI pieces are disabled + * + * Parse an URI but allows to keep intact the original fragments. + * + * URI-reference = URI / relative-ref + * + * Returns a newly built xmlURIPtr or NULL in case of error + */ +xmlURIPtr +xmlParseURIRaw(const char *str, int raw) { + xmlURIPtr uri; + int ret; + + if (str == NULL) + return(NULL); + uri = xmlCreateURI(); + if (uri != NULL) { + if (raw) { + uri->cleanup |= 2; + } + ret = xmlParseURIReference(uri, str); + if (ret) { + xmlFreeURI(uri); + return(NULL); + } + } + return(uri); +} /************************************************************************ * * @@ -453,7 +1205,7 @@ xmlSaveUri(xmlURIPtr uri) { (((p[1] >= 'a') && (p[1] <= 'z')) || ((p[1] >= 'A') && (p[1] <= 'Z'))) && (p[2] == ':') && - (xmlStrEqual(uri->scheme, BAD_CAST "file"))) { + (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { if (len + 3 >= max) { max *= 2; ret = (xmlChar *) xmlRealloc(ret, @@ -575,8 +1327,8 @@ xmlSaveUri(xmlURIPtr uri) { "xmlSaveUri: out of memory\n"); xmlFree(ret); return(NULL); - } - ret = temp; + } + ret = temp; } ret[len++] = '#'; p = uri->fragment; @@ -1105,7 +1857,7 @@ xmlURIEscape(const xmlChar * str) segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@"); NULLCHK(segment) if (uri->user == NULL) - ret = xmlStrcat(ret, BAD_CAST "//"); + ret = xmlStrcat(ret, BAD_CAST "//"); ret = xmlStrcat(ret, segment); xmlFree(segment); } @@ -1162,787 +1914,6 @@ xmlURIEscape(const xmlChar * str) /************************************************************************ * * - * Escaped URI parsing * - * * - ************************************************************************/ - -/** - * xmlParseURIFragment: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an URI fragment string and fills in the appropriate fields - * of the @uri structure. - * - * fragment = *uric - * - * Returns 0 or the error code - */ -static int -xmlParseURIFragment(xmlURIPtr uri, const char **str) -{ - const char *cur; - - if (str == NULL) - return (-1); - - cur = *str; - - while (IS_URIC(cur) || IS_UNWISE(cur)) - NEXT(cur); - if (uri != NULL) { - if (uri->fragment != NULL) - xmlFree(uri->fragment); - if (uri->cleanup & 2) - uri->fragment = STRNDUP(*str, cur - *str); - else - uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL); - } - *str = cur; - return (0); -} - -/** - * xmlParseURIQuery: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse the query part of an URI - * - * query = *uric - * - * Returns 0 or the error code - */ -static int -xmlParseURIQuery(xmlURIPtr uri, const char **str) -{ - const char *cur; - - if (str == NULL) - return (-1); - - cur = *str; - - while ((IS_URIC(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) - NEXT(cur); - if (uri != NULL) { - if (uri->query != NULL) - xmlFree(uri->query); - if (uri->cleanup & 2) - uri->query = STRNDUP(*str, cur - *str); - else - uri->query = xmlURIUnescapeString(*str, cur - *str, NULL); - - /* Save the raw bytes of the query as well. - * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114 - */ - if (uri->query_raw != NULL) - xmlFree (uri->query_raw); - uri->query_raw = STRNDUP (*str, cur - *str); - } - *str = cur; - return (0); -} - -/** - * xmlParseURIScheme: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an URI scheme - * - * scheme = alpha *( alpha | digit | "+" | "-" | "." ) - * - * Returns 0 or the error code - */ -static int -xmlParseURIScheme(xmlURIPtr uri, const char **str) { - const char *cur; - - if (str == NULL) - return(-1); - - cur = *str; - if (!IS_ALPHA(*cur)) - return(2); - cur++; - while (IS_SCHEME(*cur)) cur++; - if (uri != NULL) { - if (uri->scheme != NULL) xmlFree(uri->scheme); - uri->scheme = STRNDUP(*str, cur - *str); - } - *str = cur; - return(0); -} - -/** - * xmlParseURIOpaquePart: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an URI opaque part - * - * opaque_part = uric_no_slash *uric - * - * Returns 0 or the error code - */ -static int -xmlParseURIOpaquePart(xmlURIPtr uri, const char **str) -{ - const char *cur; - - if (str == NULL) - return (-1); - - cur = *str; - if (!((IS_URIC_NO_SLASH(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))) { - return (3); - } - NEXT(cur); - while ((IS_URIC(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) - NEXT(cur); - if (uri != NULL) { - if (uri->opaque != NULL) - xmlFree(uri->opaque); - if (uri->cleanup & 2) - uri->opaque = STRNDUP(*str, cur - *str); - else - uri->opaque = xmlURIUnescapeString(*str, cur - *str, NULL); - } - *str = cur; - return (0); -} - -/** - * xmlParseURIServer: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse a server subpart of an URI, it's a finer grain analysis - * of the authority part. - * - * server = [ [ userinfo "@" ] hostport ] - * userinfo = *( unreserved | escaped | - * ";" | ":" | "&" | "=" | "+" | "$" | "," ) - * hostport = host [ ":" port ] - * host = hostname | IPv4address | IPv6reference - * hostname = *( domainlabel "." ) toplabel [ "." ] - * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum - * toplabel = alpha | alpha *( alphanum | "-" ) alphanum - * IPv6reference = "[" IPv6address "]" - * IPv6address = hexpart [ ":" IPv4address ] - * IPv4address = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit - * hexpart = hexseq | hexseq "::" [ hexseq ]| "::" [ hexseq ] - * hexseq = hex4 *( ":" hex4) - * hex4 = 1*4hexdig - * port = *digit - * - * Returns 0 or the error code - */ -static int -xmlParseURIServer(xmlURIPtr uri, const char **str) { - const char *cur; - const char *host, *tmp; - const int IPV4max = 4; - const int IPV6max = 8; - int oct; - - if (str == NULL) - return(-1); - - cur = *str; - - /* - * is there a userinfo ? - */ - while (IS_USERINFO(cur)) NEXT(cur); - if (*cur == '@') { - if (uri != NULL) { - if (uri->user != NULL) xmlFree(uri->user); - if (uri->cleanup & 2) - uri->user = STRNDUP(*str, cur - *str); - else - uri->user = xmlURIUnescapeString(*str, cur - *str, NULL); - } - cur++; - } else { - if (uri != NULL) { - if (uri->user != NULL) xmlFree(uri->user); - uri->user = NULL; - } - cur = *str; - } - /* - * This can be empty in the case where there is no server - */ - host = cur; - if (*cur == '/') { - if (uri != NULL) { - if (uri->authority != NULL) xmlFree(uri->authority); - uri->authority = NULL; - if (uri->server != NULL) xmlFree(uri->server); - uri->server = NULL; - uri->port = 0; - } - return(0); - } - /* - * host part of hostport can denote an IPV4 address, an IPV6 address - * or an unresolved name. Check the IP first, its easier to detect - * errors if wrong one. - * An IPV6 address must start with a '[' and end with a ']'. - */ - if (*cur == '[') { - int compress=0; - cur++; - for (oct = 0; oct < IPV6max; ++oct) { - if (*cur == ':') { - if (compress) - return(3); /* multiple compression attempted */ - if (!oct) { /* initial char is compression */ - if (*++cur != ':') - return(3); - } - compress = 1; /* set compression-encountered flag */ - cur++; /* skip over the second ':' */ - continue; - } - while(IS_HEX(*cur)) cur++; - if (oct == (IPV6max-1)) - continue; - if (*cur != ':') - break; - cur++; - } - if ((!compress) && (oct != IPV6max)) - return(3); - if (*cur != ']') - return(3); - if (uri != NULL) { - if (uri->server != NULL) xmlFree(uri->server); - uri->server = (char *)xmlStrndup((xmlChar *)host+1, - (cur-host)-1); - } - cur++; - } else { - /* - * Not IPV6, maybe IPV4 - */ - for (oct = 0; oct < IPV4max; ++oct) { - if (*cur == '.') - return(3); /* e.g. http://.xml/ or http://18.29..30/ */ - while(IS_DIGIT(*cur)) cur++; - if (oct == (IPV4max-1)) - continue; - if (*cur != '.') - break; - cur++; - } - } - if ((host[0] != '[') && (oct < IPV4max || (*cur == '.' && cur++) || - IS_ALPHA(*cur))) { - /* maybe host_name */ - if (!IS_ALPHANUM(*cur)) - return(4); /* e.g. http://xml.$oft */ - do { - do ++cur; while (IS_ALPHANUM(*cur)); - if (*cur == '-') { - --cur; - if (*cur == '.') - return(5); /* e.g. http://xml.-soft */ - ++cur; - continue; - } - if (*cur == '.') { - --cur; - if (*cur == '-') - return(6); /* e.g. http://xml-.soft */ - if (*cur == '.') - return(7); /* e.g. http://xml..soft */ - ++cur; - continue; - } - break; - } while (1); - tmp = cur; - if (tmp[-1] == '.') - --tmp; /* e.g. http://xml.$Oft/ */ - do --tmp; while (tmp >= host && IS_ALPHANUM(*tmp)); - if ((++tmp == host || tmp[-1] == '.') && !IS_ALPHA(*tmp)) - return(8); /* e.g. http://xmlsOft.0rg/ */ - } - if (uri != NULL) { - if (uri->authority != NULL) xmlFree(uri->authority); - uri->authority = NULL; - if (host[0] != '[') { /* it's not an IPV6 addr */ - if (uri->server != NULL) xmlFree(uri->server); - if (uri->cleanup & 2) - uri->server = STRNDUP(host, cur - host); - else - uri->server = xmlURIUnescapeString(host, cur - host, NULL); - } - } - /* - * finish by checking for a port presence. - */ - if (*cur == ':') { - cur++; - if (IS_DIGIT(*cur)) { - if (uri != NULL) - uri->port = 0; - while (IS_DIGIT(*cur)) { - if (uri != NULL) - uri->port = uri->port * 10 + (*cur - '0'); - cur++; - } - } - } - *str = cur; - return(0); -} - -/** - * xmlParseURIRelSegment: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an URI relative segment - * - * rel_segment = 1*( unreserved | escaped | ";" | "@" | "&" | "=" | - * "+" | "$" | "," ) - * - * Returns 0 or the error code - */ -static int -xmlParseURIRelSegment(xmlURIPtr uri, const char **str) -{ - const char *cur; - - if (str == NULL) - return (-1); - - cur = *str; - if (!((IS_SEGMENT(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))) { - return (3); - } - NEXT(cur); - while ((IS_SEGMENT(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) - NEXT(cur); - if (uri != NULL) { - if (uri->path != NULL) - xmlFree(uri->path); - if (uri->cleanup & 2) - uri->path = STRNDUP(*str, cur - *str); - else - uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); - } - *str = cur; - return (0); -} - -/** - * xmlParseURIPathSegments: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * @slash: should we add a leading slash - * - * Parse an URI set of path segments - * - * path_segments = segment *( "/" segment ) - * segment = *pchar *( ";" param ) - * param = *pchar - * - * Returns 0 or the error code - */ -static int -xmlParseURIPathSegments(xmlURIPtr uri, const char **str, int slash) -{ - const char *cur; - - if (str == NULL) - return (-1); - - cur = *str; - - do { - while ((IS_PCHAR(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) - NEXT(cur); - while (*cur == ';') { - cur++; - while ((IS_PCHAR(cur)) || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) - NEXT(cur); - } - if (*cur != '/') - break; - cur++; - } while (1); - if (uri != NULL) { - int len, len2 = 0; - char *path; - - /* - * Concat the set of path segments to the current path - */ - len = cur - *str; - if (slash) - len++; - - if (uri->path != NULL) { - len2 = strlen(uri->path); - len += len2; - } - path = (char *) xmlMallocAtomic(len + 1); - if (path == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlParseURIPathSegments: out of memory\n"); - *str = cur; - return (-1); - } - if (uri->path != NULL) - memcpy(path, uri->path, len2); - if (slash) { - path[len2] = '/'; - len2++; - } - path[len2] = 0; - if (cur - *str > 0) { - if (uri->cleanup & 2) { - memcpy(&path[len2], *str, cur - *str); - path[len2 + (cur - *str)] = 0; - } else - xmlURIUnescapeString(*str, cur - *str, &path[len2]); - } - if (uri->path != NULL) - xmlFree(uri->path); - uri->path = path; - } - *str = cur; - return (0); -} - -/** - * xmlParseURIAuthority: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse the authority part of an URI. - * - * authority = server | reg_name - * server = [ [ userinfo "@" ] hostport ] - * reg_name = 1*( unreserved | escaped | "$" | "," | ";" | ":" | - * "@" | "&" | "=" | "+" ) - * - * Note : this is completely ambiguous since reg_name is allowed to - * use the full set of chars in use by server: - * - * 3.2.1. Registry-based Naming Authority - * - * The structure of a registry-based naming authority is specific - * to the URI scheme, but constrained to the allowed characters - * for an authority component. - * - * Returns 0 or the error code - */ -static int -xmlParseURIAuthority(xmlURIPtr uri, const char **str) { - const char *cur; - int ret; - - if (str == NULL) - return(-1); - - cur = *str; - - /* - * try first to parse it as a server string. - */ - ret = xmlParseURIServer(uri, str); - if ((ret == 0) && (*str != NULL) && - ((**str == 0) || (**str == '/') || (**str == '?'))) - return(0); - *str = cur; - - /* - * failed, fallback to reg_name - */ - if (!IS_REG_NAME(cur)) { - return(5); - } - NEXT(cur); - while (IS_REG_NAME(cur)) NEXT(cur); - if (uri != NULL) { - if (uri->server != NULL) xmlFree(uri->server); - uri->server = NULL; - if (uri->user != NULL) xmlFree(uri->user); - uri->user = NULL; - if (uri->authority != NULL) xmlFree(uri->authority); - if (uri->cleanup & 2) - uri->authority = STRNDUP(*str, cur - *str); - else - uri->authority = xmlURIUnescapeString(*str, cur - *str, NULL); - } - *str = cur; - return(0); -} - -/** - * xmlParseURIHierPart: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an URI hierarchical part - * - * hier_part = ( net_path | abs_path ) [ "?" query ] - * abs_path = "/" path_segments - * net_path = "//" authority [ abs_path ] - * - * Returns 0 or the error code - */ -static int -xmlParseURIHierPart(xmlURIPtr uri, const char **str) { - int ret; - const char *cur; - - if (str == NULL) - return(-1); - - cur = *str; - - if ((cur[0] == '/') && (cur[1] == '/')) { - cur += 2; - ret = xmlParseURIAuthority(uri, &cur); - if (ret != 0) - return(ret); - if (cur[0] == '/') { - cur++; - ret = xmlParseURIPathSegments(uri, &cur, 1); - } - } else if (cur[0] == '/') { - cur++; - ret = xmlParseURIPathSegments(uri, &cur, 1); - } else { - return(4); - } - if (ret != 0) - return(ret); - if (*cur == '?') { - cur++; - ret = xmlParseURIQuery(uri, &cur); - if (ret != 0) - return(ret); - } - *str = cur; - return(0); -} - -/** - * xmlParseAbsoluteURI: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an URI reference string and fills in the appropriate fields - * of the @uri structure - * - * absoluteURI = scheme ":" ( hier_part | opaque_part ) - * - * Returns 0 or the error code - */ -static int -xmlParseAbsoluteURI(xmlURIPtr uri, const char **str) { - int ret; - const char *cur; - - if (str == NULL) - return(-1); - - cur = *str; - - ret = xmlParseURIScheme(uri, str); - if (ret != 0) return(ret); - if (**str != ':') { - *str = cur; - return(1); - } - (*str)++; - if (**str == '/') - return(xmlParseURIHierPart(uri, str)); - return(xmlParseURIOpaquePart(uri, str)); -} - -/** - * xmlParseRelativeURI: - * @uri: pointer to an URI structure - * @str: pointer to the string to analyze - * - * Parse an relative URI string and fills in the appropriate fields - * of the @uri structure - * - * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] - * abs_path = "/" path_segments - * net_path = "//" authority [ abs_path ] - * rel_path = rel_segment [ abs_path ] - * - * Returns 0 or the error code - */ -static int -xmlParseRelativeURI(xmlURIPtr uri, const char **str) { - int ret = 0; - const char *cur; - - if (str == NULL) - return(-1); - - cur = *str; - if ((cur[0] == '/') && (cur[1] == '/')) { - cur += 2; - ret = xmlParseURIAuthority(uri, &cur); - if (ret != 0) - return(ret); - if (cur[0] == '/') { - cur++; - ret = xmlParseURIPathSegments(uri, &cur, 1); - } - } else if (cur[0] == '/') { - cur++; - ret = xmlParseURIPathSegments(uri, &cur, 1); - } else if (cur[0] != '#' && cur[0] != '?') { - ret = xmlParseURIRelSegment(uri, &cur); - if (ret != 0) - return(ret); - if (cur[0] == '/') { - cur++; - ret = xmlParseURIPathSegments(uri, &cur, 1); - } - } - if (ret != 0) - return(ret); - if (*cur == '?') { - cur++; - ret = xmlParseURIQuery(uri, &cur); - if (ret != 0) - return(ret); - } - *str = cur; - return(ret); -} - -/** - * xmlParseURIReference: - * @uri: pointer to an URI structure - * @str: the string to analyze - * - * Parse an URI reference string and fills in the appropriate fields - * of the @uri structure - * - * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] - * - * Returns 0 or the error code - */ -int -xmlParseURIReference(xmlURIPtr uri, const char *str) { - int ret; - const char *tmp = str; - - if (str == NULL) - return(-1); - xmlCleanURI(uri); - - /* - * Try first to parse absolute refs, then fallback to relative if - * it fails. - */ - ret = xmlParseAbsoluteURI(uri, &str); - if (ret != 0) { - xmlCleanURI(uri); - str = tmp; - ret = xmlParseRelativeURI(uri, &str); - } - if (ret != 0) { - xmlCleanURI(uri); - return(ret); - } - - if (*str == '#') { - str++; - ret = xmlParseURIFragment(uri, &str); - if (ret != 0) return(ret); - } - if (*str != 0) { - xmlCleanURI(uri); - return(1); - } - return(0); -} - -/** - * xmlParseURI: - * @str: the URI string to analyze - * - * Parse an URI - * - * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] - * - * Returns a newly built xmlURIPtr or NULL in case of error - */ -xmlURIPtr -xmlParseURI(const char *str) { - xmlURIPtr uri; - int ret; - - if (str == NULL) - return(NULL); - uri = xmlCreateURI(); - if (uri != NULL) { - ret = xmlParseURIReference(uri, str); - if (ret) { - xmlFreeURI(uri); - return(NULL); - } - } - return(uri); -} - -/** - * xmlParseURIRaw: - * @str: the URI string to analyze - * @raw: if 1 unescaping of URI pieces are disabled - * - * Parse an URI but allows to keep intact the original fragments. - * - * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] - * - * Returns a newly built xmlURIPtr or NULL in case of error - */ -xmlURIPtr -xmlParseURIRaw(const char *str, int raw) { - xmlURIPtr uri; - int ret; - - if (str == NULL) - return(NULL); - uri = xmlCreateURI(); - if (uri != NULL) { - if (raw) { - uri->cleanup |= 2; - } - ret = xmlParseURIReference(uri, str); - if (ret) { - xmlFreeURI(uri); - return(NULL); - } - } - return(uri); -} - -/************************************************************************ - * * * Public functions * * * ************************************************************************/ |