]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
setopt: split Curl_vsetopt() into several sub functions
authorDaniel Stenberg <daniel@haxx.se>
Tue, 22 Oct 2024 14:48:05 +0000 (16:48 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 23 Oct 2024 21:09:48 +0000 (23:09 +0200)
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

index 43f6905147b71ddc33d0a124b710c64d070ba61d..84e605d5ef71fa5106f76fcb870ed2344002b18b 100644 (file)
@@ -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=<a|i>) 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=<a|i>) 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 *));
 }
 
 /*