]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
urlapi: allow setting port number zero
authorDaniel Stenberg <daniel@haxx.se>
Fri, 19 Apr 2024 12:42:39 +0000 (14:42 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 19 Apr 2024 21:54:21 +0000 (23:54 +0200)
Also set and check errno when strtoul() parsing numbers for better error
checking.

Updated test 1560

Closes #13427

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

index 308bc2745ae28a09693488395ef56a32d4f6d2ae..8e8625d6f22e854b03cfa8c4445d23e6314ca88c 100644 (file)
@@ -79,7 +79,7 @@ struct Curl_URL {
   char *path;
   char *query;
   char *fragment;
-  unsigned short portnum; /* the numerical version */
+  unsigned short portnum; /* the numerical version (if 'port' is set) */
   BIT(query_present);    /* to support blank */
   BIT(fragment_present); /* to support blank */
 };
@@ -537,7 +537,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
 
   if(portptr) {
     char *rest = NULL;
-    long port;
+    unsigned long port;
     size_t keep = portptr - hostname;
 
     /* Browser behavior adaptation. If there's a colon with no digits after,
@@ -555,12 +555,10 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
     if(!ISDIGIT(*portptr))
       return CURLUE_BAD_PORT_NUMBER;
 
-    port = strtol(portptr, &rest, 10);  /* Port number must be decimal */
+    errno = 0;
+    port = strtoul(portptr, &rest, 10);  /* Port number must be decimal */
 
-    if(port > 0xffff)
-      return CURLUE_BAD_PORT_NUMBER;
-
-    if(rest[0])
+    if(errno || (port > 0xffff) || *rest)
       return CURLUE_BAD_PORT_NUMBER;
 
     u->portnum = (unsigned short) port;
@@ -685,6 +683,7 @@ static int ipv4_normalize(struct dynbuf *host)
   if(*c == '[')
     return HOST_IPV6;
 
+  errno = 0; /* for strtoul */
   while(!done) {
     char *endp = NULL;
     unsigned long l;
@@ -692,6 +691,13 @@ static int ipv4_normalize(struct dynbuf *host)
       /* most importantly this doesn't allow a leading plus or minus */
       return HOST_NAME;
     l = strtoul(c, &endp, 0);
+    if(errno)
+      return HOST_NAME;
+#if SIZEOF_LONG > 4
+    /* a value larger than 32 bits */
+    if(l > UINT_MAX)
+      return HOST_NAME;
+#endif
 
     parts[n] = l;
     c = endp;
@@ -711,16 +717,6 @@ static int ipv4_normalize(struct dynbuf *host)
     default:
       return HOST_NAME;
     }
-
-    /* overflow */
-    if((l == ULONG_MAX) && (errno == ERANGE))
-      return HOST_NAME;
-
-#if SIZEOF_LONG > 4
-    /* a value larger than 32 bits */
-    if(l > UINT_MAX)
-      return HOST_NAME;
-#endif
   }
 
   switch(n) {
@@ -1707,7 +1703,6 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
                        const char *part, unsigned int flags)
 {
   char **storep = NULL;
-  long port = 0;
   bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
   bool plusencode = FALSE;
   bool urlskipslash = FALSE;
@@ -1816,18 +1811,26 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
     storep = &u->zoneid;
     break;
   case CURLUPART_PORT:
-  {
-    char *endp;
-    urlencode = FALSE; /* never */
-    port = strtol(part, &endp, 10);  /* Port number must be decimal */
-    if((port <= 0) || (port > 0xffff))
+    if(!ISDIGIT(part[0]))
+      /* not a number */
       return CURLUE_BAD_PORT_NUMBER;
-    if(*endp)
-      /* weirdly provided number, not good! */
-      return CURLUE_BAD_PORT_NUMBER;
-    storep = &u->port;
-  }
-  break;
+    else {
+      char *tmp;
+      char *endp;
+      unsigned long port;
+      errno = 0;
+      port = strtoul(part, &endp, 10);  /* must be decimal */
+      if(errno || (port > 0xffff) || *endp)
+        /* weirdly provided number, not good! */
+        return CURLUE_BAD_PORT_NUMBER;
+      tmp = strdup(part);
+      if(!tmp)
+        return CURLUE_OUT_OF_MEMORY;
+      free(u->port);
+      u->port = tmp;
+      u->portnum = (unsigned short)port;
+      return CURLUE_OK;
+    }
   case CURLUPART_PATH:
     urlskipslash = TRUE;
     leadingslash = TRUE; /* enforce */
@@ -1990,9 +1993,5 @@ nomem:
     free(*storep);
     *storep = (char *)newp;
   }
-  /* set after the string, to make it not assigned if the allocation above
-     fails */
-  if(port)
-    u->portnum = (unsigned short)port;
   return CURLUE_OK;
 }
index 0a872e9496ebd37ac2b55df59fe74a088803b4ea..7e44de940dacae994ebbfd2c7bfe859b942446ea 100644 (file)
@@ -151,6 +151,9 @@ struct clearurlcase {
 };
 
 static const struct testcase get_parts_list[] ={
+  {"https://curl.se:0/#",
+   "https | [11] | [12] | [13] | curl.se | 0 | / | [16] | ",
+   0, CURLU_GET_EMPTY, CURLUE_OK},
   {"https://curl.se/#",
    "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | ",
    0, CURLU_GET_EMPTY, CURLUE_OK},
@@ -941,8 +944,8 @@ static const struct setcase set_parts_list[] = {
    0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
   {"https://host:1234/",
    "port=0,",
-   "https://host:1234/",
-   0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER},
+   "https://host:0/",
+   0, 0, CURLUE_OK, CURLUE_OK},
   {"https://host:1234/",
    "port=65535,",
    "https://host:65535/",