]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urlapi: do the port number extraction without using sscanf()
authorDaniel Stenberg <daniel@haxx.se>
Thu, 16 Feb 2023 23:16:39 +0000 (00:16 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 17 Feb 2023 15:21:26 +0000 (16:21 +0100)
- 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

lib/urlapi.c
tests/libtest/lib1560.c
tests/unit/unit1653.c

index 4387e945df45b540e7bb6f79b0dd47acdaa1b038..29927b3d92dd38ef53f2c0c80644af0a10f4b2a3 100644 (file)
@@ -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)
index 8b31cbdc94c77ae71939202e093f5e493da1fa3d..d4eeef0e594575884c4d9caee187fa004e4a8429 100644 (file)
@@ -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);
index 10ec3cfe6414c20655a1cb3af09833108a56f675..cf848c6a32de3429b1f22ce637833bacca2a5fcd 100644 (file)
@@ -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);