From 4183b8fe9a8558b8f62c9dbf8271deed75bff28b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 23 Nov 2021 17:07:31 +0100 Subject: urlapi: provide more detailed return codes Previously, the return code CURLUE_MALFORMED_INPUT was used for almost 30 different URL format violations. This made it hard for users to understand why a particular URL was not acceptable. Since the API cannot point out a specific position within the URL for the problem, this now instead introduces a number of additional and more fine-grained error codes to allow the API to return more exactly in what "part" or section of the URL a problem was detected. Also bug-fixes curl_url_get() with CURLUPART_ZONEID, which previously returned CURLUE_OK even if no zoneid existed. Test cases in 1560 have been adjusted and extended. Tests 1538 and 1559 have been updated. Updated libcurl-errors.3 and curl_url_strerror() accordingly. Closes #8049 --- docs/libcurl/libcurl-errors.3 | 26 +++++++- docs/libcurl/symbols-in-versions | 12 ++++ include/curl/urlapi.h | 12 ++++ lib/strerror.c | 56 +++++++++++++--- lib/urlapi.c | 136 +++++++++++++++++++++++---------------- tests/data/test1538 | 34 ++++++---- tests/data/test1559 | 6 +- tests/libtest/lib1560.c | 118 ++++++++++++++++++++++++--------- 8 files changed, 289 insertions(+), 111 deletions(-) diff --git a/docs/libcurl/libcurl-errors.3 b/docs/libcurl/libcurl-errors.3 index b124e447c..4b4d24fd7 100644 --- a/docs/libcurl/libcurl-errors.3 +++ b/docs/libcurl/libcurl-errors.3 @@ -20,7 +20,7 @@ .\" * .\" ************************************************************************** .\" -.TH libcurl-errors 3 "1 Jan 2010" "libcurl 7.20.0" "libcurl errors" +.TH libcurl-errors 3 "23 Nov 2021" "libcurl 7.81.0" "libcurl errors" .SH NAME libcurl-errors \- error codes in libcurl .SH DESCRIPTION @@ -361,6 +361,30 @@ There is no port part in the URL. There is no query part in the URL. .IP "CURLUE_NO_FRAGMENT (17)" There is no fragment part in the URL. +.IP "CURLUE_NO_ZONEID (18)" +There is no zoneid set in the URL. +.IP "CURLUE_BAD_FILE_URL (19)" +The file:// URL is invalid. +.IP "CURLUE_BAD_FRAGMENT (20)" +The fragment part of the URL contained bad or invalid characters. +.IP "CURLUE_BAD_HOSTNAME (21)" +The hostname contained bad or invalid characters. +.IP "CURLUE_BAD_IPV6 (22)" +The IPv6 address hostname contained bad or invalid characters. +.IP "CURLUE_BAD_LOGIN (23)" +The login part of the URL contained bad or invalid characters. +.IP "CURLUE_BAD_PASSWORD (24)" +The password part of the URL contained bad or invalid characters. +.IP "CURLUE_BAD_PATH (25)" +The path part of the URL contained bad or invalid characters. +.IP "CURLUE_BAD_QUERY (26)" +The query part of the URL contained bad or invalid characters. +.IP "CURLUE_BAD_SCHEME (27)" +The scheme part of the URL contained bad or invalid characters. +.IP "CURLUE_BAD_SLASHES (28)" +The URL contained an invalid number of slashes. +.IP "CURLUE_BAD_USER (29)" +The user part of the URL contained bad or invalid characters. .SH "SEE ALSO" .BR curl_easy_strerror "(3), " curl_multi_strerror "(3), " .BR curl_share_strerror "(3), " curl_url_strerror "(3), " diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 791834d6e..feec675fe 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -838,9 +838,20 @@ CURLSSLSET_UNKNOWN_BACKEND 7.56.0 CURLSTS_DONE 7.74.0 CURLSTS_FAIL 7.74.0 CURLSTS_OK 7.74.0 +CURLUE_BAD_FILE_URL 7.81.0 +CURLUE_BAD_FRAGMENT 7.81.0 CURLUE_BAD_HANDLE 7.62.0 +CURLUE_BAD_HOSTNAME 7.81.0 +CURLUE_BAD_IPV6 7.81.0 +CURLUE_BAD_LOGIN 7.81.0 CURLUE_BAD_PARTPOINTER 7.62.0 +CURLUE_BAD_PASSWORD 7.81.0 +CURLUE_BAD_PATH 7.81.0 CURLUE_BAD_PORT_NUMBER 7.62.0 +CURLUE_BAD_QUERY 7.81.0 +CURLUE_BAD_SCHEME 7.81.0 +CURLUE_BAD_SLASHES 7.81.0 +CURLUE_BAD_USER 7.81.0 CURLUE_MALFORMED_INPUT 7.62.0 CURLUE_NO_FRAGMENT 7.62.0 CURLUE_NO_HOST 7.62.0 @@ -850,6 +861,7 @@ CURLUE_NO_PORT 7.62.0 CURLUE_NO_QUERY 7.62.0 CURLUE_NO_SCHEME 7.62.0 CURLUE_NO_USER 7.62.0 +CURLUE_NO_ZONEID 7.81.0 CURLUE_OK 7.62.0 CURLUE_OUT_OF_MEMORY 7.62.0 CURLUE_UNKNOWN_PART 7.62.0 diff --git a/include/curl/urlapi.h b/include/curl/urlapi.h index 3c4b4e18a..a475f91b6 100644 --- a/include/curl/urlapi.h +++ b/include/curl/urlapi.h @@ -48,6 +48,18 @@ typedef enum { CURLUE_NO_PORT, /* 15 */ CURLUE_NO_QUERY, /* 16 */ CURLUE_NO_FRAGMENT, /* 17 */ + CURLUE_NO_ZONEID, /* 18 */ + CURLUE_BAD_FILE_URL, /* 19 */ + CURLUE_BAD_FRAGMENT, /* 20 */ + CURLUE_BAD_HOSTNAME, /* 21 */ + CURLUE_BAD_IPV6, /* 22 */ + CURLUE_BAD_LOGIN, /* 23 */ + CURLUE_BAD_PASSWORD, /* 24 */ + CURLUE_BAD_PATH, /* 25 */ + CURLUE_BAD_QUERY, /* 26 */ + CURLUE_BAD_SCHEME, /* 27 */ + CURLUE_BAD_SLASHES, /* 28 */ + CURLUE_BAD_USER, /* 29 */ CURLUE_LAST } CURLUcode; diff --git a/lib/strerror.c b/lib/strerror.c index 31eb2bf79..b8ab0abbc 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -468,10 +468,10 @@ curl_url_strerror(CURLUcode error) return "An invalid 'part' argument was passed as argument"; case CURLUE_MALFORMED_INPUT: - return "A malformed input was passed to a URL API function"; + return "Malformed input to a URL function"; case CURLUE_BAD_PORT_NUMBER: - return "The port number was not a decimal number between 0 and 65535"; + return "Port number was not a decimal number between 0 and 65535"; case CURLUE_UNSUPPORTED_SCHEME: return "This libcurl build doesn't support the given URL scheme"; @@ -489,28 +489,64 @@ curl_url_strerror(CURLUcode error) return "An unknown part ID was passed to a URL API function"; case CURLUE_NO_SCHEME: - return "There is no scheme part in the URL"; + return "No scheme part in the URL"; case CURLUE_NO_USER: - return "There is no user part in the URL"; + return "No user part in the URL"; case CURLUE_NO_PASSWORD: - return "There is no password part in the URL"; + return "No password part in the URL"; case CURLUE_NO_OPTIONS: - return "There is no options part in the URL"; + return "No options part in the URL"; case CURLUE_NO_HOST: - return "There is no host part in the URL"; + return "No host part in the URL"; case CURLUE_NO_PORT: - return "There is no port part in the URL"; + return "No port part in the URL"; case CURLUE_NO_QUERY: - return "There is no query part in the URL"; + return "No query part in the URL"; case CURLUE_NO_FRAGMENT: - return "There is no fragment part in the URL"; + return "No fragment part in the URL"; + + case CURLUE_NO_ZONEID: + return "No zoneid part in the URL"; + + case CURLUE_BAD_LOGIN: + return "Bad login part"; + + case CURLUE_BAD_IPV6: + return "Bad IPv6 address"; + + case CURLUE_BAD_HOSTNAME: + return "Bad hostname"; + + case CURLUE_BAD_FILE_URL: + return "Bad file:// URL"; + + case CURLUE_BAD_SLASHES: + return "Unsupported number of slashes"; + + case CURLUE_BAD_SCHEME: + return "Bad scheme"; + + case CURLUE_BAD_PATH: + return "Bad path"; + + case CURLUE_BAD_FRAGMENT: + return "Bad fragment"; + + case CURLUE_BAD_QUERY: + return "Bad query"; + + case CURLUE_BAD_PASSWORD: + return "Bad password"; + + case CURLUE_BAD_USER: + return "Bad user"; case CURLUE_LAST: break; diff --git a/lib/urlapi.c b/lib/urlapi.c index 6963a805b..372ffe50a 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -428,6 +428,29 @@ static char *concat_url(const char *base, const char *relurl) return newest; } +/* scan for byte values < 31 or 127 */ +static bool junkscan(const char *part, unsigned int flags) +{ + if(part) { + static const char badbytes[]={ + /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x7f, 0x00 /* null-terminate */ + }; + size_t n = strlen(part); + size_t nfine = strcspn(part, badbytes); + if(nfine != n) + /* since we don't know which part is scanned, return a generic error + code */ + return TRUE; + if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' ')) + return TRUE; + } + return FALSE; +} + /* * parse_hostname_login() * @@ -475,7 +498,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, (h && (h->flags & PROTOPT_URLOPTIONS)) ? &optionsp:NULL); if(ccode) { - result = CURLUE_MALFORMED_INPUT; + result = CURLUE_BAD_LOGIN; goto out; } @@ -485,15 +508,28 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, result = CURLUE_USER_NOT_ALLOWED; goto out; } - + if(junkscan(userp, flags)) { + result = CURLUE_BAD_USER; + goto out; + } u->user = userp; } - if(passwdp) + if(passwdp) { + if(junkscan(passwdp, flags)) { + result = CURLUE_BAD_PASSWORD; + goto out; + } u->password = passwdp; + } - if(optionsp) + if(optionsp) { + if(junkscan(optionsp, flags)) { + result = CURLUE_BAD_LOGIN; + goto out; + } u->options = optionsp; + } return CURLUE_OK; out: @@ -501,6 +537,9 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, free(userp); free(passwdp); free(optionsp); + u->user = NULL; + u->password = NULL; + u->options = NULL; return result; } @@ -524,19 +563,19 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, int zonelen = len; if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) { if(']' != endbracket) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; portptr = &hostname[--zonelen + len + 1]; } else - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; } else - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; /* this is a RFC2732-style specified IP-address */ if(portptr && *portptr) { if(*portptr != ':') - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; } else portptr = NULL; @@ -587,29 +626,6 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, return CURLUE_OK; } -/* scan for byte values < 31 or 127 */ -static bool junkscan(const char *part, unsigned int flags) -{ - if(part) { - static const char badbytes[]={ - /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x7f, 0x00 /* null-terminate */ - }; - size_t n = strlen(part); - size_t nfine = strcspn(part, badbytes); - if(nfine != n) - /* since we don't know which part is scanned, return a generic error - code */ - return TRUE; - if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' ')) - return TRUE; - } - return FALSE; -} - static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) { size_t len; @@ -621,12 +637,12 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) #endif const char *l = "0123456789abcdefABCDEF:."; if(hlen < 4) /* '[::]' is the shortest possible valid string */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; hostname++; hlen -= 2; if(hostname[hlen] != ']') - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; /* only valid letters are ok */ len = strspn(hostname, l); @@ -643,6 +659,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) while(*h && (*h != ']') && (i < 15)) zoneid[i++] = *h++; if(!i || (']' != *h)) + /* impossible to reach? */ return CURLUE_MALFORMED_INPUT; zoneid[i] = 0; u->zoneid = strdup(zoneid); @@ -652,13 +669,13 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) hostname[len + 1] = 0; /* terminate the hostname */ } else - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; /* hostname is fine */ } #ifdef ENABLE_IPV6 hostname[hlen] = 0; /* end the address there */ if(1 != Curl_inet_pton(AF_INET6, hostname, dest)) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_IPV6; hostname[hlen] = ']'; /* restore ending bracket */ #endif } @@ -667,7 +684,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) len = strcspn(hostname, " \r\n"); if(hlen != len) /* hostname with bad content */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; } if(!hostname[0]) return CURLUE_NO_HOST; @@ -782,7 +799,7 @@ static CURLUcode decode_host(char *hostname, char **outp) CURLcode result = Curl_urldecode(NULL, hostname, 0, outp, &dlen, REJECT_CTRL); if(result) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; } return CURLUE_OK; @@ -830,7 +847,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(url_has_scheme && !strcmp(schemebuf, "file")) { if(urllen <= 6) /* file:/ is not enough to actually be a complete file: URL */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; /* path has been allocated large enough to hold this */ strcpy(path, &url[5]); @@ -884,7 +901,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) host name */ path = strpbrk(ptr, "/\\:*?\"<>|"); if(!path || *path != '/') - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; len = path - ptr; if(len) { @@ -897,7 +914,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) #else /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; #endif } } @@ -914,7 +931,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) || STARTS_WITH_URL_DRIVE_PREFIX(path)) { /* File drive letters are only accepted in MSDOS/Windows */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_FILE_URL; } #else /* If the path starts with a slash and a drive letter, ditch the slash */ @@ -941,7 +958,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } if((i < 1) || (i>3)) /* less than one or more than three slashes */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SLASHES; schemep = schemebuf; if(!Curl_builtin_scheme(schemep) && @@ -949,13 +966,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) return CURLUE_UNSUPPORTED_SCHEME; if(junkscan(schemep, flags)) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SCHEME; } else { /* no scheme! */ if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SCHEME; if(flags & CURLU_DEFAULT_SCHEME) schemep = DEFAULT_SCHEME; @@ -966,7 +983,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } hostp = p; /* host name starts here */ - while(*p && !HOSTNAME_END(*p)) /* find end of host name */ + /* find the end of the host name + port number */ + while(*p && !HOSTNAME_END(*p)) p++; len = p - hostp; @@ -976,7 +994,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } else { if(!(flags & CURLU_NO_AUTHORITY)) - return CURLUE_MALFORMED_INPUT; + return CURLUE_NO_HOST; } len = strlen(p); @@ -990,9 +1008,6 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } } - if(junkscan(path, flags)) - return CURLUE_MALFORMED_INPUT; - if((flags & CURLU_URLENCODE) && path[0]) { /* worst case output length is 3x the original! */ char *newp = malloc(strlen(path) * 3); @@ -1006,6 +1021,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) fragment = strchr(path, '#'); if(fragment) { *fragment++ = 0; + if(junkscan(fragment, flags)) + return CURLUE_BAD_FRAGMENT; if(fragment[0]) { u->fragment = strdup(fragment); if(!u->fragment) @@ -1016,12 +1033,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) query = strchr(path, '?'); if(query) { *query++ = 0; + if(junkscan(query, flags)) + return CURLUE_BAD_QUERY; /* done even if the query part is a blank string */ u->query = strdup(query); if(!u->query) return CURLUE_OUT_OF_MEMORY; } + if(junkscan(path, flags)) + return CURLUE_BAD_PATH; + if(!path[0]) /* if there's no path left set, unset */ path = NULL; @@ -1051,12 +1073,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(hostname) { char normalized_ipv4[sizeof("255.255.255.255") + 1]; + /* * Parse the login details and strip them out of the host name. */ - if(junkscan(hostname, flags)) - return CURLUE_MALFORMED_INPUT; - result = parse_hostname_login(u, &hostname, flags); if(result) return result; @@ -1065,6 +1085,9 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(result) return result; + if(junkscan(hostname, flags)) + return CURLUE_BAD_HOSTNAME; + if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ u->host = strdup(""); @@ -1210,6 +1233,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, break; case CURLUPART_ZONEID: ptr = u->zoneid; + ifmissing = CURLUE_NO_ZONEID; break; case CURLUPART_PORT: ptr = u->port; @@ -1467,7 +1491,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, case CURLUPART_SCHEME: if(strlen(part) > MAX_SCHEME_LEN) /* too long */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_SCHEME; if(!(flags & CURLU_NON_SUPPORT_SCHEME) && /* verify that it is a fine scheme */ !Curl_builtin_scheme(part)) @@ -1488,7 +1512,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, size_t len = strcspn(part, " \r\n"); if(strlen(part) != len) /* hostname with bad content */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; storep = &u->host; Curl_safefree(u->zoneid); break; @@ -1505,7 +1529,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_BAD_PORT_NUMBER; if(*endp) /* weirdly provided number, not good! */ - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_PORT_NUMBER; storep = &u->port; } break; @@ -1669,7 +1693,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, else { if(hostname_check(u, (char *)newp)) { free((char *)newp); - return CURLUE_MALFORMED_INPUT; + return CURLUE_BAD_HOSTNAME; } } } diff --git a/tests/data/test1538 b/tests/data/test1538 index 1e5287fe1..06810d42a 100644 --- a/tests/data/test1538 +++ b/tests/data/test1538 @@ -155,22 +155,34 @@ s6: CURLSHcode unknown u0: No error u1: An invalid CURLU pointer was passed as argument u2: An invalid 'part' argument was passed as argument -u3: A malformed input was passed to a URL API function -u4: The port number was not a decimal number between 0 and 65535 +u3: Malformed input to a URL function +u4: Port number was not a decimal number between 0 and 65535 u5: This libcurl build doesn't support the given URL scheme u6: URL decode error, most likely because of rubbish in the input u7: A memory function failed u8: Credentials was passed in the URL when prohibited u9: An unknown part ID was passed to a URL API function -u10: There is no scheme part in the URL -u11: There is no user part in the URL -u12: There is no password part in the URL -u13: There is no options part in the URL -u14: There is no host part in the URL -u15: There is no port part in the URL -u16: There is no query part in the URL -u17: There is no fragment part in the URL -u18: CURLUcode unknown +u10: No scheme part in the URL +u11: No user part in the URL +u12: No password part in the URL +u13: No options part in the URL +u14: No host part in the URL +u15: No port part in the URL +u16: No query part in the URL +u17: No fragment part in the URL +u18: No zoneid part in the URL +u19: Bad file:// URL +u20: Bad fragment +u21: Bad hostname +u22: Bad IPv6 address +u23: Bad login part +u24: Bad password +u25: Bad path +u26: Bad query +u27: Bad scheme +u28: Unsupported number of slashes +u29: Bad user +u30: CURLUcode unknown diff --git a/tests/data/test1559 b/tests/data/test1559 index 6366afb51..e62b073f4 100644 --- a/tests/data/test1559 +++ b/tests/data/test1559 @@ -35,9 +35,9 @@ Set excessive URL lengths CURLOPT_URL 10000000 bytes URL == 43 CURLOPT_POSTFIELDS 10000000 bytes data == 0 -CURLUPART_URL 10000000 bytes URL == 3 (A malformed input was passed to a URL API function) -CURLUPART_SCHEME 10000000 bytes scheme == 3 (A malformed input was passed to a URL API function) -CURLUPART_USER 10000000 bytes user == 3 (A malformed input was passed to a URL API function) +CURLUPART_URL 10000000 bytes URL == 3 (Malformed input to a URL function) +CURLUPART_SCHEME 10000000 bytes scheme == 27 (Bad scheme) +CURLUPART_USER 10000000 bytes user == 3 (Malformed input to a URL function) diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 1cc1a60ec..f09454c45 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -129,17 +129,21 @@ struct querycase { }; static const struct testcase get_parts_list[] ={ + {"https://user:password@example.net/get?this=and#but frag then", "", + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_FRAGMENT}, {"https://user:password@example.net/get?this=and what", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_QUERY}, {"https://user:password@example.net/ge t?this=and-what", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PATH}, {"https://user:pass word@example.net/get?this=and-what", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_PASSWORD}, {"https://u ser:password@example.net/get?this=and-what", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_USER}, + {"imap://user:pass;opt ion@server/path", "", + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_LOGIN}, /* no space allowed in scheme */ {"htt ps://user:password@example.net/get?this=and-what", "", - CURLU_NON_SUPPORT_SCHEME|CURLU_ALLOW_SPACE, 0, CURLUE_MALFORMED_INPUT}, + CURLU_NON_SUPPORT_SCHEME|CURLU_ALLOW_SPACE, 0, CURLUE_BAD_SCHEME}, {"https://user:password@example.net/get?this=and what", "https | user | password | [13] | example.net | [15] | /get | " "this=and what | [17]", @@ -213,9 +217,9 @@ static const struct testcase get_parts_list[] ={ "com/color/?green#no-red", CURLU_DEFAULT_SCHEME, 0, CURLUE_OK }, {"http://[ab.be:1]/x", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_IPV6}, {"http://[ab.be]/x", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_IPV6}, /* URL without host name */ {"http://a:b@/x", "", CURLU_DEFAULT_SCHEME, 0, CURLUE_NO_HOST}, @@ -254,7 +258,7 @@ static const struct testcase get_parts_list[] ={ 0, 0, CURLUE_OK}, {"file://hello.html", "", - 0, 0, CURLUE_MALFORMED_INPUT}, + 0, 0, CURLUE_BAD_FILE_URL}, {"http://HO0_-st/", "http | [11] | [12] | [13] | HO0_-st | [15] | / | [16] | [17]", 0, 0, CURLUE_OK}, @@ -272,7 +276,7 @@ static const struct testcase get_parts_list[] ={ 0, 0, CURLUE_OK}, {"file:/", "file | [11] | [12] | [13] | [14] | [15] | | [16] | [17]", - 0, 0, CURLUE_MALFORMED_INPUT}, + 0, 0, CURLUE_BAD_FILE_URL}, {"file://127.0.0.1/hello.html", "file | [11] | [12] | [13] | [14] | [15] | /hello.html | [16] | [17]", 0, 0, CURLUE_OK}, @@ -295,9 +299,9 @@ static const struct testcase get_parts_list[] ={ "https | [11] | [12] | [13] | 127abc.com | [15] | / | [16] | [17]", CURLU_DEFAULT_SCHEME, 0, CURLUE_OK}, {"https:// example.com?check", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_HOSTNAME}, {"https://e x a m p l e.com?check", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_HOSTNAME}, {"https://example.com?check", "https | [11] | [12] | [13] | example.com | [15] | / | check | [17]", CURLU_DEFAULT_SCHEME, 0, CURLUE_OK}, @@ -357,7 +361,7 @@ static const struct testcase get_parts_list[] ={ CURLU_DEFAULT_SCHEME, 0, CURLUE_OK}, {"http:////user:password@example.com:1234/path/html?query=name#anchor", "", - CURLU_DEFAULT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_SLASHES}, {NULL, NULL, 0, 0, CURLUE_OK}, }; @@ -367,8 +371,8 @@ static const struct urltestcase get_url_list[] = { {"https://h%c", "https://h%25c/", 0, 0, CURLUE_OK}, {"https://%%%%%%", "https://%25%25%25%25%25%25/", 0, 0, CURLUE_OK}, {"https://%41", "https://A/", 0, 0, CURLUE_OK}, - {"https://%20", "", 0, 0, CURLUE_MALFORMED_INPUT}, - {"https://%41%0d", "", 0, 0, CURLUE_MALFORMED_INPUT}, + {"https://%20", "", 0, 0, CURLUE_BAD_HOSTNAME}, + {"https://%41%0d", "", 0, 0, CURLUE_BAD_HOSTNAME}, {"https://%25", "https://%25/", 0, 0, CURLUE_OK}, {"https://_%c0_", "https://_\xC0_/", 0, 0, CURLUE_OK}, {"https://_%c0_", "https://_%C0_/", 0, CURLU_URLENCODE, CURLUE_OK}, @@ -385,7 +389,7 @@ static const struct urltestcase get_url_list[] = { {"https://+127.0.0.1", "https://%2B127.0.0.1/", 0, CURLU_URLENCODE, CURLUE_OK}, {"https://127.-0.0.1", "https://127.-0.0.1/", 0, 0, CURLUE_OK}, - {"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_MALFORMED_INPUT}, + {"https://127.0. 1", "https://127.0.0.1/", 0, 0, CURLUE_BAD_HOSTNAME}, {"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_OK}, {"https://1.2.3.256", "https://1.2.3.256/", 0, 0, CURLUE_OK}, {"https://1.2.3.4.5", "https://1.2.3.4.5/", 0, 0, CURLUE_OK}, @@ -398,10 +402,10 @@ static const struct urltestcase get_url_list[] = { /* 41 bytes scheme is not allowed */ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA://hostname/path", "", - CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_BAD_SCHEME}, {"https://[fe80::20c:29ff:fe9c:409b%]:1234", "", - 0, 0, CURLUE_MALFORMED_INPUT}, + 0, 0, CURLUE_BAD_IPV6}, {"https://[fe80::20c:29ff:fe9c:409b%25]:1234", "https://[fe80::20c:29ff:fe9c:409b%2525]:1234/", 0, 0, CURLUE_OK}, @@ -437,14 +441,14 @@ static const struct urltestcase get_url_list[] = { CURLU_GUESS_SCHEME, 0, CURLUE_OK}, {"HTTP://test/", "http://test/", 0, 0, CURLUE_OK}, {"http://HO0_-st..~./", "http://HO0_-st..~./", 0, 0, CURLUE_OK}, - {"http:/@example.com: 123/", "", 0, 0, CURLUE_MALFORMED_INPUT}, - {"http:/@example.com:123 /", "", 0, 0, CURLUE_MALFORMED_INPUT}, + {"http:/@example.com: 123/", "", 0, 0, CURLUE_BAD_PORT_NUMBER}, + {"http:/@example.com:123 /", "", 0, 0, CURLUE_BAD_PORT_NUMBER}, {"http:/@example.com:123a/", "", 0, 0, CURLUE_BAD_PORT_NUMBER}, - {"http://host/file\r", "", 0, 0, CURLUE_MALFORMED_INPUT}, - {"http://host/file\n\x03", "", 0, 0, CURLUE_MALFORMED_INPUT}, + {"http://host/file\r", "", 0, 0, CURLUE_BAD_PATH}, + {"http://host/file\n\x03", "", 0, 0, CURLUE_BAD_PATH}, {"htt\x02://host/file", "", - CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, - {" http://host/file", "", 0, 0, CURLUE_MALFORMED_INPUT}, + CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_BAD_SCHEME}, + {" http://host/file", "", 0, 0, CURLUE_BAD_SCHEME}, /* here the password ends at the semicolon and options is 'word' */ {"imap://user:pass;word@host/file", "imap://user:pass;word@host/file", @@ -464,7 +468,7 @@ static const struct urltestcase get_url_list[] = { 0, 0, CURLUE_OK}, {"file:./", "file://", - 0, 0, CURLUE_MALFORMED_INPUT}, + 0, 0, CURLUE_BAD_SCHEME}, {"http://example.com/hello/../here", "http://example.com/hello/../here", CURLU_PATH_AS_IS, 0, CURLUE_OK}, @@ -500,7 +504,7 @@ static const struct urltestcase get_url_list[] = { CURLU_DEFAULT_SCHEME, 0, CURLUE_OK}, {"example.com/path/html", "", - 0, 0, CURLUE_MALFORMED_INPUT}, + 0, 0, CURLUE_BAD_SCHEME}, {"http://user:password@example.com:1234/path/html?query=name#anchor", "http://user:password@example.com:1234/path/html?query=name#anchor", 0, 0, CURLUE_OK}, @@ -524,7 +528,7 @@ static const struct urltestcase get_url_list[] = { CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_OK}, {"custom-scheme://?expected=test-bad", "", - CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_MALFORMED_INPUT}, + CURLU_NON_SUPPORT_SCHEME, 0, CURLUE_NO_HOST}, {"custom-scheme://?expected=test-new-good", "custom-scheme:///?expected=test-new-good", CURLU_NON_SUPPORT_SCHEME | CURLU_NO_AUTHORITY, 0, CURLUE_OK}, @@ -565,7 +569,7 @@ static const struct setcase set_parts_list[] = { /* Set a 41 bytes scheme. That's too long so the old scheme remains set. */ "scheme=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbc,", "https://example.com/", - 0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_MALFORMED_INPUT}, + 0, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, CURLUE_BAD_SCHEME}, {"https://example.com/", /* set a 40 bytes scheme */ "scheme=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,", @@ -586,7 +590,7 @@ static const struct setcase set_parts_list[] = { {"https://host:1234/", "port=56 78,", "https://host:1234/", - 0, 0, CURLUE_OK, CURLUE_MALFORMED_INPUT}, + 0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER}, {"https://host:1234/", "port=0,", "https://host:1234/", @@ -619,7 +623,7 @@ static const struct setcase set_parts_list[] = { {NULL, "scheme=https,host= ,path= ,user= ,password= ,query= ,fragment= ,", "[nothing]", - 0, CURLU_URLENCODE, CURLUE_OK, CURLUE_MALFORMED_INPUT}, + 0, CURLU_URLENCODE, CURLUE_OK, CURLUE_BAD_HOSTNAME}, {NULL, "scheme=https,host=foobar,path=/this /path /is /here,", "https://foobar/this%20/path%20/is%20/here", @@ -688,7 +692,7 @@ static const struct setcase set_parts_list[] = { "host=\"\",", "custom-scheme://host/", CURLU_NON_SUPPORT_SCHEME, CURLU_NON_SUPPORT_SCHEME, CURLUE_OK, - CURLUE_MALFORMED_INPUT}, + CURLUE_BAD_HOSTNAME}, {"custom-scheme://host", "host=\"\",", "custom-scheme:///", @@ -1164,10 +1168,64 @@ static int scopeid(void) return error; } +static int get_nothing(void) +{ + CURLU *u = curl_url(); + if(u) { + char *p; + CURLUcode rc; + + rc = curl_url_get(u, CURLUPART_SCHEME, &p, 0); + if(rc != CURLUE_NO_SCHEME) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_HOST, &p, 0); + if(rc != CURLUE_NO_HOST) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_USER, &p, 0); + if(rc != CURLUE_NO_USER) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_PASSWORD, &p, 0); + if(rc != CURLUE_NO_PASSWORD) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_OPTIONS, &p, 0); + if(rc != CURLUE_NO_OPTIONS) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_PATH, &p, 0); + if(rc != CURLUE_OK) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + else + curl_free(p); + + rc = curl_url_get(u, CURLUPART_QUERY, &p, 0); + if(rc != CURLUE_NO_QUERY) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_FRAGMENT, &p, 0); + if(rc != CURLUE_NO_FRAGMENT) + fprintf(stderr, "unexpected return code line %u\n", __LINE__); + + rc = curl_url_get(u, CURLUPART_ZONEID, &p, 0); + if(rc != CURLUE_OK) + fprintf(stderr, "unexpected return code %u on line %u\n", (int)rc, + __LINE__); + + curl_url_cleanup(u); + } + return 0; +} + int test(char *URL) { (void)URL; /* not used */ + if(get_nothing()) + return 7; + if(scopeid()) return 6; -- cgit v1.2.1