]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
cli tool: do not use disabled protocols
authorPatrick Monnerat <patrick@monnerat.net>
Thu, 15 Sep 2022 12:31:36 +0000 (14:31 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 16 Sep 2022 21:29:08 +0000 (23:29 +0200)
As they are now rejected by the library, take care of not passing
disabled protocol names to CURLOPT_PROTOCOLS_STR and
CURLOPT_REDIR_PROTOCOLS_STR.

Rather than using the CURLPROTO_* constants, dynamically assign protocol
numbers based on the order they are listed by curl_version_info().

New type proto_set_t implements prototype bit masks: it should therefore
be large enough to accomodate all library-enabled protocols. If not,
protocol numbers beyond the bit count of proto_set_t are recognized but
"inaccessible": when used, a warning is displayed and the value is
ignored. Should proto_set_t overflows, enabled protocols are reordered to
force those having a public CURLPROTO_* representation to be accessible.

Code has been added to subordinate RTMP?* protocols to the presence of
RTMP in the enabled protocol list, being returned by curl_version_info()
or not.

src/tool_cb_hdr.c
src/tool_getparam.c
src/tool_help.c
src/tool_libinfo.c
src/tool_libinfo.h
src/tool_operate.c
src/tool_paramhlp.c
src/tool_paramhlp.h
src/tool_setopt.c
src/tool_setopt.h

index ec55c6419b6d8bd4a404981681791a3bb70331c9..f9adb4a2bcf5d595988f55c165e113b7f823ce7f 100644 (file)
@@ -35,6 +35,7 @@
 #include "tool_cb_hdr.h"
 #include "tool_cb_wrt.h"
 #include "tool_operate.h"
+#include "tool_libinfo.h"
 
 #include "memdebug.h" /* keep this as LAST include */
 
@@ -74,7 +75,8 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
   const char *str = ptr;
   const size_t cb = size * nmemb;
   const char *end = (char *)ptr + cb;
-  long protocol = 0;
+  char *scheme;
+  proto_t protocol = proto_last;
 
   /*
    * Once that libcurl has called back tool_header_cb() the returned value
@@ -139,10 +141,12 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
    * Content-Disposition header specifying a filename property.
    */
 
-  curl_easy_getinfo(per->curl, CURLINFO_PROTOCOL, &protocol);
+  curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
+  if(scheme)
+    protocol = scheme2protocol(scheme);
   if(hdrcbdata->honor_cd_filename &&
      (cb > 20) && checkprefix("Content-disposition:", str) &&
-     (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) {
+     (protocol == proto_https || protocol == proto_http)) {
     const char *p = str + 20;
 
     /* look for the 'filename=' parameter
@@ -202,8 +206,8 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
       per->was_last_header_empty = TRUE;
   }
   if(hdrcbdata->config->show_headers &&
-    (protocol &
-     (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) {
+    (protocol == proto_http || protocol == proto_https ||
+     protocol == proto_rtsp || protocol == proto_file)) {
     /* bold headers only for selected protocols */
     char *value = NULL;
 
index 351b07ad119becf9bfdbe8eff00ab0a85ba4661a..f345ed7f7164a8a61fc60aabcc8ce854a90aa16d 100644 (file)
@@ -1209,15 +1209,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
         break;
       case 'D': /* --proto */
         config->proto_present = TRUE;
-        err = proto2num(config, (unsigned int)CURLPROTO_ALL,
-                        &config->proto_str, nextarg);
+        err = proto2num(config, PROTO_ALL, &config->proto_str, nextarg);
         if(err)
           return err;
         break;
       case 'E': /* --proto-redir */
         config->proto_redir_present = TRUE;
-        if(proto2num(config, CURLPROTO_HTTP|CURLPROTO_HTTPS|
-                     CURLPROTO_FTP|CURLPROTO_FTPS,
+        if(proto2num(config, PROTO_BIT(proto_http) | PROTO_BIT(proto_https) |
+                     PROTO_BIT(proto_ftp) | PROTO_BIT(proto_ftps),
                      &config->proto_redir_str, nextarg))
           return PARAM_BAD_USE;
         break;
index 75400d94c16b7fe1ba971daa5a73bc7907033b34..f24a5f2ed8ae98ec0d53c0f8eed065e7091c53e8 100644 (file)
@@ -221,7 +221,10 @@ void tool_version_info(void)
   if(curlinfo->protocols) {
     printf("Protocols: ");
     for(proto = curlinfo->protocols; *proto; ++proto) {
-      printf("%s ", *proto);
+      /* Special case: do not list rtmp?* protocols.
+         They may only appear together with "rtmp" */
+      if(!curl_strnequal(*proto, "rtmp", 4) || !proto[0][4])
+        printf("%s ", *proto);
     }
     puts(""); /* newline */
   }
index 039443e239f205e916e5c88dfa9d5bb68c8ba2f5..5f7bd608f57b105d42c233d4fa47e5507f74787a 100644 (file)
 
 /* global variable definitions, for libcurl run-time info */
 
+#define MAX_PROTOS      64      /* Maximum number of supported protocols. */
+
 curl_version_info_data *curlinfo = NULL;
-long built_in_protos = 0;
 
-static struct proto_name_pattern {
-  const char *proto_name;
-  long        proto_pattern;
+proto_t proto_last = 0;
+
+proto_t proto_ftp = PROTO_NONE;
+proto_t proto_ftps = PROTO_NONE;
+proto_t proto_http = PROTO_NONE;
+proto_t proto_https = PROTO_NONE;
+proto_t proto_file = PROTO_NONE;
+proto_t proto_rtsp = PROTO_NONE;
+proto_t proto_scp = PROTO_NONE;
+proto_t proto_sftp = PROTO_NONE;
+proto_t proto_tftp = PROTO_NONE;
+
+static struct proto_name_nump {
+  const char    *proto_name;
+  proto_t       *proto_nump;
 } const possibly_built_in[] = {
-  { "dict",   CURLPROTO_DICT   },
-  { "file",   CURLPROTO_FILE   },
-  { "ftp",    CURLPROTO_FTP    },
-  { "ftps",   CURLPROTO_FTPS   },
-  { "gopher", CURLPROTO_GOPHER },
-  { "gophers",CURLPROTO_GOPHERS},
-  { "http",   CURLPROTO_HTTP   },
-  { "https",  CURLPROTO_HTTPS  },
-  { "imap",   CURLPROTO_IMAP   },
-  { "imaps",  CURLPROTO_IMAPS  },
-  { "ldap",   CURLPROTO_LDAP   },
-  { "ldaps",  CURLPROTO_LDAPS  },
-  { "mqtt",   CURLPROTO_MQTT   },
-  { "pop3",   CURLPROTO_POP3   },
-  { "pop3s",  CURLPROTO_POP3S  },
-  { "rtmp",   CURLPROTO_RTMP   },
-  { "rtmps",  CURLPROTO_RTMPS  },
-  { "rtsp",   CURLPROTO_RTSP   },
-  { "scp",    CURLPROTO_SCP    },
-  { "sftp",   CURLPROTO_SFTP   },
-  { "smb",    CURLPROTO_SMB    },
-  { "smbs",   CURLPROTO_SMBS   },
-  { "smtp",   CURLPROTO_SMTP   },
-  { "smtps",  CURLPROTO_SMTPS  },
-  { "telnet", CURLPROTO_TELNET },
-  { "tftp",   CURLPROTO_TFTP   },
-  {  NULL,    0                }
+  /* Keep entries in CURLPROTO_* order for sorting purpose. */
+  { "http",     &proto_http  },
+  { "https",    &proto_https },
+  { "ftp",      &proto_ftp   },
+  { "ftps",     &proto_ftps  },
+  { "scp",      &proto_scp   },
+  { "sftp",     &proto_sftp  },
+  { "telnet",   NULL         },
+  { "ldap",     NULL         },
+  { "ldaps",    NULL         },
+  { "dict",     NULL         },
+  { "file",     &proto_file  },
+  { "tftp",     &proto_tftp  },
+  { "imap",     NULL         },
+  { "imaps",    NULL         },
+  { "pop3",     NULL         },
+  { "pop3s",    NULL         },
+  { "smtp",     NULL         },
+  { "smtps",    NULL         },
+  { "rtsp",     &proto_rtsp  },
+  { "rtmp",     NULL         },
+  { "rtmpt",    NULL         },
+  { "rtmpe",    NULL         },
+  { "rtmpte",   NULL         },
+  { "rtmps",    NULL         },
+  { "rtmpts",   NULL         },
+  { "gopher",   NULL         },
+  { "smb",      NULL         },
+  { "smbs",     NULL         },
+  { "mqtt",     NULL         },
+  { "gophers",  NULL         },
+  { "ws",       NULL         },
+  { "wss",      NULL         },
+  {  NULL,      NULL         }
 };
 
+static const char *built_in_protos[MAX_PROTOS + 1] = {NULL};
+
+/*
+ * scheme2protocol() returns the protocol number for the specified URL scheme
+ */
+proto_t scheme2protocol(const char *scheme)
+{
+  proto_t p;
+
+  for(p = 0; built_in_protos[p]; p++)
+    if(curl_strequal(scheme, built_in_protos[p]))
+      return p;
+  return PROTO_NONE;
+}
+
+/*
+ * protocol2scheme() returns the name of the specified protocol.
+ */
+const char *protocol2scheme(proto_t proto)
+{
+  return proto < proto_last? built_in_protos[proto]: NULL;
+}
+
+/* Enter a protoype in the built-in prototype table. */
+static CURLcode enter_proto(const char *proto)
+{
+  if(scheme2protocol(proto) == PROTO_NONE) {
+    if(proto_last >= MAX_PROTOS)
+      return CURLE_OUT_OF_MEMORY;
+    built_in_protos[proto_last] = proto;
+    built_in_protos[++proto_last] = NULL;
+  }
+
+  return CURLE_OK;
+}
+
+/* qsort helper functions for prototype array. */
+static int sortkey(const void *arg)
+{
+  const char *proto = *(const char **) arg;
+  const struct proto_name_nump *p;
+
+  for(p = possibly_built_in; p->proto_name; p++)
+    if(curl_strequal(p->proto_name, proto))
+      break;
+
+  return (int) (p - possibly_built_in);
+}
+
+static int protocmp(const void *p1, const void *p2)
+{
+  return sortkey(p1) - sortkey(p2);
+}
+
 /*
  * libcurl_info_init: retrieves run-time information about libcurl,
  * setting a global pointer 'curlinfo' to libcurl's run-time info
- * struct, and a global bit pattern 'built_in_protos' composed of
- * CURLPROTO_* bits indicating which protocols are actually built
- * into library being used.
+ * struct, Assigning numbers to specific protocols and identifying protocols
+ * we are interested in.
  */
 
 CURLcode get_libcurl_info(void)
 {
-  const char *const *proto;
+  CURLcode result = CURLE_OK;
 
   /* Pointer to libcurl's run-time version information */
   curlinfo = curl_version_info(CURLVERSION_NOW);
   if(!curlinfo)
     return CURLE_FAILED_INIT;
 
-  /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */
-  built_in_protos = 0;
   if(curlinfo->protocols) {
-    for(proto = curlinfo->protocols; *proto; proto++) {
-      struct proto_name_pattern const *p;
-      for(p = possibly_built_in; p->proto_name; p++) {
-        if(curl_strequal(*proto, p->proto_name)) {
-          built_in_protos |= p->proto_pattern;
-          break;
-        }
-      }
+    const char *const *builtin;
+    const struct proto_name_nump *p;
+
+    /* Copy protocols to local table. */
+    for(builtin = curlinfo->protocols; !result && *builtin; builtin++)
+      result = enter_proto(*builtin);
+
+    /* Special case: if RTMP is present, also include RTMPE, RTMPS, RTMPT,
+       RTMPTE and RTMPTS. */
+    if(scheme2protocol("rtmp") != PROTO_NONE) {
+      if(!result)
+        result = enter_proto("rtmpe");
+      if(!result)
+        result = enter_proto("rtmps");
+      if(!result)
+        result = enter_proto("rtmpt");
+      if(!result)
+        result = enter_proto("rtmpte");
+      if(!result)
+        result = enter_proto("rtmpts");
     }
-  }
 
-  return CURLE_OK;
-}
+    if(result)
+      return result;
 
-/*
- * scheme2protocol() returns the protocol bit for the specified URL scheme
- */
-long scheme2protocol(const char *scheme)
-{
-  struct proto_name_pattern const *p;
-  for(p = possibly_built_in; p->proto_name; p++) {
-    if(curl_strequal(scheme, p->proto_name))
-      return p->proto_pattern;
+    /* Sort the protocols to be sure the primary ones are always accessible and
+     * to retain their list order for testing purposes. */
+    qsort(built_in_protos, proto_last, sizeof(built_in_protos[0]), protocmp);
+
+    /* Identify protocols we are interested in. */
+    for(p = possibly_built_in; p->proto_name; p++)
+      if(p->proto_nump)
+        *p->proto_nump = scheme2protocol(p->proto_name);
   }
-  return 0;
+
+  return CURLE_OK;
 }
index ba6fc0ec1b64536d7e2a57ae9e87e52888aba3f1..19c75b1bb6be353b04d6d5c66dd627b1b5fa0371 100644 (file)
 
 /* global variable declarations, for libcurl run-time info */
 
+typedef unsigned int proto_t;   /* A protocol number.*/
+
+#define PROTO_NONE ((proto_t) -1)
+
+/* Protocol numbers set type. This should have enough bits for all
+ * enabled protocols.
+ */
+typedef unsigned int proto_set_t;
+
+#define PROTO_MAX       ((proto_t) (8 * sizeof(proto_set_t)))
+
+#define PROTO_BIT(p)    ((p) < PROTO_MAX? (proto_set_t) 1 << (p):       \
+                                          (proto_set_t) 0)
+
+#define PROTO_ALL       (PROTO_BIT(proto_last) - (proto_set_t) 1)
+
+
 extern curl_version_info_data *curlinfo;
-extern long built_in_protos;
+extern proto_t proto_last;
+
+extern proto_t proto_ftp;
+extern proto_t proto_ftps;
+extern proto_t proto_http;
+extern proto_t proto_https;
+extern proto_t proto_file;
+extern proto_t proto_rtsp;
+extern proto_t proto_scp;
+extern proto_t proto_sftp;
+extern proto_t proto_tftp;
 
 CURLcode get_libcurl_info(void);
-long scheme2protocol(const char *scheme);
+proto_t scheme2protocol(const char *scheme);
+const char *protocol2scheme(proto_t proto);
 
 #endif /* HEADER_CURL_TOOL_LIBINFO_H */
index 7d64c1c4d2b821fae4d1dc217ca5b4f25d9e1fb1..b859ab05c59eeee15f1b8404830809ce631ba1a1 100644 (file)
@@ -465,9 +465,12 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
       /* If it returned OK. _or_ failonerror was enabled and it
          returned due to such an error, check for HTTP transient
          errors to retry on. */
-      long protocol = 0;
-      curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
-      if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) {
+      char *scheme;
+      proto_t protocol = proto_last;
+      curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
+      if(scheme)
+        protocol = scheme2protocol(scheme);
+      if(protocol == proto_http || protocol == proto_https) {
         /* This was HTTP(S) */
         curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
 
@@ -494,12 +497,16 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
       }
     } /* if CURLE_OK */
     else if(result) {
-      long protocol = 0;
+      char *scheme;
+      proto_t protocol = proto_last;
 
       curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
-      curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
+      curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
 
-      if((protocol == CURLPROTO_FTP || protocol == CURLPROTO_FTPS) &&
+      if(scheme)
+        protocol = scheme2protocol(scheme);
+
+      if((protocol == proto_ftp || protocol == proto_ftps) &&
          response / 100 == 4)
         /*
          * This is typically when the FTP server only allows a certain
@@ -688,10 +695,11 @@ static void single_transfer_cleanup(struct OperationConfig *config)
 /*
  * Return the proto bit for the scheme used in the given URL
  */
-static long url_proto(char *url)
+static proto_t url_proto(char *url)
 {
   CURLU *uh = curl_url();
-  long proto = 0;
+  proto_t proto = PROTO_NONE;
+
   if(uh) {
     if(url) {
       if(!curl_url_set(uh, CURLUPART_URL, url,
@@ -850,7 +858,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         struct OutStruct *etag_save;
         struct HdrCbData *hdrcbdata = NULL;
         struct OutStruct etag_first;
-        long use_proto;
+        proto_t use_proto;
         CURL *curl;
 
         /* --etag-save */
@@ -1249,8 +1257,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
 
         /* here */
         use_proto = url_proto(per->this_url);
+        if(use_proto == PROTO_NONE)
+          use_proto = proto_last;  /* Do not match any identified protocol. */
 #if 0
-        if(!(use_proto & built_in_protos)) {
+        if(use_proto >= proto_last) {
           warnf(global, "URL is '%s' but no support for the scheme\n",
                 per->this_url);
         }
@@ -1406,13 +1416,12 @@ static CURLcode single_transfer(struct GlobalConfig *global,
 
         my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
 
-        if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) {
+        if(proto_http < proto_last || proto_rtsp < proto_last) {
           my_setopt_str(curl, CURLOPT_REFERER, config->referer);
           my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
         }
 
-        if(built_in_protos & CURLPROTO_HTTP) {
-
+        if(proto_http < proto_last) {
           long postRedir = 0;
 
           my_setopt(curl, CURLOPT_FOLLOWLOCATION,
@@ -1462,9 +1471,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
             return result;
           }
 
-        } /* (built_in_protos & CURLPROTO_HTTP) */
+        } /* (proto_http < proto_last) */
 
-        my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
+        if(proto_ftp < proto_last)
+          my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
         my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
                   config->low_speed_limit);
         my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
@@ -1481,7 +1491,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
         my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
 
-        if(use_proto & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
+        if(use_proto == proto_scp || use_proto == proto_sftp) {
 
           /* SSH and SSL private key uses same command-line option */
           /* new in libcurl 7.16.1 */
@@ -1752,7 +1762,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         if(config->path_as_is)
           my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
 
-        if((use_proto & (CURLPROTO_SCP|CURLPROTO_SFTP)) &&
+        if((use_proto == proto_scp || use_proto == proto_sftp) &&
            !config->insecure_ok) {
           char *known = findfile(".ssh/known_hosts", FALSE);
           if(known) {
@@ -1962,7 +1972,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
 
         /* curl 7.15.1 */
-        my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod);
+        if(proto_ftp < proto_last)
+          my_setopt(curl, CURLOPT_FTP_FILEMETHOD,
+                    (long)config->ftp_filemethod);
 
         /* curl 7.15.2 */
         if(config->localport) {
@@ -1997,7 +2009,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
 
         /* curl 7.20.0 */
-        if(config->tftp_blksize)
+        if(config->tftp_blksize && proto_tftp < proto_last)
           my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
 
         if(config->mail_from)
@@ -2110,7 +2122,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
                         (long)(config->expect100timeout*1000));
 
         /* new in 7.48.0 */
-        if(config->tftp_no_options)
+        if(config->tftp_no_options && proto_tftp < proto_last)
           my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
 
         /* new in 7.59.0 */
index 9306498e2393ac0140c68e4b752eff9fdf152533..f5745b057684d62dbfeefd0063b31cc96b6c9170 100644 (file)
@@ -34,6 +34,7 @@
 #include "tool_getpass.h"
 #include "tool_msgs.h"
 #include "tool_paramhlp.h"
+#include "tool_libinfo.h"
 #include "tool_version.h"
 #include "dynbuf.h"
 
@@ -270,48 +271,19 @@ ParameterError str2udouble(double *valp, const char *str, long max)
  * data.
  */
 
+#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
+
 ParameterError proto2num(struct OperationConfig *config,
-                         unsigned int val, char **ostr, const char *str)
+                         proto_set_t val, char **ostr, const char *str)
 {
   char *buffer;
   const char *sep = ",";
   char *token;
-  char obuf[256] = "";
-  size_t olen = sizeof(obuf);
-  char *optr;
-  struct sprotos const *pp;
-
-  static struct sprotos {
-    const char *name;
-    unsigned int bit;
-  } const protos[] = {
-    { "all", (unsigned int)CURLPROTO_ALL },
-    { "http", CURLPROTO_HTTP },
-    { "https", CURLPROTO_HTTPS },
-    { "ftp", CURLPROTO_FTP },
-    { "ftps", CURLPROTO_FTPS },
-    { "scp", CURLPROTO_SCP },
-    { "sftp", CURLPROTO_SFTP },
-    { "telnet", CURLPROTO_TELNET },
-    { "ldap", CURLPROTO_LDAP },
-    { "ldaps", CURLPROTO_LDAPS },
-    { "mqtt", CURLPROTO_MQTT },
-    { "dict", CURLPROTO_DICT },
-    { "file", CURLPROTO_FILE },
-    { "tftp", CURLPROTO_TFTP },
-    { "imap", CURLPROTO_IMAP },
-    { "imaps", CURLPROTO_IMAPS },
-    { "pop3", CURLPROTO_POP3 },
-    { "pop3s", CURLPROTO_POP3S },
-    { "smtp", CURLPROTO_SMTP },
-    { "smtps", CURLPROTO_SMTPS },
-    { "rtsp", CURLPROTO_RTSP },
-    { "gopher", CURLPROTO_GOPHER },
-    { "gophers", CURLPROTO_GOPHERS },
-    { "smb", CURLPROTO_SMB },
-    { "smbs", CURLPROTO_SMBS },
-    { NULL, 0 }
-  };
+  struct curlx_dynbuf obuf;
+  proto_t proto;
+  CURLcode result;
+
+  curlx_dyn_init(&obuf, MAX_PROTOSTRING);
 
   if(!str)
     return PARAM_OPTION_AMBIGUOUS;
@@ -345,44 +317,52 @@ ParameterError proto2num(struct OperationConfig *config,
       }
     }
 
-    for(pp = protos; pp->name; pp++) {
-      if(curl_strequal(token, pp->name)) {
+    if(curl_strequal(token, "all")) {
+      switch(action) {
+      case deny:
+        val = 0;
+        break;
+      case allow:
+      case set:
+        val = PROTO_ALL;
+        break;
+      }
+    }
+    else {
+      proto = scheme2protocol(token);
+      if(proto != PROTO_NONE) {
         switch(action) {
         case deny:
-          val &= ~(pp->bit);
-          break;
-        case allow:
-          val |= pp->bit;
+          val &= ~PROTO_BIT(proto);
           break;
         case set:
-          val = pp->bit;
+          val = 0;
+          /* FALLTHROUGH */
+        case allow:
+          if(proto >= PROTO_MAX)
+            warnf(config->global, "protocol '%s' enabled but not accessible\n",
+                  token);
+          val |= PROTO_BIT(proto);
           break;
         }
-        break;
       }
-    }
-
-    if(!(pp->name)) { /* unknown protocol */
-      /* If they have specified only this protocol, we say treat it as
-         if no protocols are allowed */
-      if(action == set)
-        val = 0;
-      warnf(config->global, "unrecognized protocol '%s'\n", token);
+      else { /* unknown protocol */
+        /* If they have specified only this protocol, we say treat it as
+           if no protocols are allowed */
+        if(action == set)
+          val = 0;
+        warnf(config->global, "unrecognized protocol '%s'\n", token);
+      }
     }
   }
   Curl_safefree(buffer);
 
-  optr = obuf;
-  for(pp = &protos[1]; pp->name; pp++) {
-    if(val & pp->bit) {
-      size_t n = msnprintf(optr, olen, "%s%s",
-                           olen != sizeof(obuf) ? "," : "",
-                           pp->name);
-      olen -= n;
-      optr += n;
-    }
-  }
-  *ostr = strdup(obuf);
+  result = curlx_dyn_addn(&obuf, "", 0);
+  for(proto = 0; proto < proto_last && proto < PROTO_MAX && !result; proto++)
+    if(val & PROTO_BIT(proto))
+      result = curlx_dyn_addf(&obuf, "%s,", protocol2scheme(proto));
+  curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
+  *ostr = curlx_dyn_ptr(&obuf);
 
   return *ostr ? PARAM_OK : PARAM_NO_MEM;
 }
@@ -397,14 +377,14 @@ ParameterError proto2num(struct OperationConfig *config,
  */
 ParameterError check_protocol(const char *str)
 {
-  const char * const *pp;
-  const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW);
+  proto_t proto;
+
   if(!str)
     return PARAM_REQUIRES_PARAMETER;
-  for(pp = curlinfo->protocols; *pp; pp++) {
-    if(curl_strequal(*pp, str))
-      return PARAM_OK;
-  }
+
+  proto = scheme2protocol(str);
+  if(proto < proto_last)
+    return PARAM_OK;
   return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
 }
 
index 6d9451f1d9439087435b5b4c40736bc048d0380b..95338a07ebbbe6658ff0994d57c0a50fe4f93d5b 100644 (file)
@@ -24,6 +24,7 @@
  *
  ***************************************************************************/
 #include "tool_setup.h"
+#include "tool_libinfo.h"
 
 struct getout *new_getout(struct OperationConfig *config);
 
@@ -38,7 +39,7 @@ ParameterError str2unummax(long *val, const char *str, long max);
 ParameterError str2udouble(double *val, const char *str, long max);
 
 ParameterError proto2num(struct OperationConfig *config,
-                         unsigned int val, char **obuf,
+                         proto_set_t val, char **obuf,
                          const char *str);
 
 ParameterError check_protocol(const char *str);
index 5ea2541e0dacf59486f5e645e54878121f1c7bb2..b051388895544e0d10e2cba72a02dd681bcda78c 100644 (file)
@@ -145,35 +145,6 @@ const struct NameValue setopt_nv_CURL_NETRC[] = {
   NVEND,
 };
 
-/* These mappings essentially triplicated - see
- * tool_libinfo.c and tool_paramhlp.c */
-const struct NameValue setopt_nv_CURLPROTO[] = {
-  NV(CURLPROTO_ALL),            /* combination */
-  NV(CURLPROTO_DICT),
-  NV(CURLPROTO_FILE),
-  NV(CURLPROTO_FTP),
-  NV(CURLPROTO_FTPS),
-  NV(CURLPROTO_GOPHER),
-  NV(CURLPROTO_HTTP),
-  NV(CURLPROTO_HTTPS),
-  NV(CURLPROTO_IMAP),
-  NV(CURLPROTO_IMAPS),
-  NV(CURLPROTO_LDAP),
-  NV(CURLPROTO_LDAPS),
-  NV(CURLPROTO_POP3),
-  NV(CURLPROTO_POP3S),
-  NV(CURLPROTO_RTSP),
-  NV(CURLPROTO_SCP),
-  NV(CURLPROTO_SFTP),
-  NV(CURLPROTO_SMB),
-  NV(CURLPROTO_SMBS),
-  NV(CURLPROTO_SMTP),
-  NV(CURLPROTO_SMTPS),
-  NV(CURLPROTO_TELNET),
-  NV(CURLPROTO_TFTP),
-  NVEND,
-};
-
 /* These options have non-zero default values. */
 static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
   NV1(CURLOPT_SSL_VERIFYPEER, 1),
index 2646edb44b4e2f2ccf7e7e3c2c5d70e07b015b06..bc5afe9bcb9f713c8439a751f1ed174177877083 100644 (file)
@@ -57,7 +57,6 @@ extern const struct NameValue setopt_nv_CURLFTPSSL_CCC[];
 extern const struct NameValue setopt_nv_CURLUSESSL[];
 extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[];
 extern const struct NameValue setopt_nv_CURL_NETRC[];
-extern const struct NameValue setopt_nv_CURLPROTO[];
 extern const struct NameValueUnsigned setopt_nv_CURLAUTH[];
 extern const struct NameValueUnsigned setopt_nv_CURLHSTS[];
 
@@ -73,8 +72,6 @@ extern const struct NameValueUnsigned setopt_nv_CURLHSTS[];
 #define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT
 #define setopt_nv_CURLOPT_PROXY_SSL_OPTIONS setopt_nv_CURLSSLOPT
 #define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC
-#define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO
-#define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO
 #define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY
 #define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH
 #define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH