tool: use feature names instead of bit mask, when possible

If the run-time libcurl is too old to support feature names, the name
array is created locally from the bit masks. This is the only sequence
left that uses feature bit masks.

Closes #9583
This commit is contained in:
Patrick Monnerat 2022-11-09 00:37:49 +01:00 committed by Daniel Stenberg
parent e1e482517f
commit 184fc6f07a
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
6 changed files with 160 additions and 129 deletions

View file

@ -626,8 +626,7 @@ CURLcode FindWin32CACert(struct OperationConfig *config,
* ignored. We allow setting CA location for schannel only when explicitly
* specified by the user via CURLOPT_CAINFO / --cacert.
*/
if((curlinfo->features & CURL_VERSION_SSL) &&
backend != CURLSSLBACKEND_SCHANNEL) {
if(feature_ssl && backend != CURLSSLBACKEND_SCHANNEL) {
DWORD res_len;
TCHAR buf[PATH_MAX];

View file

@ -920,9 +920,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case 'j': /* --compressed */
if(toggle &&
!(curlinfo->features & (CURL_VERSION_LIBZ |
CURL_VERSION_BROTLI | CURL_VERSION_ZSTD)))
if(toggle && !(feature_libz || feature_brotli || feature_zstd))
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->encoding = toggle;
break;
@ -939,36 +937,30 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case 'l': /* --negotiate */
if(toggle) {
if(curlinfo->features & CURL_VERSION_SPNEGO)
config->authtype |= CURLAUTH_NEGOTIATE;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
else
if(!toggle)
config->authtype &= ~CURLAUTH_NEGOTIATE;
else if(feature_spnego)
config->authtype |= CURLAUTH_NEGOTIATE;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;
case 'm': /* --ntlm */
if(toggle) {
if(curlinfo->features & CURL_VERSION_NTLM)
config->authtype |= CURLAUTH_NTLM;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
else
if(!toggle)
config->authtype &= ~CURLAUTH_NTLM;
else if(feature_ntlm)
config->authtype |= CURLAUTH_NTLM;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;
case 'M': /* --ntlm-wb */
if(toggle) {
if(curlinfo->features & CURL_VERSION_NTLM_WB)
config->authtype |= CURLAUTH_NTLM_WB;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
else
if(!toggle)
config->authtype &= ~CURLAUTH_NTLM_WB;
else if(feature_ntlm_wb)
config->authtype |= CURLAUTH_NTLM_WB;
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
break;
case 'n': /* --basic for completeness */
@ -1014,10 +1006,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case 't': /* --proxy-ntlm */
if(curlinfo->features & CURL_VERSION_NTLM)
config->proxyntlm = toggle;
else
if(!feature_ntlm)
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->proxyntlm = toggle;
break;
case 'u': /* --crlf */
@ -1051,10 +1042,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case 'x': /* --krb */
/* kerberos level string */
if(curlinfo->features & CURL_VERSION_SPNEGO)
GetStr(&config->krblevel, nextarg);
else
if(!feature_spnego)
return PARAM_LIBCURL_DOESNT_SUPPORT;
GetStr(&config->krblevel, nextarg);
break;
case 'X': /* --haproxy-protocol */
config->haproxy_protocol = toggle;
@ -1114,7 +1104,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case '$': /* more options without a short option */
switch(subletter) {
case 'a': /* --ssl */
if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
if(toggle && !feature_ssl)
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->ftp_ssl = toggle;
if(config->ftp_ssl)
@ -1174,10 +1164,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case 'k': /* --proxy-negotiate */
if(curlinfo->features & CURL_VERSION_SPNEGO)
config->proxynegotiate = toggle;
else
if(!feature_spnego)
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->proxynegotiate = toggle;
break;
case 'l': /* --form-escape */
@ -1238,7 +1227,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
GetStr(&config->ftp_alternative_to_user, nextarg);
break;
case 'v': /* --ssl-reqd */
if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
if(toggle && !feature_ssl)
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->ftp_ssl_reqd = toggle;
break;
@ -1246,7 +1235,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
config->disable_sessionid = (!toggle)?TRUE:FALSE;
break;
case 'x': /* --ftp-ssl-control */
if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
if(toggle && !feature_ssl)
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->ftp_ssl_control = toggle;
break;
@ -1443,10 +1432,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case '4': /* --http3 */
/* HTTP version 3 go over QUIC - at once */
if(curlinfo->features & CURL_VERSION_HTTP3)
config->httpversion = CURL_HTTP_VERSION_3;
else
if(!feature_http3)
return PARAM_LIBCURL_DOESNT_SUPPORT;
config->httpversion = CURL_HTTP_VERSION_3;
break;
case '9':
/* Allow HTTP/0.9 responses! */
@ -1511,16 +1499,14 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case 'b':
switch(subletter) {
case 'a': /* --alt-svc */
if(curlinfo->features & CURL_VERSION_ALTSVC)
GetStr(&config->altsvc, nextarg);
else
if(!feature_altsvc)
return PARAM_LIBCURL_DOESNT_SUPPORT;
GetStr(&config->altsvc, nextarg);
break;
case 'b': /* --hsts */
if(curlinfo->features & CURL_VERSION_HSTS)
GetStr(&config->hsts, nextarg);
else
if(!feature_hsts)
return PARAM_LIBCURL_DOESNT_SUPPORT;
GetStr(&config->hsts, nextarg);
break;
default: /* --cookie string coming up: */
if(nextarg[0] == '@') {
@ -1762,7 +1748,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
GetStr(&config->crlfile, nextarg);
break;
case 'k': /* TLS username */
if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) {
if(!feature_tls_srp) {
cleanarg(clearthis);
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
@ -1770,7 +1756,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
cleanarg(clearthis);
break;
case 'l': /* TLS password */
if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) {
if(!feature_tls_srp) {
cleanarg(clearthis);
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
@ -1778,26 +1764,24 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
cleanarg(clearthis);
break;
case 'm': /* TLS authentication type */
if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
GetStr(&config->tls_authtype, nextarg);
if(!curl_strequal(config->tls_authtype, "SRP"))
return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
}
else
if(!feature_tls_srp)
return PARAM_LIBCURL_DOESNT_SUPPORT;
GetStr(&config->tls_authtype, nextarg);
if(!curl_strequal(config->tls_authtype, "SRP"))
return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
break;
case 'n': /* no empty SSL fragments, --ssl-allow-beast */
if(curlinfo->features & CURL_VERSION_SSL)
if(feature_ssl)
config->ssl_allow_beast = toggle;
break;
case 'o': /* --ssl-auto-client-cert */
if(curlinfo->features & CURL_VERSION_SSL)
if(feature_ssl)
config->ssl_auto_client_cert = toggle;
break;
case 'O': /* --proxy-ssl-auto-client-cert */
if(curlinfo->features & CURL_VERSION_SSL)
if(feature_ssl)
config->proxy_ssl_auto_client_cert = toggle;
break;
@ -1822,12 +1806,12 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case 's': /* --ssl-no-revoke */
if(curlinfo->features & CURL_VERSION_SSL)
if(feature_ssl)
config->ssl_no_revoke = TRUE;
break;
case 'S': /* --ssl-revoke-best-effort */
if(curlinfo->features & CURL_VERSION_SSL)
if(feature_ssl)
config->ssl_revoke_best_effort = TRUE;
break;
@ -1837,28 +1821,24 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case 'u': /* TLS username for proxy */
cleanarg(clearthis);
if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) {
if(!feature_tls_srp)
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
GetStr(&config->proxy_tls_username, nextarg);
break;
case 'v': /* TLS password for proxy */
cleanarg(clearthis);
if(!(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)) {
if(!feature_tls_srp)
return PARAM_LIBCURL_DOESNT_SUPPORT;
}
GetStr(&config->proxy_tls_password, nextarg);
break;
case 'w': /* TLS authentication type for proxy */
if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
GetStr(&config->proxy_tls_authtype, nextarg);
if(!curl_strequal(config->proxy_tls_authtype, "SRP"))
return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
}
else
if(!feature_tls_srp)
return PARAM_LIBCURL_DOESNT_SUPPORT;
GetStr(&config->proxy_tls_authtype, nextarg);
if(!curl_strequal(config->proxy_tls_authtype, "SRP"))
return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
break;
case 'x': /* certificate file for proxy */
@ -1893,7 +1873,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
case '4': /* no empty SSL fragments for proxy */
if(curlinfo->features & CURL_VERSION_SSL)
if(feature_ssl)
config->proxy_ssl_allow_beast = toggle;
break;

View file

@ -76,42 +76,6 @@ static const struct category_descriptors categories[] = {
extern const struct helptxt helptext[];
struct feat {
const char *name;
int bitmask;
};
static const struct feat feats[] = {
{"AsynchDNS", CURL_VERSION_ASYNCHDNS},
{"Debug", CURL_VERSION_DEBUG},
{"TrackMemory", CURL_VERSION_CURLDEBUG},
{"IDN", CURL_VERSION_IDN},
{"IPv6", CURL_VERSION_IPV6},
{"Largefile", CURL_VERSION_LARGEFILE},
{"Unicode", CURL_VERSION_UNICODE},
{"SSPI", CURL_VERSION_SSPI},
{"GSS-API", CURL_VERSION_GSSAPI},
{"Kerberos", CURL_VERSION_KERBEROS5},
{"SPNEGO", CURL_VERSION_SPNEGO},
{"NTLM", CURL_VERSION_NTLM},
{"NTLM_WB", CURL_VERSION_NTLM_WB},
{"SSL", CURL_VERSION_SSL},
{"libz", CURL_VERSION_LIBZ},
{"brotli", CURL_VERSION_BROTLI},
{"zstd", CURL_VERSION_ZSTD},
{"CharConv", CURL_VERSION_CONV},
{"TLS-SRP", CURL_VERSION_TLSAUTH_SRP},
{"HTTP2", CURL_VERSION_HTTP2},
{"HTTP3", CURL_VERSION_HTTP3},
{"UnixSockets", CURL_VERSION_UNIX_SOCKETS},
{"HTTPS-proxy", CURL_VERSION_HTTPS_PROXY},
{"MultiSSL", CURL_VERSION_MULTI_SSL},
{"PSL", CURL_VERSION_PSL},
{"alt-svc", CURL_VERSION_ALTSVC},
{"HSTS", CURL_VERSION_HSTS},
{"gsasl", CURL_VERSION_GSASL},
{"threadsafe", CURL_VERSION_THREADSAFE},
};
static void print_category(curlhelp_t category)
{
@ -191,7 +155,7 @@ void tool_help(char *category)
void tool_version_info(void)
{
const char *const *proto;
const char *const *builtin;
printf(CURL_ID "%s\n", curl_version());
#ifdef CURL_PATCHSTAMP
@ -200,28 +164,20 @@ void tool_version_info(void)
#else
printf("Release-Date: %s\n", LIBCURL_TIMESTAMP);
#endif
if(curlinfo->protocols) {
printf("Protocols: ");
for(proto = curlinfo->protocols; *proto; ++proto) {
if(built_in_protos[0]) {
printf("Protocols:");
for(builtin = built_in_protos; *builtin; ++builtin) {
/* 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);
if(!curl_strnequal(*builtin, "rtmp", 4) || !builtin[0][4])
printf(" %s", *builtin);
}
puts(""); /* newline */
}
if(curlinfo->features) {
char *featp[ sizeof(feats) / sizeof(feats[0]) + 1];
size_t numfeat = 0;
unsigned int i;
if(feature_names[0]) {
printf("Features:");
for(i = 0; i < sizeof(feats)/sizeof(feats[0]); i++) {
if(curlinfo->features & feats[i].bitmask)
featp[numfeat++] = (char *)feats[i].name;
}
qsort(&featp[0], numfeat, sizeof(char *), struplocompare4sort);
for(i = 0; i< numfeat; i++)
printf(" %s", featp[i]);
for(builtin = feature_names; *builtin; ++builtin)
printf(" %s", *builtin);
puts(""); /* newline */
}
if(strcmp(CURL_VERSION, curlinfo->version)) {

View file

@ -68,15 +68,73 @@ static struct proto_name_tokenp {
{ NULL, NULL }
};
bool feature_altsvc = FALSE;
bool feature_brotli = FALSE;
bool feature_hsts = FALSE;
bool feature_http2 = FALSE;
bool feature_http3 = FALSE;
bool feature_libz = FALSE;
bool feature_ntlm = FALSE;
bool feature_ntlm_wb = FALSE;
bool feature_spnego = FALSE;
bool feature_ssl = FALSE;
bool feature_tls_srp = FALSE;
bool feature_zstd = FALSE;
static struct feature_name_presentp {
const char *feature_name;
bool *feature_presentp;
int feature_bitmask;
} const maybe_feature[] = {
/* Keep alphabetically sorted. */
{"alt-svc", &feature_altsvc, CURL_VERSION_ALTSVC},
{"AsynchDNS", NULL, CURL_VERSION_ASYNCHDNS},
{"brotli", &feature_brotli, CURL_VERSION_BROTLI},
{"CharConv", NULL, CURL_VERSION_CONV},
{"Debug", NULL, CURL_VERSION_DEBUG},
{"gsasl", NULL, CURL_VERSION_GSASL},
{"GSS-API", NULL, CURL_VERSION_GSSAPI},
{"HSTS", &feature_hsts, CURL_VERSION_HSTS},
{"HTTP2", &feature_http2, CURL_VERSION_HTTP2},
{"HTTP3", &feature_http3, CURL_VERSION_HTTP3},
{"HTTPS-proxy", NULL, CURL_VERSION_HTTPS_PROXY},
{"IDN", NULL, CURL_VERSION_IDN},
{"IPv6", NULL, CURL_VERSION_IPV6},
{"Kerberos", NULL, CURL_VERSION_KERBEROS5},
{"Largefile", NULL, CURL_VERSION_LARGEFILE},
{"libz", &feature_libz, CURL_VERSION_LIBZ},
{"MultiSSL", NULL, CURL_VERSION_MULTI_SSL},
{"NTLM", &feature_ntlm, CURL_VERSION_NTLM},
{"NTLM_WB", &feature_ntlm_wb, CURL_VERSION_NTLM_WB},
{"PSL", NULL, CURL_VERSION_PSL},
{"SPNEGO", &feature_spnego, CURL_VERSION_SPNEGO},
{"SSL", &feature_ssl, CURL_VERSION_SSL},
{"SSPI", NULL, CURL_VERSION_SSPI},
{"threadsafe", NULL, CURL_VERSION_THREADSAFE},
{"TLS-SRP", &feature_tls_srp, CURL_VERSION_TLSAUTH_SRP},
{"TrackMemory", NULL, CURL_VERSION_CURLDEBUG},
{"Unicode", NULL, CURL_VERSION_UNICODE},
{"UnixSockets", NULL, CURL_VERSION_UNIX_SOCKETS},
{"zstd", &feature_zstd, CURL_VERSION_ZSTD},
{NULL, NULL, 0}
};
static const char *fnames[sizeof(maybe_feature) / sizeof(maybe_feature[0])];
const char * const *feature_names = fnames;
/*
* libcurl_info_init: retrieves run-time information about libcurl,
* setting a global pointer 'curlinfo' to libcurl's run-time info
* struct, count protocols and flag those we are interested in.
* Global pointer feature_names is set to the feature names array. If
* the latter is not returned by curl_version_info(), it is built from
* the returned features bit mask.
*/
CURLcode get_libcurl_info(void)
{
CURLcode result = CURLE_OK;
const char *const *builtin;
/* Pointer to libcurl's run-time version information */
curlinfo = curl_version_info(CURLVERSION_NOW);
@ -84,7 +142,6 @@ CURLcode get_libcurl_info(void)
return CURLE_FAILED_INIT;
if(curlinfo->protocols) {
const char *const *builtin;
const struct proto_name_tokenp *p;
built_in_protos = curlinfo->protocols;
@ -100,6 +157,30 @@ CURLcode get_libcurl_info(void)
proto_count = builtin - built_in_protos;
}
if(curlinfo->age >= CURLVERSION_ELEVENTH && curlinfo->feature_names)
feature_names = curlinfo->feature_names;
else {
const struct feature_name_presentp *p;
const char **cpp = fnames;
for(p = maybe_feature; p->feature_name; p++)
if(curlinfo->features & p->feature_bitmask)
*cpp++ = p->feature_name;
*cpp = NULL;
}
/* Identify features we are interested in. */
for(builtin = feature_names; *builtin; builtin++) {
const struct feature_name_presentp *p;
for(p = maybe_feature; p->feature_name; p++)
if(curl_strequal(p->feature_name, *builtin)) {
if(p->feature_presentp)
*p->feature_presentp = TRUE;
break;
}
}
return CURLE_OK;
}

View file

@ -29,9 +29,12 @@
extern curl_version_info_data *curlinfo;
extern const char * const *built_in_protos;
extern size_t proto_count;
extern const char * const *feature_names;
extern const char *proto_file;
extern const char *proto_ftp;
extern const char *proto_ftps;
@ -42,6 +45,19 @@ extern const char *proto_scp;
extern const char *proto_sftp;
extern const char *proto_tftp;
extern bool feature_altsvc;
extern bool feature_brotli;
extern bool feature_hsts;
extern bool feature_http2;
extern bool feature_http3;
extern bool feature_libz;
extern bool feature_ntlm;
extern bool feature_ntlm_wb;
extern bool feature_spnego;
extern bool feature_ssl;
extern bool feature_tls_srp;
extern bool feature_zstd;
CURLcode get_libcurl_info(void);
const char *proto_token(const char *proto);

View file

@ -1414,9 +1414,8 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->httpversion)
my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
else if(curlinfo->features & CURL_VERSION_HTTP2) {
else if(feature_http2)
my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
}
/* curl 7.19.1 (the 301 version existed in 7.18.2),
303 was added in 7.26.0 */
@ -1531,7 +1530,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->ssl_ec_curves)
my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves);
if(curlinfo->features & CURL_VERSION_SSL) {
if(feature_ssl) {
/* Check if config->cert is a PKCS#11 URI and set the
* config->cert_type if necessary */
if(config->cert) {
@ -2030,7 +2029,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
/* new in 7.21.4 */
if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
if(feature_tls_srp) {
if(config->tls_username)
my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
config->tls_username);