From: Daniel Stenberg Date: Thu, 16 Feb 2023 23:16:39 +0000 (+0100) Subject: urlapi: do the port number extraction without using sscanf() X-Git-Tag: curl-7_88_1~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b27799f8c5e51187533edb04c66dd9079e1c478;p=thirdparty%2Fcurl.git urlapi: do the port number extraction without using sscanf() - sscanf() is rather complex and slow, strchr() much simpler - the port number function does not need to fully verify the IPv6 address anyway as it is done later in the hostname_check() function and doing it twice is unnecessary. Closes #10541 --- diff --git a/lib/urlapi.c b/lib/urlapi.c index 4387e945df..29927b3d92 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -493,35 +493,21 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, bool has_scheme) { - char *portptr = NULL; - char endbracket; - int len; + char *portptr; char *hostname = Curl_dyn_ptr(host); /* * Find the end of an IPv6 address, either on the ']' ending bracket or * a percent-encoded zone index. */ - if(1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.]%c%n", - &endbracket, &len)) { - if(']' == endbracket) - portptr = &hostname[len]; - else if('%' == endbracket) { - int zonelen = len; - if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) { - if(']' != endbracket) - return CURLUE_BAD_IPV6; - portptr = &hostname[--zonelen + len + 1]; - } - else - return CURLUE_BAD_IPV6; - } - else + if(hostname[0] == '[') { + portptr = strchr(hostname, ']'); + if(!portptr) return CURLUE_BAD_IPV6; - + portptr++; /* this is a RFC2732-style specified IP-address */ - if(portptr && *portptr) { + if(*portptr) { if(*portptr != ':') - return CURLUE_BAD_IPV6; + return CURLUE_BAD_PORT_NUMBER; } else portptr = NULL; @@ -585,11 +571,9 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname, hostname++; hlen -= 2; - if(hostname[hlen] != ']') - return CURLUE_BAD_IPV6; - - /* only valid letters are ok */ + /* only valid IPv6 letters are ok */ len = strspn(hostname, l); + if(hlen != len) { hlen = len; if(hostname[len] == '%') { @@ -603,8 +587,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; + return CURLUE_BAD_IPV6; zoneid[i] = 0; u->zoneid = strdup(zoneid); if(!u->zoneid) diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 8b31cbdc94..d4eeef0e59 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -466,6 +466,12 @@ static const struct testcase get_parts_list[] ={ }; static const struct urltestcase get_url_list[] = { + {"https://[::%25fakeit];80/moo", + "", + 0, 0, CURLUE_BAD_PORT_NUMBER}, + {"https://[fe80::20c:29ff:fe9c:409b]-80/moo", + "", + 0, 0, CURLUE_BAD_PORT_NUMBER}, #ifdef USE_IDN {"https://räksmörgås.se/path?q#frag", "https://xn--rksmrgs-5wao1o.se/path?q#frag", 0, CURLU_PUNYCODE, CURLUE_OK}, @@ -658,11 +664,14 @@ static const struct urltestcase get_url_list[] = { {NULL, NULL, 0, 0, CURLUE_OK} }; -static int checkurl(const char *url, const char *out) +static int checkurl(const char *org, const char *url, const char *out) { if(strcmp(out, url)) { - fprintf(stderr, "Wanted: %s\nGot : %s\n", - out, url); + fprintf(stderr, + "Org: %s\n" + "Wanted: %s\n" + "Got : %s\n", + org, out, url); return 1; } return 0; @@ -967,7 +976,7 @@ static int set_url(void) error++; } else { - if(checkurl(url, set_url_list[i].out)) { + if(checkurl(set_url_list[i].in, url, set_url_list[i].out)) { error++; } } @@ -1020,7 +1029,7 @@ static int set_parts(void) __FILE__, __LINE__, (int)rc, curl_url_strerror(rc)); error++; } - else if(checkurl(url, set_parts_list[i].out)) { + else if(checkurl(set_parts_list[i].in, url, set_parts_list[i].out)) { error++; } } @@ -1060,7 +1069,7 @@ static int get_url(void) error++; } else { - if(checkurl(url, get_url_list[i].out)) { + if(checkurl(get_url_list[i].in, url, get_url_list[i].out)) { error++; } } @@ -1163,7 +1172,7 @@ static int append(void) error++; } else { - if(checkurl(url, append_list[i].out)) { + if(checkurl(append_list[i].in, url, append_list[i].out)) { error++; } curl_free(url); diff --git a/tests/unit/unit1653.c b/tests/unit/unit1653.c index 10ec3cfe64..cf848c6a32 100644 --- a/tests/unit/unit1653.c +++ b/tests/unit/unit1653.c @@ -92,11 +92,16 @@ UNITTEST_START u = curl_url(); if(!u) goto fail; - ipv6port = strdup("[fe80::250:56ff;fea7:da15]:80"); + ipv6port = strdup("[fe80::250:56ff;fea7:da15]:808"); if(!ipv6port) goto fail; ret = parse_port(u, ipv6port, FALSE); - fail_unless(ret != CURLUE_OK, "parse_port true on error"); + fail_unless(ret == CURLUE_OK, "parse_port returned error"); + ret = curl_url_get(u, CURLUPART_PORT, &portnum, 0); + fail_unless(ret == CURLUE_OK, "curl_url_get portnum returned error"); + fail_unless(portnum && !strcmp(portnum, "808"), "Check portnumber"); + + curl_free(portnum); free_and_clear(ipv6port); curl_url_cleanup(u); @@ -180,15 +185,19 @@ UNITTEST_START free_and_clear(ipv6port); curl_url_cleanup(u); - /* Incorrect zone index syntax */ + /* Incorrect zone index syntax, but the port extractor doesn't care */ u = curl_url(); if(!u) goto fail; - ipv6port = strdup("[fe80::250:56ff:fea7:da15!25eth3]:80"); + ipv6port = strdup("[fe80::250:56ff:fea7:da15!25eth3]:180"); if(!ipv6port) goto fail; ret = parse_port(u, ipv6port, FALSE); - fail_unless(ret != CURLUE_OK, "parse_port returned non-error"); + fail_unless(ret == CURLUE_OK, "parse_port returned error"); + ret = curl_url_get(u, CURLUPART_PORT, &portnum, 0); + fail_unless(ret == CURLUE_OK, "curl_url_get portnum returned error"); + fail_unless(portnum && !strcmp(portnum, "180"), "Check portnumber"); + curl_free(portnum); free_and_clear(ipv6port); curl_url_cleanup(u);