From 30da1f5974d34841b30c4fac3fa5837386f15589 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 22 Oct 2024 16:48:05 +0200 Subject: [PATCH] setopt: split Curl_vsetopt() into several sub functions Reduce the ~3000 line super function into smaller pieces, easier to read and manage. Extract the option's argument earlier and use a fixed type instead of using va_arg() everywhere. Closes #15376 --- lib/setopt.c | 3933 ++++++++++++++++++++++++-------------------------- 1 file changed, 1892 insertions(+), 2041 deletions(-) diff --git a/lib/setopt.c b/lib/setopt.c index 43f6905147..84e605d5ef 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -210,10 +210,9 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val) return CURLE_OK; } -static CURLcode httpauth(struct Curl_easy *data, bool proxy, va_list param) +static CURLcode httpauth(struct Curl_easy *data, bool proxy, + unsigned long auth) { - unsigned long auth = va_arg(param, unsigned long); - if(auth != CURLAUTH_NONE) { int bitcheck = 0; bool authbits = FALSE; @@ -256,21 +255,13 @@ static CURLcode httpauth(struct Curl_easy *data, bool proxy, va_list param) return CURLE_OK; } -/* - * Do not make Curl_vsetopt() static: it is called from - * packages/OS400/ccsidcurl.c. - */ -CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, + long arg) { - char *argptr; - CURLcode result = CURLE_OK; - long arg; - unsigned long uarg; - curl_off_t bigsize; - + bool enabled = (0 != arg); + unsigned long uarg = (unsigned long)arg; switch(option) { case CURLOPT_DNS_CACHE_TIMEOUT: - arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; else if(arg > INT_MAX) @@ -280,7 +271,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_CA_CACHE_TIMEOUT: if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) { - arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; else if(arg > INT_MAX) @@ -291,95 +281,47 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) else return CURLE_NOT_BUILT_IN; break; - case CURLOPT_DNS_USE_GLOBAL_CACHE: - /* deprecated */ - break; - case CURLOPT_SSL_CIPHER_LIST: - if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) { - /* set a list of cipher we want to use in the SSL connection */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], - va_arg(param, char *)); - } - else - return CURLE_NOT_BUILT_IN; - break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSL_CIPHER_LIST: - if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) { - /* set a list of cipher we want to use in the SSL connection for proxy */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], - va_arg(param, char *)); - } - else - return CURLE_NOT_BUILT_IN; - break; -#endif - case CURLOPT_TLS13_CIPHERS: - if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) { - /* set preferred list of TLS 1.3 cipher suites */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST], - va_arg(param, char *)); - } - else - return CURLE_NOT_BUILT_IN; - break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_TLS13_CIPHERS: - if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) { - /* set preferred list of TLS 1.3 cipher suites for proxy */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY], - va_arg(param, char *)); - } - else - return CURLE_NOT_BUILT_IN; - break; -#endif - case CURLOPT_RANDOM_FILE: - break; - case CURLOPT_EGDSOCKET: - break; case CURLOPT_MAXCONNECTS: /* * Set the absolute number of maximum simultaneous alive connection that * libcurl is allowed to have. */ - uarg = va_arg(param, unsigned long); if(uarg > UINT_MAX) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.maxconnects = (unsigned int)uarg; break; - case CURLOPT_FORBID_REUSE: + case CURLOPT_FORBID_REUSE: /* * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ - data->set.reuse_forbid = (0 != va_arg(param, long)); + data->set.reuse_forbid = enabled; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ - data->set.reuse_fresh = (0 != va_arg(param, long)); + data->set.reuse_fresh = enabled; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ - data->set.verbose = (0 != va_arg(param, long)); + data->set.verbose = enabled; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = (0 != va_arg(param, long)); + data->set.include_header = enabled; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ - data->set.hide_progress = (0 != va_arg(param, long)); + data->set.hide_progress = enabled; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else @@ -389,7 +331,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = (0 != va_arg(param, long)); + data->set.opt_no_body = enabled; #ifndef CURL_DISABLE_HTTP if(data->set.opt_no_body) /* in HTTP lingo, no body means using the HEAD request... */ @@ -403,10 +345,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Do not output the >=400 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = (0 != va_arg(param, long)); + data->set.http_fail_on_error = enabled; break; case CURLOPT_KEEP_SENDING_ON_ERROR: - data->set.http_keep_sending_on_error = (0 != va_arg(param, long)); + data->set.http_keep_sending_on_error = enabled; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -414,7 +356,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - arg = va_arg(param, long); if(arg) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.method = HTTPREQ_PUT; @@ -425,23 +366,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) then this can be changed to HEAD later on) */ data->set.method = HTTPREQ_GET; break; - case CURLOPT_REQUEST_TARGET: - result = Curl_setstropt(&data->set.str[STRING_TARGET], - va_arg(param, char *)); - break; case CURLOPT_FILETIME: /* * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ - data->set.get_filetime = (0 != va_arg(param, long)); + data->set.get_filetime = enabled; break; case CURLOPT_SERVER_RESPONSE_TIMEOUT: /* * Option that specifies how quickly a server response must be obtained * before it is considered failure. For pingpong protocols. */ - arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) data->set.server_response_timeout = (unsigned int)arg * 1000; else @@ -452,7 +388,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Option that specifies how quickly a server response must be obtained * before it is considered failure. For pingpong protocols. */ - arg = va_arg(param, long); if((arg >= 0) && (arg <= INT_MAX)) data->set.server_response_timeout = (unsigned int)arg; else @@ -464,13 +399,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Option that prevents libcurl from sending TFTP option requests to the * server. */ - data->set.tftp_no_options = va_arg(param, long) != 0; + data->set.tftp_no_options = enabled; break; case CURLOPT_TFTP_BLKSIZE: /* * TFTP option that specifies the block size to use for data transmission. */ - arg = va_arg(param, long); if(arg < TFTP_BLKSIZE_MIN) arg = 512; else if(arg > TFTP_BLKSIZE_MAX) @@ -483,18 +417,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* * Parse the $HOME/.netrc file */ - arg = va_arg(param, long); if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.use_netrc = (unsigned char)arg; break; - case CURLOPT_NETRC_FILE: - /* - * Use this file instead of the $HOME/.netrc file - */ - result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE], - va_arg(param, char *)); - break; #endif case CURLOPT_TRANSFERTEXT: /* @@ -503,14 +429,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * * Transfer using ASCII (instead of BINARY). */ - data->set.prefer_ascii = (0 != va_arg(param, long)); + data->set.prefer_ascii = enabled; break; case CURLOPT_TIMECONDITION: /* * Set HTTP time condition. This must be one of the defines in the * curl/curl.h header file. */ - arg = va_arg(param, long); if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.timecondition = (unsigned char)(curl_TimeCond)arg; @@ -520,17 +445,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * This is the value to compare with the remote document with the * method set with CURLOPT_TIMECONDITION */ - data->set.timevalue = (time_t)va_arg(param, long); - break; - - case CURLOPT_TIMEVALUE_LARGE: - /* - * This is the value to compare with the remote document with the - * method set with CURLOPT_TIMECONDITION - */ - data->set.timevalue = (time_t)va_arg(param, curl_off_t); + data->set.timevalue = (time_t)arg; break; - case CURLOPT_SSLVERSION: #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLVERSION: @@ -547,9 +463,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) if(option != CURLOPT_SSLVERSION) primary = &data->set.proxy_ssl.primary; #endif - - arg = va_arg(param, long); - version = C_SSLVERSION_VALUE(arg); version_max = (long)C_SSLVERSION_MAX_VALUE(arg); @@ -565,136 +478,54 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) primary->version_max = (unsigned int)version_max; } #else - result = CURLE_NOT_BUILT_IN; + return CURLE_NOT_BUILT_IN; #endif break; - - /* MQTT "borrows" some of the HTTP options */ -#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT) - case CURLOPT_COPYPOSTFIELDS: - /* - * A string with POST data. Makes curl HTTP POST. Even if it is NULL. - * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to - * CURLOPT_COPYPOSTFIELDS and not altered later. - */ - argptr = va_arg(param, char *); - - if(!argptr || data->set.postfieldsize == -1) - result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr); - else { - /* - * Check that requested length does not overflow the size_t type. - */ - - if((data->set.postfieldsize < 0) || - ((sizeof(curl_off_t) != sizeof(size_t)) && - (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) - result = CURLE_OUT_OF_MEMORY; - else { - /* Allocate even when size == 0. This satisfies the need of possible - later address compare to detect the COPYPOSTFIELDS mode, and to - mark that postfields is used rather than read function or form - data. - */ - char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize); - if(!p) - result = CURLE_OUT_OF_MEMORY; - else { - free(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.str[STRING_COPYPOSTFIELDS] = p; - } - } - } - - data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; - data->set.method = HTTPREQ_POST; - break; - - case CURLOPT_POSTFIELDS: - /* - * Like above, but use static data instead of copying it. - */ - data->set.postfields = va_arg(param, void *); - /* Release old copied data. */ - Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.method = HTTPREQ_POST; - break; - case CURLOPT_POSTFIELDSIZE: /* * The size of the POSTFIELD data to prevent libcurl to do strlen() to * figure it out. Enables binary posts. */ - bigsize = va_arg(param, long); - if(bigsize < -1) + if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - if(data->set.postfieldsize < bigsize && + if(data->set.postfieldsize < arg && data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); data->set.postfields = NULL; } - data->set.postfieldsize = bigsize; + data->set.postfieldsize = arg; break; - - case CURLOPT_POSTFIELDSIZE_LARGE: +#ifndef CURL_DISABLE_HTTP +#if !defined(CURL_DISABLE_COOKIES) + case CURLOPT_COOKIESESSION: /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. + * Set this option to TRUE to start a new "cookie session". It will + * prevent the forthcoming read-cookies-from-file actions to accept + * cookies that are marked as being session cookies, as they belong to a + * previous session. */ - bigsize = va_arg(param, curl_off_t); - if(bigsize < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - - if(data->set.postfieldsize < bigsize && - data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { - /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ - Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.postfields = NULL; - } - - data->set.postfieldsize = bigsize; + data->set.cookiesession = enabled; break; #endif -#ifndef CURL_DISABLE_HTTP case CURLOPT_AUTOREFERER: /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = (0 != va_arg(param, long)); - break; - - case CURLOPT_ACCEPT_ENCODING: - /* - * String to use at the value of Accept-Encoding header. - * - * If the encoding is set to "" we use an Accept-Encoding header that - * encompasses all the encodings we support. - * If the encoding is set to NULL we do not send an Accept-Encoding header - * and ignore an received Content-Encoding header. - * - */ - argptr = va_arg(param, char *); - if(argptr && !*argptr) { - char all[256]; - Curl_all_content_encodings(all, sizeof(all)); - result = Curl_setstropt(&data->set.str[STRING_ENCODING], all); - } - else - result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr); + data->set.http_auto_referer = enabled; break; case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = (0 != va_arg(param, long)); + data->set.http_transfer_encoding = enabled; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on an HTTP-server. */ - data->set.http_follow_location = (0 != va_arg(param, long)); + data->set.http_follow_location = enabled; break; case CURLOPT_UNRESTRICTED_AUTH: @@ -702,7 +533,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Send authentication (user+password) when following locations, even when * hostname changed. */ - data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long)); + data->set.allow_auth_to_other_hosts = enabled; break; case CURLOPT_MAXREDIRS: @@ -710,7 +541,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * The maximum amount of hops you allow curl to follow Location: * headers. This should mostly be used to detect never-ending loops. */ - arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.maxredirs = arg; @@ -726,7 +556,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 * other - POST is kept as POST after 301 and 302 */ - arg = va_arg(param, long); if(arg < CURL_REDIR_GET_ALL) /* no return error on too high numbers since the bitmask could be extended in a future */ @@ -738,705 +567,290 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* Does this option serve a purpose anymore? Yes it does, when CURLOPT_POSTFIELDS is not used and the POST data is read off the callback! */ - if(va_arg(param, long)) { + if(arg) { data->set.method = HTTPREQ_POST; data->set.opt_no_body = FALSE; /* this is implied */ } else data->set.method = HTTPREQ_GET; break; - -#ifndef CURL_DISABLE_FORM_API - case CURLOPT_HTTPPOST: + case CURLOPT_HEADEROPT: /* - * Set to make us do HTTP POST. Legacy API-style. + * Set header option. */ - data->set.httppost = va_arg(param, struct curl_httppost *); - data->set.method = HTTPREQ_POST_FORM; - data->set.opt_no_body = FALSE; /* this is implied */ - Curl_mime_cleanpart(data->state.formp); - Curl_safefree(data->state.formp); - data->state.mimepost = NULL; + data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE); break; -#endif + case CURLOPT_HTTPAUTH: + return httpauth(data, FALSE, uarg); -#if !defined(CURL_DISABLE_AWS) - case CURLOPT_AWS_SIGV4: - /* - * String that is merged to some authentication - * parameters are used by the algorithm. - */ - result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4], - va_arg(param, char *)); + case CURLOPT_HTTPGET: /* - * Basic been set by default it need to be unset here + * Set to force us do HTTP GET */ - if(data->set.str[STRING_AWS_SIGV4]) - data->set.httpauth = CURLAUTH_AWS_SIGV4; + if(enabled) { + data->set.method = HTTPREQ_GET; + data->set.opt_no_body = FALSE; /* this is implied */ + } break; -#endif - case CURLOPT_REFERER: + case CURLOPT_HTTP_VERSION: /* - * String to set in the HTTP Referer: field. + * This sets a requested HTTP version to be used. The value is one of + * the listed enums in curl/curl.h. */ - if(data->state.referer_alloc) { - Curl_safefree(data->state.referer); - data->state.referer_alloc = FALSE; + switch(arg) { + case CURL_HTTP_VERSION_NONE: +#ifdef USE_HTTP2 + /* TODO: this seems an undesirable quirk to force a behaviour on + * lower implementations that they should recognize independently? */ + arg = CURL_HTTP_VERSION_2TLS; +#endif + /* accepted */ + break; + case CURL_HTTP_VERSION_1_0: + case CURL_HTTP_VERSION_1_1: + /* accepted */ + break; +#ifdef USE_HTTP2 + case CURL_HTTP_VERSION_2_0: + case CURL_HTTP_VERSION_2TLS: + case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE: + /* accepted */ + break; +#endif +#ifdef USE_HTTP3 + case CURL_HTTP_VERSION_3: + case CURL_HTTP_VERSION_3ONLY: + /* accepted */ + break; +#endif + default: + /* not accepted */ + if(arg < CURL_HTTP_VERSION_NONE) + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_UNSUPPORTED_PROTOCOL; } - result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], - va_arg(param, char *)); - data->state.referer = data->set.str[STRING_SET_REFERER]; + data->set.httpwant = (unsigned char)arg; break; - case CURLOPT_USERAGENT: + case CURLOPT_EXPECT_100_TIMEOUT_MS: /* - * String to use in the HTTP User-Agent field + * Time to wait for a response to an HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ - result = Curl_setstropt(&data->set.str[STRING_USERAGENT], - va_arg(param, char *)); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.expect_100_timeout = arg; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXYHEADER: - /* - * Set a list with proxy headers to use (or replace internals with) - * - * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a - * long time we remain doing it this way until CURLOPT_PROXYHEADER is - * used. As soon as this option has been used, if set to anything but - * NULL, custom headers for proxies are only picked from this list. - * - * Set this option to NULL to restore the previous behavior. - */ - data->set.proxyheaders = va_arg(param, struct curl_slist *); + case CURLOPT_HTTP09_ALLOWED: +#ifdef USE_HYPER + /* Hyper does not support HTTP/0.9 */ + if(enabled) + return CURLE_BAD_FUNCTION_ARGUMENT; +#else + data->set.http09_allowed = enabled; +#endif + break; +#endif /* ! CURL_DISABLE_HTTP */ + +#ifndef CURL_DISABLE_MIME + case CURLOPT_MIME_OPTIONS: + data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE); break; #endif - case CURLOPT_HEADEROPT: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_HTTPPROXYTUNNEL: /* - * Set header option. + * Tunnel operations through the proxy instead of normal proxy use */ - arg = va_arg(param, long); - data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE); + data->set.tunnel_thru_httpproxy = enabled; break; -#if !defined(CURL_DISABLE_COOKIES) - case CURLOPT_COOKIE: + case CURLOPT_PROXYPORT: /* - * Cookie string to send to the remote server in the request. + * Explicitly set HTTP proxy port number. */ - result = Curl_setstropt(&data->set.str[STRING_COOKIE], - va_arg(param, char *)); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.proxyport = (unsigned short)arg; break; - case CURLOPT_COOKIEFILE: - /* - * Set cookie file to read and parse. Can be used multiple times. - */ - argptr = (char *)va_arg(param, void *); - if(argptr) { - struct curl_slist *cl; - /* general protection against mistakes and abuse */ - if(strlen(argptr) > CURL_MAX_INPUT_LENGTH) - return CURLE_BAD_FUNCTION_ARGUMENT; - /* append the cookie filename to the list of filenames, and deal with - them later */ - cl = curl_slist_append(data->state.cookielist, argptr); - if(!cl) { - curl_slist_free_all(data->state.cookielist); - data->state.cookielist = NULL; - return CURLE_OUT_OF_MEMORY; - } - data->state.cookielist = cl; /* store the list for later use */ - } - else { - /* clear the list of cookie files */ - curl_slist_free_all(data->state.cookielist); - data->state.cookielist = NULL; - - if(!data->share || !data->share->cookies) { - /* throw away all existing cookies if this is not a shared cookie - container */ - Curl_cookie_clearall(data->cookies); - Curl_cookie_cleanup(data->cookies); - } - /* disable the cookie engine */ - data->cookies = NULL; - } - break; + case CURLOPT_PROXYAUTH: + return httpauth(data, TRUE, uarg); - case CURLOPT_COOKIEJAR: + case CURLOPT_PROXYTYPE: /* - * Set cookie filename to dump all cookies to when we are done. + * Set proxy type. */ - result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], - va_arg(param, char *)); - if(!result) { - /* - * Activate the cookie parser. This may or may not already - * have been made. - */ - struct CookieInfo *newcookies = - Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession); - if(!newcookies) - result = CURLE_OUT_OF_MEMORY; - data->cookies = newcookies; - } + if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.proxytype = (unsigned char)(curl_proxytype)arg; break; - case CURLOPT_COOKIESESSION: + case CURLOPT_PROXY_TRANSFER_MODE: /* - * Set this option to TRUE to start a new "cookie session". It will - * prevent the forthcoming read-cookies-from-file actions to accept - * cookies that are marked as being session cookies, as they belong to a - * previous session. + * set transfer mode (;type=) when doing FTP via an HTTP proxy */ - data->set.cookiesession = (0 != va_arg(param, long)); + if(uarg > 1) + /* reserve other values for future use */ + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.proxy_transfer_mode = (bool)uarg; break; - - case CURLOPT_COOKIELIST: - argptr = va_arg(param, char *); - - if(!argptr) - break; - - if(strcasecompare(argptr, "ALL")) { - /* clear all cookies */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_clearall(data->cookies); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - else if(strcasecompare(argptr, "SESS")) { - /* clear session cookies */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_clearsess(data->cookies); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - else if(strcasecompare(argptr, "FLUSH")) { - /* flush cookies to file, takes care of the locking */ - Curl_flush_cookies(data, FALSE); - } - else if(strcasecompare(argptr, "RELOAD")) { - /* reload cookies from file */ - Curl_cookie_loadfiles(data); - break; - } - else { - if(!data->cookies) - /* if cookie engine was not running, activate it */ - data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); - - /* general protection against mistakes and abuse */ - if(strlen(argptr) > CURL_MAX_INPUT_LENGTH) - return CURLE_BAD_FUNCTION_ARGUMENT; - argptr = strdup(argptr); - if(!argptr || !data->cookies) { - result = CURLE_OUT_OF_MEMORY; - free(argptr); - } - else { - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - - if(checkprefix("Set-Cookie:", argptr)) - /* HTTP Header format line */ - Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL, - NULL, TRUE); - - else - /* Netscape format line */ - Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL, - NULL, TRUE); - - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - free(argptr); - } - } - + case CURLOPT_SOCKS5_AUTH: + if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + return CURLE_NOT_BUILT_IN; + data->set.socks5auth = (unsigned char)uarg; break; -#endif /* !CURL_DISABLE_COOKIES */ - - case CURLOPT_HTTPGET: + case CURLOPT_HAPROXYPROTOCOL: /* - * Set to force us do HTTP GET + * Set to send the HAProxy Proxy Protocol header */ - if(va_arg(param, long)) { - data->set.method = HTTPREQ_GET; - data->set.opt_no_body = FALSE; /* this is implied */ - } + data->set.haproxyprotocol = enabled; break; + case CURLOPT_PROXY_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying for proxy. + */ + data->set.proxy_ssl.primary.verifypeer = enabled; - case CURLOPT_HTTP_VERSION: + /* Update the current connection proxy_ssl_config. */ + Curl_ssl_conn_config_update(data, TRUE); + break; + case CURLOPT_PROXY_SSL_VERIFYHOST: /* - * This sets a requested HTTP version to be used. The value is one of - * the listed enums in curl/curl.h. + * Enable verification of the hostname in the peer certificate for proxy */ - arg = va_arg(param, long); - switch(arg) { - case CURL_HTTP_VERSION_NONE: -#ifdef USE_HTTP2 - /* TODO: this seems an undesirable quirk to force a behaviour on - * lower implementations that they should recognize independently? */ - arg = CURL_HTTP_VERSION_2TLS; -#endif - /* accepted */ - break; - case CURL_HTTP_VERSION_1_0: - case CURL_HTTP_VERSION_1_1: - /* accepted */ - break; -#ifdef USE_HTTP2 - case CURL_HTTP_VERSION_2_0: - case CURL_HTTP_VERSION_2TLS: - case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE: - /* accepted */ - break; -#endif -#ifdef USE_HTTP3 - case CURL_HTTP_VERSION_3: - case CURL_HTTP_VERSION_3ONLY: - /* accepted */ - break; -#endif - default: - /* not accepted */ - if(arg < CURL_HTTP_VERSION_NONE) - return CURLE_BAD_FUNCTION_ARGUMENT; - return CURLE_UNSUPPORTED_PROTOCOL; - } - data->set.httpwant = (unsigned char)arg; + data->set.proxy_ssl.primary.verifyhost = enabled; + + /* Update the current connection proxy_ssl_config. */ + Curl_ssl_conn_config_update(data, TRUE); break; +#endif /* ! CURL_DISABLE_PROXY */ - case CURLOPT_EXPECT_100_TIMEOUT_MS: +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case CURLOPT_SOCKS5_GSSAPI_NEC: /* - * Time to wait for a response to an HTTP request containing an - * Expect: 100-continue header before sending the data anyway. + * Set flag for NEC SOCK5 support */ - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.expect_100_timeout = arg; + data->set.socks5_gssapi_nec = enabled; break; - - case CURLOPT_HTTP09_ALLOWED: - arg = (long)va_arg(param, unsigned long); - if(arg > 1L) - return CURLE_BAD_FUNCTION_ARGUMENT; -#ifdef USE_HYPER - /* Hyper does not support HTTP/0.9 */ - if(arg) - return CURLE_BAD_FUNCTION_ARGUMENT; -#else - data->set.http09_allowed = !!arg; #endif - break; - - case CURLOPT_HTTP200ALIASES: +#ifdef CURL_LIST_ONLY_PROTOCOL + case CURLOPT_DIRLISTONLY: /* - * Set a list of aliases for HTTP 200 in response header + * An option that changes the command to one that asks for a list only, no + * file info details. Used for FTP, POP3 and SFTP. */ - data->set.http200aliases = va_arg(param, struct curl_slist *); + data->set.list_only = enabled; break; -#endif /* CURL_DISABLE_HTTP */ - -#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ - !defined(CURL_DISABLE_IMAP) -# if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) - case CURLOPT_HTTPHEADER: +#endif + case CURLOPT_APPEND: /* - * Set a list with HTTP headers to use (or replace internals with) + * We want to upload and append to an existing file. Used for FTP and + * SFTP. */ - data->set.headers = va_arg(param, struct curl_slist *); + data->set.remote_append = enabled; break; -# endif -# ifndef CURL_DISABLE_MIME - case CURLOPT_MIMEPOST: +#ifndef CURL_DISABLE_FTP + case CURLOPT_FTP_FILEMETHOD: /* - * Set to make us do MIME POST + * How do access files over FTP. */ - result = Curl_mime_set_subparts(&data->set.mimepost, - va_arg(param, curl_mime *), FALSE); - if(!result) { - data->set.method = HTTPREQ_POST_MIME; - data->set.opt_no_body = FALSE; /* this is implied */ -#ifndef CURL_DISABLE_FORM_API - Curl_mime_cleanpart(data->state.formp); - Curl_safefree(data->state.formp); - data->state.mimepost = NULL; -#endif - } + if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ftp_filemethod = (unsigned char)arg; + break; + case CURLOPT_FTP_USE_EPRT: + data->set.ftp_use_eprt = enabled; break; - case CURLOPT_MIME_OPTIONS: - arg = va_arg(param, long); - data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE); - break; -# endif -#endif - - case CURLOPT_HTTPAUTH: - return httpauth(data, FALSE, param); + case CURLOPT_FTP_USE_EPSV: + data->set.ftp_use_epsv = enabled; + break; - case CURLOPT_CUSTOMREQUEST: - /* - * Set a custom string to use as request - */ - result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], - va_arg(param, char *)); + case CURLOPT_FTP_USE_PRET: + data->set.ftp_use_pret = enabled; + break; - /* we do not set - data->set.method = HTTPREQ_CUSTOM; - here, we continue as if we were using the already set type - and this just changes the actual request keyword */ + case CURLOPT_FTP_SSL_CCC: + if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ftp_ccc = (unsigned char)arg; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_HTTPPROXYTUNNEL: + case CURLOPT_FTP_SKIP_PASV_IP: /* - * Tunnel operations through the proxy instead of normal proxy use + * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the + * bypass of the IP address in PASV responses. */ - data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)); + data->set.ftp_skip_ip = enabled; break; - case CURLOPT_PROXYPORT: + case CURLOPT_FTPSSLAUTH: /* - * Explicitly set HTTP proxy port number. + * Set a specific auth for FTP-SSL transfers. */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 65535)) + if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.proxyport = (unsigned short)arg; + data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg; break; - - case CURLOPT_PROXYAUTH: - return httpauth(data, TRUE, param); - - case CURLOPT_PROXY: - /* - * Set proxy server:port to use as proxy. - * - * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) - * we explicitly say that we do not want to use a proxy - * (even though there might be environment variables saying so). - * - * Setting it to NULL, means no proxy but allows the environment variables - * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). - */ - result = Curl_setstropt(&data->set.str[STRING_PROXY], - va_arg(param, char *)); - break; - - case CURLOPT_PRE_PROXY: - /* - * Set proxy server:port to use as SOCKS proxy. - * - * If the proxy is set to "" or NULL we explicitly say that we do not want - * to use the socks proxy. - */ - result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY], - va_arg(param, char *)); - break; - - case CURLOPT_PROXYTYPE: - /* - * Set proxy type. - */ - arg = va_arg(param, long); - if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.proxytype = (unsigned char)(curl_proxytype)arg; - break; - - case CURLOPT_PROXY_TRANSFER_MODE: - /* - * set transfer mode (;type=) when doing FTP via an HTTP proxy - */ - switch(va_arg(param, long)) { - case 0: - data->set.proxy_transfer_mode = FALSE; - break; - case 1: - data->set.proxy_transfer_mode = TRUE; - break; - default: - /* reserve other values for future use */ - result = CURLE_BAD_FUNCTION_ARGUMENT; - break; - } - break; - - case CURLOPT_SOCKS5_AUTH: - data->set.socks5auth = (unsigned char)va_arg(param, unsigned long); - if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) - result = CURLE_NOT_BUILT_IN; - break; -#endif /* CURL_DISABLE_PROXY */ - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case CURLOPT_SOCKS5_GSSAPI_NEC: - /* - * Set flag for NEC SOCK5 support - */ - data->set.socks5_gssapi_nec = (0 != va_arg(param, long)); - break; -#endif -#ifndef CURL_DISABLE_PROXY - case CURLOPT_SOCKS5_GSSAPI_SERVICE: - case CURLOPT_PROXY_SERVICE_NAME: - /* - * Set proxy authentication service name for Kerberos 5 and SPNEGO - */ - result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], - va_arg(param, char *)); - break; -#endif - case CURLOPT_SERVICE_NAME: - /* - * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO - */ - result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], - va_arg(param, char *)); - break; - - case CURLOPT_HEADERDATA: - /* - * Custom pointer to pass the header write callback function - */ - data->set.writeheader = (void *)va_arg(param, void *); - break; - case CURLOPT_ERRORBUFFER: - /* - * Error buffer provided by the caller to get the human readable - * error string in. - */ - data->set.errorbuffer = va_arg(param, char *); - break; - case CURLOPT_WRITEDATA: - /* - * FILE pointer to write to. Or possibly - * used as argument to the write callback. - */ - data->set.out = va_arg(param, void *); - break; - -#ifdef CURL_LIST_ONLY_PROTOCOL - case CURLOPT_DIRLISTONLY: - /* - * An option that changes the command to one that asks for a list only, no - * file info details. Used for FTP, POP3 and SFTP. - */ - data->set.list_only = (0 != va_arg(param, long)); - break; -#endif - case CURLOPT_APPEND: - /* - * We want to upload and append to an existing file. Used for FTP and - * SFTP. - */ - data->set.remote_append = (0 != va_arg(param, long)); - break; - -#ifndef CURL_DISABLE_FTP - case CURLOPT_FTP_FILEMETHOD: - /* - * How do access files over FTP. - */ - arg = va_arg(param, long); - if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftp_filemethod = (unsigned char)arg; - break; - case CURLOPT_FTPPORT: - /* - * Use FTP PORT, this also specifies which IP address to use - */ - result = Curl_setstropt(&data->set.str[STRING_FTPPORT], - va_arg(param, char *)); - data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]); - break; - - case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_SSL_CCC: - arg = va_arg(param, long); - if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftp_ccc = (unsigned char)arg; - break; - - case CURLOPT_FTP_SKIP_PASV_IP: - /* - * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the - * bypass of the IP address in PASV responses. - */ - data->set.ftp_skip_ip = (0 != va_arg(param, long)); - break; - - case CURLOPT_FTP_ACCOUNT: - result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], - va_arg(param, char *)); - break; - - case CURLOPT_FTP_ALTERNATIVE_TO_USER: - result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], - va_arg(param, char *)); - break; - - case CURLOPT_FTPSSLAUTH: + case CURLOPT_ACCEPTTIMEOUT_MS: /* - * Set a specific auth for FTP-SSL transfers. + * The maximum time for curl to wait for FTP server connect */ - arg = va_arg(param, long); - if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg; + if(uarg > UINT_MAX) + uarg = UINT_MAX; + data->set.accepttimeout = (unsigned int)uarg; break; -#ifdef HAVE_GSSAPI - case CURLOPT_KRBLEVEL: - /* - * A string that defines the kerberos security level. - */ - result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], - va_arg(param, char *)); - data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]); + case CURLOPT_WILDCARDMATCH: + data->set.wildcard_enabled = enabled; break; -#endif -#endif +#endif /* ! CURL_DISABLE_FTP */ #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) case CURLOPT_FTP_CREATE_MISSING_DIRS: /* * An FTP/SFTP option that modifies an upload to create missing * directories on the server. */ - arg = va_arg(param, long); /* reserve other values for future use */ - if((arg < CURLFTP_CREATE_DIR_NONE) || - (arg > CURLFTP_CREATE_DIR_RETRY)) - result = CURLE_BAD_FUNCTION_ARGUMENT; - else - data->set.ftp_create_missing_dirs = (unsigned char)arg; - break; - - case CURLOPT_POSTQUOTE: - /* - * List of RAW FTP commands to use after a transfer - */ - data->set.postquote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_PREQUOTE: - /* - * List of RAW FTP commands to use prior to RETR (Wesley Laxton) - */ - data->set.prequote = va_arg(param, struct curl_slist *); - break; - case CURLOPT_QUOTE: - /* - * List of RAW FTP commands to use before a transfer - */ - data->set.quote = va_arg(param, struct curl_slist *); - break; -#endif - case CURLOPT_READDATA: - /* - * FILE pointer to read the file to be uploaded from. Or possibly - * used as argument to the read callback. - */ - data->set.in_set = va_arg(param, void *); + if((arg < CURLFTP_CREATE_DIR_NONE) || (arg > CURLFTP_CREATE_DIR_RETRY)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ftp_create_missing_dirs = (unsigned char)arg; break; +#endif /* ! CURL_DISABLE_FTP || USE_SSH */ case CURLOPT_INFILESIZE: /* * If known, this should inform curl about the file size of the * to-be-uploaded file. */ - arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.filesize = arg; break; - case CURLOPT_INFILESIZE_LARGE: - /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. - */ - bigsize = va_arg(param, curl_off_t); - if(bigsize < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.filesize = bigsize; - break; case CURLOPT_LOW_SPEED_LIMIT: /* * The low speed limit that if transfers are below this for * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. */ - arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.low_speed_limit = arg; break; - case CURLOPT_MAX_SEND_SPEED_LARGE: - /* - * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE - * bytes per second the transfer is throttled.. - */ - bigsize = va_arg(param, curl_off_t); - if(bigsize < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_send_speed = bigsize; - break; - case CURLOPT_MAX_RECV_SPEED_LARGE: - /* - * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per - * second the transfer is throttled.. - */ - bigsize = va_arg(param, curl_off_t); - if(bigsize < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_recv_speed = bigsize; - break; case CURLOPT_LOW_SPEED_TIME: /* * The low speed time that if transfers are below the set * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. */ - arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.low_speed_time = arg; break; - case CURLOPT_CURLU: - /* - * pass CURLU to set URL - */ - data->set.uh = va_arg(param, CURLU *); - break; - case CURLOPT_URL: - /* - * The URL to fetch. - */ - if(data->state.url_alloc) { - /* the already set URL is allocated, free it first! */ - Curl_safefree(data->state.url); - data->state.url_alloc = FALSE; - } - result = Curl_setstropt(&data->set.str[STRING_SET_URL], - va_arg(param, char *)); - data->state.url = data->set.str[STRING_SET_URL]; - break; case CURLOPT_PORT: /* * The port number to use when getting the URL. 0 disables it. */ - arg = va_arg(param, long); if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.use_port = (unsigned short)arg; @@ -1446,7 +860,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * The maximum time you allow curl to use for a single transfer * operation. */ - arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) data->set.timeout = (unsigned int)arg * 1000; else @@ -1454,7 +867,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_TIMEOUT_MS: - uarg = va_arg(param, unsigned long); if(uarg > UINT_MAX) uarg = UINT_MAX; data->set.timeout = (unsigned int)uarg; @@ -1464,7 +876,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* * The maximum time you allow curl to use to connect. */ - arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) data->set.connecttimeout = (unsigned int)arg * 1000; else @@ -1472,1076 +883,1564 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_CONNECTTIMEOUT_MS: - uarg = va_arg(param, unsigned long); if(uarg > UINT_MAX) uarg = UINT_MAX; data->set.connecttimeout = (unsigned int)uarg; break; -#ifndef CURL_DISABLE_FTP - case CURLOPT_ACCEPTTIMEOUT_MS: + case CURLOPT_RESUME_FROM: /* - * The maximum time for curl to wait for FTP server connect + * Resume transfer at the given file position */ - uarg = va_arg(param, unsigned long); - if(uarg > UINT_MAX) - uarg = UINT_MAX; - data->set.accepttimeout = (unsigned int)uarg; + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.set_resume_from = arg; break; -#endif - case CURLOPT_USERPWD: + case CURLOPT_CRLF: /* - * user:password to use in the operation + * Kludgy option to enable CRLF conversions. Subject for removal. */ - result = setstropt_userpwd(va_arg(param, char *), - &data->set.str[STRING_USERNAME], - &data->set.str[STRING_PASSWORD]); + data->set.crlf = enabled; break; - case CURLOPT_USERNAME: +#ifndef CURL_DISABLE_BINDLOCAL + case CURLOPT_LOCALPORT: /* - * authentication username to use in the operation + * Set what local port to bind the socket to when performing an operation. */ - result = Curl_setstropt(&data->set.str[STRING_USERNAME], - va_arg(param, char *)); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.localport = curlx_sltous(arg); break; - case CURLOPT_PASSWORD: + case CURLOPT_LOCALPORTRANGE: /* - * authentication password to use in the operation + * Set number of local ports to try, starting with CURLOPT_LOCALPORT. */ - result = Curl_setstropt(&data->set.str[STRING_PASSWORD], - va_arg(param, char *)); + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.localportrange = curlx_sltous(arg); break; +#endif - case CURLOPT_LOGIN_OPTIONS: + case CURLOPT_GSSAPI_DELEGATION: /* - * authentication options to use in the operation + * GSS-API credential delegation bitmask */ - result = Curl_setstropt(&data->set.str[STRING_OPTIONS], - va_arg(param, char *)); + data->set.gssapi_delegation = (unsigned char)uarg& + (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG); break; - - case CURLOPT_XOAUTH2_BEARER: + case CURLOPT_SSL_VERIFYPEER: /* - * OAuth 2.0 bearer token to use in the operation + * Enable peer SSL verifying. */ - result = Curl_setstropt(&data->set.str[STRING_BEARER], - va_arg(param, char *)); - break; + data->set.ssl.primary.verifypeer = enabled; - case CURLOPT_RESOLVE: + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); + break; +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_SSL_VERIFYPEER: /* - * List of HOST:PORT:[addresses] strings to populate the DNS cache with - * Entries added this way will remain in the cache until explicitly - * removed or the handle is cleaned up. - * - * Prefix the HOST with plus sign (+) to have the entry expire just like - * automatically added entries. - * - * Prefix the HOST with dash (-) to _remove_ the entry from the cache. - * - * This API can remove any entry from the DNS cache, but only entries - * that are not actually in use right now will be pruned immediately. + * Enable peer SSL verifying for DoH. */ - data->set.resolve = va_arg(param, struct curl_slist *); - data->state.resolve = data->set.resolve; + data->set.doh_verifypeer = enabled; break; - case CURLOPT_PROGRESSFUNCTION: + case CURLOPT_DOH_SSL_VERIFYHOST: /* - * Progress callback function + * Enable verification of the hostname in the peer certificate for DoH */ - data->set.fprogress = va_arg(param, curl_progress_callback); - if(data->set.fprogress) - data->progress.callback = TRUE; /* no longer internal */ - else - data->progress.callback = FALSE; /* NULL enforces internal */ + data->set.doh_verifyhost = enabled; break; - - case CURLOPT_XFERINFOFUNCTION: + case CURLOPT_DOH_SSL_VERIFYSTATUS: /* - * Transfer info callback function + * Enable certificate status verifying for DoH. */ - data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); - if(data->set.fxferinfo) - data->progress.callback = TRUE; /* no longer internal */ - else - data->progress.callback = FALSE; /* NULL enforces internal */ + if(!Curl_ssl_cert_status_request()) + return CURLE_NOT_BUILT_IN; + data->set.doh_verifystatus = enabled; break; - - case CURLOPT_PROGRESSDATA: +#endif /* ! CURL_DISABLE_DOH */ + case CURLOPT_SSL_VERIFYHOST: /* - * Custom client data to pass to the progress callback + * Enable verification of the hostname in the peer certificate */ - data->set.progress_client = va_arg(param, void *); - break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXYUSERPWD: { + /* Obviously people are not reading documentation and too many thought + this argument took a boolean when it was not and misused it. + Treat 1 and 2 the same */ + data->set.ssl.primary.verifyhost = enabled; + + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); + break; + case CURLOPT_SSL_VERIFYSTATUS: /* - * user:password needed to use the proxy + * Enable certificate status verifying. */ - char *u = NULL; - char *p = NULL; - result = setstropt_userpwd(va_arg(param, char *), &u, &p); + if(!Curl_ssl_cert_status_request()) + return CURLE_NOT_BUILT_IN; - /* URL decode the components */ - if(!result && u) - result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL, - REJECT_ZERO); - if(!result && p) - result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL, - REJECT_ZERO); - free(u); - free(p); - } + data->set.ssl.primary.verifystatus = enabled; + + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); break; - case CURLOPT_PROXYUSERNAME: + case CURLOPT_SSL_FALSESTART: /* - * authentication username to use in the operation + * Enable TLS false start. */ - result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME], - va_arg(param, char *)); + if(!Curl_ssl_false_start(data)) + return CURLE_NOT_BUILT_IN; + + data->set.ssl.falsestart = enabled; break; - case CURLOPT_PROXYPASSWORD: + case CURLOPT_CERTINFO: +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CERTINFO)) + data->set.ssl.certinfo = enabled; + else +#endif + return CURLE_NOT_BUILT_IN; + break; + case CURLOPT_BUFFERSIZE: /* - * authentication password to use in the operation + * The application kindly asks for a differently sized receive buffer. + * If it seems reasonable, we will use it. */ - result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD], - va_arg(param, char *)); + if(arg > READBUFFER_MAX) + arg = READBUFFER_MAX; + else if(arg < 1) + arg = READBUFFER_SIZE; + else if(arg < READBUFFER_MIN) + arg = READBUFFER_MIN; + + data->set.buffer_size = (unsigned int)arg; break; - case CURLOPT_NOPROXY: + + case CURLOPT_UPLOAD_BUFFERSIZE: /* - * proxy exception list + * The application kindly asks for a differently sized upload buffer. + * Cap it to sensible. */ - result = Curl_setstropt(&data->set.str[STRING_NOPROXY], - va_arg(param, char *)); + if(arg > UPLOADBUFFER_MAX) + arg = UPLOADBUFFER_MAX; + else if(arg < UPLOADBUFFER_MIN) + arg = UPLOADBUFFER_MIN; + + data->set.upload_buffer_size = (unsigned int)arg; break; -#endif - case CURLOPT_RANGE: + case CURLOPT_NOSIGNAL: /* - * What range of the file you want to transfer + * The application asks not to set any signal() or alarm() handlers, + * even when using a timeout. */ - result = Curl_setstropt(&data->set.str[STRING_SET_RANGE], - va_arg(param, char *)); + data->set.no_signal = enabled; break; - case CURLOPT_RESUME_FROM: + case CURLOPT_MAXFILESIZE: /* - * Resume transfer at the given file position + * Set the maximum size of a file to download. */ - arg = va_arg(param, long); - if(arg < -1) + if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.set_resume_from = arg; + data->set.max_filesize = arg; break; - case CURLOPT_RESUME_FROM_LARGE: + +#ifdef USE_SSL + case CURLOPT_USE_SSL: /* - * Resume transfer at the given file position + * Make transfers attempt to use SSL/TLS. */ - bigsize = va_arg(param, curl_off_t); - if(bigsize < -1) + if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.set_resume_from = bigsize; + data->set.use_ssl = (unsigned char)arg; break; - case CURLOPT_DEBUGFUNCTION: + case CURLOPT_SSL_OPTIONS: + data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); + data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); + data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT); + data->set.ssl.earlydata = !!(arg & CURLSSLOPT_EARLYDATA); + /* If a setting is added here it should also be added in dohprobe() + which sets its own CURLOPT_SSL_OPTIONS based on these settings. */ + break; + +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSL_OPTIONS: + data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff); + data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); + data->set.proxy_ssl.revoke_best_effort = + !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); + data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); + data->set.proxy_ssl.auto_client_cert = + !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT); + break; +#endif + +#endif /* USE_SSL */ + case CURLOPT_IPRESOLVE: + if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.ipver = (unsigned char) arg; + break; + case CURLOPT_TCP_NODELAY: /* - * stderr write callback. + * Enable or disable TCP_NODELAY, which will disable/enable the Nagle + * algorithm */ - data->set.fdebug = va_arg(param, curl_debug_callback); + data->set.tcp_nodelay = enabled; + break; + + case CURLOPT_IGNORE_CONTENT_LENGTH: + data->set.ignorecl = enabled; + break; + + case CURLOPT_CONNECT_ONLY: /* - * if the callback provided is NULL, it will use the default callback + * No data transfer. + * (1) - only do connection + * (2) - do first get request but get no content */ + if(arg > 2) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.connect_only = (unsigned char)arg; break; - case CURLOPT_DEBUGDATA: + + case CURLOPT_SSL_SESSIONID_CACHE: + data->set.ssl.primary.cache_session = enabled; +#ifndef CURL_DISABLE_PROXY + data->set.proxy_ssl.primary.cache_session = + data->set.ssl.primary.cache_session; +#endif + break; + +#ifdef USE_SSH + /* we only include SSH options if explicitly built to support SSH */ + case CURLOPT_SSH_AUTH_TYPES: + data->set.ssh_auth_types = (int)arg; + break; + case CURLOPT_SSH_COMPRESSION: + data->set.ssh_compression = enabled; + break; +#endif + + case CURLOPT_HTTP_TRANSFER_DECODING: /* - * Set to a void * that should receive all error writes. This - * defaults to CURLOPT_STDERR for normal operations. + * disable libcurl transfer encoding is used */ - data->set.debugdata = va_arg(param, void *); +#ifndef USE_HYPER + data->set.http_te_skip = !enabled; /* reversed */ break; - case CURLOPT_STDERR: +#else + return CURLE_NOT_BUILT_IN; /* hyper does not support */ +#endif + + case CURLOPT_HTTP_CONTENT_DECODING: /* - * Set to a FILE * that should receive all error writes. This - * defaults to stderr for normal operations. + * raw data passed to the application when content encoding is used */ - data->set.err = va_arg(param, FILE *); - if(!data->set.err) - data->set.err = stderr; + data->set.http_ce_skip = enabled; break; - case CURLOPT_HEADERFUNCTION: + +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) + case CURLOPT_NEW_FILE_PERMS: /* - * Set header write callback + * Uses these permissions instead of 0644 */ - data->set.fwrite_header = va_arg(param, curl_write_callback); + if((arg < 0) || (arg > 0777)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.new_file_perms = (unsigned int)arg; break; - case CURLOPT_WRITEFUNCTION: +#endif +#ifdef USE_SSH + case CURLOPT_NEW_DIRECTORY_PERMS: /* - * Set data write callback + * Uses these permissions instead of 0755 */ - data->set.fwrite_func = va_arg(param, curl_write_callback); - if(!data->set.fwrite_func) - /* When set to NULL, reset to our internal default function */ - data->set.fwrite_func = (curl_write_callback)fwrite; + if((arg < 0) || (arg > 0777)) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.new_directory_perms = (unsigned int)arg; break; - case CURLOPT_READFUNCTION: +#endif +#ifdef USE_IPV6 + case CURLOPT_ADDRESS_SCOPE: /* - * Read data callback + * Use this scope id when using IPv6 + * We always get longs when passed plain numericals so we should check + * that the value fits into an unsigned 32-bit integer. */ - data->set.fread_func_set = va_arg(param, curl_read_callback); - if(!data->set.fread_func_set) { - data->set.is_fread_set = 0; - /* When set to NULL, reset to our internal default function */ - data->set.fread_func_set = (curl_read_callback)fread; - } - else - data->set.is_fread_set = 1; +#if SIZEOF_LONG > 4 + if(uarg > UINT_MAX) + return CURLE_BAD_FUNCTION_ARGUMENT; +#endif + data->set.scope_id = (unsigned int)uarg; break; - case CURLOPT_SEEKFUNCTION: +#endif + case CURLOPT_PROTOCOLS: + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal with. + Defaults to CURLPROTO_ALL. */ + data->set.allowed_protocols = (curl_prot_t)arg; + break; + + case CURLOPT_REDIR_PROTOCOLS: + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol + needs to be set in both bitmasks to be allowed to get redirected to. */ + data->set.redir_protocols = (curl_prot_t)arg; + break; + +#ifndef CURL_DISABLE_SMTP + case CURLOPT_MAIL_RCPT_ALLOWFAILS: + /* allow RCPT TO command to fail for some recipients */ + data->set.mail_rcpt_allowfails = enabled; + break; +#endif /* !CURL_DISABLE_SMTP */ + case CURLOPT_SASL_IR: + /* Enable/disable SASL initial response */ + data->set.sasl_ir = enabled; + break; +#ifndef CURL_DISABLE_RTSP + case CURLOPT_RTSP_REQUEST: + { /* - * Seek callback. Might be NULL. + * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...) + * Would this be better if the RTSPREQ_* were just moved into here? */ - data->set.seek_func = va_arg(param, curl_seek_callback); + Curl_RtspReq rtspreq = RTSPREQ_NONE; + switch(arg) { + case CURL_RTSPREQ_OPTIONS: + rtspreq = RTSPREQ_OPTIONS; + break; + + case CURL_RTSPREQ_DESCRIBE: + rtspreq = RTSPREQ_DESCRIBE; + break; + + case CURL_RTSPREQ_ANNOUNCE: + rtspreq = RTSPREQ_ANNOUNCE; + break; + + case CURL_RTSPREQ_SETUP: + rtspreq = RTSPREQ_SETUP; + break; + + case CURL_RTSPREQ_PLAY: + rtspreq = RTSPREQ_PLAY; + break; + + case CURL_RTSPREQ_PAUSE: + rtspreq = RTSPREQ_PAUSE; + break; + + case CURL_RTSPREQ_TEARDOWN: + rtspreq = RTSPREQ_TEARDOWN; + break; + + case CURL_RTSPREQ_GET_PARAMETER: + rtspreq = RTSPREQ_GET_PARAMETER; + break; + + case CURL_RTSPREQ_SET_PARAMETER: + rtspreq = RTSPREQ_SET_PARAMETER; + break; + + case CURL_RTSPREQ_RECORD: + rtspreq = RTSPREQ_RECORD; + break; + + case CURL_RTSPREQ_RECEIVE: + rtspreq = RTSPREQ_RECEIVE; + break; + default: + rtspreq = RTSPREQ_NONE; + } + + data->set.rtspreq = rtspreq; break; - case CURLOPT_SEEKDATA: + } + case CURLOPT_RTSP_CLIENT_CSEQ: /* - * Seek control callback. Might be NULL. + * Set the CSEQ number to issue for the next RTSP request. Useful if the + * application is resuming a previously broken connection. The CSEQ + * will increment from this new number henceforth. */ - data->set.seek_client = va_arg(param, void *); + data->state.rtsp_next_client_CSeq = arg; break; - case CURLOPT_IOCTLFUNCTION: + + case CURLOPT_RTSP_SERVER_CSEQ: + /* Same as the above, but for server-initiated requests */ + data->state.rtsp_next_server_CSeq = arg; + break; + +#endif /* ! CURL_DISABLE_RTSP */ + + case CURLOPT_TCP_KEEPALIVE: + data->set.tcp_keepalive = enabled; + break; + case CURLOPT_TCP_KEEPIDLE: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepidle = (int)arg; + break; + case CURLOPT_TCP_KEEPINTVL: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepintvl = (int)arg; + break; + case CURLOPT_TCP_KEEPCNT: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepcnt = (int)arg; + break; + case CURLOPT_TCP_FASTOPEN: +#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ + defined(TCP_FASTOPEN_CONNECT) + data->set.tcp_fastopen = enabled; +#else + return CURLE_NOT_BUILT_IN; +#endif + break; + case CURLOPT_SSL_ENABLE_NPN: + break; + case CURLOPT_SSL_ENABLE_ALPN: + data->set.ssl_enable_alpn = enabled; + break; + case CURLOPT_PATH_AS_IS: + data->set.path_as_is = enabled; + break; + case CURLOPT_PIPEWAIT: + data->set.pipewait = enabled; + break; + case CURLOPT_STREAM_WEIGHT: +#if defined(USE_HTTP2) || defined(USE_HTTP3) + if((arg >= 1) && (arg <= 256)) + data->set.priority.weight = (int)arg; + break; +#else + return CURLE_NOT_BUILT_IN; +#endif + case CURLOPT_SUPPRESS_CONNECT_HEADERS: + data->set.suppress_connect_headers = enabled; + break; + case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: + if(uarg > UINT_MAX) + uarg = UINT_MAX; + data->set.happy_eyeballs_timeout = (unsigned int)uarg; + break; +#ifndef CURL_DISABLE_SHUFFLE_DNS + case CURLOPT_DNS_SHUFFLE_ADDRESSES: + data->set.dns_shuffle_addresses = enabled; + break; +#endif + case CURLOPT_DISALLOW_USERNAME_IN_URL: + data->set.disallow_username_in_url = enabled; + break; + + case CURLOPT_UPKEEP_INTERVAL_MS: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.upkeep_interval_ms = arg; + break; + case CURLOPT_MAXAGE_CONN: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxage_conn = arg; + break; + case CURLOPT_MAXLIFETIME_CONN: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxlifetime_conn = arg; + break; +#ifndef CURL_DISABLE_HSTS + case CURLOPT_HSTS_CTRL: + if(arg & CURLHSTS_ENABLE) { + if(!data->hsts) { + data->hsts = Curl_hsts_init(); + if(!data->hsts) + return CURLE_OUT_OF_MEMORY; + } + } + else + Curl_hsts_cleanup(&data->hsts); + break; +#endif /* ! CURL_DISABLE_HSTS */ +#ifndef CURL_DISABLE_ALTSVC + case CURLOPT_ALTSVC_CTRL: + if(!arg) { + DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input")); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!data->asi) { + data->asi = Curl_altsvc_init(); + if(!data->asi) + return CURLE_OUT_OF_MEMORY; + } + return Curl_altsvc_ctrl(data->asi, arg); +#endif /* ! CURL_DISABLE_ALTSVC */ +#ifndef CURL_DISABLE_WEBSOCKETS + case CURLOPT_WS_OPTIONS: + data->set.ws_raw_mode = (bool)(arg & CURLWS_RAW_MODE); + break; +#endif + case CURLOPT_QUICK_EXIT: + data->set.quick_exit = enabled; + break; + case CURLOPT_DNS_USE_GLOBAL_CACHE: + /* deprecated */ + break; + case CURLOPT_SSLENGINE_DEFAULT: /* - * I/O control callback. Might be NULL. + * flag to set engine as default. */ - data->set.ioctl_func = va_arg(param, curl_ioctl_callback); - break; - case CURLOPT_IOCTLDATA: + Curl_safefree(data->set.str[STRING_SSL_ENGINE]); + return Curl_ssl_set_engine_default(data); + + default: + /* unknown option */ + return CURLE_UNKNOWN_OPTION; + } + return CURLE_OK; +} + +static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, + struct curl_slist *slist) +{ + CURLcode result = CURLE_OK; + switch(option) { +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXYHEADER: /* - * I/O control data pointer. Might be NULL. + * Set a list with proxy headers to use (or replace internals with) + * + * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a + * long time we remain doing it this way until CURLOPT_PROXYHEADER is + * used. As soon as this option has been used, if set to anything but + * NULL, custom headers for proxies are only picked from this list. + * + * Set this option to NULL to restore the previous behavior. */ - data->set.ioctl_client = va_arg(param, void *); + data->set.proxyheaders = slist; break; - case CURLOPT_SSLCERT: +#endif +#ifndef CURL_DISABLE_HTTP + case CURLOPT_HTTP200ALIASES: /* - * String that holds filename of the SSL certificate to use + * Set a list of aliases for HTTP 200 in response header */ - result = Curl_setstropt(&data->set.str[STRING_CERT], - va_arg(param, char *)); + data->set.http200aliases = slist; break; - case CURLOPT_SSLCERT_BLOB: +#endif +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) + case CURLOPT_POSTQUOTE: /* - * Blob that holds file content of the SSL certificate to use + * List of RAW FTP commands to use after a transfer */ - result = Curl_setblobopt(&data->set.blobs[BLOB_CERT], - va_arg(param, struct curl_blob *)); + data->set.postquote = slist; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSLCERT: + case CURLOPT_PREQUOTE: /* - * String that holds filename of the SSL certificate to use for proxy + * List of RAW FTP commands to use prior to RETR (Wesley Laxton) */ - result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY], - va_arg(param, char *)); + data->set.prequote = slist; break; - case CURLOPT_PROXY_SSLCERT_BLOB: + case CURLOPT_QUOTE: /* - * Blob that holds file content of the SSL certificate to use for proxy + * List of RAW FTP commands to use before a transfer */ - result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY], - va_arg(param, struct curl_blob *)); + data->set.quote = slist; break; #endif - case CURLOPT_SSLCERTTYPE: + case CURLOPT_RESOLVE: /* - * String that holds file type of the SSL certificate to use + * List of HOST:PORT:[addresses] strings to populate the DNS cache with + * Entries added this way will remain in the cache until explicitly + * removed or the handle is cleaned up. + * + * Prefix the HOST with plus sign (+) to have the entry expire just like + * automatically added entries. + * + * Prefix the HOST with dash (-) to _remove_ the entry from the cache. + * + * This API can remove any entry from the DNS cache, but only entries + * that are not actually in use right now will be pruned immediately. */ - result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE], - va_arg(param, char *)); + data->set.resolve = slist; + data->state.resolve = data->set.resolve; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSLCERTTYPE: +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) + case CURLOPT_HTTPHEADER: /* - * String that holds file type of the SSL certificate to use for proxy + * Set a list with HTTP headers to use (or replace internals with) */ - result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], - va_arg(param, char *)); + data->set.headers = slist; break; #endif - case CURLOPT_SSLKEY: +#ifndef CURL_DISABLE_TELNET + case CURLOPT_TELNETOPTIONS: /* - * String that holds filename of the SSL key to use + * Set a linked list of telnet options */ - result = Curl_setstropt(&data->set.str[STRING_KEY], - va_arg(param, char *)); + data->set.telnet_options = slist; break; - case CURLOPT_SSLKEY_BLOB: +#endif +#ifndef CURL_DISABLE_SMTP + case CURLOPT_MAIL_RCPT: + /* Set the list of mail recipients */ + data->set.mail_rcpt = slist; + break; +#endif + case CURLOPT_CONNECT_TO: + data->set.connect_to = slist; + break; + default: + return CURLE_UNKNOWN_OPTION; + } + return result; +} + +/* assorted pointer type arguments */ +static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, + va_list param) +{ + CURLcode result = CURLE_OK; + switch(option) { +#ifndef CURL_DISABLE_HTTP +#ifndef CURL_DISABLE_FORM_API + case CURLOPT_HTTPPOST: /* - * Blob that holds file content of the SSL key to use + * Set to make us do HTTP POST. Legacy API-style. */ - result = Curl_setblobopt(&data->set.blobs[BLOB_KEY], - va_arg(param, struct curl_blob *)); + data->set.httppost = va_arg(param, struct curl_httppost *); + data->set.method = HTTPREQ_POST_FORM; + data->set.opt_no_body = FALSE; /* this is implied */ + Curl_mime_cleanpart(data->state.formp); + Curl_safefree(data->state.formp); + data->state.mimepost = NULL; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSLKEY: +#endif /* ! CURL_DISABLE_FORM_API */ +#endif /* ! CURL_DISABLE_HTTP */ +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) +# ifndef CURL_DISABLE_MIME + case CURLOPT_MIMEPOST: /* - * String that holds filename of the SSL key to use for proxy + * Set to make us do MIME POST */ - result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY], - va_arg(param, char *)); + result = Curl_mime_set_subparts(&data->set.mimepost, + va_arg(param, curl_mime *), + FALSE); + if(!result) { + data->set.method = HTTPREQ_POST_MIME; + data->set.opt_no_body = FALSE; /* this is implied */ +#ifndef CURL_DISABLE_FORM_API + Curl_mime_cleanpart(data->state.formp); + Curl_safefree(data->state.formp); + data->state.mimepost = NULL; +#endif + } break; - case CURLOPT_PROXY_SSLKEY_BLOB: +#endif /* ! CURL_DISABLE_MIME */ +#endif /* ! disabled HTTP, SMTP or IMAP */ + case CURLOPT_STDERR: /* - * Blob that holds file content of the SSL key to use for proxy + * Set to a FILE * that should receive all error writes. This + * defaults to stderr for normal operations. */ - result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY], - va_arg(param, struct curl_blob *)); + data->set.err = va_arg(param, FILE *); + if(!data->set.err) + data->set.err = stderr; break; + case CURLOPT_SHARE: + { + struct Curl_share *set = va_arg(param, struct Curl_share *); + + /* disconnect from old share, if any */ + if(data->share) { + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + + if(data->dns.hostcachetype == HCACHE_SHARED) { + data->dns.hostcache = NULL; + data->dns.hostcachetype = HCACHE_NONE; + } + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(data->share->cookies == data->cookies) + data->cookies = NULL; #endif - case CURLOPT_SSLKEYTYPE: - /* - * String that holds file type of the SSL key to use - */ - result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE], - va_arg(param, char *)); + +#ifndef CURL_DISABLE_HSTS + if(data->share->hsts == data->hsts) + data->hsts = NULL; +#endif +#ifdef USE_SSL + if(data->share->sslsession == data->state.session) + data->state.session = NULL; +#endif +#ifdef USE_LIBPSL + if(data->psl == &data->share->psl) + data->psl = data->multi ? &data->multi->psl : NULL; +#endif + + data->share->dirty--; + + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + data->share = NULL; + } + + if(GOOD_SHARE_HANDLE(set)) + /* use new share if it set */ + data->share = set; + if(data->share) { + + Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + + data->share->dirty++; + + if(data->share->specifier & (1 << CURL_LOCK_DATA_DNS)) { + /* use shared host cache */ + data->dns.hostcache = &data->share->hostcache; + data->dns.hostcachetype = HCACHE_SHARED; + } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + if(data->share->cookies) { + /* use shared cookie list, first free own one if any */ + Curl_cookie_cleanup(data->cookies); + /* enable cookies since we now use a share that uses cookies! */ + data->cookies = data->share->cookies; + } +#endif /* CURL_DISABLE_HTTP */ +#ifndef CURL_DISABLE_HSTS + if(data->share->hsts) { + /* first free the private one if any */ + Curl_hsts_cleanup(&data->hsts); + data->hsts = data->share->hsts; + } +#endif +#ifdef USE_SSL + if(data->share->sslsession) { + data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; + data->state.session = data->share->sslsession; + } +#endif +#ifdef USE_LIBPSL + if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) + data->psl = &data->share->psl; +#endif + + Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); + } + /* check for host cache not needed, + * it will be done by curl_easy_perform */ + } + break; + +#ifdef USE_HTTP2 + case CURLOPT_STREAM_DEPENDS: + case CURLOPT_STREAM_DEPENDS_E: { + struct Curl_easy *dep = va_arg(param, struct Curl_easy *); + if(!dep || GOOD_EASY_HANDLE(dep)) + return Curl_data_priority_add_child(dep, data, + option == CURLOPT_STREAM_DEPENDS_E); + break; + } +#endif + + default: + return CURLE_UNKNOWN_OPTION; + } + return result; +} + +static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, + char *ptr) +{ + CURLcode result = CURLE_OK; + switch(option) { + case CURLOPT_SSL_CIPHER_LIST: + if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) + /* set a list of cipher we want to use in the SSL connection */ + return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], ptr); + return CURLE_NOT_BUILT_IN; break; #ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSLKEYTYPE: - /* - * String that holds file type of the SSL key to use for proxy - */ - result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], - va_arg(param, char *)); + case CURLOPT_PROXY_SSL_CIPHER_LIST: + if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) { + /* set a list of cipher we want to use in the SSL connection for proxy */ + return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], + ptr); + } + else + return CURLE_NOT_BUILT_IN; break; #endif - case CURLOPT_KEYPASSWD: - /* - * String that holds the SSL or SSH private key password. - */ - result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD], - va_arg(param, char *)); + case CURLOPT_TLS13_CIPHERS: + if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) { + /* set preferred list of TLS 1.3 cipher suites */ + return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST], ptr); + } + else + return CURLE_NOT_BUILT_IN; break; #ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_KEYPASSWD: + case CURLOPT_PROXY_TLS13_CIPHERS: + if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) + /* set preferred list of TLS 1.3 cipher suites for proxy */ + return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY], + ptr); + else + return CURLE_NOT_BUILT_IN; + break; +#endif + case CURLOPT_RANDOM_FILE: + break; + case CURLOPT_EGDSOCKET: + break; + case CURLOPT_REQUEST_TARGET: + return Curl_setstropt(&data->set.str[STRING_TARGET], ptr); +#ifndef CURL_DISABLE_NETRC + case CURLOPT_NETRC_FILE: /* - * String that holds the SSL private key password for proxy. + * Use this file instead of the $HOME/.netrc file */ - result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_NETRC_FILE], ptr); #endif - case CURLOPT_SSLENGINE: + +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT) + case CURLOPT_COPYPOSTFIELDS: /* - * String that holds the SSL crypto engine. + * A string with POST data. Makes curl HTTP POST. Even if it is NULL. + * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to + * CURLOPT_COPYPOSTFIELDS and not altered later. */ - argptr = va_arg(param, char *); - if(argptr && argptr[0]) { - result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], argptr); - if(!result) { - result = Curl_ssl_set_engine(data, argptr); + if(!ptr || data->set.postfieldsize == -1) + result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], ptr); + else { + /* + * Check that requested length does not overflow the size_t type. + */ + + if((data->set.postfieldsize < 0) || + ((sizeof(curl_off_t) != sizeof(size_t)) && + (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) + return CURLE_OUT_OF_MEMORY; + else { + /* Allocate even when size == 0. This satisfies the need of possible + later address compare to detect the COPYPOSTFIELDS mode, and to + mark that postfields is used rather than read function or form + data. + */ + char *p = Curl_memdup0(ptr, (size_t)data->set.postfieldsize); + if(!p) + return CURLE_OUT_OF_MEMORY; + else { + free(data->set.str[STRING_COPYPOSTFIELDS]); + data->set.str[STRING_COPYPOSTFIELDS] = p; + } } } + + data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; + data->set.method = HTTPREQ_POST; break; - case CURLOPT_SSLENGINE_DEFAULT: + case CURLOPT_POSTFIELDS: /* - * flag to set engine as default. + * Like above, but use static data instead of copying it. */ - Curl_safefree(data->set.str[STRING_SSL_ENGINE]); - result = Curl_ssl_set_engine_default(data); + data->set.postfields = ptr; + /* Release old copied data. */ + Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); + data->set.method = HTTPREQ_POST; break; - case CURLOPT_CRLF: + +#ifndef CURL_DISABLE_HTTP + case CURLOPT_ACCEPT_ENCODING: /* - * Kludgy option to enable CRLF conversions. Subject for removal. + * String to use at the value of Accept-Encoding header. + * + * If the encoding is set to "" we use an Accept-Encoding header that + * encompasses all the encodings we support. + * If the encoding is set to NULL we do not send an Accept-Encoding header + * and ignore an received Content-Encoding header. + * */ - data->set.crlf = (0 != va_arg(param, long)); - break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_HAPROXYPROTOCOL: + if(ptr && !*ptr) { + char all[256]; + Curl_all_content_encodings(all, sizeof(all)); + return Curl_setstropt(&data->set.str[STRING_ENCODING], all); + } + return Curl_setstropt(&data->set.str[STRING_ENCODING], ptr); + +#if !defined(CURL_DISABLE_AWS) + case CURLOPT_AWS_SIGV4: /* - * Set to send the HAProxy Proxy Protocol header + * String that is merged to some authentication + * parameters are used by the algorithm. */ - data->set.haproxyprotocol = (0 != va_arg(param, long)); - break; - case CURLOPT_HAPROXY_CLIENT_IP: + result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4], ptr); /* - * Set the client IP to send through HAProxy PROXY protocol + * Basic been set by default it need to be unset here */ - result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP], - va_arg(param, char *)); - /* We enable implicitly the HAProxy protocol if we use this flag. */ - data->set.haproxyprotocol = TRUE; + if(data->set.str[STRING_AWS_SIGV4]) + data->set.httpauth = CURLAUTH_AWS_SIGV4; break; #endif - case CURLOPT_INTERFACE: - /* - * Set what interface or address/hostname to bind the socket to when - * performing an operation and thus what from-IP your connection will use. - */ - result = setstropt_interface(va_arg(param, char *), - &data->set.str[STRING_DEVICE], - &data->set.str[STRING_INTERFACE], - &data->set.str[STRING_BINDHOST]); - break; -#ifndef CURL_DISABLE_BINDLOCAL - case CURLOPT_LOCALPORT: + case CURLOPT_REFERER: /* - * Set what local port to bind the socket to when performing an operation. + * String to set in the HTTP Referer: field. */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.localport = curlx_sltous(arg); + if(data->state.referer_alloc) { + Curl_safefree(data->state.referer); + data->state.referer_alloc = FALSE; + } + result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], ptr); + data->state.referer = data->set.str[STRING_SET_REFERER]; break; - case CURLOPT_LOCALPORTRANGE: + + case CURLOPT_USERAGENT: /* - * Set number of local ports to try, starting with CURLOPT_LOCALPORT. + * String to use in the HTTP User-Agent field */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.localportrange = curlx_sltous(arg); - break; -#endif - case CURLOPT_GSSAPI_DELEGATION: + return Curl_setstropt(&data->set.str[STRING_USERAGENT], ptr); + +#if !defined(CURL_DISABLE_COOKIES) + case CURLOPT_COOKIE: /* - * GSS-API credential delegation bitmask + * Cookie string to send to the remote server in the request. */ - uarg = va_arg(param, unsigned long); - data->set.gssapi_delegation = (unsigned char)uarg& - (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG); - break; - case CURLOPT_SSL_VERIFYPEER: + return Curl_setstropt(&data->set.str[STRING_COOKIE], ptr); + + case CURLOPT_COOKIEFILE: /* - * Enable peer SSL verifying. + * Set cookie file to read and parse. Can be used multiple times. */ - data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)); + if(ptr) { + struct curl_slist *cl; + /* general protection against mistakes and abuse */ + if(strlen(ptr) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + /* append the cookie filename to the list of filenames, and deal with + them later */ + cl = curl_slist_append(data->state.cookielist, ptr); + if(!cl) { + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; + return CURLE_OUT_OF_MEMORY; + } + data->state.cookielist = cl; /* store the list for later use */ + } + else { + /* clear the list of cookie files */ + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; - /* Update the current connection ssl_config. */ - Curl_ssl_conn_config_update(data, FALSE); + if(!data->share || !data->share->cookies) { + /* throw away all existing cookies if this is not a shared cookie + container */ + Curl_cookie_clearall(data->cookies); + Curl_cookie_cleanup(data->cookies); + } + /* disable the cookie engine */ + data->cookies = NULL; + } break; -#ifndef CURL_DISABLE_DOH - case CURLOPT_DOH_SSL_VERIFYPEER: + + case CURLOPT_COOKIEJAR: /* - * Enable peer SSL verifying for DoH. + * Set cookie filename to dump all cookies to when we are done. */ - data->set.doh_verifypeer = (0 != va_arg(param, long)); + result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], ptr); + if(!result) { + /* + * Activate the cookie parser. This may or may not already + * have been made. + */ + struct CookieInfo *newcookies = + Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession); + if(!newcookies) + result = CURLE_OUT_OF_MEMORY; + data->cookies = newcookies; + } break; -#endif -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSL_VERIFYPEER: - /* - * Enable peer SSL verifying for proxy. - */ - data->set.proxy_ssl.primary.verifypeer = - (0 != va_arg(param, long)); - /* Update the current connection proxy_ssl_config. */ - Curl_ssl_conn_config_update(data, TRUE); - break; -#endif - case CURLOPT_SSL_VERIFYHOST: - /* - * Enable verification of the hostname in the peer certificate - */ - arg = va_arg(param, long); + case CURLOPT_COOKIELIST: + if(!ptr) + break; - /* Obviously people are not reading documentation and too many thought - this argument took a boolean when it was not and misused it. - Treat 1 and 2 the same */ - data->set.ssl.primary.verifyhost = !!(arg & 3); + if(strcasecompare(ptr, "ALL")) { + /* clear all cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_clearall(data->cookies); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + else if(strcasecompare(ptr, "SESS")) { + /* clear session cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_clearsess(data->cookies); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + else if(strcasecompare(ptr, "FLUSH")) { + /* flush cookies to file, takes care of the locking */ + Curl_flush_cookies(data, FALSE); + } + else if(strcasecompare(ptr, "RELOAD")) { + /* reload cookies from file */ + Curl_cookie_loadfiles(data); + break; + } + else { + if(!data->cookies) { + /* if cookie engine was not running, activate it */ + data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); + if(!data->cookies) + return CURLE_OUT_OF_MEMORY; + } - /* Update the current connection ssl_config. */ - Curl_ssl_conn_config_update(data, FALSE); + /* general protection against mistakes and abuse */ + if(strlen(ptr) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + if(checkprefix("Set-Cookie:", ptr)) + /* HTTP Header format line */ + Curl_cookie_add(data, data->cookies, TRUE, FALSE, ptr + 11, NULL, + NULL, TRUE); + else + /* Netscape format line */ + Curl_cookie_add(data, data->cookies, FALSE, FALSE, ptr, NULL, + NULL, TRUE); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } break; -#ifndef CURL_DISABLE_DOH - case CURLOPT_DOH_SSL_VERIFYHOST: +#endif /* !CURL_DISABLE_COOKIES */ + +#endif /* ! CURL_DISABLE_HTTP */ + + case CURLOPT_CUSTOMREQUEST: /* - * Enable verification of the hostname in the peer certificate for DoH + * Set a custom string to use as request */ - arg = va_arg(param, long); + return Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], ptr); + + /* we do not set + data->set.method = HTTPREQ_CUSTOM; + here, we continue as if we were using the already set type + and this just changes the actual request keyword */ - /* Treat both 1 and 2 as TRUE */ - data->set.doh_verifyhost = !!(arg & 3); - break; -#endif #ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSL_VERIFYHOST: + case CURLOPT_PROXY: /* - * Enable verification of the hostname in the peer certificate for proxy + * Set proxy server:port to use as proxy. + * + * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) + * we explicitly say that we do not want to use a proxy + * (even though there might be environment variables saying so). + * + * Setting it to NULL, means no proxy but allows the environment variables + * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). */ - arg = va_arg(param, long); - - /* Treat both 1 and 2 as TRUE */ - data->set.proxy_ssl.primary.verifyhost = !!(arg & 3); - /* Update the current connection proxy_ssl_config. */ - Curl_ssl_conn_config_update(data, TRUE); + return Curl_setstropt(&data->set.str[STRING_PROXY], ptr); break; -#endif - case CURLOPT_SSL_VERIFYSTATUS: - /* - * Enable certificate status verifying. - */ - if(!Curl_ssl_cert_status_request()) { - result = CURLE_NOT_BUILT_IN; - break; - } - data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)); - - /* Update the current connection ssl_config. */ - Curl_ssl_conn_config_update(data, FALSE); - break; -#ifndef CURL_DISABLE_DOH - case CURLOPT_DOH_SSL_VERIFYSTATUS: + case CURLOPT_PRE_PROXY: /* - * Enable certificate status verifying for DoH. + * Set proxy server:port to use as SOCKS proxy. + * + * If the proxy is set to "" or NULL we explicitly say that we do not want + * to use the socks proxy. */ - if(!Curl_ssl_cert_status_request()) { - result = CURLE_NOT_BUILT_IN; - break; - } + return Curl_setstropt(&data->set.str[STRING_PRE_PROXY], ptr); +#endif /* CURL_DISABLE_PROXY */ - data->set.doh_verifystatus = (0 != va_arg(param, long)); - break; -#endif - case CURLOPT_SSL_CTX_FUNCTION: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_SOCKS5_GSSAPI_SERVICE: + case CURLOPT_PROXY_SERVICE_NAME: /* - * Set a SSL_CTX callback + * Set proxy authentication service name for Kerberos 5 and SPNEGO */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) - data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); - else + return Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], ptr); #endif - result = CURLE_NOT_BUILT_IN; - break; - case CURLOPT_SSL_CTX_DATA: + case CURLOPT_SERVICE_NAME: /* - * Set a SSL_CTX callback parameter pointer + * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) - data->set.ssl.fsslctxp = va_arg(param, void *); - else -#endif - result = CURLE_NOT_BUILT_IN; + return Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], ptr); break; - case CURLOPT_SSL_FALSESTART: + + case CURLOPT_HEADERDATA: /* - * Enable TLS false start. + * Custom pointer to pass the header write callback function */ - if(!Curl_ssl_false_start(data)) { - result = CURLE_NOT_BUILT_IN; - break; - } - - data->set.ssl.falsestart = (0 != va_arg(param, long)); + data->set.writeheader = (void *)ptr; break; - case CURLOPT_CERTINFO: -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CERTINFO)) - data->set.ssl.certinfo = (0 != va_arg(param, long)); - else -#endif - result = CURLE_NOT_BUILT_IN; + case CURLOPT_READDATA: + /* + * FILE pointer to read the file to be uploaded from. Or possibly used as + * argument to the read callback. + */ + data->set.in_set = (void *)ptr; break; - case CURLOPT_PINNEDPUBLICKEY: + case CURLOPT_WRITEDATA: /* - * Set pinned public key for SSL connection. - * Specify filename of the public key in DER format. + * FILE pointer to write to. Or possibly used as argument to the write + * callback. */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) - result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; + data->set.out = (void *)ptr; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_PINNEDPUBLICKEY: + case CURLOPT_DEBUGDATA: /* - * Set pinned public key for SSL connection. - * Specify filename of the public key in DER format. + * Set to a void * that should receive all error writes. This + * defaults to CURLOPT_STDERR for normal operations. */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) - result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; + data->set.debugdata = (void *)ptr; break; -#endif - case CURLOPT_CAINFO: + case CURLOPT_PROGRESSDATA: /* - * Set CA info for SSL connection. Specify filename of the CA certificate + * Custom client data to pass to the progress callback */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], - va_arg(param, char *)); + data->set.progress_client = (void *)ptr; break; - case CURLOPT_CAINFO_BLOB: + case CURLOPT_SEEKDATA: /* - * Blob that holds CA info for SSL connection. - * Specify entire PEM of the CA certificate + * Seek control callback. Might be NULL. */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) { - result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO], - va_arg(param, struct curl_blob *)); - break; - } - else -#endif - return CURLE_NOT_BUILT_IN; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_CAINFO: + data->set.seek_client = (void *)ptr; + break; + case CURLOPT_IOCTLDATA: /* - * Set CA info SSL connection for proxy. Specify filename of the - * CA certificate + * I/O control data pointer. Might be NULL. */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], - va_arg(param, char *)); + data->set.ioctl_client = (void *)ptr; break; - case CURLOPT_PROXY_CAINFO_BLOB: + case CURLOPT_SSL_CTX_DATA: /* - * Blob that holds CA info for SSL connection proxy. - * Specify entire PEM of the CA certificate + * Set a SSL_CTX callback parameter pointer */ #ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) { - result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY], - va_arg(param, struct curl_blob *)); - break; - } + if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) + data->set.ssl.fsslctxp = (void *)ptr; else #endif return CURLE_NOT_BUILT_IN; -#endif - case CURLOPT_CAPATH: + break; + case CURLOPT_SOCKOPTDATA: /* - * Set CA path info for SSL connection. Specify directory name of the CA - * certificates which have been prepared using openssl c_rehash utility. + * socket callback data pointer. Might be NULL. */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) - /* This does not work on Windows. */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; + data->set.sockopt_client = (void *)ptr; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_CAPATH: + case CURLOPT_OPENSOCKETDATA: /* - * Set CA path info for SSL connection proxy. Specify directory name of the - * CA certificates which have been prepared using openssl c_rehash utility. + * socket callback data pointer. Might be NULL. */ -#ifdef USE_SSL - if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) - /* This does not work on Windows. */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], - va_arg(param, char *)); - else -#endif - result = CURLE_NOT_BUILT_IN; + data->set.opensocket_client = (void *)ptr; break; -#endif - case CURLOPT_CRLFILE: + case CURLOPT_RESOLVER_START_DATA: /* - * Set CRL file info for SSL connection. Specify filename of the CRL - * to check certificates revocation + * resolver start callback data pointer. Might be NULL. */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE], - va_arg(param, char *)); + data->set.resolver_start_client = (void *)ptr; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_CRLFILE: + case CURLOPT_CLOSESOCKETDATA: /* - * Set CRL file info for SSL connection for proxy. Specify filename of the - * CRL to check certificates revocation + * socket callback data pointer. Might be NULL. */ - result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], - va_arg(param, char *)); + data->set.closesocket_client = (void *)ptr; break; + case CURLOPT_TRAILERDATA: +#ifndef CURL_DISABLE_HTTP + data->set.trailer_data = (void *)ptr; #endif - case CURLOPT_ISSUERCERT: - /* - * Set Issuer certificate file - * to check certificates issuer - */ - result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT], - va_arg(param, char *)); break; - case CURLOPT_ISSUERCERT_BLOB: - /* - * Blob that holds Issuer certificate to check certificates issuer - */ - result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT], - va_arg(param, struct curl_blob *)); + case CURLOPT_PREREQDATA: + data->set.prereq_userp = (void *)ptr; break; -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_ISSUERCERT: + + case CURLOPT_ERRORBUFFER: /* - * Set Issuer certificate file - * to check certificates issuer + * Error buffer provided by the caller to get the human readable error + * string in. */ - result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], - va_arg(param, char *)); + data->set.errorbuffer = ptr; break; - case CURLOPT_PROXY_ISSUERCERT_BLOB: + +#ifndef CURL_DISABLE_FTP + case CURLOPT_FTPPORT: /* - * Blob that holds Issuer certificate to check certificates issuer + * Use FTP PORT, this also specifies which IP address to use */ - result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY], - va_arg(param, struct curl_blob *)); + result = Curl_setstropt(&data->set.str[STRING_FTPPORT], ptr); + data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]); break; -#endif -#ifndef CURL_DISABLE_TELNET - case CURLOPT_TELNETOPTIONS: + + case CURLOPT_FTP_ACCOUNT: + return Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], ptr); + + case CURLOPT_FTP_ALTERNATIVE_TO_USER: + return Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], ptr); + +#ifdef HAVE_GSSAPI + case CURLOPT_KRBLEVEL: /* - * Set a linked list of telnet options + * A string that defines the kerberos security level. */ - data->set.telnet_options = va_arg(param, struct curl_slist *); + result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], ptr); + data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]); break; #endif - case CURLOPT_BUFFERSIZE: +#endif + case CURLOPT_URL: /* - * The application kindly asks for a differently sized receive buffer. - * If it seems reasonable, we will use it. + * The URL to fetch. */ - arg = va_arg(param, long); - - if(arg > READBUFFER_MAX) - arg = READBUFFER_MAX; - else if(arg < 1) - arg = READBUFFER_SIZE; - else if(arg < READBUFFER_MIN) - arg = READBUFFER_MIN; - - data->set.buffer_size = (unsigned int)arg; + if(data->state.url_alloc) { + /* the already set URL is allocated, free it first! */ + Curl_safefree(data->state.url); + data->state.url_alloc = FALSE; + } + result = Curl_setstropt(&data->set.str[STRING_SET_URL], ptr); + data->state.url = data->set.str[STRING_SET_URL]; break; - case CURLOPT_UPLOAD_BUFFERSIZE: + case CURLOPT_USERPWD: /* - * The application kindly asks for a differently sized upload buffer. - * Cap it to sensible. + * user:password to use in the operation */ - arg = va_arg(param, long); - - if(arg > UPLOADBUFFER_MAX) - arg = UPLOADBUFFER_MAX; - else if(arg < UPLOADBUFFER_MIN) - arg = UPLOADBUFFER_MIN; + return setstropt_userpwd(ptr, &data->set.str[STRING_USERNAME], + &data->set.str[STRING_PASSWORD]); - data->set.upload_buffer_size = (unsigned int)arg; - break; - - case CURLOPT_NOSIGNAL: + case CURLOPT_USERNAME: /* - * The application asks not to set any signal() or alarm() handlers, - * even when using a timeout. + * authentication username to use in the operation */ - data->set.no_signal = (0 != va_arg(param, long)); - break; - - case CURLOPT_SHARE: - { - struct Curl_share *set; - set = va_arg(param, struct Curl_share *); + return Curl_setstropt(&data->set.str[STRING_USERNAME], ptr); - /* disconnect from old share, if any */ - if(data->share) { - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); - - if(data->dns.hostcachetype == HCACHE_SHARED) { - data->dns.hostcache = NULL; - data->dns.hostcachetype = HCACHE_NONE; - } - -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(data->share->cookies == data->cookies) - data->cookies = NULL; -#endif - -#ifndef CURL_DISABLE_HSTS - if(data->share->hsts == data->hsts) - data->hsts = NULL; -#endif -#ifdef USE_SSL - if(data->share->sslsession == data->state.session) - data->state.session = NULL; -#endif -#ifdef USE_LIBPSL - if(data->psl == &data->share->psl) - data->psl = data->multi ? &data->multi->psl : NULL; -#endif + case CURLOPT_PASSWORD: + /* + * authentication password to use in the operation + */ + return Curl_setstropt(&data->set.str[STRING_PASSWORD], ptr); - data->share->dirty--; + case CURLOPT_LOGIN_OPTIONS: + /* + * authentication options to use in the operation + */ + return Curl_setstropt(&data->set.str[STRING_OPTIONS], ptr); - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - data->share = NULL; - } + case CURLOPT_XOAUTH2_BEARER: + /* + * OAuth 2.0 bearer token to use in the operation + */ + return Curl_setstropt(&data->set.str[STRING_BEARER], ptr); - if(GOOD_SHARE_HANDLE(set)) - /* use new share if it set */ - data->share = set; - if(data->share) { +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXYUSERPWD: { + /* + * user:password needed to use the proxy + */ + char *u = NULL; + char *p = NULL; + result = setstropt_userpwd(ptr, &u, &p); - Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE); + /* URL decode the components */ + if(!result && u) + result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL, + REJECT_ZERO); + if(!result && p) + result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL, + REJECT_ZERO); + free(u); + free(p); + } + break; + case CURLOPT_PROXYUSERNAME: + /* + * authentication username to use in the operation + */ + return Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME], ptr); - data->share->dirty++; + case CURLOPT_PROXYPASSWORD: + /* + * authentication password to use in the operation + */ + return Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD], ptr); - if(data->share->specifier & (1 << CURL_LOCK_DATA_DNS)) { - /* use shared host cache */ - data->dns.hostcache = &data->share->hostcache; - data->dns.hostcachetype = HCACHE_SHARED; - } -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - if(data->share->cookies) { - /* use shared cookie list, first free own one if any */ - Curl_cookie_cleanup(data->cookies); - /* enable cookies since we now use a share that uses cookies! */ - data->cookies = data->share->cookies; - } -#endif /* CURL_DISABLE_HTTP */ -#ifndef CURL_DISABLE_HSTS - if(data->share->hsts) { - /* first free the private one if any */ - Curl_hsts_cleanup(&data->hsts); - data->hsts = data->share->hsts; - } -#endif -#ifdef USE_SSL - if(data->share->sslsession) { - data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; - data->state.session = data->share->sslsession; - } -#endif -#ifdef USE_LIBPSL - if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL)) - data->psl = &data->share->psl; + case CURLOPT_NOPROXY: + /* + * proxy exception list + */ + return Curl_setstropt(&data->set.str[STRING_NOPROXY], ptr); #endif - Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); - } - /* check for host cache not needed, - * it will be done by curl_easy_perform */ - } - break; - - case CURLOPT_PRIVATE: + case CURLOPT_RANGE: /* - * Set private data pointer. + * What range of the file you want to transfer */ - data->set.private_data = va_arg(param, void *); - break; + return Curl_setstropt(&data->set.str[STRING_SET_RANGE], ptr); - case CURLOPT_MAXFILESIZE: +#endif /* ! CURL_DISABLE_PROXY */ + case CURLOPT_CURLU: /* - * Set the maximum size of a file to download. + * pass CURLU to set URL */ - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_filesize = arg; + data->set.uh = (CURLU *)ptr; break; + case CURLOPT_SSLCERT: + /* + * String that holds filename of the SSL certificate to use + */ + return Curl_setstropt(&data->set.str[STRING_CERT], ptr); -#ifdef USE_SSL - case CURLOPT_USE_SSL: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLCERT: /* - * Make transfers attempt to use SSL/TLS. + * String that holds filename of the SSL certificate to use for proxy */ - arg = va_arg(param, long); - if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_ssl = (unsigned char)arg; - break; + return Curl_setstropt(&data->set.str[STRING_CERT_PROXY], ptr); - case CURLOPT_SSL_OPTIONS: - arg = va_arg(param, long); - data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff); - data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); - data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); - data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); - data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); - data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); - data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT); - data->set.ssl.earlydata = !!(arg & CURLSSLOPT_EARLYDATA); - /* If a setting is added here it should also be added in dohprobe() - which sets its own CURLOPT_SSL_OPTIONS based on these settings. */ - break; +#endif + case CURLOPT_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use + */ + return Curl_setstropt(&data->set.str[STRING_CERT_TYPE], ptr); #ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSL_OPTIONS: - arg = va_arg(param, long); - data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff); - data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); - data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); - data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN); - data->set.proxy_ssl.revoke_best_effort = - !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT); - data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA); - data->set.proxy_ssl.auto_client_cert = - !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT); - break; + case CURLOPT_PROXY_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use for proxy + */ + return Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], ptr); #endif + case CURLOPT_SSLKEY: + /* + * String that holds filename of the SSL key to use + */ + return Curl_setstropt(&data->set.str[STRING_KEY], ptr); - case CURLOPT_SSL_EC_CURVES: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLKEY: /* - * Set accepted curves in SSL connection setup. - * Specify colon-delimited list of curve algorithm names. + * String that holds filename of the SSL key to use for proxy */ - result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_KEY_PROXY], ptr); + #endif - case CURLOPT_IPRESOLVE: - arg = va_arg(param, long); - if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ipver = (unsigned char) arg; + case CURLOPT_SSLKEYTYPE: + /* + * String that holds file type of the SSL key to use + */ + return Curl_setstropt(&data->set.str[STRING_KEY_TYPE], ptr); break; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLKEYTYPE: + /* + * String that holds file type of the SSL key to use for proxy + */ + return Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], ptr); - case CURLOPT_MAXFILESIZE_LARGE: +#endif + case CURLOPT_KEYPASSWD: /* - * Set the maximum size of a file to download. + * String that holds the SSL or SSH private key password. */ - bigsize = va_arg(param, curl_off_t); - if(bigsize < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_filesize = bigsize; - break; + return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD], ptr); - case CURLOPT_TCP_NODELAY: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_KEYPASSWD: /* - * Enable or disable TCP_NODELAY, which will disable/enable the Nagle - * algorithm + * String that holds the SSL private key password for proxy. + */ + return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], ptr); +#endif + case CURLOPT_SSLENGINE: + /* + * String that holds the SSL crypto engine. */ - data->set.tcp_nodelay = (0 != va_arg(param, long)); + if(ptr && ptr[0]) { + result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], ptr); + if(!result) { + result = Curl_ssl_set_engine(data, ptr); + } + } break; - case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (0 != va_arg(param, long)); +#ifndef CURL_DISABLE_PROXY + case CURLOPT_HAPROXY_CLIENT_IP: + /* + * Set the client IP to send through HAProxy PROXY protocol + */ + result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP], ptr); + /* enable the HAProxy protocol */ + data->set.haproxyprotocol = TRUE; break; +#endif + case CURLOPT_INTERFACE: + /* + * Set what interface or address/hostname to bind the socket to when + * performing an operation and thus what from-IP your connection will use. + */ + return setstropt_interface(ptr, + &data->set.str[STRING_DEVICE], + &data->set.str[STRING_INTERFACE], + &data->set.str[STRING_BINDHOST]); - case CURLOPT_CONNECT_ONLY: + case CURLOPT_PINNEDPUBLICKEY: /* - * No data transfer. - * (1) - only do connection - * (2) - do first get request but get no content + * Set pinned public key for SSL connection. + * Specify filename of the public key in DER format. */ - arg = va_arg(param, long); - if(arg > 2) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.connect_only = (unsigned char)arg; - break; +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) + return Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], ptr); +#endif + return CURLE_NOT_BUILT_IN; - case CURLOPT_SOCKOPTFUNCTION: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_PINNEDPUBLICKEY: /* - * socket callback function: called after socket() but before connect() + * Set pinned public key for SSL connection. + * Specify filename of the public key in DER format. */ - data->set.fsockopt = va_arg(param, curl_sockopt_callback); - break; +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) + return Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], + ptr); +#endif + return CURLE_NOT_BUILT_IN; +#endif + case CURLOPT_CAINFO: + /* + * Set CA info for SSL connection. Specify filename of the CA certificate + */ + return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], ptr); - case CURLOPT_SOCKOPTDATA: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_CAINFO: /* - * socket callback data pointer. Might be NULL. + * Set CA info SSL connection for proxy. Specify filename of the + * CA certificate */ - data->set.sockopt_client = va_arg(param, void *); - break; + return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], ptr); +#endif - case CURLOPT_OPENSOCKETFUNCTION: + case CURLOPT_CAPATH: /* - * open/create socket callback function: called instead of socket(), - * before connect() + * Set CA path info for SSL connection. Specify directory name of the CA + * certificates which have been prepared using openssl c_rehash utility. */ - data->set.fopensocket = va_arg(param, curl_opensocket_callback); - break; +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) + /* This does not work on Windows. */ + return Curl_setstropt(&data->set.str[STRING_SSL_CAPATH], ptr); +#endif + return CURLE_NOT_BUILT_IN; +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_CAPATH: + /* + * Set CA path info for SSL connection proxy. Specify directory name of the + * CA certificates which have been prepared using openssl c_rehash utility. + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) + /* This does not work on Windows. */ + return Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], ptr); +#endif + return CURLE_NOT_BUILT_IN; +#endif + case CURLOPT_CRLFILE: + /* + * Set CRL file info for SSL connection. Specify filename of the CRL + * to check certificates revocation + */ + return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE], ptr); - case CURLOPT_OPENSOCKETDATA: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_CRLFILE: /* - * socket callback data pointer. Might be NULL. + * Set CRL file info for SSL connection for proxy. Specify filename of the + * CRL to check certificates revocation */ - data->set.opensocket_client = va_arg(param, void *); - break; - - case CURLOPT_CLOSESOCKETFUNCTION: + return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], ptr); +#endif + case CURLOPT_ISSUERCERT: /* - * close socket callback function: called instead of close() - * when shutting down a connection + * Set Issuer certificate file + * to check certificates issuer */ - data->set.fclosesocket = va_arg(param, curl_closesocket_callback); - break; + return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT], ptr); - case CURLOPT_RESOLVER_START_FUNCTION: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_ISSUERCERT: /* - * resolver start callback function: called before a new resolver request - * is started + * Set Issuer certificate file + * to check certificates issuer */ - data->set.resolver_start = va_arg(param, curl_resolver_start_callback); - break; + return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], ptr); - case CURLOPT_RESOLVER_START_DATA: +#endif + + case CURLOPT_PRIVATE: /* - * resolver start callback data pointer. Might be NULL. + * Set private data pointer. */ - data->set.resolver_start_client = va_arg(param, void *); + data->set.private_data = (void *)ptr; break; - case CURLOPT_CLOSESOCKETDATA: +#ifdef USE_SSL + case CURLOPT_SSL_EC_CURVES: /* - * socket callback data pointer. Might be NULL. + * Set accepted curves in SSL connection setup. + * Specify colon-delimited list of curve algorithm names. */ - data->set.closesocket_client = va_arg(param, void *); - break; - - case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.primary.cache_session = (0 != va_arg(param, long)); -#ifndef CURL_DISABLE_PROXY - data->set.proxy_ssl.primary.cache_session = - data->set.ssl.primary.cache_session; + return Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], ptr); #endif - break; - #ifdef USE_SSH - /* we only include SSH options if explicitly built to support SSH */ - case CURLOPT_SSH_AUTH_TYPES: - data->set.ssh_auth_types = (int)va_arg(param, long); - break; - case CURLOPT_SSH_PUBLIC_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa.pub file */ - result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], ptr); case CURLOPT_SSH_PRIVATE_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa file */ - result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], ptr); + case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: /* * Option to allow for the MD5 of the host public key to be checked * for validation purposes. */ - result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], ptr); case CURLOPT_SSH_KNOWNHOSTS: /* * Store the filename to read known hosts from. */ - result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], - va_arg(param, char *)); + return Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], ptr); + + case CURLOPT_SSH_KEYDATA: + /* + * Custom client data to pass to the SSH keyfunc callback + */ + data->set.ssh_keyfunc_userp = (void *)ptr; break; #ifdef USE_LIBSSH2 case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256: @@ -2549,659 +2448,611 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Option to allow for the SHA256 of the host public key to be checked * for validation purposes. */ - result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], - va_arg(param, char *)); - break; - - case CURLOPT_SSH_HOSTKEYFUNCTION: - /* the callback to check the hostkey without the knownhost file */ - data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback); - break; + return Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], + ptr); case CURLOPT_SSH_HOSTKEYDATA: /* * Custom client data to pass to the SSH keyfunc callback */ - data->set.ssh_hostkeyfunc_userp = va_arg(param, void *); - break; -#endif - - case CURLOPT_SSH_KEYFUNCTION: - /* setting to NULL is fine since the ssh.c functions themselves will - then revert to use the internal default */ - data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); - break; - - case CURLOPT_SSH_KEYDATA: - /* - * Custom client data to pass to the SSH keyfunc callback - */ - data->set.ssh_keyfunc_userp = va_arg(param, void *); - break; - - case CURLOPT_SSH_COMPRESSION: - data->set.ssh_compression = (0 != va_arg(param, long)); + data->set.ssh_hostkeyfunc_userp = (void *)ptr; break; +#endif /* USE_LIBSSH2 */ #endif /* USE_SSH */ - - case CURLOPT_HTTP_TRANSFER_DECODING: - /* - * disable libcurl transfer encoding is used - */ -#ifndef USE_HYPER - data->set.http_te_skip = (0 == va_arg(param, long)); - break; -#else - return CURLE_NOT_BUILT_IN; /* hyper does not support */ -#endif - - case CURLOPT_HTTP_CONTENT_DECODING: - /* - * raw data passed to the application when content encoding is used - */ - data->set.http_ce_skip = (0 == va_arg(param, long)); - break; - -#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) - case CURLOPT_NEW_FILE_PERMS: - /* - * Uses these permissions instead of 0644 - */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 0777)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.new_file_perms = (unsigned int)arg; - break; -#endif -#ifdef USE_SSH - case CURLOPT_NEW_DIRECTORY_PERMS: - /* - * Uses these permissions instead of 0755 - */ - arg = va_arg(param, long); - if((arg < 0) || (arg > 0777)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.new_directory_perms = (unsigned int)arg; - break; -#endif - -#ifdef USE_IPV6 - case CURLOPT_ADDRESS_SCOPE: - /* - * Use this scope id when using IPv6 - * We always get longs when passed plain numericals so we should check - * that the value fits into an unsigned 32-bit integer. - */ - uarg = va_arg(param, unsigned long); -#if SIZEOF_LONG > 4 - if(uarg > UINT_MAX) - return CURLE_BAD_FUNCTION_ARGUMENT; -#endif - data->set.scope_id = (unsigned int)uarg; + case CURLOPT_PROTOCOLS_STR: + if(ptr) + return protocol2num(ptr, &data->set.allowed_protocols); + /* make a NULL argument reset to default */ + data->set.allowed_protocols = (curl_prot_t) CURLPROTO_ALL; break; -#endif - - case CURLOPT_PROTOCOLS: - /* set the bitmask for the protocols that are allowed to be used for the - transfer, which thus helps the app which takes URLs from users or other - external inputs and want to restrict what protocol(s) to deal - with. Defaults to CURLPROTO_ALL. */ - data->set.allowed_protocols = (curl_prot_t)va_arg(param, long); - break; - - case CURLOPT_REDIR_PROTOCOLS: - /* set the bitmask for the protocols that libcurl is allowed to follow to, - as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs - to be set in both bitmasks to be allowed to get redirected to. */ - data->set.redir_protocols = (curl_prot_t)va_arg(param, long); - break; - - case CURLOPT_PROTOCOLS_STR: { - argptr = va_arg(param, char *); - if(argptr) { - result = protocol2num(argptr, &data->set.allowed_protocols); - if(result) - return result; - } - else - /* make a NULL argument reset to default */ - data->set.allowed_protocols = (curl_prot_t) CURLPROTO_ALL; - break; - } - case CURLOPT_REDIR_PROTOCOLS_STR: { - argptr = va_arg(param, char *); - if(argptr) { - result = protocol2num(argptr, &data->set.redir_protocols); - if(result) - return result; - } - else - /* make a NULL argument reset to default */ - data->set.redir_protocols = (curl_prot_t) CURLPROTO_REDIR; + case CURLOPT_REDIR_PROTOCOLS_STR: + if(ptr) + return protocol2num(ptr, &data->set.redir_protocols); + /* make a NULL argument reset to default */ + data->set.redir_protocols = (curl_prot_t) CURLPROTO_REDIR; break; - } case CURLOPT_DEFAULT_PROTOCOL: /* Set the protocol to use when the URL does not include any protocol */ - result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], ptr); + #ifndef CURL_DISABLE_SMTP case CURLOPT_MAIL_FROM: /* Set the SMTP mail originator */ - result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_MAIL_FROM], ptr); case CURLOPT_MAIL_AUTH: /* Set the SMTP auth originator */ - result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], - va_arg(param, char *)); - break; - - case CURLOPT_MAIL_RCPT: - /* Set the list of mail recipients */ - data->set.mail_rcpt = va_arg(param, struct curl_slist *); - break; - case CURLOPT_MAIL_RCPT_ALLOWFAILS: - /* allow RCPT TO command to fail for some recipients */ - data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)); - break; + return Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], ptr); #endif case CURLOPT_SASL_AUTHZID: /* Authorization identity (identity to act as) */ - result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], ptr); - case CURLOPT_SASL_IR: - /* Enable/disable SASL initial response */ - data->set.sasl_ir = (0 != va_arg(param, long)); - break; #ifndef CURL_DISABLE_RTSP - case CURLOPT_RTSP_REQUEST: - { - /* - * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...) - * Would this be better if the RTSPREQ_* were just moved into here? - */ - long in_rtspreq = va_arg(param, long); - Curl_RtspReq rtspreq = RTSPREQ_NONE; - switch(in_rtspreq) { - case CURL_RTSPREQ_OPTIONS: - rtspreq = RTSPREQ_OPTIONS; - break; - - case CURL_RTSPREQ_DESCRIBE: - rtspreq = RTSPREQ_DESCRIBE; - break; - - case CURL_RTSPREQ_ANNOUNCE: - rtspreq = RTSPREQ_ANNOUNCE; - break; - - case CURL_RTSPREQ_SETUP: - rtspreq = RTSPREQ_SETUP; - break; - - case CURL_RTSPREQ_PLAY: - rtspreq = RTSPREQ_PLAY; - break; - - case CURL_RTSPREQ_PAUSE: - rtspreq = RTSPREQ_PAUSE; - break; - - case CURL_RTSPREQ_TEARDOWN: - rtspreq = RTSPREQ_TEARDOWN; - break; - - case CURL_RTSPREQ_GET_PARAMETER: - rtspreq = RTSPREQ_GET_PARAMETER; - break; - - case CURL_RTSPREQ_SET_PARAMETER: - rtspreq = RTSPREQ_SET_PARAMETER; - break; - - case CURL_RTSPREQ_RECORD: - rtspreq = RTSPREQ_RECORD; - break; - - case CURL_RTSPREQ_RECEIVE: - rtspreq = RTSPREQ_RECEIVE; - break; - default: - rtspreq = RTSPREQ_NONE; - } - - data->set.rtspreq = rtspreq; - break; - } - - case CURLOPT_RTSP_SESSION_ID: /* * Set the RTSP Session ID manually. Useful if the application is * resuming a previously established RTSP session */ - result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID], ptr); case CURLOPT_RTSP_STREAM_URI: /* * Set the Stream URI for the RTSP request. Unless the request is * for generic server options, the application will need to set this. */ - result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], - va_arg(param, char *)); + return Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], ptr); break; case CURLOPT_RTSP_TRANSPORT: /* * The content of the Transport: header for the RTSP request */ - result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], - va_arg(param, char *)); - break; - - case CURLOPT_RTSP_CLIENT_CSEQ: - /* - * Set the CSEQ number to issue for the next RTSP request. Useful if the - * application is resuming a previously broken connection. The CSEQ - * will increment from this new number henceforth. - */ - data->state.rtsp_next_client_CSeq = va_arg(param, long); - break; - - case CURLOPT_RTSP_SERVER_CSEQ: - /* Same as the above, but for server-initiated requests */ - data->state.rtsp_next_server_CSeq = va_arg(param, long); - break; + return Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], ptr); case CURLOPT_INTERLEAVEDATA: - data->set.rtp_out = va_arg(param, void *); - break; - case CURLOPT_INTERLEAVEFUNCTION: - /* Set the user defined RTP write function */ - data->set.fwrite_rtp = va_arg(param, curl_write_callback); + data->set.rtp_out = (void *)ptr; break; -#endif +#endif /* ! CURL_DISABLE_RTSP */ #ifndef CURL_DISABLE_FTP - case CURLOPT_WILDCARDMATCH: - data->set.wildcard_enabled = (0 != va_arg(param, long)); - break; - case CURLOPT_CHUNK_BGN_FUNCTION: - data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); - break; - case CURLOPT_CHUNK_END_FUNCTION: - data->set.chunk_end = va_arg(param, curl_chunk_end_callback); - break; - case CURLOPT_FNMATCH_FUNCTION: - data->set.fnmatch = va_arg(param, curl_fnmatch_callback); - break; case CURLOPT_CHUNK_DATA: - data->set.wildcardptr = va_arg(param, void *); + data->set.wildcardptr = (void *)ptr; break; case CURLOPT_FNMATCH_DATA: - data->set.fnmatch_data = va_arg(param, void *); + data->set.fnmatch_data = (void *)ptr; break; #endif #ifdef USE_TLS_SRP case CURLOPT_TLSAUTH_USERNAME: - result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], ptr); + #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_USERNAME: - result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], ptr); + #endif case CURLOPT_TLSAUTH_PASSWORD: - result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], ptr); + #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_PASSWORD: - result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], - va_arg(param, char *)); - break; + return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], ptr); #endif case CURLOPT_TLSAUTH_TYPE: - argptr = va_arg(param, char *); - if(argptr && !strcasecompare(argptr, "SRP")) + if(ptr && !strcasecompare(ptr, "SRP")) return CURLE_BAD_FUNCTION_ARGUMENT; break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_TYPE: - argptr = va_arg(param, char *); - if(argptr && !strcasecompare(argptr, "SRP")) + if(ptr && !strcasecompare(ptr, "SRP")) return CURLE_BAD_FUNCTION_ARGUMENT; break; #endif #endif #ifdef USE_ARES case CURLOPT_DNS_SERVERS: - result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], - va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], ptr); if(result) return result; - result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]); - break; + return Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]); + case CURLOPT_DNS_INTERFACE: - result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], - va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], ptr); if(result) return result; - result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]); - break; + return Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]); + case CURLOPT_DNS_LOCAL_IP4: - result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], - va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], ptr); if(result) return result; - result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]); - break; + return Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]); + case CURLOPT_DNS_LOCAL_IP6: - result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], - va_arg(param, char *)); + result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], ptr); if(result) return result; - result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]); + return Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]); + +#endif +#ifdef USE_UNIX_SOCKETS + case CURLOPT_UNIX_SOCKET_PATH: + data->set.abstract_unix_socket = FALSE; + return Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ptr); + + case CURLOPT_ABSTRACT_UNIX_SOCKET: + data->set.abstract_unix_socket = TRUE; + return Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ptr); + +#endif + +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_URL: + result = Curl_setstropt(&data->set.str[STRING_DOH], ptr); + data->set.doh = !!(data->set.str[STRING_DOH]); break; #endif - case CURLOPT_TCP_KEEPALIVE: - data->set.tcp_keepalive = (0 != va_arg(param, long)); +#ifndef CURL_DISABLE_HSTS + case CURLOPT_HSTSREADDATA: + data->set.hsts_read_userp = (void *)ptr; break; - case CURLOPT_TCP_KEEPIDLE: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - data->set.tcp_keepidle = (int)arg; + case CURLOPT_HSTSWRITEDATA: + data->set.hsts_write_userp = (void *)ptr; break; - case CURLOPT_TCP_KEEPINTVL: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - data->set.tcp_keepintvl = (int)arg; + case CURLOPT_HSTS: { + struct curl_slist *h; + if(!data->hsts) { + data->hsts = Curl_hsts_init(); + if(!data->hsts) + return CURLE_OUT_OF_MEMORY; + } + if(ptr) { + result = Curl_setstropt(&data->set.str[STRING_HSTS], ptr); + if(result) + return result; + /* this needs to build a list of filenames to read from, so that it can + read them later, as we might get a shared HSTS handle to load them + into */ + h = curl_slist_append(data->state.hstslist, ptr); + if(!h) { + curl_slist_free_all(data->state.hstslist); + data->state.hstslist = NULL; + return CURLE_OUT_OF_MEMORY; + } + data->state.hstslist = h; /* store the list for later use */ + } + else { + /* clear the list of HSTS files */ + curl_slist_free_all(data->state.hstslist); + data->state.hstslist = NULL; + if(!data->share || !data->share->hsts) + /* throw away the HSTS cache unless shared */ + Curl_hsts_cleanup(&data->hsts); + } break; - case CURLOPT_TCP_KEEPCNT: - arg = va_arg(param, long); - if(arg < 0) + } +#endif /* ! CURL_DISABLE_HSTS */ +#ifndef CURL_DISABLE_ALTSVC + case CURLOPT_ALTSVC: + if(!data->asi) { + data->asi = Curl_altsvc_init(); + if(!data->asi) + return CURLE_OUT_OF_MEMORY; + } + result = Curl_setstropt(&data->set.str[STRING_ALTSVC], ptr); + if(result) + return result; + if(ptr) + (void)Curl_altsvc_load(data->asi, ptr); + break; +#endif /* ! CURL_DISABLE_ALTSVC */ +#ifdef USE_ECH + case CURLOPT_ECH: { + size_t plen = 0; + + if(!ptr) { + data->set.tls_ech = CURLECH_DISABLE; + return CURLE_OK; + } + plen = strlen(ptr); + if(plen > CURL_MAX_INPUT_LENGTH) { + data->set.tls_ech = CURLECH_DISABLE; return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - data->set.tcp_keepcnt = (int)arg; + } + /* set tls_ech flag value, preserving CLA_CFG bit */ + if(!strcmp(ptr, "false")) + data->set.tls_ech = CURLECH_DISABLE | + (data->set.tls_ech & CURLECH_CLA_CFG); + else if(!strcmp(ptr, "grease")) + data->set.tls_ech = CURLECH_GREASE | + (data->set.tls_ech & CURLECH_CLA_CFG); + else if(!strcmp(ptr, "true")) + data->set.tls_ech = CURLECH_ENABLE | + (data->set.tls_ech & CURLECH_CLA_CFG); + else if(!strcmp(ptr, "hard")) + data->set.tls_ech = CURLECH_HARD | + (data->set.tls_ech & CURLECH_CLA_CFG); + else if(plen > 5 && !strncmp(ptr, "ecl:", 4)) { + result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], ptr + 4); + if(result) + return result; + data->set.tls_ech |= CURLECH_CLA_CFG; + } + else if(plen > 4 && !strncmp(ptr, "pn:", 3)) { + result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], ptr + 3); + if(result) + return result; + } break; - case CURLOPT_TCP_FASTOPEN: -#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ - defined(TCP_FASTOPEN_CONNECT) - data->set.tcp_fastopen = (0 != va_arg(param, long)); -#else - result = CURLE_NOT_BUILT_IN; + } #endif + default: + return CURLE_UNKNOWN_OPTION; + } + return result; +} + +static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, + va_list param) +{ + switch(option) { + case CURLOPT_PROGRESSFUNCTION: + /* + * Progress callback function + */ + data->set.fprogress = va_arg(param, curl_progress_callback); + if(data->set.fprogress) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ break; - case CURLOPT_SSL_ENABLE_NPN: + + case CURLOPT_XFERINFOFUNCTION: + /* + * Transfer info callback function + */ + data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); + if(data->set.fxferinfo) + data->progress.callback = TRUE; /* no longer internal */ + else + data->progress.callback = FALSE; /* NULL enforces internal */ + break; - case CURLOPT_SSL_ENABLE_ALPN: - data->set.ssl_enable_alpn = (0 != va_arg(param, long)); + case CURLOPT_DEBUGFUNCTION: + /* + * stderr write callback. + */ + data->set.fdebug = va_arg(param, curl_debug_callback); + /* + * if the callback provided is NULL, it will use the default callback + */ break; -#ifdef USE_UNIX_SOCKETS - case CURLOPT_UNIX_SOCKET_PATH: - data->set.abstract_unix_socket = FALSE; - result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], - va_arg(param, char *)); + case CURLOPT_HEADERFUNCTION: + /* + * Set header write callback + */ + data->set.fwrite_header = va_arg(param, curl_write_callback); break; - case CURLOPT_ABSTRACT_UNIX_SOCKET: - data->set.abstract_unix_socket = TRUE; - result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], - va_arg(param, char *)); + case CURLOPT_WRITEFUNCTION: + /* + * Set data write callback + */ + data->set.fwrite_func = va_arg(param, curl_write_callback); + if(!data->set.fwrite_func) + /* When set to NULL, reset to our internal default function */ + data->set.fwrite_func = (curl_write_callback)fwrite; break; -#endif - - case CURLOPT_PATH_AS_IS: - data->set.path_as_is = (0 != va_arg(param, long)); + case CURLOPT_READFUNCTION: + /* + * Read data callback + */ + data->set.fread_func_set = va_arg(param, curl_read_callback); + if(!data->set.fread_func_set) { + data->set.is_fread_set = 0; + /* When set to NULL, reset to our internal default function */ + data->set.fread_func_set = (curl_read_callback)fread; + } + else + data->set.is_fread_set = 1; break; - case CURLOPT_PIPEWAIT: - data->set.pipewait = (0 != va_arg(param, long)); + case CURLOPT_SEEKFUNCTION: + /* + * Seek callback. Might be NULL. + */ + data->set.seek_func = va_arg(param, curl_seek_callback); break; - case CURLOPT_STREAM_WEIGHT: -#if defined(USE_HTTP2) || defined(USE_HTTP3) - arg = va_arg(param, long); - if((arg >= 1) && (arg <= 256)) - data->set.priority.weight = (int)arg; + case CURLOPT_IOCTLFUNCTION: + /* + * I/O control callback. Might be NULL. + */ + data->set.ioctl_func = va_arg(param, curl_ioctl_callback); break; -#else - return CURLE_NOT_BUILT_IN; + case CURLOPT_SSL_CTX_FUNCTION: + /* + * Set a SSL_CTX callback + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) + data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); + else #endif - case CURLOPT_STREAM_DEPENDS: - case CURLOPT_STREAM_DEPENDS_E: - { - struct Curl_easy *dep = va_arg(param, struct Curl_easy *); - if(!dep || GOOD_EASY_HANDLE(dep)) { - return Curl_data_priority_add_child(dep, data, - option == CURLOPT_STREAM_DEPENDS_E); - } + return CURLE_NOT_BUILT_IN; break; - } - case CURLOPT_CONNECT_TO: - data->set.connect_to = va_arg(param, struct curl_slist *); + + case CURLOPT_SOCKOPTFUNCTION: + /* + * socket callback function: called after socket() but before connect() + */ + data->set.fsockopt = va_arg(param, curl_sockopt_callback); break; - case CURLOPT_SUPPRESS_CONNECT_HEADERS: - data->set.suppress_connect_headers = (0 != va_arg(param, long)); + + case CURLOPT_OPENSOCKETFUNCTION: + /* + * open/create socket callback function: called instead of socket(), + * before connect() + */ + data->set.fopensocket = va_arg(param, curl_opensocket_callback); break; - case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: - uarg = va_arg(param, unsigned long); - if(uarg > UINT_MAX) - uarg = UINT_MAX; - data->set.happy_eyeballs_timeout = (unsigned int)uarg; + + case CURLOPT_CLOSESOCKETFUNCTION: + /* + * close socket callback function: called instead of close() + * when shutting down a connection + */ + data->set.fclosesocket = va_arg(param, curl_closesocket_callback); break; -#ifndef CURL_DISABLE_SHUFFLE_DNS - case CURLOPT_DNS_SHUFFLE_ADDRESSES: - data->set.dns_shuffle_addresses = (0 != va_arg(param, long)); + + case CURLOPT_RESOLVER_START_FUNCTION: + /* + * resolver start callback function: called before a new resolver request + * is started + */ + data->set.resolver_start = va_arg(param, curl_resolver_start_callback); + break; + + +#ifdef USE_SSH +#ifdef USE_LIBSSH2 + case CURLOPT_SSH_HOSTKEYFUNCTION: + /* the callback to check the hostkey without the knownhost file */ + data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback); break; #endif - case CURLOPT_DISALLOW_USERNAME_IN_URL: - data->set.disallow_username_in_url = (0 != va_arg(param, long)); + + case CURLOPT_SSH_KEYFUNCTION: + /* setting to NULL is fine since the ssh.c functions themselves will + then revert to use the internal default */ + data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); break; -#ifndef CURL_DISABLE_DOH - case CURLOPT_DOH_URL: - result = Curl_setstropt(&data->set.str[STRING_DOH], - va_arg(param, char *)); - data->set.doh = !!(data->set.str[STRING_DOH]); + +#endif /* USE_SSH */ + +#ifndef CURL_DISABLE_RTSP + case CURLOPT_INTERLEAVEFUNCTION: + /* Set the user defined RTP write function */ + data->set.fwrite_rtp = va_arg(param, curl_write_callback); break; #endif - case CURLOPT_UPKEEP_INTERVAL_MS: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.upkeep_interval_ms = arg; +#ifndef CURL_DISABLE_FTP + case CURLOPT_CHUNK_BGN_FUNCTION: + data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); break; - case CURLOPT_MAXAGE_CONN: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.maxage_conn = arg; + case CURLOPT_CHUNK_END_FUNCTION: + data->set.chunk_end = va_arg(param, curl_chunk_end_callback); break; - case CURLOPT_MAXLIFETIME_CONN: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.maxlifetime_conn = arg; + case CURLOPT_FNMATCH_FUNCTION: + data->set.fnmatch = va_arg(param, curl_fnmatch_callback); break; - case CURLOPT_TRAILERFUNCTION: +#endif #ifndef CURL_DISABLE_HTTP + case CURLOPT_TRAILERFUNCTION: data->set.trailer_callback = va_arg(param, curl_trailer_callback); -#endif break; - case CURLOPT_TRAILERDATA: -#ifndef CURL_DISABLE_HTTP - data->set.trailer_data = va_arg(param, void *); #endif - break; #ifndef CURL_DISABLE_HSTS case CURLOPT_HSTSREADFUNCTION: data->set.hsts_read = va_arg(param, curl_hstsread_callback); break; - case CURLOPT_HSTSREADDATA: - data->set.hsts_read_userp = va_arg(param, void *); - break; case CURLOPT_HSTSWRITEFUNCTION: data->set.hsts_write = va_arg(param, curl_hstswrite_callback); break; - case CURLOPT_HSTSWRITEDATA: - data->set.hsts_write_userp = va_arg(param, void *); - break; - case CURLOPT_HSTS: { - struct curl_slist *h; - if(!data->hsts) { - data->hsts = Curl_hsts_init(); - if(!data->hsts) - return CURLE_OUT_OF_MEMORY; - } - argptr = va_arg(param, char *); - if(argptr) { - result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr); - if(result) - return result; - /* this needs to build a list of filenames to read from, so that it can - read them later, as we might get a shared HSTS handle to load them - into */ - h = curl_slist_append(data->state.hstslist, argptr); - if(!h) { - curl_slist_free_all(data->state.hstslist); - data->state.hstslist = NULL; - return CURLE_OUT_OF_MEMORY; - } - data->state.hstslist = h; /* store the list for later use */ - } - else { - /* clear the list of HSTS files */ - curl_slist_free_all(data->state.hstslist); - data->state.hstslist = NULL; - if(!data->share || !data->share->hsts) - /* throw away the HSTS cache unless shared */ - Curl_hsts_cleanup(&data->hsts); - } +#endif + case CURLOPT_PREREQFUNCTION: + data->set.fprereq = va_arg(param, curl_prereq_callback); break; + default: + return CURLE_UNKNOWN_OPTION; } - case CURLOPT_HSTS_CTRL: - arg = va_arg(param, long); - if(arg & CURLHSTS_ENABLE) { - if(!data->hsts) { - data->hsts = Curl_hsts_init(); - if(!data->hsts) - return CURLE_OUT_OF_MEMORY; - } - } - else - Curl_hsts_cleanup(&data->hsts); + return CURLE_OK; +} + +static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, + curl_off_t offt) +{ + switch(option) { + case CURLOPT_TIMEVALUE_LARGE: + /* + * This is the value to compare with the remote document with the + * method set with CURLOPT_TIMECONDITION + */ + data->set.timevalue = (time_t)offt; break; -#endif -#ifndef CURL_DISABLE_ALTSVC - case CURLOPT_ALTSVC: - if(!data->asi) { - data->asi = Curl_altsvc_init(); - if(!data->asi) - return CURLE_OUT_OF_MEMORY; + + /* MQTT "borrows" some of the HTTP options */ + case CURLOPT_POSTFIELDSIZE_LARGE: + /* + * The size of the POSTFIELD data to prevent libcurl to do strlen() to + * figure it out. Enables binary posts. + */ + if(offt < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(data->set.postfieldsize < offt && + data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { + /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ + Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); + data->set.postfields = NULL; } - argptr = va_arg(param, char *); - result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr); - if(result) - return result; - if(argptr) - (void)Curl_altsvc_load(data->asi, argptr); + data->set.postfieldsize = offt; break; - case CURLOPT_ALTSVC_CTRL: - if(!data->asi) { - data->asi = Curl_altsvc_init(); - if(!data->asi) - return CURLE_OUT_OF_MEMORY; - } - arg = va_arg(param, long); - if(!arg) { - DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input")); + case CURLOPT_INFILESIZE_LARGE: + /* + * If known, this should inform curl about the file size of the + * to-be-uploaded file. + */ + if(offt < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - } - result = Curl_altsvc_ctrl(data->asi, arg); - if(result) - return result; + data->set.filesize = offt; break; -#endif - case CURLOPT_PREREQFUNCTION: - data->set.fprereq = va_arg(param, curl_prereq_callback); + case CURLOPT_MAX_SEND_SPEED_LARGE: + /* + * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE + * bytes per second the transfer is throttled.. + */ + if(offt < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.max_send_speed = offt; break; - case CURLOPT_PREREQDATA: - data->set.prereq_userp = va_arg(param, void *); + case CURLOPT_MAX_RECV_SPEED_LARGE: + /* + * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per + * second the transfer is throttled.. + */ + if(offt < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.max_recv_speed = offt; break; -#ifndef CURL_DISABLE_WEBSOCKETS - case CURLOPT_WS_OPTIONS: { - bool raw; - arg = va_arg(param, long); - raw = (arg & CURLWS_RAW_MODE); - data->set.ws_raw_mode = raw; + case CURLOPT_RESUME_FROM_LARGE: + /* + * Resume transfer at the given file position + */ + if(offt < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.set_resume_from = offt; break; - } -#endif -#ifdef USE_ECH - case CURLOPT_ECH: { - size_t plen = 0; - - argptr = va_arg(param, char *); - if(!argptr) { - data->set.tls_ech = CURLECH_DISABLE; - return CURLE_OK; - } - plen = strlen(argptr); - if(plen > CURL_MAX_INPUT_LENGTH) { - data->set.tls_ech = CURLECH_DISABLE; + case CURLOPT_MAXFILESIZE_LARGE: + /* + * Set the maximum size of a file to download. + */ + if(offt < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - } - /* set tls_ech flag value, preserving CLA_CFG bit */ - if(!strcmp(argptr, "false")) - data->set.tls_ech = CURLECH_DISABLE | - (data->set.tls_ech & CURLECH_CLA_CFG); - else if(!strcmp(argptr, "grease")) - data->set.tls_ech = CURLECH_GREASE | - (data->set.tls_ech & CURLECH_CLA_CFG); - else if(!strcmp(argptr, "true")) - data->set.tls_ech = CURLECH_ENABLE | - (data->set.tls_ech & CURLECH_CLA_CFG); - else if(!strcmp(argptr, "hard")) - data->set.tls_ech = CURLECH_HARD | - (data->set.tls_ech & CURLECH_CLA_CFG); - else if(plen > 5 && !strncmp(argptr, "ecl:", 4)) { - result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], argptr + 4); - if(result) - return result; - data->set.tls_ech |= CURLECH_CLA_CFG; - } - else if(plen > 4 && !strncmp(argptr, "pn:", 3)) { - result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], argptr + 3); - if(result) - return result; - } + data->set.max_filesize = offt; break; + + default: + return CURLE_UNKNOWN_OPTION; } + return CURLE_OK; +} + +static CURLcode setopt_blob(struct Curl_easy *data, CURLoption option, + struct curl_blob *blob) +{ + switch(option) { + case CURLOPT_SSLCERT_BLOB: + /* + * Blob that holds file content of the SSL certificate to use + */ + return Curl_setblobopt(&data->set.blobs[BLOB_CERT], blob); +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLCERT_BLOB: + /* + * Blob that holds file content of the SSL certificate to use for proxy + */ + return Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY], blob); + case CURLOPT_PROXY_SSLKEY_BLOB: + /* + * Blob that holds file content of the SSL key to use for proxy + */ + return Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY], blob); + case CURLOPT_PROXY_CAINFO_BLOB: + /* + * Blob that holds CA info for SSL connection proxy. + * Specify entire PEM of the CA certificate + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) + return Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY], blob); #endif - case CURLOPT_QUICK_EXIT: - data->set.quick_exit = (0 != va_arg(param, long)) ? 1L : 0L; - break; + return CURLE_NOT_BUILT_IN; + case CURLOPT_PROXY_ISSUERCERT_BLOB: + /* + * Blob that holds Issuer certificate to check certificates issuer + */ + return Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY], + blob); +#endif + case CURLOPT_SSLKEY_BLOB: + /* + * Blob that holds file content of the SSL key to use + */ + return Curl_setblobopt(&data->set.blobs[BLOB_KEY], blob); + case CURLOPT_CAINFO_BLOB: + /* + * Blob that holds CA info for SSL connection. + * Specify entire PEM of the CA certificate + */ +#ifdef USE_SSL + if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) + return Curl_setblobopt(&data->set.blobs[BLOB_CAINFO], blob); +#endif + return CURLE_NOT_BUILT_IN; + case CURLOPT_ISSUERCERT_BLOB: + /* + * Blob that holds Issuer certificate to check certificates issuer + */ + return Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT], blob); + default: - /* unknown tag and its companion, just ignore: */ - result = CURLE_UNKNOWN_OPTION; - break; + return CURLE_UNKNOWN_OPTION; } + /* unreachable */ +} - return result; +/* + * Do not make Curl_vsetopt() static: it is called from + * packages/OS400/ccsidcurl.c. + */ +CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) +{ + if(option < CURLOPTTYPE_OBJECTPOINT) + return setopt_long(data, option, va_arg(param, long)); + else if(option < CURLOPTTYPE_FUNCTIONPOINT) { + /* unfortunately, different pointer types cannot be identified any other + way than being listed explicitly */ + switch(option) { + case CURLOPT_HTTPHEADER: + case CURLOPT_QUOTE: + case CURLOPT_POSTQUOTE: + case CURLOPT_TELNETOPTIONS: + case CURLOPT_PREQUOTE: + case CURLOPT_HTTP200ALIASES: + case CURLOPT_MAIL_RCPT: + case CURLOPT_RESOLVE: + case CURLOPT_PROXYHEADER: + case CURLOPT_CONNECT_TO: + return setopt_slist(data, option, va_arg(param, struct curl_slist *)); + case CURLOPT_HTTPPOST: /* curl_httppost * */ + case CURLOPT_MIMEPOST: /* curl_mime * */ + case CURLOPT_STDERR: /* FILE * */ + case CURLOPT_SHARE: /* CURLSH * */ + case CURLOPT_STREAM_DEPENDS: /* CURL * */ + case CURLOPT_STREAM_DEPENDS_E: /* CURL * */ + return setopt_pointers(data, option, param); + default: + break; + } + /* the char pointer options */ + return setopt_cptr(data, option, va_arg(param, char *)); + } + else if(option < CURLOPTTYPE_OFF_T) + return setopt_func(data, option, param); + else if(option < CURLOPTTYPE_BLOB) + return setopt_offt(data, option, va_arg(param, curl_off_t)); + return setopt_blob(data, option, va_arg(param, struct curl_blob *)); } /* -- 2.47.3