summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2022-09-15 13:30:09 +0200
committerDaniel Stenberg <daniel@haxx.se>2022-09-16 23:29:01 +0200
commit9d51329047952ebfc2b944b7448b8f87f9e6ed51 (patch)
tree65e16f03a3efce60410c79d751793260ca172e17
parent1bbffa08336d6dc647c45a3dbf7462174702bb88 (diff)
downloadcurl-9d51329047952ebfc2b944b7448b8f87f9e6ed51.tar.gz
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
-rw-r--r--lib/setopt.c83
-rw-r--r--lib/transfer.c2
-rw-r--r--lib/url.c12
-rw-r--r--lib/url.h3
-rw-r--r--lib/urlapi.c12
-rw-r--r--tests/data/test14015
-rw-r--r--tests/libtest/lib1597.c70
-rw-r--r--tests/libtest/lib1911.c1
8 files changed, 90 insertions, 98 deletions
diff --git a/lib/setopt.c b/lib/setopt.c
index 7289a4e78..bc98d199f 100644
--- a/lib/setopt.c
+++ b/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_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;
}
diff --git a/lib/transfer.c b/lib/transfer.c
index fcc4006af..441da7342 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -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);
diff --git a/lib/url.c b/lib/url.c
index 4a3a0e50c..cb76a56de 100644
--- a/lib/url.c
+++ b/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 */
-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)) {
diff --git a/lib/url.h b/lib/url.h
index e3b294030..ba4270d52 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -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,
diff --git a/lib/urlapi.c b/lib/urlapi.c
index 2276b93dd..c28960ac1 100644
--- a/lib/urlapi.c
+++ b/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(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 */
diff --git a/tests/data/test1401 b/tests/data/test1401
index e4bc3b736..7edf76cc5 100644
--- a/tests/data/test1401
+++ b/tests/data/test1401
@@ -31,6 +31,11 @@ http
<name>
--libcurl for GET with various options
</name>
+<features>
+http
+ftp
+file
+</features>
<setenv>
SSL_CERT_FILE=
</setenv>
diff --git a/tests/libtest/lib1597.c b/tests/libtest/lib1597.c
index d39fae663..cb167e84f 100644
--- a/tests/libtest/lib1597.c
+++ b/tests/libtest/lib1597.c
@@ -30,7 +30,7 @@
struct pair {
const char *in;
- CURLcode exp;
+ CURLcode *exp;
};
int test(char *URL)
@@ -38,27 +38,34 @@ int test(char *URL)
CURL *curl = NULL;
int res = 0;
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;
struct pair prots[] = {
- {"goobar", CURLE_BAD_FUNCTION_ARGUMENT},
- {"http ", CURLE_BAD_FUNCTION_ARGUMENT},
- {" http", CURLE_BAD_FUNCTION_ARGUMENT},
- {"http", CURLE_OK},
- {"http,", CURLE_OK},
- {"https,", CURLE_OK},
- {"https,http", CURLE_OK},
- {"http,http", CURLE_OK},
- {"HTTP,HTTP", CURLE_OK},
- {",HTTP,HTTP", CURLE_OK},
- {"http,http,ft", CURLE_BAD_FUNCTION_ARGUMENT},
- {"", CURLE_BAD_FUNCTION_ARGUMENT},
- {",,", CURLE_BAD_FUNCTION_ARGUMENT},
- {"DICT,FILE,FTP,FTPS,GOPHER,GOPHERS,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,"
- "POP3,POP3S,RTMP,RTMPE,RTMPS,RTMPT,RTMPTE,RTMPTS,RTSP,SCP,SFTP,SMB,"
- "SMBS,SMTP,SMTPS,TELNET,TFTP", CURLE_OK},
- {"all", CURLE_OK},
- {NULL, CURLE_OK},
+ {"goobar", &unsup},
+ {"http ", &unsup},
+ {" http", &unsup},
+ {"http", &httpcode},
+ {"http,", &httpcode},
+ {"https,", &httpscode},
+ {"https,http", &httpscode},
+ {"http,http", &httpcode},
+ {"HTTP,HTTP", &httpcode},
+ {",HTTP,HTTP", &httpcode},
+ {"http,http,ft", &unsup},
+ {"", &bad},
+ {",,", &bad},
+ {protolist, &ok},
+ {"all", &ok},
+ {NULL, NULL},
};
(void)URL;
@@ -66,9 +73,32 @@ int test(char *URL)
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++) {
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",
prots[i].in, result);
break;
diff --git a/tests/libtest/lib1911.c b/tests/libtest/lib1911.c
index e78f64484..97b45040f 100644
--- a/tests/libtest/lib1911.c
+++ b/tests/libtest/lib1911.c
@@ -79,6 +79,7 @@ int test(char *URL)
case CURLE_BAD_FUNCTION_ARGUMENT: /* the most normal */
case CURLE_UNKNOWN_OPTION: /* left out from the build */
case CURLE_NOT_BUILT_IN: /* not supported */
+ case CURLE_UNSUPPORTED_PROTOCOL: /* detected by protocol2num() */
break;
default:
/* all other return codes are unexpected */