mirror of
https://github.com/curl/curl.git
synced 2025-02-11 14:50:40 +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
|
#endif
|
||||||
#ifdef USE_LIBRTMP
|
#ifdef USE_LIBRTMP
|
||||||
"rtmp",
|
"rtmp",
|
||||||
|
"rtmpe",
|
||||||
|
"rtmps",
|
||||||
|
"rtmpt",
|
||||||
|
"rtmpte",
|
||||||
|
"rtmpts",
|
||||||
#endif
|
#endif
|
||||||
#ifndef CURL_DISABLE_RTSP
|
#ifndef CURL_DISABLE_RTSP
|
||||||
"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 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;
|
||||||
char *scheme;
|
const char *scheme = NULL;
|
||||||
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
|
||||||
@ -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);
|
curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
|
||||||
if(scheme)
|
scheme = proto_token(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 == proto_https || protocol == proto_http)) {
|
(scheme == proto_http || scheme == proto_https)) {
|
||||||
const char *p = str + 20;
|
const char *p = str + 20;
|
||||||
|
|
||||||
/* look for the 'filename=' parameter
|
/* 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;
|
per->was_last_header_empty = TRUE;
|
||||||
}
|
}
|
||||||
if(hdrcbdata->config->show_headers &&
|
if(hdrcbdata->config->show_headers &&
|
||||||
(protocol == proto_http || protocol == proto_https ||
|
(scheme == proto_http || scheme == proto_https ||
|
||||||
protocol == proto_rtsp || protocol == proto_file)) {
|
scheme == proto_rtsp || scheme == proto_file)) {
|
||||||
/* bold headers only for selected protocols */
|
/* bold headers only for selected protocols */
|
||||||
char *value = NULL;
|
char *value = NULL;
|
||||||
|
|
||||||
|
@ -578,6 +578,15 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
|
|||||||
#ifdef HAVE_WRITABLE_ARGV
|
#ifdef HAVE_WRITABLE_ARGV
|
||||||
argv_item_t clearthis = NULL;
|
argv_item_t clearthis = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const char *redir_protos[] = {
|
||||||
|
"http",
|
||||||
|
"https",
|
||||||
|
"ftp",
|
||||||
|
"ftps",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
*usedarg = FALSE; /* default is that we don't use the arg */
|
*usedarg = FALSE; /* default is that we don't use the arg */
|
||||||
|
|
||||||
if(('-' != flag[0]) || ('-' == flag[1])) {
|
if(('-' != flag[0]) || ('-' == flag[1])) {
|
||||||
@ -1209,15 +1218,13 @@ 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, PROTO_ALL, &config->proto_str, nextarg);
|
err = proto2num(config, built_in_protos, &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, PROTO_BIT(proto_http) | PROTO_BIT(proto_https) |
|
if(proto2num(config, redir_protos, &config->proto_redir_str, nextarg))
|
||||||
PROTO_BIT(proto_ftp) | PROTO_BIT(proto_ftps),
|
|
||||||
&config->proto_redir_str, nextarg))
|
|
||||||
return PARAM_BAD_USE;
|
return PARAM_BAD_USE;
|
||||||
break;
|
break;
|
||||||
case 'F': /* --resolve */
|
case 'F': /* --resolve */
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
*
|
*
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "tool_setup.h"
|
#include "tool_setup.h"
|
||||||
#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H)
|
|
||||||
#include <strings.h>
|
|
||||||
#endif
|
|
||||||
#define ENABLE_CURLX_PRINTF
|
#define ENABLE_CURLX_PRINTF
|
||||||
/* use our own printf() functions */
|
/* use our own printf() functions */
|
||||||
#include "curlx.h"
|
#include "curlx.h"
|
||||||
@ -32,6 +29,7 @@
|
|||||||
#include "tool_panykey.h"
|
#include "tool_panykey.h"
|
||||||
#include "tool_help.h"
|
#include "tool_help.h"
|
||||||
#include "tool_libinfo.h"
|
#include "tool_libinfo.h"
|
||||||
|
#include "tool_util.h"
|
||||||
#include "tool_version.h"
|
#include "tool_version.h"
|
||||||
|
|
||||||
#include "memdebug.h" /* keep this as LAST include */
|
#include "memdebug.h" /* keep this as LAST include */
|
||||||
@ -190,22 +188,6 @@ void tool_help(char *category)
|
|||||||
free(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)
|
void tool_version_info(void)
|
||||||
{
|
{
|
||||||
@ -237,7 +219,7 @@ void tool_version_info(void)
|
|||||||
if(curlinfo->features & feats[i].bitmask)
|
if(curlinfo->features & feats[i].bitmask)
|
||||||
featp[numfeat++] = (char *)feats[i].name;
|
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++)
|
for(i = 0; i< numfeat; i++)
|
||||||
printf(" %s", featp[i]);
|
printf(" %s", featp[i]);
|
||||||
puts(""); /* newline */
|
puts(""); /* newline */
|
||||||
|
@ -35,121 +35,43 @@
|
|||||||
|
|
||||||
/* global variable definitions, for libcurl run-time info */
|
/* 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;
|
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;
|
const char *proto_file = NULL;
|
||||||
proto_t proto_ftps = PROTO_NONE;
|
const char *proto_ftp = NULL;
|
||||||
proto_t proto_http = PROTO_NONE;
|
const char *proto_ftps = NULL;
|
||||||
proto_t proto_https = PROTO_NONE;
|
const char *proto_http = NULL;
|
||||||
proto_t proto_file = PROTO_NONE;
|
const char *proto_https = NULL;
|
||||||
proto_t proto_rtsp = PROTO_NONE;
|
const char *proto_rtsp = NULL;
|
||||||
proto_t proto_scp = PROTO_NONE;
|
const char *proto_scp = NULL;
|
||||||
proto_t proto_sftp = PROTO_NONE;
|
const char *proto_sftp = NULL;
|
||||||
proto_t proto_tftp = PROTO_NONE;
|
const char *proto_tftp = NULL;
|
||||||
|
|
||||||
static struct proto_name_nump {
|
static struct proto_name_tokenp {
|
||||||
const char *proto_name;
|
const char *proto_name;
|
||||||
proto_t *proto_nump;
|
const char **proto_tokenp;
|
||||||
} const possibly_built_in[] = {
|
} const possibly_built_in[] = {
|
||||||
/* Keep entries in CURLPROTO_* order for sorting purpose. */
|
{ "file", &proto_file },
|
||||||
{ "http", &proto_http },
|
|
||||||
{ "https", &proto_https },
|
|
||||||
{ "ftp", &proto_ftp },
|
{ "ftp", &proto_ftp },
|
||||||
{ "ftps", &proto_ftps },
|
{ "ftps", &proto_ftps },
|
||||||
|
{ "http", &proto_http },
|
||||||
|
{ "https", &proto_https },
|
||||||
|
{ "rtsp", &proto_rtsp },
|
||||||
{ "scp", &proto_scp },
|
{ "scp", &proto_scp },
|
||||||
{ "sftp", &proto_sftp },
|
{ "sftp", &proto_sftp },
|
||||||
{ "telnet", NULL },
|
|
||||||
{ "ldap", NULL },
|
|
||||||
{ "ldaps", NULL },
|
|
||||||
{ "dict", NULL },
|
|
||||||
{ "file", &proto_file },
|
|
||||||
{ "tftp", &proto_tftp },
|
{ "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 }
|
{ 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,
|
* 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, Assigning numbers to specific protocols and identifying protocols
|
* struct, count protocols and flag those we are interested in.
|
||||||
* we are interested in.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CURLcode get_libcurl_info(void)
|
CURLcode get_libcurl_info(void)
|
||||||
@ -163,40 +85,40 @@ CURLcode get_libcurl_info(void)
|
|||||||
|
|
||||||
if(curlinfo->protocols) {
|
if(curlinfo->protocols) {
|
||||||
const char *const *builtin;
|
const char *const *builtin;
|
||||||
const struct proto_name_nump *p;
|
const struct proto_name_tokenp *p;
|
||||||
|
|
||||||
/* Copy protocols to local table. */
|
built_in_protos = curlinfo->protocols;
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
for(builtin = built_in_protos; !result && *builtin; builtin++) {
|
||||||
/* Identify protocols we are interested in. */
|
/* Identify protocols we are interested in. */
|
||||||
for(p = possibly_built_in; p->proto_name; p++)
|
for(p = possibly_built_in; p->proto_name; p++)
|
||||||
if(p->proto_nump)
|
if(curl_strequal(p->proto_name, *builtin)) {
|
||||||
*p->proto_nump = scheme2protocol(p->proto_name);
|
*p->proto_tokenp = *builtin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proto_count = builtin - built_in_protos;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
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 */
|
/* 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 proto_t proto_last;
|
extern const char * const *built_in_protos;
|
||||||
|
extern size_t proto_count;
|
||||||
|
|
||||||
extern proto_t proto_ftp;
|
extern const char *proto_file;
|
||||||
extern proto_t proto_ftps;
|
extern const char *proto_ftp;
|
||||||
extern proto_t proto_http;
|
extern const char *proto_ftps;
|
||||||
extern proto_t proto_https;
|
extern const char *proto_http;
|
||||||
extern proto_t proto_file;
|
extern const char *proto_https;
|
||||||
extern proto_t proto_rtsp;
|
extern const char *proto_rtsp;
|
||||||
extern proto_t proto_scp;
|
extern const char *proto_scp;
|
||||||
extern proto_t proto_sftp;
|
extern const char *proto_sftp;
|
||||||
extern proto_t proto_tftp;
|
extern const char *proto_tftp;
|
||||||
|
|
||||||
CURLcode get_libcurl_info(void);
|
CURLcode get_libcurl_info(void);
|
||||||
proto_t scheme2protocol(const char *scheme);
|
const char *proto_token(const char *proto);
|
||||||
const char *protocol2scheme(proto_t proto);
|
|
||||||
|
|
||||||
#endif /* HEADER_CURL_TOOL_LIBINFO_H */
|
#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
|
/* 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. */
|
||||||
char *scheme;
|
const char *scheme;
|
||||||
proto_t protocol = proto_last;
|
|
||||||
curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
|
curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
|
||||||
if(scheme)
|
scheme = proto_token(scheme);
|
||||||
protocol = scheme2protocol(scheme);
|
if(scheme == proto_http || scheme == proto_https) {
|
||||||
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);
|
||||||
|
|
||||||
@ -497,17 +495,13 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
|
|||||||
}
|
}
|
||||||
} /* if CURLE_OK */
|
} /* if CURLE_OK */
|
||||||
else if(result) {
|
else if(result) {
|
||||||
char *scheme;
|
const 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_SCHEME, &scheme);
|
curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
|
||||||
|
scheme = proto_token(scheme);
|
||||||
|
|
||||||
if(scheme)
|
if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4)
|
||||||
protocol = scheme2protocol(scheme);
|
|
||||||
|
|
||||||
if((protocol == proto_ftp || protocol == proto_ftps) &&
|
|
||||||
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
|
||||||
* amount of users and we are not one of them. All 4xx codes
|
* 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();
|
CURLU *uh = curl_url();
|
||||||
proto_t proto = PROTO_NONE;
|
const char *proto = NULL;
|
||||||
|
|
||||||
if(uh) {
|
if(uh) {
|
||||||
if(url) {
|
if(url) {
|
||||||
@ -708,14 +702,14 @@ static proto_t url_proto(char *url)
|
|||||||
if(!curl_url_get(uh, CURLUPART_SCHEME, &schemep,
|
if(!curl_url_get(uh, CURLUPART_SCHEME, &schemep,
|
||||||
CURLU_DEFAULT_SCHEME) &&
|
CURLU_DEFAULT_SCHEME) &&
|
||||||
schemep) {
|
schemep) {
|
||||||
proto = scheme2protocol(schemep);
|
proto = proto_token(schemep);
|
||||||
curl_free(schemep);
|
curl_free(schemep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
curl_url_cleanup(uh);
|
curl_url_cleanup(uh);
|
||||||
}
|
}
|
||||||
return proto;
|
return proto? proto: "???"; /* Never match if not found. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the next (singular) transfer */
|
/* create the next (singular) transfer */
|
||||||
@ -858,7 +852,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;
|
||||||
proto_t use_proto;
|
const char *use_proto;
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
|
|
||||||
/* --etag-save */
|
/* --etag-save */
|
||||||
@ -1257,10 +1251,8 @@ 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 >= proto_last) {
|
if(!use_proto) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -1416,12 +1408,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(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_REFERER, config->referer);
|
||||||
my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
|
my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proto_http < proto_last) {
|
if(proto_http) {
|
||||||
long postRedir = 0;
|
long postRedir = 0;
|
||||||
|
|
||||||
my_setopt(curl, CURLOPT_FOLLOWLOCATION,
|
my_setopt(curl, CURLOPT_FOLLOWLOCATION,
|
||||||
@ -1471,9 +1463,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
|||||||
return result;
|
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_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);
|
||||||
@ -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);
|
my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
|
||||||
|
|
||||||
/* curl 7.15.1 */
|
/* curl 7.15.1 */
|
||||||
if(proto_ftp < proto_last)
|
if(proto_ftp)
|
||||||
my_setopt(curl, CURLOPT_FTP_FILEMETHOD,
|
my_setopt(curl, CURLOPT_FTP_FILEMETHOD,
|
||||||
(long)config->ftp_filemethod);
|
(long)config->ftp_filemethod);
|
||||||
|
|
||||||
@ -2009,7 +2001,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 && proto_tftp < proto_last)
|
if(config->tftp_blksize && proto_tftp)
|
||||||
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)
|
||||||
@ -2122,7 +2114,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 && proto_tftp < proto_last)
|
if(config->tftp_no_options && proto_tftp)
|
||||||
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 */
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "tool_msgs.h"
|
#include "tool_msgs.h"
|
||||||
#include "tool_paramhlp.h"
|
#include "tool_paramhlp.h"
|
||||||
#include "tool_libinfo.h"
|
#include "tool_libinfo.h"
|
||||||
|
#include "tool_util.h"
|
||||||
#include "tool_version.h"
|
#include "tool_version.h"
|
||||||
#include "dynbuf.h"
|
#include "dynbuf.h"
|
||||||
|
|
||||||
@ -260,6 +261,51 @@ ParameterError str2udouble(double *valp, const char *str, long max)
|
|||||||
return PARAM_OK;
|
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
|
* Parse the string and provide an allocated libcurl compatible protocol
|
||||||
* string output. Return non-zero on failure, zero on success.
|
* 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. */
|
#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
|
||||||
|
|
||||||
ParameterError proto2num(struct OperationConfig *config,
|
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;
|
char *buffer;
|
||||||
const char *sep = ",";
|
const char *sep = ",";
|
||||||
char *token;
|
char *token;
|
||||||
|
const char **protoset;
|
||||||
struct curlx_dynbuf obuf;
|
struct curlx_dynbuf obuf;
|
||||||
proto_t proto;
|
size_t proto;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
curlx_dyn_init(&obuf, MAX_PROTOSTRING);
|
curlx_dyn_init(&obuf, MAX_PROTOSTRING);
|
||||||
@ -292,6 +339,21 @@ ParameterError proto2num(struct OperationConfig *config,
|
|||||||
if(!buffer)
|
if(!buffer)
|
||||||
return PARAM_NO_MEM;
|
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 */
|
/* Allow strtok() here since this isn't used threaded */
|
||||||
/* !checksrc! disable BANNEDFUNC 2 */
|
/* !checksrc! disable BANNEDFUNC 2 */
|
||||||
for(token = strtok(buffer, sep);
|
for(token = strtok(buffer, sep);
|
||||||
@ -312,7 +374,8 @@ ParameterError proto2num(struct OperationConfig *config,
|
|||||||
action = allow;
|
action = allow;
|
||||||
break;
|
break;
|
||||||
default: /* Includes case of terminating NULL */
|
default: /* Includes case of terminating NULL */
|
||||||
Curl_safefree(buffer);
|
free(buffer);
|
||||||
|
free((char *) protoset);
|
||||||
return PARAM_BAD_USE;
|
return PARAM_BAD_USE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,47 +383,49 @@ ParameterError proto2num(struct OperationConfig *config,
|
|||||||
if(curl_strequal(token, "all")) {
|
if(curl_strequal(token, "all")) {
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case deny:
|
case deny:
|
||||||
val = 0;
|
protoset[0] = NULL;
|
||||||
break;
|
break;
|
||||||
case allow:
|
case allow:
|
||||||
case set:
|
case set:
|
||||||
val = PROTO_ALL;
|
memcpy((char *) protoset,
|
||||||
|
built_in_protos, (proto_count + 1) * sizeof(*protoset));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
proto = scheme2protocol(token);
|
const char *p = proto_token(token);
|
||||||
if(proto != PROTO_NONE) {
|
|
||||||
|
if(p)
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case deny:
|
case deny:
|
||||||
val &= ~PROTO_BIT(proto);
|
protoset_clear(protoset, p);
|
||||||
break;
|
break;
|
||||||
case set:
|
case set:
|
||||||
val = 0;
|
protoset[0] = NULL;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case allow:
|
case allow:
|
||||||
if(proto >= PROTO_MAX)
|
protoset_set(protoset, p);
|
||||||
warnf(config->global, "protocol '%s' enabled but not accessible\n",
|
|
||||||
token);
|
|
||||||
val |= PROTO_BIT(proto);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else { /* unknown protocol */
|
else { /* unknown protocol */
|
||||||
/* If they have specified only this protocol, we say treat it as
|
/* If they have specified only this protocol, we say treat it as
|
||||||
if no protocols are allowed */
|
if no protocols are allowed */
|
||||||
if(action == set)
|
if(action == set)
|
||||||
val = 0;
|
protoset[0] = NULL;
|
||||||
warnf(config->global, "unrecognized protocol '%s'\n", token);
|
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);
|
result = curlx_dyn_addn(&obuf, "", 0);
|
||||||
for(proto = 0; proto < proto_last && proto < PROTO_MAX && !result; proto++)
|
for(proto = 0; protoset[proto] && !result; proto++)
|
||||||
if(val & PROTO_BIT(proto))
|
result = curlx_dyn_addf(&obuf, "%s,", protoset[proto]);
|
||||||
result = curlx_dyn_addf(&obuf, "%s,", protocol2scheme(proto));
|
free((char *) protoset);
|
||||||
curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
|
curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
|
||||||
*ostr = curlx_dyn_ptr(&obuf);
|
*ostr = curlx_dyn_ptr(&obuf);
|
||||||
|
|
||||||
@ -377,13 +442,10 @@ ParameterError proto2num(struct OperationConfig *config,
|
|||||||
*/
|
*/
|
||||||
ParameterError check_protocol(const char *str)
|
ParameterError check_protocol(const char *str)
|
||||||
{
|
{
|
||||||
proto_t proto;
|
|
||||||
|
|
||||||
if(!str)
|
if(!str)
|
||||||
return PARAM_REQUIRES_PARAMETER;
|
return PARAM_REQUIRES_PARAMETER;
|
||||||
|
|
||||||
proto = scheme2protocol(str);
|
if(proto_token(str))
|
||||||
if(proto < proto_last)
|
|
||||||
return PARAM_OK;
|
return PARAM_OK;
|
||||||
return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
|
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 str2udouble(double *val, const char *str, long max);
|
||||||
|
|
||||||
ParameterError proto2num(struct OperationConfig *config,
|
ParameterError proto2num(struct OperationConfig *config,
|
||||||
proto_set_t val, char **obuf,
|
const char * const *val, char **obuf,
|
||||||
const char *str);
|
const char *str);
|
||||||
|
|
||||||
ParameterError check_protocol(const char *str);
|
ParameterError check_protocol(const char *str);
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "tool_setup.h"
|
#include "tool_setup.h"
|
||||||
|
|
||||||
|
#if defined(HAVE_STRCASECMP) && defined(HAVE_STRINGS_H)
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "tool_util.h"
|
#include "tool_util.h"
|
||||||
|
|
||||||
#include "memdebug.h" /* keep this as LAST include */
|
#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+
|
return (long)(newer.tv_sec-older.tv_sec)*1000+
|
||||||
(long)(newer.tv_usec-older.tv_usec)/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);
|
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 */
|
#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);
|
curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
|
||||||
%endif
|
%endif
|
||||||
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
|
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
|
/* 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
|
as source easily. You may choose to either not use them or implement
|
||||||
|
Loading…
Reference in New Issue
Block a user