diff --git a/src/tool_doswin.c b/src/tool_doswin.c index d8695e93c2..812dac616b 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -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]; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index ea5a21ae5c..d899a9263b 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -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; diff --git a/src/tool_help.c b/src/tool_help.c index 65a1f43dfa..e25917f57a 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -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)) { diff --git a/src/tool_libinfo.c b/src/tool_libinfo.c index 801fd579f3..ba6c5c530b 100644 --- a/src/tool_libinfo.c +++ b/src/tool_libinfo.c @@ -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; } diff --git a/src/tool_libinfo.h b/src/tool_libinfo.h index 40e5aff3ee..940ed71cb6 100644 --- a/src/tool_libinfo.h +++ b/src/tool_libinfo.h @@ -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); diff --git a/src/tool_operate.c b/src/tool_operate.c index 52b766db9c..095c24bacf 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -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);