mirror of
https://github.com/curl/curl.git
synced 2026-07-26 20:57:18 +03:00
setopt: use the handler table for protocol name to number conversions
This also returns error CURLE_UNSUPPORTED_PROTOCOL rather than CURLE_BAD_FUNCTION_ARGUMENT when a listed protocol name is not found. A new schemelen parameter is added to Curl_builtin_scheme() to support this extended use. Note that disabled protocols are not recognized anymore. Tests adapted accordingly. Closes #9472
This commit is contained in:
parent
1bbffa0833
commit
9d51329047
8 changed files with 90 additions and 98 deletions
83
lib/setopt.c
83
lib/setopt.c
|
|
@ -148,85 +148,36 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
|
||||||
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
|
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
|
||||||
#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
|
#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
|
||||||
|
|
||||||
static CURLcode protocol2num(char *str, curl_prot_t *val)
|
static CURLcode protocol2num(const char *str, curl_prot_t *val)
|
||||||
{
|
{
|
||||||
bool found_comma = FALSE;
|
|
||||||
static struct scheme {
|
|
||||||
const char *name;
|
|
||||||
curl_prot_t bit;
|
|
||||||
} const protos[] = {
|
|
||||||
{ "dict", CURLPROTO_DICT },
|
|
||||||
{ "file", CURLPROTO_FILE },
|
|
||||||
{ "ftp", CURLPROTO_FTP },
|
|
||||||
{ "ftps", CURLPROTO_FTPS },
|
|
||||||
{ "gopher", CURLPROTO_GOPHER },
|
|
||||||
{ "gophers", CURLPROTO_GOPHERS },
|
|
||||||
{ "http", CURLPROTO_HTTP },
|
|
||||||
{ "https", CURLPROTO_HTTPS },
|
|
||||||
{ "imap", CURLPROTO_IMAP },
|
|
||||||
{ "imaps", CURLPROTO_IMAPS },
|
|
||||||
{ "ldap", CURLPROTO_LDAP },
|
|
||||||
{ "ldaps", CURLPROTO_LDAPS },
|
|
||||||
{ "mqtt", CURLPROTO_MQTT },
|
|
||||||
{ "pop3", CURLPROTO_POP3 },
|
|
||||||
{ "pop3s", CURLPROTO_POP3S },
|
|
||||||
{ "rtmp", CURLPROTO_RTMP },
|
|
||||||
{ "rtmpe", CURLPROTO_RTMPE },
|
|
||||||
{ "rtmps", CURLPROTO_RTMPS },
|
|
||||||
{ "rtmpt", CURLPROTO_RTMPT },
|
|
||||||
{ "rtmpte", CURLPROTO_RTMPTE },
|
|
||||||
{ "rtmpts", CURLPROTO_RTMPTS },
|
|
||||||
{ "rtsp", CURLPROTO_RTSP },
|
|
||||||
{ "scp", CURLPROTO_SCP },
|
|
||||||
{ "sftp", CURLPROTO_SFTP },
|
|
||||||
{ "smb", CURLPROTO_SMB },
|
|
||||||
{ "smbs", CURLPROTO_SMBS },
|
|
||||||
{ "smtp", CURLPROTO_SMTP },
|
|
||||||
{ "smtps", CURLPROTO_SMTPS },
|
|
||||||
{ "telnet", CURLPROTO_TELNET },
|
|
||||||
{ "tftp", CURLPROTO_TFTP },
|
|
||||||
#ifdef USE_WEBSOCKETS
|
|
||||||
{ "ws", CURLPROTO_WS },
|
|
||||||
{ "wss", CURLPROTO_WSS },
|
|
||||||
#endif
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
if(!str)
|
if(!str)
|
||||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
else if(curl_strequal(str, "all")) {
|
|
||||||
*val = (curl_prot_t)~0;
|
if(curl_strequal(str, "all")) {
|
||||||
|
*val = ~(curl_prot_t) 0;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
*val = 0;
|
*val = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
const char *token = str;
|
||||||
size_t tlen;
|
size_t tlen;
|
||||||
struct scheme const *pp;
|
|
||||||
char *token;
|
str = strchr(str, ',');
|
||||||
token = strchr(str, ',');
|
tlen = str? (size_t) (str - token): strlen(token);
|
||||||
found_comma = token ? TRUE : FALSE;
|
|
||||||
if(!token)
|
|
||||||
token = strchr(str, '\0');
|
|
||||||
tlen = token - str;
|
|
||||||
if(tlen) {
|
if(tlen) {
|
||||||
for(pp = protos; pp->name; pp++) {
|
const struct Curl_handler *h = Curl_builtin_scheme(token, tlen);
|
||||||
if((strlen(pp->name) == tlen) &&
|
|
||||||
curl_strnequal(str, pp->name, tlen)) {
|
if(!h)
|
||||||
*val |= pp->bit;
|
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
break;
|
|
||||||
}
|
*val |= h->protocol;
|
||||||
}
|
|
||||||
if(!(pp->name))
|
|
||||||
/* protocol name didn't match */
|
|
||||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
|
||||||
}
|
}
|
||||||
if(found_comma)
|
} while(str++);
|
||||||
str = token + 1;
|
|
||||||
} while(found_comma);
|
|
||||||
if(!*val)
|
if(!*val)
|
||||||
/* no matching protocol */
|
/* no protocol listed */
|
||||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1700,7 +1700,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
|
||||||
return Curl_uc_to_curlcode(uc);
|
return Curl_uc_to_curlcode(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
p = Curl_builtin_scheme(scheme);
|
p = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED);
|
||||||
if(p && (p->protocol != data->info.conn_protocol)) {
|
if(p && (p->protocol != data->info.conn_protocol)) {
|
||||||
infof(data, "Clear auth, redirects scheme from %s to %s",
|
infof(data, "Clear auth, redirects scheme from %s to %s",
|
||||||
data->info.conn_scheme, scheme);
|
data->info.conn_scheme, scheme);
|
||||||
|
|
|
||||||
12
lib/url.c
12
lib/url.c
|
|
@ -1853,15 +1853,18 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the handler if the given scheme is built-in */
|
/* returns the handler if the given scheme is built-in */
|
||||||
const struct Curl_handler *Curl_builtin_scheme(const char *scheme)
|
const struct Curl_handler *Curl_builtin_scheme(const char *scheme,
|
||||||
|
size_t schemelen)
|
||||||
{
|
{
|
||||||
const struct Curl_handler * const *pp;
|
const struct Curl_handler * const *pp;
|
||||||
const struct Curl_handler *p;
|
const struct Curl_handler *p;
|
||||||
/* Scan protocol handler table and match against 'scheme'. The handler may
|
/* Scan protocol handler table and match against 'scheme'. The handler may
|
||||||
be changed later when the protocol specific setup function is called. */
|
be changed later when the protocol specific setup function is called. */
|
||||||
|
if(schemelen == CURL_ZERO_TERMINATED)
|
||||||
|
schemelen = strlen(scheme);
|
||||||
for(pp = protocols; (p = *pp) != NULL; pp++)
|
for(pp = protocols; (p = *pp) != NULL; pp++)
|
||||||
if(strcasecompare(p->scheme, scheme))
|
if(strncasecompare(p->scheme, scheme, schemelen) && !p->scheme[schemelen])
|
||||||
/* Protocol found in table. Check if allowed */
|
/* Protocol found in table. */
|
||||||
return p;
|
return p;
|
||||||
return NULL; /* not found */
|
return NULL; /* not found */
|
||||||
}
|
}
|
||||||
|
|
@ -1871,7 +1874,8 @@ static CURLcode findprotocol(struct Curl_easy *data,
|
||||||
struct connectdata *conn,
|
struct connectdata *conn,
|
||||||
const char *protostr)
|
const char *protostr)
|
||||||
{
|
{
|
||||||
const struct Curl_handler *p = Curl_builtin_scheme(protostr);
|
const struct Curl_handler *p = Curl_builtin_scheme(protostr,
|
||||||
|
CURL_ZERO_TERMINATED);
|
||||||
|
|
||||||
if(p && /* Protocol found in table. Check if allowed */
|
if(p && /* Protocol found in table. Check if allowed */
|
||||||
(data->set.allowed_protocols & p->protocol)) {
|
(data->set.allowed_protocols & p->protocol)) {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
|
||||||
char **userptr, char **passwdptr,
|
char **userptr, char **passwdptr,
|
||||||
char **optionsptr);
|
char **optionsptr);
|
||||||
|
|
||||||
const struct Curl_handler *Curl_builtin_scheme(const char *scheme);
|
const struct Curl_handler *Curl_builtin_scheme(const char *scheme,
|
||||||
|
size_t schemelen);
|
||||||
|
|
||||||
bool Curl_is_ASCII_name(const char *hostname);
|
bool Curl_is_ASCII_name(const char *hostname);
|
||||||
CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
|
CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
|
||||||
|
|
|
||||||
12
lib/urlapi.c
12
lib/urlapi.c
|
|
@ -431,7 +431,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
|
||||||
|
|
||||||
/* if this is a known scheme, get some details */
|
/* if this is a known scheme, get some details */
|
||||||
if(u->scheme)
|
if(u->scheme)
|
||||||
h = Curl_builtin_scheme(u->scheme);
|
h = Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
|
||||||
|
|
||||||
/* We could use the login information in the URL so extract it. Only parse
|
/* We could use the login information in the URL so extract it. Only parse
|
||||||
options if the handler says we should. Note that 'h' might be NULL! */
|
options if the handler says we should. Note that 'h' might be NULL! */
|
||||||
|
|
@ -1071,7 +1071,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
schemep = schemebuf;
|
schemep = schemebuf;
|
||||||
if(!Curl_builtin_scheme(schemep) &&
|
if(!Curl_builtin_scheme(schemep, CURL_ZERO_TERMINATED) &&
|
||||||
!(flags & CURLU_NON_SUPPORT_SCHEME)) {
|
!(flags & CURLU_NON_SUPPORT_SCHEME)) {
|
||||||
result = CURLUE_UNSUPPORTED_SCHEME;
|
result = CURLUE_UNSUPPORTED_SCHEME;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1412,7 +1412,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||||
/* there's no stored port number, but asked to deliver
|
/* there's no stored port number, but asked to deliver
|
||||||
a default one for the scheme */
|
a default one for the scheme */
|
||||||
const struct Curl_handler *h =
|
const struct Curl_handler *h =
|
||||||
Curl_builtin_scheme(u->scheme);
|
Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
|
||||||
if(h) {
|
if(h) {
|
||||||
msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
|
msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
|
||||||
ptr = portbuf;
|
ptr = portbuf;
|
||||||
|
|
@ -1422,7 +1422,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||||
/* there is a stored port number, but ask to inhibit if
|
/* there is a stored port number, but ask to inhibit if
|
||||||
it matches the default one for the scheme */
|
it matches the default one for the scheme */
|
||||||
const struct Curl_handler *h =
|
const struct Curl_handler *h =
|
||||||
Curl_builtin_scheme(u->scheme);
|
Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
|
||||||
if(h && (h->defport == u->portnum) &&
|
if(h && (h->defport == u->portnum) &&
|
||||||
(flags & CURLU_NO_DEFAULT_PORT))
|
(flags & CURLU_NO_DEFAULT_PORT))
|
||||||
ptr = NULL;
|
ptr = NULL;
|
||||||
|
|
@ -1468,7 +1468,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
|
||||||
else
|
else
|
||||||
return CURLUE_NO_SCHEME;
|
return CURLUE_NO_SCHEME;
|
||||||
|
|
||||||
h = Curl_builtin_scheme(scheme);
|
h = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED);
|
||||||
if(!port && (flags & CURLU_DEFAULT_PORT)) {
|
if(!port && (flags & CURLU_DEFAULT_PORT)) {
|
||||||
/* there's no stored port number, but asked to deliver
|
/* there's no stored port number, but asked to deliver
|
||||||
a default one for the scheme */
|
a default one for the scheme */
|
||||||
|
|
@ -1674,7 +1674,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|
||||||
return CURLUE_BAD_SCHEME;
|
return CURLUE_BAD_SCHEME;
|
||||||
if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
|
if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
|
||||||
/* verify that it is a fine scheme */
|
/* verify that it is a fine scheme */
|
||||||
!Curl_builtin_scheme(part))
|
!Curl_builtin_scheme(part, CURL_ZERO_TERMINATED))
|
||||||
return CURLUE_UNSUPPORTED_SCHEME;
|
return CURLUE_UNSUPPORTED_SCHEME;
|
||||||
storep = &u->scheme;
|
storep = &u->scheme;
|
||||||
urlencode = FALSE; /* never */
|
urlencode = FALSE; /* never */
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@ http
|
||||||
<name>
|
<name>
|
||||||
--libcurl for GET with various options
|
--libcurl for GET with various options
|
||||||
</name>
|
</name>
|
||||||
|
<features>
|
||||||
|
http
|
||||||
|
ftp
|
||||||
|
file
|
||||||
|
</features>
|
||||||
<setenv>
|
<setenv>
|
||||||
SSL_CERT_FILE=
|
SSL_CERT_FILE=
|
||||||
</setenv>
|
</setenv>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
struct pair {
|
struct pair {
|
||||||
const char *in;
|
const char *in;
|
||||||
CURLcode exp;
|
CURLcode *exp;
|
||||||
};
|
};
|
||||||
|
|
||||||
int test(char *URL)
|
int test(char *URL)
|
||||||
|
|
@ -38,27 +38,34 @@ int test(char *URL)
|
||||||
CURL *curl = NULL;
|
CURL *curl = NULL;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
|
CURLcode ok = CURLE_OK;
|
||||||
|
CURLcode bad = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
CURLcode unsup = CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
CURLcode httpcode = CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
CURLcode httpscode = CURLE_UNSUPPORTED_PROTOCOL;
|
||||||
|
curl_version_info_data *curlinfo;
|
||||||
|
const char *const *proto;
|
||||||
|
char protolist[1024];
|
||||||
|
int n;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
struct pair prots[] = {
|
struct pair prots[] = {
|
||||||
{"goobar", CURLE_BAD_FUNCTION_ARGUMENT},
|
{"goobar", &unsup},
|
||||||
{"http ", CURLE_BAD_FUNCTION_ARGUMENT},
|
{"http ", &unsup},
|
||||||
{" http", CURLE_BAD_FUNCTION_ARGUMENT},
|
{" http", &unsup},
|
||||||
{"http", CURLE_OK},
|
{"http", &httpcode},
|
||||||
{"http,", CURLE_OK},
|
{"http,", &httpcode},
|
||||||
{"https,", CURLE_OK},
|
{"https,", &httpscode},
|
||||||
{"https,http", CURLE_OK},
|
{"https,http", &httpscode},
|
||||||
{"http,http", CURLE_OK},
|
{"http,http", &httpcode},
|
||||||
{"HTTP,HTTP", CURLE_OK},
|
{"HTTP,HTTP", &httpcode},
|
||||||
{",HTTP,HTTP", CURLE_OK},
|
{",HTTP,HTTP", &httpcode},
|
||||||
{"http,http,ft", CURLE_BAD_FUNCTION_ARGUMENT},
|
{"http,http,ft", &unsup},
|
||||||
{"", CURLE_BAD_FUNCTION_ARGUMENT},
|
{"", &bad},
|
||||||
{",,", CURLE_BAD_FUNCTION_ARGUMENT},
|
{",,", &bad},
|
||||||
{"DICT,FILE,FTP,FTPS,GOPHER,GOPHERS,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,"
|
{protolist, &ok},
|
||||||
"POP3,POP3S,RTMP,RTMPE,RTMPS,RTMPT,RTMPTE,RTMPTS,RTSP,SCP,SFTP,SMB,"
|
{"all", &ok},
|
||||||
"SMBS,SMTP,SMTPS,TELNET,TFTP", CURLE_OK},
|
{NULL, NULL},
|
||||||
{"all", CURLE_OK},
|
|
||||||
{NULL, CURLE_OK},
|
|
||||||
};
|
};
|
||||||
(void)URL;
|
(void)URL;
|
||||||
|
|
||||||
|
|
@ -66,9 +73,32 @@ int test(char *URL)
|
||||||
|
|
||||||
easy_init(curl);
|
easy_init(curl);
|
||||||
|
|
||||||
|
/* Get enabled protocols.*/
|
||||||
|
curlinfo = curl_version_info(CURLVERSION_NOW);
|
||||||
|
if(!curlinfo) {
|
||||||
|
fputs("curl_version_info failed\n", stderr);
|
||||||
|
res = (int) TEST_ERR_FAILURE;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for(proto = curlinfo->protocols; *proto; proto++) {
|
||||||
|
if((size_t) n >= sizeof(protolist)) {
|
||||||
|
puts("protolist buffer too small\n");
|
||||||
|
res = (int) TEST_ERR_FAILURE;
|
||||||
|
goto test_cleanup;
|
||||||
|
}
|
||||||
|
n += msnprintf(protolist + n, sizeof(protolist) - n, ",%s", *proto);
|
||||||
|
if(curl_strequal(*proto, "http"))
|
||||||
|
httpcode = CURLE_OK;
|
||||||
|
if(curl_strequal(*proto, "https"))
|
||||||
|
httpscode = CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run the tests. */
|
||||||
for(i = 0; prots[i].in; i++) {
|
for(i = 0; prots[i].in; i++) {
|
||||||
result = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, prots[i].in);
|
result = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, prots[i].in);
|
||||||
if(result != prots[i].exp) {
|
if(result != *prots[i].exp) {
|
||||||
printf("unexpectedly '%s' returned %u\n",
|
printf("unexpectedly '%s' returned %u\n",
|
||||||
prots[i].in, result);
|
prots[i].in, result);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ int test(char *URL)
|
||||||
case CURLE_BAD_FUNCTION_ARGUMENT: /* the most normal */
|
case CURLE_BAD_FUNCTION_ARGUMENT: /* the most normal */
|
||||||
case CURLE_UNKNOWN_OPTION: /* left out from the build */
|
case CURLE_UNKNOWN_OPTION: /* left out from the build */
|
||||||
case CURLE_NOT_BUILT_IN: /* not supported */
|
case CURLE_NOT_BUILT_IN: /* not supported */
|
||||||
|
case CURLE_UNSUPPORTED_PROTOCOL: /* detected by protocol2num() */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* all other return codes are unexpected */
|
/* all other return codes are unexpected */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue