]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
lib: use Curl_str_number() for parsing decimal numbers
authorDaniel Stenberg <daniel@haxx.se>
Thu, 13 Feb 2025 07:45:43 +0000 (08:45 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 14 Feb 2025 09:38:56 +0000 (10:38 +0100)
Instead of strtoul() and strtol() calls.

Easier API with better integer overflow detection and built-in max check
that now comes automatic everywhere this is used.

Closes #16319

16 files changed:
lib/altsvc.c
lib/cf-socket.c
lib/ftp.c
lib/ftplistparser.c
lib/hostip.c
lib/imap.c
lib/parsedate.c
lib/pingpong.h
lib/pop3.c
lib/rtsp.c
lib/smtp.c
lib/telnet.c
lib/tftp.c
lib/url.c
lib/urlapi.c
tests/data/test1664

index e269079388b2193eb575b1b4ec2befe5f76beebe..a958ea58117b050f28e2ea42a9b16b1948092e17 100644 (file)
@@ -528,8 +528,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
         size_t dstlen = 0; /* destination hostname length */
         const char *value_ptr;
         char option[32];
-        unsigned long num;
-        char *end_ptr;
+        size_t num;
         bool quoted = FALSE;
         time_t maxage = 24 * 3600; /* default is 24 hours */
         bool persist = FALSE;
@@ -567,21 +566,14 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
           dstlen = strlen(srchost);
         }
         if(*p == ':') {
-          unsigned long port = 0;
+          size_t port = 0;
           p++;
-          if(ISDIGIT(*p))
-            /* a port number */
-            port = strtoul(p, &end_ptr, 10);
-          else
-            end_ptr = (char *)p; /* not left uninitialized */
-          if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
+          if(Curl_str_number(&p, &port, 0xffff) || (*p != '\"')) {
             infof(data, "Unknown alt-svc port number, ignoring.");
             valid = FALSE;
           }
-          else {
-            dstport = curlx_ultous(port);
-            p = end_ptr;
-          }
+          else
+            dstport = (unsigned short)port;
         }
         if(*p++ != '\"')
           break;
@@ -625,8 +617,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
             while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
               p++;
           }
-          num = strtoul(value_ptr, &end_ptr, 10);
-          if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
+          if(!Curl_str_number(&value_ptr, &num, SIZE_T_MAX)) {
             if(strcasecompare("ma", option))
               maxage = (time_t)num;
             else if(strcasecompare("persist", option) && (num == 1))
index 6250d46499cadcd2dcb7772ec79367c29a2074f6..b7262b19e9e3db935b5b145f88e76a9d85df88b8 100644 (file)
@@ -83,6 +83,7 @@
 #include "share.h"
 #include "strdup.h"
 #include "version_win32.h"
+#include "strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -741,10 +742,9 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
                Curl_printable_address. The latter returns only numeric scope
                IDs and the former returns none at all. So the scope ID, if
                present, is known to be numeric */
-            unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
-            if(scope_id > UINT_MAX)
+            size_t scope_id;
+            if(Curl_str_number((const char **)&scope_ptr, &scope_id, UINT_MAX))
               return CURLE_UNSUPPORTED_PROTOCOL;
-
             si6->sin6_scope_id = (unsigned int)scope_id;
           }
 #endif
index 6c6a20704f0244841bde7227d150b3ed7dbd2b8a..2210d8145f866ddcd079bed8620508a822336d59 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -73,6 +73,7 @@
 #include "http_proxy.h"
 #include "socks.h"
 #include "strdup.h"
+#include "strparse.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -464,7 +465,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data)
   if(response) {
     infof(data, "Ctrl conn has data while waiting for data conn");
     if(pp->overflow > 3) {
-      char *r = Curl_dyn_ptr(&pp->recvbuf);
+      const char *r = Curl_dyn_ptr(&pp->recvbuf);
 
       DEBUGASSERT((pp->overflow + pp->nfinal) <=
                   Curl_dyn_len(&pp->recvbuf));
@@ -472,8 +473,8 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data)
       r += pp->nfinal;
 
       if(LASTLINE(r)) {
-        int status = curlx_sltosi(strtol(r, NULL, 10));
-        if(status == 226) {
+        size_t status;
+        if(!Curl_str_number(&r, &status, 999) && (status == 226)) {
           /* funny timing situation where we get the final message on the
              control connection before traffic on the data connection has been
              noticed. Leave the 226 in there and use this as a trigger to read
@@ -541,13 +542,14 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
 }
 
 static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
-                          char *line, size_t len, int *code)
+                          const char *line, size_t len, int *code)
 {
+  size_t status;
   (void)data;
   (void)conn;
 
-  if((len > 3) && LASTLINE(line)) {
-    *code = curlx_sltosi(strtol(line, NULL, 10));
+  if((len > 3) && LASTLINE(line) && !Curl_str_number(&line, &status, 999)) {
+    *code = (int)status;
     return TRUE;
   }
 
@@ -925,13 +927,20 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
 
     /* parse the port */
     if(ip_end) {
-      char *port_sep = NULL;
-      char *port_start = strchr(ip_end, ':');
-      if(port_start) {
-        port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
-        port_sep = strchr(port_start, '-');
-        if(port_sep) {
-          port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
+      const char *portp = strchr(ip_end, ':');
+      if(portp) {
+        size_t start;
+        size_t end;
+        portp++;
+        if(!Curl_str_number(&portp, &start, 0xffff)) {
+          /* got the first number */
+          port_min = (unsigned short)start;
+          if(!Curl_str_single(&portp, '-')) {
+            /* got the dash */
+            if(!Curl_str_number(&portp, &end, 0xffff))
+              /* got the second number */
+              port_max = (unsigned short)end;
+          }
         }
         else
           port_max = port_min;
@@ -1758,20 +1767,15 @@ static bool match_pasv_6nums(const char *p,
 {
   int i;
   for(i = 0; i < 6; i++) {
-    unsigned long num;
-    char *endp;
+    size_t num;
     if(i) {
       if(*p != ',')
         return FALSE;
       p++;
     }
-    if(!ISDIGIT(*p))
-      return FALSE;
-    num = strtoul(p, &endp, 10);
-    if(num > 255)
+    if(Curl_str_number(&p, &num, 0xff))
       return FALSE;
     array[i] = (unsigned int)num;
-    p = endp;
   }
   return TRUE;
 }
@@ -1804,20 +1808,16 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
       /* the ISDIGIT() check here is because strtoul() accepts leading minus
          etc */
       if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
-        char *endp;
-        unsigned long num = strtoul(&ptr[3], &endp, 10);
-        if(*endp != sep)
-          ptr = NULL;
-        else if(num > 0xffff) {
+        const char *p = &ptr[3];
+        size_t num;
+        if(Curl_str_number(&p, &num, 0xffff) || (*p != sep)) {
           failf(data, "Illegal port number in EPSV reply");
           return CURLE_FTP_WEIRD_PASV_REPLY;
         }
-        if(ptr) {
-          ftpc->newport = (unsigned short)(num & 0xffff);
-          ftpc->newhost = strdup(control_address(conn));
-          if(!ftpc->newhost)
-            return CURLE_OUT_OF_MEMORY;
-        }
+        ftpc->newport = (unsigned short)num;
+        ftpc->newhost = strdup(control_address(conn));
+        if(!ftpc->newhost)
+          return CURLE_OUT_OF_MEMORY;
       }
       else
         ptr = NULL;
index 3088470abd38470bef38fbe41e58efa0d4f03ac5..b4c0574785ae1f7faba4cd9af1d517f46685aba6 100644 (file)
 #include "ftp.h"
 #include "ftplistparser.h"
 #include "curl_fnmatch.h"
-#include "curl_memory.h"
 #include "multiif.h"
-/* The last #include file should be: */
+#include "strparse.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
 #include "memdebug.h"
 
 typedef enum {
@@ -543,13 +546,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
         case PL_UNIX_HLINKS_NUMBER:
           parser->item_length ++;
           if(c == ' ') {
-            char *p;
-            long int hlinks;
+            const char *p = &mem[parser->item_offset];
+            size_t hlinks;
             mem[parser->item_offset + parser->item_length - 1] = 0;
-            hlinks = strtol(mem + parser->item_offset, &p, 10);
-            if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
+
+            if(!Curl_str_number(&p, &hlinks, LONG_MAX)) {
               parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
-              parser->file_data->info.hardlinks = hlinks;
+              parser->file_data->info.hardlinks = (long)hlinks;
             }
             parser->item_length = 0;
             parser->item_offset = 0;
index 5ab854d1ce8cfb86afb2ec2c1eac325e22bc6c64..d14476ccaeb6392937d9f98ace029970875a7ba2 100644 (file)
@@ -58,6 +58,8 @@
 #include "warnless.h"
 #include "strcase.h"
 #include "easy_lock.h"
+#include "strparse.h"
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -1122,7 +1124,7 @@ void Curl_hostcache_clean(struct Curl_easy *data,
 CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 {
   struct curl_slist *hostp;
-  char *host_end;
+  const char *host_end;
 
   /* Default is no wildcard found */
   data->state.wildcard_resolve = FALSE;
@@ -1132,15 +1134,15 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
     if(!hostp->data)
       continue;
     if(hostp->data[0] == '-') {
-      unsigned long num = 0;
+      size_t num = 0;
       size_t entry_len;
       size_t hlen = 0;
       host_end = strchr(&hostp->data[1], ':');
 
       if(host_end) {
         hlen = host_end - &hostp->data[1];
-        num = strtoul(++host_end, NULL, 10);
-        if(!hlen || (num > 0xffff))
+        host_end++;
+        if(Curl_str_number(&host_end, &num, 0xffff))
           host_end = NULL;
       }
       if(!host_end) {
@@ -1166,15 +1168,14 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       size_t entry_len;
       char address[64];
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-      char *addresses = NULL;
+      const char *addresses = NULL;
 #endif
-      char *addr_begin;
-      char *addr_end;
-      char *port_ptr;
-      int port = 0;
-      char *end_ptr;
+      const char *addr_begin;
+      const char *addr_end;
+      const char *port_ptr;
+      size_t port = 0;
+      const char *end_ptr;
       bool permanent = TRUE;
-      unsigned long tmp_port;
       bool error = TRUE;
       char *host_begin = hostp->data;
       size_t hlen = 0;
@@ -1189,11 +1190,11 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       hlen = host_end - host_begin;
 
       port_ptr = host_end + 1;
-      tmp_port = strtoul(port_ptr, &end_ptr, 10);
-      if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':')
+      if(Curl_str_number(&port_ptr, &port, 0xffff) ||
+         (*port_ptr != ':'))
         goto err;
+      end_ptr = port_ptr;
 
-      port = (int)tmp_port;
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
       addresses = end_ptr + 1;
 #endif
@@ -1234,7 +1235,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         }
 #endif
 
-        ai = Curl_str2addr(address, port);
+        ai = Curl_str2addr(address, (int)port);
         if(!ai) {
           infof(data, "Resolve address '%s' found illegal", address);
           goto err;
@@ -1262,7 +1263,7 @@ err:
       }
 
       /* Create an entry id, based upon the hostname and port */
-      entry_len = create_hostcache_id(host_begin, hlen, port,
+      entry_len = create_hostcache_id(host_begin, hlen, (int)port,
                                       entry_id, sizeof(entry_id));
 
       if(data->share)
@@ -1272,7 +1273,7 @@ err:
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
-        infof(data, "RESOLVE %.*s:%d - old addresses discarded",
+        infof(data, "RESOLVE %.*s:%zd - old addresses discarded",
               (int)hlen, host_begin, port);
         /* delete old entry, there are two reasons for this
          1. old entry may have different addresses.
@@ -1289,7 +1290,8 @@ err:
       }
 
       /* put this new host in the cache */
-      dns = Curl_cache_addr(data, head, host_begin, hlen, port, permanent);
+      dns = Curl_cache_addr(data, head, host_begin, hlen, (int)port,
+                            permanent);
       if(dns) {
         /* release the returned reference; the cache itself will keep the
          * entry alive: */
@@ -1304,14 +1306,14 @@ err:
         return CURLE_OUT_OF_MEMORY;
       }
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-      infof(data, "Added %.*s:%d:%s to DNS cache%s",
+      infof(data, "Added %.*s:%zd:%s to DNS cache%s",
             (int)hlen, host_begin, port, addresses,
             permanent ? "" : " (non-permanent)");
 #endif
 
       /* Wildcard hostname */
       if((hlen == 1) && (host_begin[0] == '*')) {
-        infof(data, "RESOLVE *:%d using wildcard", port);
+        infof(data, "RESOLVE *:%zd using wildcard", port);
         data->state.wildcard_resolve = TRUE;
       }
     }
index 49abaf4277d88789d9a78f127f5393af79bd7187..c15e96e7f85d1caf40fe0a075758441f19794777 100644 (file)
@@ -242,7 +242,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
  * response which can be processed by the response handler.
  */
 static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
-                           char *line, size_t len, int *resp)
+                           const char *line, size_t len, int *resp)
 {
   struct IMAP *imap = data->req.p.imap;
   struct imap_conn *imapc = &conn->proto.imapc;
index 7bb93616e798fcb33faaf0d7d4b54d807d60d027..030a3c59b822ea672ad8ffa8c010193d149a0bc1 100644 (file)
@@ -83,6 +83,7 @@
 #include "strcase.h"
 #include "warnless.h"
 #include "parsedate.h"
+#include "strparse.h"
 
 /*
  * parsedate()
@@ -411,7 +412,7 @@ static int parsedate(const char *date, time_t *output)
     }
     else if(ISDIGIT(*date)) {
       /* a digit */
-      int val;
+      unsigned int val;
       char *end;
       if((secnum == -1) &&
          match_time(date, &hournum, &minnum, &secnum, &end)) {
@@ -419,29 +420,18 @@ static int parsedate(const char *date, time_t *output)
         date = end;
       }
       else {
-        long lval;
-        int error;
-        int old_errno;
-
-        old_errno = errno;
-        errno = 0;
-        lval = strtol(date, &end, 10);
-        error = errno;
-        if(errno != old_errno)
-          errno = old_errno;
-
-        if(error)
+        size_t lval;
+        int num_digits = 0;
+        const char *p = date;
+        if(Curl_str_number(&p, &lval, 99999999))
           return PARSEDATE_FAIL;
 
-#if LONG_MAX != INT_MAX
-        if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
-          return PARSEDATE_FAIL;
-#endif
-
-        val = curlx_sltosi(lval);
+        /* we know num_digits cannot be larger than 8 */
+        num_digits = (int)(p - date);
+        val = (unsigned int)lval;
 
         if((tzoff == -1) &&
-           ((end - date) == 4) &&
+           (num_digits == 4) &&
            (val <= 1400) &&
            (indate < date) &&
            ((date[-1] == '+' || date[-1] == '-'))) {
@@ -461,10 +451,10 @@ static int parsedate(const char *date, time_t *output)
           tzoff = date[-1]=='+' ? -tzoff : tzoff;
         }
 
-        if(((end - date) == 8) &&
-           (yearnum == -1) &&
-           (monnum == -1) &&
-           (mdaynum == -1)) {
+        else if((num_digits == 8) &&
+                (yearnum == -1) &&
+                (monnum == -1) &&
+                (mdaynum == -1)) {
           /* 8 digits, no year, month or day yet. This is YYYYMMDD */
           found = TRUE;
           yearnum = val/10000;
@@ -496,7 +486,7 @@ static int parsedate(const char *date, time_t *output)
         if(!found)
           return PARSEDATE_FAIL;
 
-        date = end;
+        date = p;
       }
     }
 
index 72239ff05913d5f0275ce39f6a352cc8b2dcdb5a..dcd565fafd28202170b09bc2fec7c53f6fe204d8 100644 (file)
@@ -69,7 +69,7 @@ struct pingpong {
 
   CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn);
   bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn,
-                    char *ptr, size_t len, int *code);
+                    const char *ptr, size_t len, int *code);
 };
 
 #define PINGPONG_SETUP(pp,s,e)                   \
index 48a584e1cd9aa8df10a60fbac6a52a3dbdb115ec..4028123933cb08a22895281953df69452313e17a 100644 (file)
@@ -244,7 +244,7 @@ static bool pop3_is_multiline(const char *cmdline)
  * types and allowed SASL mechanisms.
  */
 static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
-                           char *line, size_t len, int *resp)
+                           const char *line, size_t len, int *resp)
 {
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   (void)data;
index 4325240ee67c3608fba5c0b08833d095353f0e04..253c4551a0737c64f27c002e0458d1b7aa069979 100644 (file)
@@ -40,6 +40,7 @@
 #include "connect.h"
 #include "cfilters.h"
 #include "strdup.h"
+#include "strparse.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -925,21 +926,17 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
 CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
 {
   if(checkprefix("CSeq:", header)) {
-    long CSeq = 0;
-    char *endp;
+    size_t CSeq = 0;
+    struct RTSP *rtsp = data->req.p.rtsp;
     const char *p = &header[5];
     while(ISBLANK(*p))
       p++;
-    CSeq = strtol(p, &endp, 10);
-    if(p != endp) {
-      struct RTSP *rtsp = data->req.p.rtsp;
-      rtsp->CSeq_recv = CSeq; /* mark the request */
-      data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
-    }
-    else {
+    if(Curl_str_number(&p, &CSeq, LONG_MAX)) {
       failf(data, "Unable to read the CSeq header: [%s]", header);
       return CURLE_RTSP_CSEQ_ERROR;
     }
+    rtsp->CSeq_recv = (long)CSeq; /* mark the request */
+    data->state.rtsp_CSeq_recv = (long)CSeq; /* update the handle */
   }
   else if(checkprefix("Session:", header)) {
     const char *start, *end;
@@ -1010,25 +1007,21 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
       start++;
     end = strchr(start, ';');
     if(checkprefix("interleaved=", start)) {
-      long chan1, chan2, chan;
-      char *endp;
+      size_t chan1, chan2, chan;
       const char *p = start + 12;
-      chan1 = strtol(p, &endp, 10);
-      if(p != endp && chan1 >= 0 && chan1 <= 255) {
+      if(!Curl_str_number(&p, &chan1, 255)) {
         unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
         chan2 = chan1;
-        if(*endp == '-') {
-          p = endp + 1;
-          chan2 = strtol(p, &endp, 10);
-          if(p == endp || chan2 < 0 || chan2 > 255) {
+        if(!Curl_str_single(&p, '-')) {
+          if(Curl_str_number(&p, &chan2, 255)) {
             infof(data, "Unable to read the interleaved parameter from "
                   "Transport header: [%s]", transport);
             chan2 = chan1;
           }
         }
         for(chan = chan1; chan <= chan2; chan++) {
-          long idx = chan / 8;
-          long off = chan % 8;
+          int idx = (int)chan / 8;
+          int off = (int)chan % 8;
           rtp_channel_mask[idx] |= (unsigned char)(1 << off);
         }
       }
index b6d42321b5e6f2662aba6732d176d19cd32ace62..e5ad4f56b1a05f41812220c32fcf6dc197cadeb0 100644 (file)
@@ -80,6 +80,8 @@
 #include "curl_sasl.h"
 #include "warnless.h"
 #include "idn.h"
+#include "strparse.h"
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -197,7 +199,7 @@ static const struct SASLproto saslsmtp = {
  * supported authentication mechanisms.
  */
 static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
-                           char *line, size_t len, int *resp)
+                           const char *line, size_t len, int *resp)
 {
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   bool result = FALSE;
@@ -213,11 +215,14 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
      only send the response code instead as per Section 4.2. */
   if(line[3] == ' ' || len == 5) {
     char tmpline[6];
-
+    size_t code;
+    const char *p = tmpline;
     result = TRUE;
-    memset(tmpline, '\0', sizeof(tmpline));
     memcpy(tmpline, line, (len == 5 ? 5 : 3));
-    *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
+    tmpline[len == 5 ? 5 : 3 ] = 0;
+    if(Curl_str_number(&p, &code, len == 5 ? 99999 : 999))
+      return FALSE;
+    *resp = (int) code;
 
     /* Make sure real server never sends internal value */
     if(*resp == 1)
index e383917eed9bd1783d848934b127d3ebee9ac358..bd85b119ec59558e06b5e4a4e6c32c6734e503fe 100644 (file)
@@ -58,6 +58,7 @@
 #include "select.h"
 #include "strcase.h"
 #include "warnless.h"
+#include "strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -862,22 +863,20 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
       case 2:
         /* Window Size */
         if(strncasecompare(option, "WS", 2)) {
-          char *p;
-          unsigned long x = strtoul(arg, &p, 10);
-          unsigned long y = 0;
-          if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') {
-            p++;
-            y = strtoul(p, NULL, 10);
-            if(y && (y <= 0xffff)) {
-              tn->subopt_wsx = (unsigned short)x;
-              tn->subopt_wsy = (unsigned short)y;
-              tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
-            }
-          }
-          if(!y) {
+          const char *p = arg;
+          size_t x = 0;
+          size_t y = 0;
+          if(Curl_str_number(&p, &x, 0xffff) ||
+             Curl_str_single(&p, 'x') ||
+             Curl_str_number(&p, &y, 0xffff)) {
             failf(data, "Syntax error in telnet option: %s", head->data);
             result = CURLE_SETOPT_OPTION_SYNTAX;
           }
+          else {
+            tn->subopt_wsx = (unsigned short)x;
+            tn->subopt_wsy = (unsigned short)y;
+            tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
+          }
         }
         else
           result = CURLE_UNKNOWN_OPTION;
index 3f214d55b65b70f2aa0cb5723584d65ca912135d..7f1eef518827fe6c2d70aedbe52f9617d50002fc 100644 (file)
@@ -62,6 +62,7 @@
 #include "speedcheck.h"
 #include "select.h"
 #include "escape.h"
+#include "strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -135,9 +136,9 @@ struct tftp_state_data {
   struct Curl_sockaddr_storage   remote_addr;
   curl_socklen_t  remote_addrlen;
   int             rbytes;
-  int             sbytes;
-  int             blksize;
-  int             requested_blksize;
+  size_t          sbytes;
+  unsigned int    blksize;
+  unsigned int    requested_blksize;
   unsigned short  block;
   struct tftp_packet rpacket;
   struct tftp_packet spacket;
@@ -330,19 +331,16 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
     infof(data, "got option=(%s) value=(%s)", option, value);
 
     if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
-      long blksize;
-
-      blksize = strtol(value, NULL, 10);
-
-      if(!blksize) {
-        failf(data, "invalid blocksize value in OACK packet");
-        return CURLE_TFTP_ILLEGAL;
-      }
-      if(blksize > TFTP_BLKSIZE_MAX) {
+      size_t blksize;
+      if(Curl_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) {
         failf(data, "%s (%d)", "blksize is larger than max supported",
               TFTP_BLKSIZE_MAX);
         return CURLE_TFTP_ILLEGAL;
       }
+      if(!blksize) {
+        failf(data, "invalid blocksize value in OACK packet");
+        return CURLE_TFTP_ILLEGAL;
+      }
       else if(blksize < TFTP_BLKSIZE_MIN) {
         failf(data, "%s (%d)", "blksize is smaller than min supported",
               TFTP_BLKSIZE_MIN);
@@ -352,28 +350,26 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
         /* could realloc pkt buffers here, but the spec does not call out
          * support for the server requesting a bigger blksize than the client
          * requests */
-        failf(data, "%s (%ld)",
-              "server requested blksize larger than allocated", blksize);
+        failf(data, "server requested blksize larger than allocated (%zd)",
+              blksize);
         return CURLE_TFTP_ILLEGAL;
       }
 
       state->blksize = (int)blksize;
-      infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
-            state->blksize, "requested", state->requested_blksize);
+      infof(data, "blksize parsed from OACK (%d) requested (%d)",
+            state->blksize, state->requested_blksize);
     }
     else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
-      long tsize = 0;
-
-      tsize = strtol(value, NULL, 10);
-      infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
-
+      size_t tsize = 0;
       /* tsize should be ignored on upload: Who cares about the size of the
          remote file? */
-      if(!data->state.upload) {
+      if(!data->state.upload &&
+         !Curl_str_number(&value, &tsize, SIZE_T_MAX)) {
         if(!tsize) {
           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
           return CURLE_TFTP_ILLEGAL;
         }
+        infof(data, "tsize parsed from OACK (%zd)", tsize);
         Curl_pgrsSetDownloadSize(data, tsize);
       }
     }
@@ -776,7 +772,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
                                 &cb, &eos);
       if(result)
         return result;
-      state->sbytes += (int)cb;
+      state->sbytes += cb;
       bufptr += cb;
     } while(state->sbytes < state->blksize && cb);
 
index 94e495e3c0e4345d92dc7b5093dd411411a475b0..564971d68e9388370b62ee1503bb45d52bff65f7 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
 #include "altsvc.h"
 #include "dynbuf.h"
 #include "headers.h"
-
+#include "strparse.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -1680,9 +1680,9 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
 #endif
 
   if(!uc && zoneid) {
-    char *endp;
-    unsigned long scope = strtoul(zoneid, &endp, 10);
-    if(!*endp && (scope < UINT_MAX))
+    const char *p = zoneid;
+    size_t scope;
+    if(!Curl_str_number(&p, &scope, UINT_MAX))
       /* A plain number, use it directly as a scope id. */
       conn->scope_id = (unsigned int)scope;
 #if defined(HAVE_IF_NAMETOINDEX)
@@ -1919,10 +1919,17 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
       return CURLE_OUT_OF_MEMORY;
   }
   else {
-    unsigned long port = strtoul(data->state.up.port, NULL, 10);
-    conn->primary.remote_port = conn->remote_port =
-      (data->set.use_port && data->state.allow_port) ?
-      data->set.use_port : curlx_ultous(port);
+    size_t port;
+    bool valid = TRUE;
+    if(data->set.use_port && data->state.allow_port)
+      port = data->set.use_port;
+    else {
+      const char *p = data->state.up.port;
+      if(Curl_str_number(&p, &port, 0xffff))
+        valid = FALSE;
+    }
+    if(valid)
+      conn->primary.remote_port = conn->remote_port = (unsigned short)port;
   }
 
   (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
@@ -2251,7 +2258,10 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
 
   if(portptr) {
-    port = (int)strtol(portptr, NULL, 10);
+    size_t num;
+    const char *p = portptr;
+    if(!Curl_str_number(&p, &num, 0xffff))
+      port = (int)num;
     free(portptr);
   }
   else {
@@ -2889,19 +2899,18 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
   /* Get port number off server.com:1080 */
   host_portno = strchr(portptr, ':');
   if(host_portno) {
-    char *endp = NULL;
     *host_portno = '\0'; /* cut off number from hostname */
     host_portno++;
     if(*host_portno) {
-      long portparse = strtol(host_portno, &endp, 10);
-      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
+      size_t portparse;
+      const char *p = host_portno;
+      if(Curl_str_number(&p, &portparse, 0xffff)) {
         failf(data, "No valid port number in connect to host string (%s)",
               host_portno);
         result = CURLE_SETOPT_OPTION_SYNTAX;
         goto error;
       }
-      else
-        port = (int)portparse; /* we know it will fit */
+      port = (int)portparse; /* we know it will fit */
     }
   }
 
@@ -2972,12 +2981,11 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data,
       /* check whether the URL's port matches */
       char *ptr_next = strchr(ptr, ':');
       if(ptr_next) {
-        char *endp = NULL;
-        long port_to_match = strtol(ptr, &endp, 10);
-        if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+        size_t port_to_match;
+        if(!Curl_str_number(&ptr, &port_to_match, 0xffff) &&
+           (port_to_match == (size_t)conn->remote_port))
           port_match = TRUE;
-          ptr = ptr_next + 1;
-        }
+        ptr = ptr_next + 1;
       }
     }
   }
index c93c9722eb5eec8f3eb7e074979fedc0df1e5cea..33684ccee175e9ee302fc20dff2a82bef5460a68 100644 (file)
@@ -34,6 +34,7 @@
 #include "inet_ntop.h"
 #include "strdup.h"
 #include "idn.h"
+#include "strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -445,7 +446,7 @@ out:
 UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
                                    bool has_scheme)
 {
-  char *portptr;
+  const char *portptr;
   char *hostname = Curl_dyn_ptr(host);
   /*
    * Find the end of an IPv6 address on the ']' ending bracket.
@@ -467,8 +468,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
     portptr = strchr(hostname, ':');
 
   if(portptr) {
-    char *rest = NULL;
-    unsigned long port;
+    size_t port;
     size_t keep = portptr - hostname;
 
     /* Browser behavior adaptation. If there is a colon with no digits after,
@@ -483,19 +483,13 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
     if(!*portptr)
       return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;
 
-    if(!ISDIGIT(*portptr))
-      return CURLUE_BAD_PORT_NUMBER;
-
-    errno = 0;
-    port = strtoul(portptr, &rest, 10);  /* Port number must be decimal */
-
-    if(errno || (port > 0xffff) || *rest)
+    if(Curl_str_number(&portptr, &port, 0xffff) || *portptr)
       return CURLUE_BAD_PORT_NUMBER;
 
     u->portnum = (unsigned short) port;
     /* generate a new port number string to get rid of leading zeroes etc */
     free(u->port);
-    u->port = aprintf("%ld", port);
+    u->port = aprintf("%zd", port);
     if(!u->port)
       return CURLUE_OUT_OF_MEMORY;
   }
@@ -1751,14 +1745,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
       return CURLUE_BAD_PORT_NUMBER;
     else {
       char *tmp;
-      char *endp;
-      unsigned long port;
-      errno = 0;
-      port = strtoul(part, &endp, 10);  /* must be decimal */
-      if(errno || (port > 0xffff) || *endp)
+      size_t port;
+      if(Curl_str_number(&part, &port, 0xffff) || *part)
         /* weirdly provided number, not good! */
         return CURLUE_BAD_PORT_NUMBER;
-      tmp = strdup(part);
+      tmp = aprintf("%zd", port);
       if(!tmp)
         return CURLUE_OUT_OF_MEMORY;
       free(u->port);
index b5f0fa689b11af986cce39c1d89b671beaecbf8c..7ae67f0f2b741225774024e21eab6b64ee31391a 100644 (file)
@@ -93,9 +93,9 @@ Curl_str_number
 6: ("00000000000000000000000000001234") 0, [1234] line 32
 7: ("0123 345") 0, [123] line 4
 8: ("0123O345") 0, [123] line 4
-9: ("-12") 0, [0] line 0
-10: (" 123") 0, [0] line 0
-11: ("") 0, [0] line 0
+9: ("-12") 8, [0] line 0
+10: (" 123") 8, [0] line 0
+11: ("") 8, [0] line 0
 Curl_str_number / max
 0: ("9223372036854775808") 0, [9223372036854775808] line 19
 1: ("9223372036854775809") 0, [9223372036854775809] line 19