lib: separate scheme info from protocol implementation

This allows builds know about all schemes - but only have the protocol
implementations for those actually built-in.

It further allows multiple protocols to reuse the same protocol setup
and functions for both TLS and non-TLS implementations instead of
needing two (or more) structs.

The scheme information is now in 'struct Curl_scheme' and all the
function pointers for each scheme/protocol implementation are in struct
Curl_protocol.

The URL API now always work with all known protocols.

Closes #20351
This commit is contained in:
Daniel Stenberg 2026-01-19 00:15:41 +01:00
parent 63baa10951
commit 8edc0338f3
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
59 changed files with 831 additions and 1040 deletions

View file

@ -29,53 +29,41 @@
* function in url.c.
*/
struct detail {
const char *n;
const char *ifdef;
};
static const struct detail scheme[] = {
{ "dict", "#ifndef CURL_DISABLE_DICT" },
{ "file", "#ifndef CURL_DISABLE_FILE" },
{ "ftp", "#ifndef CURL_DISABLE_FTP" },
{ "ftps", "#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)" },
{ "gopher", "#ifndef CURL_DISABLE_GOPHER" },
{ "gophers", "#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)" },
{ "http", "#ifndef CURL_DISABLE_HTTP" },
{ "https", "#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)" },
{ "imap", "#ifndef CURL_DISABLE_IMAP" },
{ "imaps", "#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)" },
{ "ldap", "#ifndef CURL_DISABLE_LDAP" },
{ "ldaps", "#if !defined(CURL_DISABLE_LDAP) && \\\n"
" !defined(CURL_DISABLE_LDAPS) && \\\n"
" ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \\\n"
" (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))" },
{ "mqtt", "#ifndef CURL_DISABLE_MQTT" },
{ "mqtts", "#if defined(USE_SSL) && !defined(CURL_DISABLE_MQTT)" },
{ "pop3", "#ifndef CURL_DISABLE_POP3" },
{ "pop3s", "#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)" },
{ "rtmp", "#ifdef USE_LIBRTMP" },
{ "rtmpt", "#ifdef USE_LIBRTMP" },
{ "rtmpe", "#ifdef USE_LIBRTMP" },
{ "rtmpte", "#ifdef USE_LIBRTMP" },
{ "rtmps", "#ifdef USE_LIBRTMP" },
{ "rtmpts", "#ifdef USE_LIBRTMP" },
{ "rtsp", "#ifndef CURL_DISABLE_RTSP" },
{ "scp", "#ifdef USE_SSH" },
{ "sftp", "#ifdef USE_SSH" },
{ "smb", "#if !defined(CURL_DISABLE_SMB) && \\\n"
" defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)" },
{ "smbs", "#if defined(USE_SSL) && !defined(CURL_DISABLE_SMB) && \\\n"
" defined(USE_CURL_NTLM_CORE) && (SIZEOF_CURL_OFF_T > 4)" },
{ "smtp", "#ifndef CURL_DISABLE_SMTP" },
{ "smtps", "#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)" },
{ "telnet", "#ifndef CURL_DISABLE_TELNET" },
{ "tftp", "#ifndef CURL_DISABLE_TFTP" },
{ "ws",
"#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)" },
{ "wss", "#if !defined(CURL_DISABLE_WEBSOCKETS) && \\\n"
" defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)" },
{ NULL, NULL }
static const char *scheme[] = {
"dict",
"file",
"ftp",
"ftps",
"gopher",
"gophers",
"http",
"https",
"imap",
"imaps",
"ldap",
"ldaps",
"mqtt",
"mqtts",
"pop3",
"pop3s",
"rtmp",
"rtmpt",
"rtmpe",
"rtmpte",
"rtmps",
"rtmpts",
"rtsp",
"scp",
"sftp",
"smb",
"smbs",
"smtp",
"smtps",
"telnet",
"tftp",
"ws",
"wss",
NULL,
};
unsigned int calc(const char *s, int add, int shift)
@ -97,9 +85,9 @@ static void showtable(int try, int init, int shift)
{
int nulls = 0;
int i;
for(i = 0; scheme[i].n; ++i)
num[i] = calc(scheme[i].n, init, shift);
for(i = 0; scheme[i].n; ++i)
for(i = 0; scheme[i]; ++i)
num[i] = calc(scheme[i], init, shift);
for(i = 0; scheme[i]; ++i)
ix[i] = num[i] % try;
printf("/*\n"
" unsigned int c = %d\n"
@ -112,32 +100,22 @@ static void showtable(int try, int init, int shift)
"*/\n",
init, shift);
printf(" static const struct Curl_handler * const protocols[%d] = {", try);
printf(" static const struct Curl_scheme * const all_schemes[%d] = {", try);
/* generate table */
for(i = 0; i < try; i++) {
int match = 0;
int j;
for(j = 0; scheme[j].n; j++) {
for(j = 0; scheme[j]; j++) {
if(ix[j] == i) {
printf("\n");
printf("%s\n", scheme[j].ifdef);
printf(" &Curl_handler_%s,\n", scheme[j].n);
printf("#else\n NULL,\n");
printf("#endif");
printf("\n &Curl_scheme_%s,", scheme[j]);
match = 1;
nulls = 0;
break;
}
}
if(!match) {
if(!nulls || (nulls > 10)) {
printf("\n ");
nulls = 0;
}
printf(" NULL,", nulls);
nulls++;
}
if(!match)
printf(" NULL,");
}
printf("\n };\n");
}
@ -153,8 +131,8 @@ int main(void)
int shift;
for(shift = 0; shift < 8; shift++) {
for(add = 0; add < 999; add++) {
for(i = 0; scheme[i].n; ++i) {
unsigned int v = calc(scheme[i].n, add, shift);
for(i = 0; scheme[i]; ++i) {
unsigned int v = calc(scheme[i], add, shift);
int j;
int badcombo = 0;
for(j = 0; j < i; j++) {
@ -180,11 +158,11 @@ int main(void)
/* try different remainders to find smallest possible table */
for(try = 28; try < 199; try++) {
int good = 1;
for(i = 0; scheme[i].n; ++i) {
for(i = 0; scheme[i]; ++i) {
ix[i] = num[i] % try;
}
/* check for dupes */
for(i = 0; scheme[i].n && good; ++i) {
for(i = 0; scheme[i] && good; ++i) {
int j;
for(j = 0; j < i; j++) {
if(ix[j] == ix[i]) {