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:
Patrick Monnerat 2022-09-15 13:30:09 +02:00 committed by Daniel Stenberg
parent 1bbffa0833
commit 9d51329047
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
8 changed files with 90 additions and 98 deletions

View file

@ -148,85 +148,36 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
#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)
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;
}
*val = 0;
do {
const char *token = str;
size_t tlen;
struct scheme const *pp;
char *token;
token = strchr(str, ',');
found_comma = token ? TRUE : FALSE;
if(!token)
token = strchr(str, '\0');
tlen = token - str;
str = strchr(str, ',');
tlen = str? (size_t) (str - token): strlen(token);
if(tlen) {
for(pp = protos; pp->name; pp++) {
if((strlen(pp->name) == tlen) &&
curl_strnequal(str, pp->name, tlen)) {
*val |= pp->bit;
break;
}
}
if(!(pp->name))
/* protocol name didn't match */
return CURLE_BAD_FUNCTION_ARGUMENT;
const struct Curl_handler *h = Curl_builtin_scheme(token, tlen);
if(!h)
return CURLE_UNSUPPORTED_PROTOCOL;
*val |= h->protocol;
}
if(found_comma)
str = token + 1;
} while(found_comma);
} while(str++);
if(!*val)
/* no matching protocol */
/* no protocol listed */
return CURLE_BAD_FUNCTION_ARGUMENT;
return CURLE_OK;
}

View file

@ -1700,7 +1700,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
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)) {
infof(data, "Clear auth, redirects scheme from %s to %s",
data->info.conn_scheme, scheme);

View file

@ -1853,15 +1853,18 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
}
/* 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 *p;
/* Scan protocol handler table and match against 'scheme'. The handler may
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++)
if(strcasecompare(p->scheme, scheme))
/* Protocol found in table. Check if allowed */
if(strncasecompare(p->scheme, scheme, schemelen) && !p->scheme[schemelen])
/* Protocol found in table. */
return p;
return NULL; /* not found */
}
@ -1871,7 +1874,8 @@ static CURLcode findprotocol(struct Curl_easy *data,
struct connectdata *conn,
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 */
(data->set.allowed_protocols & p->protocol)) {

View file

@ -46,7 +46,8 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
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);
CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,

View file

@ -431,7 +431,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
/* if this is a known scheme, get some details */
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
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;
if(!Curl_builtin_scheme(schemep) &&
if(!Curl_builtin_scheme(schemep, CURL_ZERO_TERMINATED) &&
!(flags & CURLU_NON_SUPPORT_SCHEME)) {
result = CURLUE_UNSUPPORTED_SCHEME;
goto fail;
@ -1412,7 +1412,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
/* there's no stored port number, but asked to deliver
a default one for the scheme */
const struct Curl_handler *h =
Curl_builtin_scheme(u->scheme);
Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
if(h) {
msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
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
it matches the default one for the scheme */
const struct Curl_handler *h =
Curl_builtin_scheme(u->scheme);
Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED);
if(h && (h->defport == u->portnum) &&
(flags & CURLU_NO_DEFAULT_PORT))
ptr = NULL;
@ -1468,7 +1468,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
else
return CURLUE_NO_SCHEME;
h = Curl_builtin_scheme(scheme);
h = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED);
if(!port && (flags & CURLU_DEFAULT_PORT)) {
/* there's no stored port number, but asked to deliver
a default one for the scheme */
@ -1674,7 +1674,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
return CURLUE_BAD_SCHEME;
if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
/* verify that it is a fine scheme */
!Curl_builtin_scheme(part))
!Curl_builtin_scheme(part, CURL_ZERO_TERMINATED))
return CURLUE_UNSUPPORTED_SCHEME;
storep = &u->scheme;
urlencode = FALSE; /* never */