cli tool: do not use disabled protocols

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.
This commit is contained in:
Patrick Monnerat 2022-09-15 14:31:36 +02:00 committed by Daniel Stenberg
parent 9d51329047
commit dd2a024323
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
10 changed files with 274 additions and 197 deletions

View file

@ -35,6 +35,7 @@
#include "tool_cb_hdr.h" #include "tool_cb_hdr.h"
#include "tool_cb_wrt.h" #include "tool_cb_wrt.h"
#include "tool_operate.h" #include "tool_operate.h"
#include "tool_libinfo.h"
#include "memdebug.h" /* keep this as LAST include */ #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 char *str = ptr;
const size_t cb = size * nmemb; const size_t cb = size * nmemb;
const char *end = (char *)ptr + cb; 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 * 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. * 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 && if(hdrcbdata->honor_cd_filename &&
(cb > 20) && checkprefix("Content-disposition:", str) && (cb > 20) && checkprefix("Content-disposition:", str) &&
(protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { (protocol == proto_https || protocol == proto_http)) {
const char *p = str + 20; const char *p = str + 20;
/* look for the 'filename=' parameter /* 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; per->was_last_header_empty = TRUE;
} }
if(hdrcbdata->config->show_headers && if(hdrcbdata->config->show_headers &&
(protocol & (protocol == proto_http || protocol == proto_https ||
(CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP|CURLPROTO_FILE))) { protocol == proto_rtsp || protocol == proto_file)) {
/* bold headers only for selected protocols */ /* bold headers only for selected protocols */
char *value = NULL; char *value = NULL;

View file

@ -1209,15 +1209,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break; break;
case 'D': /* --proto */ case 'D': /* --proto */
config->proto_present = TRUE; config->proto_present = TRUE;
err = proto2num(config, (unsigned int)CURLPROTO_ALL, err = proto2num(config, PROTO_ALL, &config->proto_str, nextarg);
&config->proto_str, nextarg);
if(err) if(err)
return err; return err;
break; break;
case 'E': /* --proto-redir */ case 'E': /* --proto-redir */
config->proto_redir_present = TRUE; config->proto_redir_present = TRUE;
if(proto2num(config, CURLPROTO_HTTP|CURLPROTO_HTTPS| if(proto2num(config, PROTO_BIT(proto_http) | PROTO_BIT(proto_https) |
CURLPROTO_FTP|CURLPROTO_FTPS, PROTO_BIT(proto_ftp) | PROTO_BIT(proto_ftps),
&config->proto_redir_str, nextarg)) &config->proto_redir_str, nextarg))
return PARAM_BAD_USE; return PARAM_BAD_USE;
break; break;

View file

@ -221,7 +221,10 @@ void tool_version_info(void)
if(curlinfo->protocols) { if(curlinfo->protocols) {
printf("Protocols: "); printf("Protocols: ");
for(proto = curlinfo->protocols; *proto; ++proto) { 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 */ puts(""); /* newline */
} }

View file

@ -35,85 +35,167 @@
/* global variable definitions, for libcurl run-time info */ /* global variable definitions, for libcurl run-time info */
curl_version_info_data *curlinfo = NULL; #define MAX_PROTOS 64 /* Maximum number of supported protocols. */
long built_in_protos = 0;
static struct proto_name_pattern { curl_version_info_data *curlinfo = NULL;
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[] = { } const possibly_built_in[] = {
{ "dict", CURLPROTO_DICT }, /* Keep entries in CURLPROTO_* order for sorting purpose. */
{ "file", CURLPROTO_FILE }, { "http", &proto_http },
{ "ftp", CURLPROTO_FTP }, { "https", &proto_https },
{ "ftps", CURLPROTO_FTPS }, { "ftp", &proto_ftp },
{ "gopher", CURLPROTO_GOPHER }, { "ftps", &proto_ftps },
{ "gophers",CURLPROTO_GOPHERS}, { "scp", &proto_scp },
{ "http", CURLPROTO_HTTP }, { "sftp", &proto_sftp },
{ "https", CURLPROTO_HTTPS }, { "telnet", NULL },
{ "imap", CURLPROTO_IMAP }, { "ldap", NULL },
{ "imaps", CURLPROTO_IMAPS }, { "ldaps", NULL },
{ "ldap", CURLPROTO_LDAP }, { "dict", NULL },
{ "ldaps", CURLPROTO_LDAPS }, { "file", &proto_file },
{ "mqtt", CURLPROTO_MQTT }, { "tftp", &proto_tftp },
{ "pop3", CURLPROTO_POP3 }, { "imap", NULL },
{ "pop3s", CURLPROTO_POP3S }, { "imaps", NULL },
{ "rtmp", CURLPROTO_RTMP }, { "pop3", NULL },
{ "rtmps", CURLPROTO_RTMPS }, { "pop3s", NULL },
{ "rtsp", CURLPROTO_RTSP }, { "smtp", NULL },
{ "scp", CURLPROTO_SCP }, { "smtps", NULL },
{ "sftp", CURLPROTO_SFTP }, { "rtsp", &proto_rtsp },
{ "smb", CURLPROTO_SMB }, { "rtmp", NULL },
{ "smbs", CURLPROTO_SMBS }, { "rtmpt", NULL },
{ "smtp", CURLPROTO_SMTP }, { "rtmpe", NULL },
{ "smtps", CURLPROTO_SMTPS }, { "rtmpte", NULL },
{ "telnet", CURLPROTO_TELNET }, { "rtmps", NULL },
{ "tftp", CURLPROTO_TFTP }, { "rtmpts", NULL },
{ NULL, 0 } { "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, * libcurl_info_init: retrieves run-time information about libcurl,
* setting a global pointer 'curlinfo' to libcurl's run-time info * setting a global pointer 'curlinfo' to libcurl's run-time info
* struct, and a global bit pattern 'built_in_protos' composed of * struct, Assigning numbers to specific protocols and identifying protocols
* CURLPROTO_* bits indicating which protocols are actually built * we are interested in.
* into library being used.
*/ */
CURLcode get_libcurl_info(void) CURLcode get_libcurl_info(void)
{ {
const char *const *proto; CURLcode result = CURLE_OK;
/* Pointer to libcurl's run-time version information */ /* Pointer to libcurl's run-time version information */
curlinfo = curl_version_info(CURLVERSION_NOW); curlinfo = curl_version_info(CURLVERSION_NOW);
if(!curlinfo) if(!curlinfo)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
/* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */
built_in_protos = 0;
if(curlinfo->protocols) { if(curlinfo->protocols) {
for(proto = curlinfo->protocols; *proto; proto++) { const char *const *builtin;
struct proto_name_pattern const *p; const struct proto_name_nump *p;
for(p = possibly_built_in; p->proto_name; p++) {
if(curl_strequal(*proto, p->proto_name)) { /* Copy protocols to local table. */
built_in_protos |= p->proto_pattern; for(builtin = curlinfo->protocols; !result && *builtin; builtin++)
break; 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");
} }
if(result)
return result;
/* 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 CURLE_OK; return CURLE_OK;
} }
/*
* 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;
}
return 0;
}

View file

@ -27,10 +27,38 @@
/* global variable declarations, for libcurl run-time info */ /* 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 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); 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 */ #endif /* HEADER_CURL_TOOL_LIBINFO_H */

View file

@ -465,9 +465,12 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
/* If it returned OK. _or_ failonerror was enabled and it /* If it returned OK. _or_ failonerror was enabled and it
returned due to such an error, check for HTTP transient returned due to such an error, check for HTTP transient
errors to retry on. */ errors to retry on. */
long protocol = 0; char *scheme;
curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); proto_t protocol = proto_last;
if((protocol == CURLPROTO_HTTP) || (protocol == CURLPROTO_HTTPS)) { curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
if(scheme)
protocol = scheme2protocol(scheme);
if(protocol == proto_http || protocol == proto_https) {
/* This was HTTP(S) */ /* This was HTTP(S) */
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
@ -494,12 +497,16 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
} }
} /* if CURLE_OK */ } /* if CURLE_OK */
else if(result) { 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_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) response / 100 == 4)
/* /*
* This is typically when the FTP server only allows a certain * 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 * 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(); CURLU *uh = curl_url();
long proto = 0; proto_t proto = PROTO_NONE;
if(uh) { if(uh) {
if(url) { if(url) {
if(!curl_url_set(uh, CURLUPART_URL, 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 OutStruct *etag_save;
struct HdrCbData *hdrcbdata = NULL; struct HdrCbData *hdrcbdata = NULL;
struct OutStruct etag_first; struct OutStruct etag_first;
long use_proto; proto_t use_proto;
CURL *curl; CURL *curl;
/* --etag-save */ /* --etag-save */
@ -1249,8 +1257,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
/* here */ /* here */
use_proto = url_proto(per->this_url); 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 0
if(!(use_proto & built_in_protos)) { if(use_proto >= proto_last) {
warnf(global, "URL is '%s' but no support for the scheme\n", warnf(global, "URL is '%s' but no support for the scheme\n",
per->this_url); per->this_url);
} }
@ -1406,13 +1416,12 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers); 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_REFERER, config->referer);
my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
} }
if(built_in_protos & CURLPROTO_HTTP) { if(proto_http < proto_last) {
long postRedir = 0; long postRedir = 0;
my_setopt(curl, CURLOPT_FOLLOWLOCATION, my_setopt(curl, CURLOPT_FOLLOWLOCATION,
@ -1462,9 +1471,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
return result; 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, my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
config->low_speed_limit); config->low_speed_limit);
my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); 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_KEYPASSWD, config->key_passwd);
my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_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 */ /* SSH and SSL private key uses same command-line option */
/* new in libcurl 7.16.1 */ /* new in libcurl 7.16.1 */
@ -1752,7 +1762,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->path_as_is) if(config->path_as_is)
my_setopt(curl, CURLOPT_PATH_AS_IS, 1L); 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) { !config->insecure_ok) {
char *known = findfile(".ssh/known_hosts", FALSE); char *known = findfile(".ssh/known_hosts", FALSE);
if(known) { 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); my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
/* curl 7.15.1 */ /* 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 */ /* curl 7.15.2 */
if(config->localport) { if(config->localport) {
@ -1997,7 +2009,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L); my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
/* curl 7.20.0 */ /* 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); my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
if(config->mail_from) if(config->mail_from)
@ -2110,7 +2122,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
(long)(config->expect100timeout*1000)); (long)(config->expect100timeout*1000));
/* new in 7.48.0 */ /* 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); my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
/* new in 7.59.0 */ /* new in 7.59.0 */

View file

@ -34,6 +34,7 @@
#include "tool_getpass.h" #include "tool_getpass.h"
#include "tool_msgs.h" #include "tool_msgs.h"
#include "tool_paramhlp.h" #include "tool_paramhlp.h"
#include "tool_libinfo.h"
#include "tool_version.h" #include "tool_version.h"
#include "dynbuf.h" #include "dynbuf.h"
@ -270,48 +271,19 @@ ParameterError str2udouble(double *valp, const char *str, long max)
* data. * data.
*/ */
#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
ParameterError proto2num(struct OperationConfig *config, ParameterError proto2num(struct OperationConfig *config,
unsigned int val, char **ostr, const char *str) proto_set_t val, char **ostr, const char *str)
{ {
char *buffer; char *buffer;
const char *sep = ","; const char *sep = ",";
char *token; char *token;
char obuf[256] = ""; struct curlx_dynbuf obuf;
size_t olen = sizeof(obuf); proto_t proto;
char *optr; CURLcode result;
struct sprotos const *pp;
static struct sprotos { curlx_dyn_init(&obuf, MAX_PROTOSTRING);
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 }
};
if(!str) if(!str)
return PARAM_OPTION_AMBIGUOUS; return PARAM_OPTION_AMBIGUOUS;
@ -345,44 +317,52 @@ ParameterError proto2num(struct OperationConfig *config,
} }
} }
for(pp = protos; pp->name; pp++) { if(curl_strequal(token, "all")) {
if(curl_strequal(token, pp->name)) { switch(action) {
switch(action) { case deny:
case deny: val = 0;
val &= ~(pp->bit); break;
break; case allow:
case allow: case set:
val |= pp->bit; val = PROTO_ALL;
break;
case set:
val = pp->bit;
break;
}
break; break;
} }
} }
else {
if(!(pp->name)) { /* unknown protocol */ proto = scheme2protocol(token);
/* If they have specified only this protocol, we say treat it as if(proto != PROTO_NONE) {
if no protocols are allowed */ switch(action) {
if(action == set) case deny:
val = 0; val &= ~PROTO_BIT(proto);
warnf(config->global, "unrecognized protocol '%s'\n", token); break;
case set:
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;
}
}
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); Curl_safefree(buffer);
optr = obuf; result = curlx_dyn_addn(&obuf, "", 0);
for(pp = &protos[1]; pp->name; pp++) { for(proto = 0; proto < proto_last && proto < PROTO_MAX && !result; proto++)
if(val & pp->bit) { if(val & PROTO_BIT(proto))
size_t n = msnprintf(optr, olen, "%s%s", result = curlx_dyn_addf(&obuf, "%s,", protocol2scheme(proto));
olen != sizeof(obuf) ? "," : "", curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
pp->name); *ostr = curlx_dyn_ptr(&obuf);
olen -= n;
optr += n;
}
}
*ostr = strdup(obuf);
return *ostr ? PARAM_OK : PARAM_NO_MEM; return *ostr ? PARAM_OK : PARAM_NO_MEM;
} }
@ -397,14 +377,14 @@ ParameterError proto2num(struct OperationConfig *config,
*/ */
ParameterError check_protocol(const char *str) ParameterError check_protocol(const char *str)
{ {
const char * const *pp; proto_t proto;
const curl_version_info_data *curlinfo = curl_version_info(CURLVERSION_NOW);
if(!str) if(!str)
return PARAM_REQUIRES_PARAMETER; return PARAM_REQUIRES_PARAMETER;
for(pp = curlinfo->protocols; *pp; pp++) {
if(curl_strequal(*pp, str)) proto = scheme2protocol(str);
return PARAM_OK; if(proto < proto_last)
} return PARAM_OK;
return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL; return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
} }

View file

@ -24,6 +24,7 @@
* *
***************************************************************************/ ***************************************************************************/
#include "tool_setup.h" #include "tool_setup.h"
#include "tool_libinfo.h"
struct getout *new_getout(struct OperationConfig *config); 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 str2udouble(double *val, const char *str, long max);
ParameterError proto2num(struct OperationConfig *config, ParameterError proto2num(struct OperationConfig *config,
unsigned int val, char **obuf, proto_set_t val, char **obuf,
const char *str); const char *str);
ParameterError check_protocol(const char *str); ParameterError check_protocol(const char *str);

View file

@ -145,35 +145,6 @@ const struct NameValue setopt_nv_CURL_NETRC[] = {
NVEND, 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. */ /* These options have non-zero default values. */
static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
NV1(CURLOPT_SSL_VERIFYPEER, 1), NV1(CURLOPT_SSL_VERIFYPEER, 1),

View file

@ -57,7 +57,6 @@ extern const struct NameValue setopt_nv_CURLFTPSSL_CCC[];
extern const struct NameValue setopt_nv_CURLUSESSL[]; extern const struct NameValue setopt_nv_CURLUSESSL[];
extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[]; extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[];
extern const struct NameValue setopt_nv_CURL_NETRC[]; 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_CURLAUTH[];
extern const struct NameValueUnsigned setopt_nv_CURLHSTS[]; 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_SSL_OPTIONS setopt_nv_CURLSSLOPT
#define setopt_nv_CURLOPT_PROXY_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_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_PROXYTYPE setopt_nv_CURLPROXY
#define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH #define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH
#define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH #define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH