mirror of
https://github.com/curl/curl.git
synced 2025-02-05 14:30:10 +08:00
tool: remove protocol count limitation
Replace bit mask protocol sets by null-terminated arrays of protocol tokens. These are the addresses of the protocol names returned by curl_version_info(). Protocol names are sorted case-insensitively before output to satisfy CI tests matches consistency. The protocol list returned by curl_version_info() is augmented with all RTMP protocol variants. Test 1401 adjusted for new alpha ordered output. Closes #9546
This commit is contained in:
parent
fb11e45f9c
commit
677266c769
@ -338,6 +338,11 @@ static const char * const protocols[] = {
|
||||
#endif
|
||||
#ifdef USE_LIBRTMP
|
||||
"rtmp",
|
||||
"rtmpe",
|
||||
"rtmps",
|
||||
"rtmpt",
|
||||
"rtmpte",
|
||||
"rtmpts",
|
||||
#endif
|
||||
#ifndef CURL_DISABLE_RTSP
|
||||
"rtsp",
|
||||
|
@ -75,8 +75,7 @@ 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;
|
||||
char *scheme;
|
||||
proto_t protocol = proto_last;
|
||||
const char *scheme = NULL;
|
||||
|
||||
/*
|
||||
* Once that libcurl has called back tool_header_cb() the returned value
|
||||
@ -142,11 +141,10 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
*/
|
||||
|
||||
curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
|
||||
if(scheme)
|
||||
protocol = scheme2protocol(scheme);
|
||||
scheme = proto_token(scheme);
|
||||
if(hdrcbdata->honor_cd_filename &&
|
||||
(cb > 20) && checkprefix("Content-disposition:", str) &&
|
||||
(protocol == proto_https || protocol == proto_http)) {
|
||||
(scheme == proto_http || scheme == proto_https)) {
|
||||
const char *p = str + 20;
|
||||
|
||||
/* look for the 'filename=' parameter
|
||||
@ -206,8 +204,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 == proto_http || protocol == proto_https ||
|
||||
protocol == proto_rtsp || protocol == proto_file)) {
|
||||
(scheme == proto_http || scheme == proto_https ||
|
||||
scheme == proto_rtsp || scheme == proto_file)) {
|
||||
/* bold headers only for selected protocols */
|
||||
char *value = NULL;
|
||||
|
||||
|
@ -578,6 +578,15 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||
#ifdef HAVE_WRITABLE_ARGV
|
||||
argv_item_t clearthis = NULL;
|
||||
#endif
|
||||
|
||||
static const char *redir_protos[] = {
|
||||
"http",
|
||||
"https",
|
||||
"ftp",
|
||||
"ftps",
|
||||
NULL
|
||||
};
|
||||
|
||||
*usedarg = FALSE; /* default is that we don't use the arg */
|
||||
|
||||
if(('-' != flag[0]) || ('-' == flag[1])) {
|
||||
@ -1209,15 +1218,13 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
||||
break;
|
||||
case 'D': /* --proto */
|
||||
config->proto_present = TRUE;
|
||||
err = proto2num(config, PROTO_ALL, &config->proto_str, nextarg);
|
||||
err = proto2num(config, built_in_protos, &config->proto_str, nextarg);
|
||||
if(err)
|
||||
return err;
|
||||
break;
|
||||
case 'E': /* --proto-redir */
|
||||
config->proto_redir_present = TRUE;
|
||||
if(proto2num(config, PROTO_BIT(proto_http) | PROTO_BIT(proto_https) |
|
||||
PROTO_BIT(proto_ftp) | PROTO_BIT(proto_ftps),
|
||||
&config->proto_redir_str, nextarg))
|
||||
if(proto2num(config, redir_protos, &config->proto_redir_str, nextarg))
|
||||
return PARAM_BAD_USE;
|
||||
break;
|
||||
case 'F': /* --resolve */
|
||||
|
@ -22,9 +22,6 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H)
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#define ENABLE_CURLX_PRINTF
|
||||
/* use our own printf() functions */
|
||||
#include "curlx.h"
|
||||
@ -32,6 +29,7 @@
|
||||
#include "tool_panykey.h"
|
||||
#include "tool_help.h"
|
||||
#include "tool_libinfo.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_version.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
@ -190,22 +188,6 @@ void tool_help(char *category)
|
||||
free(category);
|
||||
}
|
||||
|
||||
static int
|
||||
featcomp(const void *p1, const void *p2)
|
||||
{
|
||||
/* The arguments to this function are "pointers to pointers to char", but
|
||||
the comparison arguments are "pointers to char", hence the following cast
|
||||
plus dereference */
|
||||
#ifdef HAVE_STRCASECMP
|
||||
return strcasecmp(* (char * const *) p1, * (char * const *) p2);
|
||||
#elif defined(HAVE_STRCMPI)
|
||||
return strcmpi(* (char * const *) p1, * (char * const *) p2);
|
||||
#elif defined(HAVE_STRICMP)
|
||||
return stricmp(* (char * const *) p1, * (char * const *) p2);
|
||||
#else
|
||||
return strcmp(* (char * const *) p1, * (char * const *) p2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tool_version_info(void)
|
||||
{
|
||||
@ -237,7 +219,7 @@ void tool_version_info(void)
|
||||
if(curlinfo->features & feats[i].bitmask)
|
||||
featp[numfeat++] = (char *)feats[i].name;
|
||||
}
|
||||
qsort(&featp[0], numfeat, sizeof(char *), featcomp);
|
||||
qsort(&featp[0], numfeat, sizeof(char *), struplocompare4sort);
|
||||
for(i = 0; i< numfeat; i++)
|
||||
printf(" %s", featp[i]);
|
||||
puts(""); /* newline */
|
||||
|
@ -35,121 +35,43 @@
|
||||
|
||||
/* global variable definitions, for libcurl run-time info */
|
||||
|
||||
#define MAX_PROTOS 64 /* Maximum number of supported protocols. */
|
||||
static const char *no_protos = NULL;
|
||||
|
||||
curl_version_info_data *curlinfo = NULL;
|
||||
const char * const *built_in_protos = &no_protos;
|
||||
|
||||
proto_t proto_last = 0;
|
||||
size_t proto_count = 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;
|
||||
const char *proto_file = NULL;
|
||||
const char *proto_ftp = NULL;
|
||||
const char *proto_ftps = NULL;
|
||||
const char *proto_http = NULL;
|
||||
const char *proto_https = NULL;
|
||||
const char *proto_rtsp = NULL;
|
||||
const char *proto_scp = NULL;
|
||||
const char *proto_sftp = NULL;
|
||||
const char *proto_tftp = NULL;
|
||||
|
||||
static struct proto_name_nump {
|
||||
const char *proto_name;
|
||||
proto_t *proto_nump;
|
||||
static struct proto_name_tokenp {
|
||||
const char *proto_name;
|
||||
const char **proto_tokenp;
|
||||
} const possibly_built_in[] = {
|
||||
/* Keep entries in CURLPROTO_* order for sorting purpose. */
|
||||
{ "http", &proto_http },
|
||||
{ "https", &proto_https },
|
||||
{ "file", &proto_file },
|
||||
{ "ftp", &proto_ftp },
|
||||
{ "ftps", &proto_ftps },
|
||||
{ "http", &proto_http },
|
||||
{ "https", &proto_https },
|
||||
{ "rtsp", &proto_rtsp },
|
||||
{ "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 prototype 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, Assigning numbers to specific protocols and identifying protocols
|
||||
* we are interested in.
|
||||
* struct, count protocols and flag those we are interested in.
|
||||
*/
|
||||
|
||||
CURLcode get_libcurl_info(void)
|
||||
@ -163,40 +85,40 @@ CURLcode get_libcurl_info(void)
|
||||
|
||||
if(curlinfo->protocols) {
|
||||
const char *const *builtin;
|
||||
const struct proto_name_nump *p;
|
||||
const struct proto_name_tokenp *p;
|
||||
|
||||
/* Copy protocols to local table. */
|
||||
for(builtin = curlinfo->protocols; !result && *builtin; builtin++)
|
||||
result = enter_proto(*builtin);
|
||||
built_in_protos = curlinfo->protocols;
|
||||
|
||||
/* 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");
|
||||
for(builtin = built_in_protos; !result && *builtin; builtin++) {
|
||||
/* Identify protocols we are interested in. */
|
||||
for(p = possibly_built_in; p->proto_name; p++)
|
||||
if(curl_strequal(p->proto_name, *builtin)) {
|
||||
*p->proto_tokenp = *builtin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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((char *)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);
|
||||
proto_count = builtin - built_in_protos;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Tokenize a protocol name.
|
||||
* Return the address of the protocol name listed by the library, or NULL if
|
||||
* not found.
|
||||
* Although this may seem useless, this always returns the same address for
|
||||
* a given protocol and thus allows comparing pointers rather than strings.
|
||||
* In addition, the returned pointer is not deallocated until the program ends.
|
||||
*/
|
||||
|
||||
const char *proto_token(const char *proto)
|
||||
{
|
||||
const char * const *builtin;
|
||||
|
||||
if(!proto)
|
||||
return NULL;
|
||||
for(builtin = built_in_protos; *builtin; builtin++)
|
||||
if(curl_strequal(*builtin, proto))
|
||||
break;
|
||||
return *builtin;
|
||||
}
|
||||
|
@ -27,38 +27,22 @@
|
||||
|
||||
/* 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 proto_t proto_last;
|
||||
extern const char * const *built_in_protos;
|
||||
extern size_t proto_count;
|
||||
|
||||
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;
|
||||
extern const char *proto_file;
|
||||
extern const char *proto_ftp;
|
||||
extern const char *proto_ftps;
|
||||
extern const char *proto_http;
|
||||
extern const char *proto_https;
|
||||
extern const char *proto_rtsp;
|
||||
extern const char *proto_scp;
|
||||
extern const char *proto_sftp;
|
||||
extern const char *proto_tftp;
|
||||
|
||||
CURLcode get_libcurl_info(void);
|
||||
proto_t scheme2protocol(const char *scheme);
|
||||
const char *protocol2scheme(proto_t proto);
|
||||
const char *proto_token(const char *proto);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_LIBINFO_H */
|
||||
|
@ -465,12 +465,10 @@ 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. */
|
||||
char *scheme;
|
||||
proto_t protocol = proto_last;
|
||||
const char *scheme;
|
||||
curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
|
||||
if(scheme)
|
||||
protocol = scheme2protocol(scheme);
|
||||
if(protocol == proto_http || protocol == proto_https) {
|
||||
scheme = proto_token(scheme);
|
||||
if(scheme == proto_http || scheme == proto_https) {
|
||||
/* This was HTTP(S) */
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
|
||||
@ -497,17 +495,13 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
|
||||
}
|
||||
} /* if CURLE_OK */
|
||||
else if(result) {
|
||||
char *scheme;
|
||||
proto_t protocol = proto_last;
|
||||
const char *scheme;
|
||||
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
|
||||
scheme = proto_token(scheme);
|
||||
|
||||
if(scheme)
|
||||
protocol = scheme2protocol(scheme);
|
||||
|
||||
if((protocol == proto_ftp || protocol == proto_ftps) &&
|
||||
response / 100 == 4)
|
||||
if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4)
|
||||
/*
|
||||
* This is typically when the FTP server only allows a certain
|
||||
* amount of users and we are not one of them. All 4xx codes
|
||||
@ -693,12 +687,12 @@ static void single_transfer_cleanup(struct OperationConfig *config)
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the proto bit for the scheme used in the given URL
|
||||
* Return the protocol token for the scheme used in the given URL
|
||||
*/
|
||||
static proto_t url_proto(char *url)
|
||||
static const char *url_proto(char *url)
|
||||
{
|
||||
CURLU *uh = curl_url();
|
||||
proto_t proto = PROTO_NONE;
|
||||
const char *proto = NULL;
|
||||
|
||||
if(uh) {
|
||||
if(url) {
|
||||
@ -708,14 +702,14 @@ static proto_t url_proto(char *url)
|
||||
if(!curl_url_get(uh, CURLUPART_SCHEME, &schemep,
|
||||
CURLU_DEFAULT_SCHEME) &&
|
||||
schemep) {
|
||||
proto = scheme2protocol(schemep);
|
||||
proto = proto_token(schemep);
|
||||
curl_free(schemep);
|
||||
}
|
||||
}
|
||||
}
|
||||
curl_url_cleanup(uh);
|
||||
}
|
||||
return proto;
|
||||
return proto? proto: "???"; /* Never match if not found. */
|
||||
}
|
||||
|
||||
/* create the next (singular) transfer */
|
||||
@ -858,7 +852,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
struct OutStruct *etag_save;
|
||||
struct HdrCbData *hdrcbdata = NULL;
|
||||
struct OutStruct etag_first;
|
||||
proto_t use_proto;
|
||||
const char *use_proto;
|
||||
CURL *curl;
|
||||
|
||||
/* --etag-save */
|
||||
@ -1257,10 +1251,8 @@ 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 >= proto_last) {
|
||||
if(!use_proto) {
|
||||
warnf(global, "URL is '%s' but no support for the scheme\n",
|
||||
per->this_url);
|
||||
}
|
||||
@ -1416,12 +1408,12 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
|
||||
my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
|
||||
|
||||
if(proto_http < proto_last || proto_rtsp < proto_last) {
|
||||
if(proto_http || proto_rtsp) {
|
||||
my_setopt_str(curl, CURLOPT_REFERER, config->referer);
|
||||
my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
|
||||
}
|
||||
|
||||
if(proto_http < proto_last) {
|
||||
if(proto_http) {
|
||||
long postRedir = 0;
|
||||
|
||||
my_setopt(curl, CURLOPT_FOLLOWLOCATION,
|
||||
@ -1471,9 +1463,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
return result;
|
||||
}
|
||||
|
||||
} /* (proto_http < proto_last) */
|
||||
} /* (proto_http) */
|
||||
|
||||
if(proto_ftp < proto_last)
|
||||
if(proto_ftp)
|
||||
my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
|
||||
my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
|
||||
config->low_speed_limit);
|
||||
@ -1972,7 +1964,7 @@ 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 */
|
||||
if(proto_ftp < proto_last)
|
||||
if(proto_ftp)
|
||||
my_setopt(curl, CURLOPT_FTP_FILEMETHOD,
|
||||
(long)config->ftp_filemethod);
|
||||
|
||||
@ -2009,7 +2001,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
|
||||
|
||||
/* curl 7.20.0 */
|
||||
if(config->tftp_blksize && proto_tftp < proto_last)
|
||||
if(config->tftp_blksize && proto_tftp)
|
||||
my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
|
||||
|
||||
if(config->mail_from)
|
||||
@ -2122,7 +2114,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
(long)(config->expect100timeout*1000));
|
||||
|
||||
/* new in 7.48.0 */
|
||||
if(config->tftp_no_options && proto_tftp < proto_last)
|
||||
if(config->tftp_no_options && proto_tftp)
|
||||
my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
|
||||
|
||||
/* new in 7.59.0 */
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_paramhlp.h"
|
||||
#include "tool_libinfo.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_version.h"
|
||||
#include "dynbuf.h"
|
||||
|
||||
@ -260,6 +261,51 @@ ParameterError str2udouble(double *valp, const char *str, long max)
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement protocol sets in null-terminated array of protocol name pointers.
|
||||
*/
|
||||
|
||||
/* Return index of prototype token in set, card(set) if not found.
|
||||
Can be called with proto == NULL to get card(set). */
|
||||
static size_t protoset_index(const char * const *protoset, const char *proto)
|
||||
{
|
||||
const char * const *p = protoset;
|
||||
|
||||
for(; *p; p++)
|
||||
if(proto == *p)
|
||||
break;
|
||||
return p - protoset;
|
||||
}
|
||||
|
||||
/* Include protocol token in set. */
|
||||
static void protoset_set(const char **protoset, const char *proto)
|
||||
{
|
||||
if(proto) {
|
||||
size_t n = protoset_index(protoset, proto);
|
||||
|
||||
if(!protoset[n]) {
|
||||
DEBUGASSERT(n < proto_count);
|
||||
protoset[n] = proto;
|
||||
protoset[n + 1] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Exclude protocol token from set. */
|
||||
static void protoset_clear(const char **protoset, const char *proto)
|
||||
{
|
||||
if(proto) {
|
||||
size_t n = protoset_index(protoset, proto);
|
||||
|
||||
if(protoset[n]) {
|
||||
size_t m = protoset_index(protoset, NULL) - 1;
|
||||
|
||||
protoset[n] = protoset[m];
|
||||
protoset[m] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string and provide an allocated libcurl compatible protocol
|
||||
* string output. Return non-zero on failure, zero on success.
|
||||
@ -274,13 +320,14 @@ ParameterError str2udouble(double *valp, const char *str, long max)
|
||||
#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
|
||||
|
||||
ParameterError proto2num(struct OperationConfig *config,
|
||||
proto_set_t val, char **ostr, const char *str)
|
||||
const char * const *val, char **ostr, const char *str)
|
||||
{
|
||||
char *buffer;
|
||||
const char *sep = ",";
|
||||
char *token;
|
||||
const char **protoset;
|
||||
struct curlx_dynbuf obuf;
|
||||
proto_t proto;
|
||||
size_t proto;
|
||||
CURLcode result;
|
||||
|
||||
curlx_dyn_init(&obuf, MAX_PROTOSTRING);
|
||||
@ -292,6 +339,21 @@ ParameterError proto2num(struct OperationConfig *config,
|
||||
if(!buffer)
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
protoset = malloc((proto_count + 1) * sizeof(*protoset));
|
||||
if(!protoset) {
|
||||
free(buffer);
|
||||
return PARAM_NO_MEM;
|
||||
}
|
||||
|
||||
/* Preset protocol set with default values. */
|
||||
protoset[0] = NULL;
|
||||
for(; *val; val++) {
|
||||
const char *p = proto_token(*val);
|
||||
|
||||
if(p)
|
||||
protoset_set(protoset, p);
|
||||
}
|
||||
|
||||
/* Allow strtok() here since this isn't used threaded */
|
||||
/* !checksrc! disable BANNEDFUNC 2 */
|
||||
for(token = strtok(buffer, sep);
|
||||
@ -312,7 +374,8 @@ ParameterError proto2num(struct OperationConfig *config,
|
||||
action = allow;
|
||||
break;
|
||||
default: /* Includes case of terminating NULL */
|
||||
Curl_safefree(buffer);
|
||||
free(buffer);
|
||||
free((char *) protoset);
|
||||
return PARAM_BAD_USE;
|
||||
}
|
||||
}
|
||||
@ -320,47 +383,49 @@ ParameterError proto2num(struct OperationConfig *config,
|
||||
if(curl_strequal(token, "all")) {
|
||||
switch(action) {
|
||||
case deny:
|
||||
val = 0;
|
||||
protoset[0] = NULL;
|
||||
break;
|
||||
case allow:
|
||||
case set:
|
||||
val = PROTO_ALL;
|
||||
memcpy((char *) protoset,
|
||||
built_in_protos, (proto_count + 1) * sizeof(*protoset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
proto = scheme2protocol(token);
|
||||
if(proto != PROTO_NONE) {
|
||||
const char *p = proto_token(token);
|
||||
|
||||
if(p)
|
||||
switch(action) {
|
||||
case deny:
|
||||
val &= ~PROTO_BIT(proto);
|
||||
protoset_clear(protoset, p);
|
||||
break;
|
||||
case set:
|
||||
val = 0;
|
||||
protoset[0] = NULL;
|
||||
/* FALLTHROUGH */
|
||||
case allow:
|
||||
if(proto >= PROTO_MAX)
|
||||
warnf(config->global, "protocol '%s' enabled but not accessible\n",
|
||||
token);
|
||||
val |= PROTO_BIT(proto);
|
||||
protoset_set(protoset, p);
|
||||
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;
|
||||
protoset[0] = NULL;
|
||||
warnf(config->global, "unrecognized protocol '%s'\n", token);
|
||||
}
|
||||
}
|
||||
}
|
||||
Curl_safefree(buffer);
|
||||
free(buffer);
|
||||
|
||||
/* We need the protocols in alphabetic order for CI tests requirements. */
|
||||
qsort((char *) protoset, protoset_index(protoset, NULL), sizeof(*protoset),
|
||||
struplocompare4sort);
|
||||
|
||||
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));
|
||||
for(proto = 0; protoset[proto] && !result; proto++)
|
||||
result = curlx_dyn_addf(&obuf, "%s,", protoset[proto]);
|
||||
free((char *) protoset);
|
||||
curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
|
||||
*ostr = curlx_dyn_ptr(&obuf);
|
||||
|
||||
@ -377,13 +442,10 @@ ParameterError proto2num(struct OperationConfig *config,
|
||||
*/
|
||||
ParameterError check_protocol(const char *str)
|
||||
{
|
||||
proto_t proto;
|
||||
|
||||
if(!str)
|
||||
return PARAM_REQUIRES_PARAMETER;
|
||||
|
||||
proto = scheme2protocol(str);
|
||||
if(proto < proto_last)
|
||||
if(proto_token(str))
|
||||
return PARAM_OK;
|
||||
return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
@ -39,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,
|
||||
proto_set_t val, char **obuf,
|
||||
const char * const *val, char **obuf,
|
||||
const char *str);
|
||||
|
||||
ParameterError check_protocol(const char *str);
|
||||
|
@ -23,6 +23,10 @@
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H)
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "tool_util.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
@ -135,3 +139,27 @@ long tvdiff(struct timeval newer, struct timeval older)
|
||||
return (long)(newer.tv_sec-older.tv_sec)*1000+
|
||||
(long)(newer.tv_usec-older.tv_usec)/1000;
|
||||
}
|
||||
|
||||
/* Case insensitive compare. Accept NULL pointers. */
|
||||
int struplocompare(const char *p1, const char *p2)
|
||||
{
|
||||
if(!p1)
|
||||
return p2? -1: 0;
|
||||
if(!p2)
|
||||
return 1;
|
||||
#ifdef HAVE_STRCASECMP
|
||||
return strcasecmp(p1, p2);
|
||||
#elif defined(HAVE_STRCMPI)
|
||||
return strcmpi(p1, p2);
|
||||
#elif defined(HAVE_STRICMP)
|
||||
return stricmp(p1, p2);
|
||||
#else
|
||||
return strcmp(p1, p2);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Indirect version to use as qsort callback. */
|
||||
int struplocompare4sort(const void *p1, const void *p2)
|
||||
{
|
||||
return struplocompare(* (char * const *) p1, * (char * const *) p2);
|
||||
}
|
||||
|
@ -35,4 +35,8 @@ struct timeval tvnow(void);
|
||||
*/
|
||||
long tvdiff(struct timeval t1, struct timeval t2);
|
||||
|
||||
/* Case insensitive comparison support. */
|
||||
int struplocompare(const char *p1, const char *p2);
|
||||
int struplocompare4sort(const void *p1, const void *p2);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_UTIL_H */
|
||||
|
@ -96,7 +96,7 @@ int main(int argc, char *argv[])
|
||||
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
|
||||
%endif
|
||||
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
|
||||
curl_easy_setopt(hnd, CURLOPT_PROTOCOLS_STR, "http,ftp,file");
|
||||
curl_easy_setopt(hnd, CURLOPT_PROTOCOLS_STR, "file,ftp,http");
|
||||
|
||||
/* Here is a list of options the curl code used that cannot get generated
|
||||
as source easily. You may choose to either not use them or implement
|
||||
|
Loading…
Reference in New Issue
Block a user