xref: /curl/lib/setopt.c (revision b77d627d)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #include <limits.h>
28 
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 
33 #ifdef HAVE_LINUX_TCP_H
34 #include <linux/tcp.h>
35 #elif defined(HAVE_NETINET_TCP_H)
36 #include <netinet/tcp.h>
37 #endif
38 
39 #include "urldata.h"
40 #include "url.h"
41 #include "progress.h"
42 #include "content_encoding.h"
43 #include "strcase.h"
44 #include "share.h"
45 #include "vtls/vtls.h"
46 #include "warnless.h"
47 #include "sendf.h"
48 #include "http2.h"
49 #include "setopt.h"
50 #include "multiif.h"
51 #include "altsvc.h"
52 #include "hsts.h"
53 #include "tftp.h"
54 #include "strdup.h"
55 #include "escape.h"
56 
57 /* The last 3 #include files should be in this order */
58 #include "curl_printf.h"
59 #include "curl_memory.h"
60 #include "memdebug.h"
61 
Curl_setstropt(char ** charp,const char * s)62 CURLcode Curl_setstropt(char **charp, const char *s)
63 {
64   /* Release the previous storage at `charp' and replace by a dynamic storage
65      copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
66 
67   Curl_safefree(*charp);
68 
69   if(s) {
70     if(strlen(s) > CURL_MAX_INPUT_LENGTH)
71       return CURLE_BAD_FUNCTION_ARGUMENT;
72 
73     *charp = strdup(s);
74     if(!*charp)
75       return CURLE_OUT_OF_MEMORY;
76   }
77 
78   return CURLE_OK;
79 }
80 
Curl_setblobopt(struct curl_blob ** blobp,const struct curl_blob * blob)81 CURLcode Curl_setblobopt(struct curl_blob **blobp,
82                          const struct curl_blob *blob)
83 {
84   /* free the previous storage at `blobp' and replace by a dynamic storage
85      copy of blob. If CURL_BLOB_COPY is set, the data is copied. */
86 
87   Curl_safefree(*blobp);
88 
89   if(blob) {
90     struct curl_blob *nblob;
91     if(blob->len > CURL_MAX_INPUT_LENGTH)
92       return CURLE_BAD_FUNCTION_ARGUMENT;
93     nblob = (struct curl_blob *)
94       malloc(sizeof(struct curl_blob) +
95              ((blob->flags & CURL_BLOB_COPY) ? blob->len : 0));
96     if(!nblob)
97       return CURLE_OUT_OF_MEMORY;
98     *nblob = *blob;
99     if(blob->flags & CURL_BLOB_COPY) {
100       /* put the data after the blob struct in memory */
101       nblob->data = (char *)nblob + sizeof(struct curl_blob);
102       memcpy(nblob->data, blob->data, blob->len);
103     }
104 
105     *blobp = nblob;
106     return CURLE_OK;
107   }
108 
109   return CURLE_OK;
110 }
111 
setstropt_userpwd(char * option,char ** userp,char ** passwdp)112 static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
113 {
114   char *user = NULL;
115   char *passwd = NULL;
116 
117   DEBUGASSERT(userp);
118   DEBUGASSERT(passwdp);
119 
120   /* Parse the login details if specified. It not then we treat NULL as a hint
121      to clear the existing data */
122   if(option) {
123     size_t len = strlen(option);
124     CURLcode result;
125     if(len > CURL_MAX_INPUT_LENGTH)
126       return CURLE_BAD_FUNCTION_ARGUMENT;
127 
128     result = Curl_parse_login_details(option, len, &user, &passwd, NULL);
129     if(result)
130       return result;
131   }
132 
133   free(*userp);
134   *userp = user;
135 
136   free(*passwdp);
137   *passwdp = passwd;
138 
139   return CURLE_OK;
140 }
141 
setstropt_interface(char * option,char ** devp,char ** ifacep,char ** hostp)142 static CURLcode setstropt_interface(
143   char *option, char **devp, char **ifacep, char **hostp)
144 {
145   char *dev = NULL;
146   char *iface = NULL;
147   char *host = NULL;
148   size_t len;
149   CURLcode result;
150 
151   DEBUGASSERT(devp);
152   DEBUGASSERT(ifacep);
153   DEBUGASSERT(hostp);
154 
155   /* Parse the interface details */
156   if(!option || !*option)
157     return CURLE_BAD_FUNCTION_ARGUMENT;
158   len = strlen(option);
159   if(len > 255)
160     return CURLE_BAD_FUNCTION_ARGUMENT;
161 
162   result = Curl_parse_interface(option, len, &dev, &iface, &host);
163   if(result)
164     return result;
165 
166   free(*devp);
167   *devp = dev;
168 
169   free(*ifacep);
170   *ifacep = iface;
171 
172   free(*hostp);
173   *hostp = host;
174 
175   return CURLE_OK;
176 }
177 
178 #define C_SSLVERSION_VALUE(x) (x & 0xffff)
179 #define C_SSLVERSION_MAX_VALUE(x) ((unsigned long)x & 0xffff0000)
180 
protocol2num(const char * str,curl_prot_t * val)181 static CURLcode protocol2num(const char *str, curl_prot_t *val)
182 {
183   /*
184    * We are asked to cherry-pick protocols, so play it safe and disallow all
185    * protocols to start with, and re-add the wanted ones back in.
186    */
187   *val = 0;
188 
189   if(!str)
190     return CURLE_BAD_FUNCTION_ARGUMENT;
191 
192   if(curl_strequal(str, "all")) {
193     *val = ~(curl_prot_t) 0;
194     return CURLE_OK;
195   }
196 
197   do {
198     const char *token = str;
199     size_t tlen;
200 
201     str = strchr(str, ',');
202     tlen = str? (size_t) (str - token): strlen(token);
203     if(tlen) {
204       const struct Curl_handler *h = Curl_getn_scheme_handler(token, tlen);
205 
206       if(!h)
207         return CURLE_UNSUPPORTED_PROTOCOL;
208 
209       *val |= h->protocol;
210     }
211   } while(str && str++);
212 
213   if(!*val)
214     /* no protocol listed */
215     return CURLE_BAD_FUNCTION_ARGUMENT;
216   return CURLE_OK;
217 }
218 
219 /*
220  * Do not make Curl_vsetopt() static: it is called from
221  * packages/OS400/ccsidcurl.c.
222  */
Curl_vsetopt(struct Curl_easy * data,CURLoption option,va_list param)223 CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
224 {
225   char *argptr;
226   CURLcode result = CURLE_OK;
227   long arg;
228   unsigned long uarg;
229   curl_off_t bigsize;
230 
231   switch(option) {
232   case CURLOPT_DNS_CACHE_TIMEOUT:
233     arg = va_arg(param, long);
234     if(arg < -1)
235       return CURLE_BAD_FUNCTION_ARGUMENT;
236     else if(arg > INT_MAX)
237       arg = INT_MAX;
238 
239     data->set.dns_cache_timeout = (int)arg;
240     break;
241   case CURLOPT_CA_CACHE_TIMEOUT:
242     if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) {
243       arg = va_arg(param, long);
244       if(arg < -1)
245         return CURLE_BAD_FUNCTION_ARGUMENT;
246       else if(arg > INT_MAX)
247         arg = INT_MAX;
248 
249       data->set.general_ssl.ca_cache_timeout = (int)arg;
250     }
251     else
252       return CURLE_NOT_BUILT_IN;
253     break;
254   case CURLOPT_DNS_USE_GLOBAL_CACHE:
255     /* deprecated */
256     break;
257   case CURLOPT_SSL_CIPHER_LIST:
258     /* set a list of cipher we want to use in the SSL connection */
259     result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
260                             va_arg(param, char *));
261     break;
262 #ifndef CURL_DISABLE_PROXY
263   case CURLOPT_PROXY_SSL_CIPHER_LIST:
264     /* set a list of cipher we want to use in the SSL connection for proxy */
265     result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
266                             va_arg(param, char *));
267     break;
268 #endif
269   case CURLOPT_TLS13_CIPHERS:
270     if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
271       /* set preferred list of TLS 1.3 cipher suites */
272       result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST],
273                               va_arg(param, char *));
274     }
275     else
276       return CURLE_NOT_BUILT_IN;
277     break;
278 #ifndef CURL_DISABLE_PROXY
279   case CURLOPT_PROXY_TLS13_CIPHERS:
280     if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
281       /* set preferred list of TLS 1.3 cipher suites for proxy */
282       result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY],
283                               va_arg(param, char *));
284     }
285     else
286       return CURLE_NOT_BUILT_IN;
287     break;
288 #endif
289   case CURLOPT_RANDOM_FILE:
290     break;
291   case CURLOPT_EGDSOCKET:
292     break;
293   case CURLOPT_MAXCONNECTS:
294     /*
295      * Set the absolute number of maximum simultaneous alive connection that
296      * libcurl is allowed to have.
297      */
298     uarg = va_arg(param, unsigned long);
299     if(uarg > UINT_MAX)
300       return CURLE_BAD_FUNCTION_ARGUMENT;
301     data->set.maxconnects = (unsigned int)uarg;
302     break;
303   case CURLOPT_FORBID_REUSE:
304     /*
305      * When this transfer is done, it must not be left to be reused by a
306      * subsequent transfer but shall be closed immediately.
307      */
308     data->set.reuse_forbid = (0 != va_arg(param, long));
309     break;
310   case CURLOPT_FRESH_CONNECT:
311     /*
312      * This transfer shall not use a previously cached connection but
313      * should be made with a fresh new connect!
314      */
315     data->set.reuse_fresh = (0 != va_arg(param, long));
316     break;
317   case CURLOPT_VERBOSE:
318     /*
319      * Verbose means infof() calls that give a lot of information about
320      * the connection and transfer procedures as well as internal choices.
321      */
322     data->set.verbose = (0 != va_arg(param, long));
323     break;
324   case CURLOPT_HEADER:
325     /*
326      * Set to include the header in the general data output stream.
327      */
328     data->set.include_header = (0 != va_arg(param, long));
329     break;
330   case CURLOPT_NOPROGRESS:
331     /*
332      * Shut off the internal supported progress meter
333      */
334     data->set.hide_progress = (0 != va_arg(param, long));
335     if(data->set.hide_progress)
336       data->progress.flags |= PGRS_HIDE;
337     else
338       data->progress.flags &= ~PGRS_HIDE;
339     break;
340   case CURLOPT_NOBODY:
341     /*
342      * Do not include the body part in the output data stream.
343      */
344     data->set.opt_no_body = (0 != va_arg(param, long));
345 #ifndef CURL_DISABLE_HTTP
346     if(data->set.opt_no_body)
347       /* in HTTP lingo, no body means using the HEAD request... */
348       data->set.method = HTTPREQ_HEAD;
349     else if(data->set.method == HTTPREQ_HEAD)
350       data->set.method = HTTPREQ_GET;
351 #endif
352     break;
353   case CURLOPT_FAILONERROR:
354     /*
355      * Don't output the >=400 error code HTML-page, but instead only
356      * return error.
357      */
358     data->set.http_fail_on_error = (0 != va_arg(param, long));
359     break;
360   case CURLOPT_KEEP_SENDING_ON_ERROR:
361     data->set.http_keep_sending_on_error = (0 != va_arg(param, long));
362     break;
363   case CURLOPT_UPLOAD:
364   case CURLOPT_PUT:
365     /*
366      * We want to sent data to the remote host. If this is HTTP, that equals
367      * using the PUT request.
368      */
369     arg = va_arg(param, long);
370     if(arg) {
371       /* If this is HTTP, PUT is what's needed to "upload" */
372       data->set.method = HTTPREQ_PUT;
373       data->set.opt_no_body = FALSE; /* this is implied */
374     }
375     else
376       /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
377          then this can be changed to HEAD later on) */
378       data->set.method = HTTPREQ_GET;
379     break;
380   case CURLOPT_REQUEST_TARGET:
381     result = Curl_setstropt(&data->set.str[STRING_TARGET],
382                             va_arg(param, char *));
383     break;
384   case CURLOPT_FILETIME:
385     /*
386      * Try to get the file time of the remote document. The time will
387      * later (possibly) become available using curl_easy_getinfo().
388      */
389     data->set.get_filetime = (0 != va_arg(param, long));
390     break;
391   case CURLOPT_SERVER_RESPONSE_TIMEOUT:
392     /*
393      * Option that specifies how quickly a server response must be obtained
394      * before it is considered failure. For pingpong protocols.
395      */
396     arg = va_arg(param, long);
397     if((arg >= 0) && (arg <= (INT_MAX/1000)))
398       data->set.server_response_timeout = (unsigned int)arg * 1000;
399     else
400       return CURLE_BAD_FUNCTION_ARGUMENT;
401     break;
402   case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS:
403     /*
404      * Option that specifies how quickly a server response must be obtained
405      * before it is considered failure. For pingpong protocols.
406      */
407     arg = va_arg(param, long);
408     if((arg >= 0) && (arg <= INT_MAX))
409       data->set.server_response_timeout = (unsigned int)arg;
410     else
411       return CURLE_BAD_FUNCTION_ARGUMENT;
412     break;
413 #ifndef CURL_DISABLE_TFTP
414   case CURLOPT_TFTP_NO_OPTIONS:
415     /*
416      * Option that prevents libcurl from sending TFTP option requests to the
417      * server.
418      */
419     data->set.tftp_no_options = va_arg(param, long) != 0;
420     break;
421   case CURLOPT_TFTP_BLKSIZE:
422     /*
423      * TFTP option that specifies the block size to use for data transmission.
424      */
425     arg = va_arg(param, long);
426     if(arg > TFTP_BLKSIZE_MAX || arg < TFTP_BLKSIZE_MIN)
427       return CURLE_BAD_FUNCTION_ARGUMENT;
428     data->set.tftp_blksize = arg;
429     break;
430 #endif
431 #ifndef CURL_DISABLE_NETRC
432   case CURLOPT_NETRC:
433     /*
434      * Parse the $HOME/.netrc file
435      */
436     arg = va_arg(param, long);
437     if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST))
438       return CURLE_BAD_FUNCTION_ARGUMENT;
439     data->set.use_netrc = (unsigned char)arg;
440     break;
441   case CURLOPT_NETRC_FILE:
442     /*
443      * Use this file instead of the $HOME/.netrc file
444      */
445     result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE],
446                             va_arg(param, char *));
447     break;
448 #endif
449   case CURLOPT_TRANSFERTEXT:
450     /*
451      * This option was previously named 'FTPASCII'. Renamed to work with
452      * more protocols than merely FTP.
453      *
454      * Transfer using ASCII (instead of BINARY).
455      */
456     data->set.prefer_ascii = (0 != va_arg(param, long));
457     break;
458   case CURLOPT_TIMECONDITION:
459     /*
460      * Set HTTP time condition. This must be one of the defines in the
461      * curl/curl.h header file.
462      */
463     arg = va_arg(param, long);
464     if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST))
465       return CURLE_BAD_FUNCTION_ARGUMENT;
466     data->set.timecondition = (unsigned char)(curl_TimeCond)arg;
467     break;
468   case CURLOPT_TIMEVALUE:
469     /*
470      * This is the value to compare with the remote document with the
471      * method set with CURLOPT_TIMECONDITION
472      */
473     data->set.timevalue = (time_t)va_arg(param, long);
474     break;
475 
476   case CURLOPT_TIMEVALUE_LARGE:
477     /*
478      * This is the value to compare with the remote document with the
479      * method set with CURLOPT_TIMECONDITION
480      */
481     data->set.timevalue = (time_t)va_arg(param, curl_off_t);
482     break;
483 
484   case CURLOPT_SSLVERSION:
485 #ifndef CURL_DISABLE_PROXY
486   case CURLOPT_PROXY_SSLVERSION:
487 #endif
488     /*
489      * Set explicit SSL version to try to connect with, as some SSL
490      * implementations are lame.
491      */
492 #ifdef USE_SSL
493     {
494       long version, version_max;
495       struct ssl_primary_config *primary = &data->set.ssl.primary;
496 #ifndef CURL_DISABLE_PROXY
497       if(option != CURLOPT_SSLVERSION)
498         primary = &data->set.proxy_ssl.primary;
499 #endif
500 
501       arg = va_arg(param, long);
502 
503       version = C_SSLVERSION_VALUE(arg);
504       version_max = (long)C_SSLVERSION_MAX_VALUE(arg);
505 
506       if(version < CURL_SSLVERSION_DEFAULT ||
507          version == CURL_SSLVERSION_SSLv2 ||
508          version == CURL_SSLVERSION_SSLv3 ||
509          version >= CURL_SSLVERSION_LAST ||
510          version_max < CURL_SSLVERSION_MAX_NONE ||
511          version_max >= CURL_SSLVERSION_MAX_LAST)
512         return CURLE_BAD_FUNCTION_ARGUMENT;
513 
514       primary->version = (unsigned char)version;
515       primary->version_max = (unsigned int)version_max;
516     }
517 #else
518     result = CURLE_NOT_BUILT_IN;
519 #endif
520     break;
521 
522     /* MQTT "borrows" some of the HTTP options */
523 #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
524   case CURLOPT_COPYPOSTFIELDS:
525     /*
526      * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
527      * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
528      *  CURLOPT_COPYPOSTFIELDS and not altered later.
529      */
530     argptr = va_arg(param, char *);
531 
532     if(!argptr || data->set.postfieldsize == -1)
533       result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
534     else {
535       /*
536        *  Check that requested length does not overflow the size_t type.
537        */
538 
539       if((data->set.postfieldsize < 0) ||
540          ((sizeof(curl_off_t) != sizeof(size_t)) &&
541           (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
542         result = CURLE_OUT_OF_MEMORY;
543       else {
544         /* Allocate even when size == 0. This satisfies the need of possible
545            later address compare to detect the COPYPOSTFIELDS mode, and to
546            mark that postfields is used rather than read function or form
547            data.
548         */
549         char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize);
550         if(!p)
551           result = CURLE_OUT_OF_MEMORY;
552         else {
553           free(data->set.str[STRING_COPYPOSTFIELDS]);
554           data->set.str[STRING_COPYPOSTFIELDS] = p;
555         }
556       }
557     }
558 
559     data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
560     data->set.method = HTTPREQ_POST;
561     break;
562 
563   case CURLOPT_POSTFIELDS:
564     /*
565      * Like above, but use static data instead of copying it.
566      */
567     data->set.postfields = va_arg(param, void *);
568     /* Release old copied data. */
569     Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
570     data->set.method = HTTPREQ_POST;
571     break;
572 
573   case CURLOPT_POSTFIELDSIZE:
574     /*
575      * The size of the POSTFIELD data to prevent libcurl to do strlen() to
576      * figure it out. Enables binary posts.
577      */
578     bigsize = va_arg(param, long);
579     if(bigsize < -1)
580       return CURLE_BAD_FUNCTION_ARGUMENT;
581 
582     if(data->set.postfieldsize < bigsize &&
583        data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
584       /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
585       Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
586       data->set.postfields = NULL;
587     }
588 
589     data->set.postfieldsize = bigsize;
590     break;
591 
592   case CURLOPT_POSTFIELDSIZE_LARGE:
593     /*
594      * The size of the POSTFIELD data to prevent libcurl to do strlen() to
595      * figure it out. Enables binary posts.
596      */
597     bigsize = va_arg(param, curl_off_t);
598     if(bigsize < -1)
599       return CURLE_BAD_FUNCTION_ARGUMENT;
600 
601     if(data->set.postfieldsize < bigsize &&
602        data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
603       /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
604       Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
605       data->set.postfields = NULL;
606     }
607 
608     data->set.postfieldsize = bigsize;
609     break;
610 #endif
611 #ifndef CURL_DISABLE_HTTP
612   case CURLOPT_AUTOREFERER:
613     /*
614      * Switch on automatic referer that gets set if curl follows locations.
615      */
616     data->set.http_auto_referer = (0 != va_arg(param, long));
617     break;
618 
619   case CURLOPT_ACCEPT_ENCODING:
620     /*
621      * String to use at the value of Accept-Encoding header.
622      *
623      * If the encoding is set to "" we use an Accept-Encoding header that
624      * encompasses all the encodings we support.
625      * If the encoding is set to NULL we don't send an Accept-Encoding header
626      * and ignore an received Content-Encoding header.
627      *
628      */
629     argptr = va_arg(param, char *);
630     if(argptr && !*argptr) {
631       char all[256];
632       Curl_all_content_encodings(all, sizeof(all));
633       result = Curl_setstropt(&data->set.str[STRING_ENCODING], all);
634     }
635     else
636       result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
637     break;
638 
639   case CURLOPT_TRANSFER_ENCODING:
640     data->set.http_transfer_encoding = (0 != va_arg(param, long));
641     break;
642 
643   case CURLOPT_FOLLOWLOCATION:
644     /*
645      * Follow Location: header hints on an HTTP-server.
646      */
647     data->set.http_follow_location = (0 != va_arg(param, long));
648     break;
649 
650   case CURLOPT_UNRESTRICTED_AUTH:
651     /*
652      * Send authentication (user+password) when following locations, even when
653      * hostname changed.
654      */
655     data->set.allow_auth_to_other_hosts = (0 != va_arg(param, long));
656     break;
657 
658   case CURLOPT_MAXREDIRS:
659     /*
660      * The maximum amount of hops you allow curl to follow Location:
661      * headers. This should mostly be used to detect never-ending loops.
662      */
663     arg = va_arg(param, long);
664     if(arg < -1)
665       return CURLE_BAD_FUNCTION_ARGUMENT;
666     data->set.maxredirs = arg;
667     break;
668 
669   case CURLOPT_POSTREDIR:
670     /*
671      * Set the behavior of POST when redirecting
672      * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
673      * CURL_REDIR_POST_301 - POST is kept as POST after 301
674      * CURL_REDIR_POST_302 - POST is kept as POST after 302
675      * CURL_REDIR_POST_303 - POST is kept as POST after 303
676      * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
677      * other - POST is kept as POST after 301 and 302
678      */
679     arg = va_arg(param, long);
680     if(arg < CURL_REDIR_GET_ALL)
681       /* no return error on too high numbers since the bitmask could be
682          extended in a future */
683       return CURLE_BAD_FUNCTION_ARGUMENT;
684     data->set.keep_post = arg & CURL_REDIR_POST_ALL;
685     break;
686 
687   case CURLOPT_POST:
688     /* Does this option serve a purpose anymore? Yes it does, when
689        CURLOPT_POSTFIELDS isn't used and the POST data is read off the
690        callback! */
691     if(va_arg(param, long)) {
692       data->set.method = HTTPREQ_POST;
693       data->set.opt_no_body = FALSE; /* this is implied */
694     }
695     else
696       data->set.method = HTTPREQ_GET;
697     break;
698 
699 #ifndef CURL_DISABLE_FORM_API
700   case CURLOPT_HTTPPOST:
701     /*
702      * Set to make us do HTTP POST. Legacy API-style.
703      */
704     data->set.httppost = va_arg(param, struct curl_httppost *);
705     data->set.method = HTTPREQ_POST_FORM;
706     data->set.opt_no_body = FALSE; /* this is implied */
707     Curl_mime_cleanpart(data->state.formp);
708     Curl_safefree(data->state.formp);
709     data->state.mimepost = NULL;
710     break;
711 #endif
712 
713 #if !defined(CURL_DISABLE_AWS)
714   case CURLOPT_AWS_SIGV4:
715     /*
716      * String that is merged to some authentication
717      * parameters are used by the algorithm.
718      */
719     result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4],
720                             va_arg(param, char *));
721     /*
722      * Basic been set by default it need to be unset here
723      */
724     if(data->set.str[STRING_AWS_SIGV4])
725       data->set.httpauth = CURLAUTH_AWS_SIGV4;
726     break;
727 #endif
728 
729   case CURLOPT_REFERER:
730     /*
731      * String to set in the HTTP Referer: field.
732      */
733     if(data->state.referer_alloc) {
734       Curl_safefree(data->state.referer);
735       data->state.referer_alloc = FALSE;
736     }
737     result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
738                             va_arg(param, char *));
739     data->state.referer = data->set.str[STRING_SET_REFERER];
740     break;
741 
742   case CURLOPT_USERAGENT:
743     /*
744      * String to use in the HTTP User-Agent field
745      */
746     result = Curl_setstropt(&data->set.str[STRING_USERAGENT],
747                             va_arg(param, char *));
748     break;
749 
750 #ifndef CURL_DISABLE_PROXY
751   case CURLOPT_PROXYHEADER:
752     /*
753      * Set a list with proxy headers to use (or replace internals with)
754      *
755      * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
756      * long time we remain doing it this way until CURLOPT_PROXYHEADER is
757      * used. As soon as this option has been used, if set to anything but
758      * NULL, custom headers for proxies are only picked from this list.
759      *
760      * Set this option to NULL to restore the previous behavior.
761      */
762     data->set.proxyheaders = va_arg(param, struct curl_slist *);
763     break;
764 #endif
765   case CURLOPT_HEADEROPT:
766     /*
767      * Set header option.
768      */
769     arg = va_arg(param, long);
770     data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE);
771     break;
772 
773 #if !defined(CURL_DISABLE_COOKIES)
774   case CURLOPT_COOKIE:
775     /*
776      * Cookie string to send to the remote server in the request.
777      */
778     result = Curl_setstropt(&data->set.str[STRING_COOKIE],
779                             va_arg(param, char *));
780     break;
781 
782   case CURLOPT_COOKIEFILE:
783     /*
784      * Set cookie file to read and parse. Can be used multiple times.
785      */
786     argptr = (char *)va_arg(param, void *);
787     if(argptr) {
788       struct curl_slist *cl;
789       /* general protection against mistakes and abuse */
790       if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
791         return CURLE_BAD_FUNCTION_ARGUMENT;
792       /* append the cookie file name to the list of file names, and deal with
793          them later */
794       cl = curl_slist_append(data->state.cookielist, argptr);
795       if(!cl) {
796         curl_slist_free_all(data->state.cookielist);
797         data->state.cookielist = NULL;
798         return CURLE_OUT_OF_MEMORY;
799       }
800       data->state.cookielist = cl; /* store the list for later use */
801     }
802     else {
803       /* clear the list of cookie files */
804       curl_slist_free_all(data->state.cookielist);
805       data->state.cookielist = NULL;
806 
807       if(!data->share || !data->share->cookies) {
808         /* throw away all existing cookies if this isn't a shared cookie
809            container */
810         Curl_cookie_clearall(data->cookies);
811         Curl_cookie_cleanup(data->cookies);
812       }
813       /* disable the cookie engine */
814       data->cookies = NULL;
815     }
816     break;
817 
818   case CURLOPT_COOKIEJAR:
819     /*
820      * Set cookie file name to dump all cookies to when we're done.
821      */
822     result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
823                             va_arg(param, char *));
824     if(!result) {
825       /*
826        * Activate the cookie parser. This may or may not already
827        * have been made.
828        */
829       struct CookieInfo *newcookies =
830         Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession);
831       if(!newcookies)
832         result = CURLE_OUT_OF_MEMORY;
833       data->cookies = newcookies;
834     }
835     break;
836 
837   case CURLOPT_COOKIESESSION:
838     /*
839      * Set this option to TRUE to start a new "cookie session". It will
840      * prevent the forthcoming read-cookies-from-file actions to accept
841      * cookies that are marked as being session cookies, as they belong to a
842      * previous session.
843      */
844     data->set.cookiesession = (0 != va_arg(param, long));
845     break;
846 
847   case CURLOPT_COOKIELIST:
848     argptr = va_arg(param, char *);
849 
850     if(!argptr)
851       break;
852 
853     if(strcasecompare(argptr, "ALL")) {
854       /* clear all cookies */
855       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
856       Curl_cookie_clearall(data->cookies);
857       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
858     }
859     else if(strcasecompare(argptr, "SESS")) {
860       /* clear session cookies */
861       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
862       Curl_cookie_clearsess(data->cookies);
863       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
864     }
865     else if(strcasecompare(argptr, "FLUSH")) {
866       /* flush cookies to file, takes care of the locking */
867       Curl_flush_cookies(data, FALSE);
868     }
869     else if(strcasecompare(argptr, "RELOAD")) {
870       /* reload cookies from file */
871       Curl_cookie_loadfiles(data);
872       break;
873     }
874     else {
875       if(!data->cookies)
876         /* if cookie engine was not running, activate it */
877         data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
878 
879       /* general protection against mistakes and abuse */
880       if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
881         return CURLE_BAD_FUNCTION_ARGUMENT;
882       argptr = strdup(argptr);
883       if(!argptr || !data->cookies) {
884         result = CURLE_OUT_OF_MEMORY;
885         free(argptr);
886       }
887       else {
888         Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
889 
890         if(checkprefix("Set-Cookie:", argptr))
891           /* HTTP Header format line */
892           Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL,
893                           NULL, TRUE);
894 
895         else
896           /* Netscape format line */
897           Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL,
898                           NULL, TRUE);
899 
900         Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
901         free(argptr);
902       }
903     }
904 
905     break;
906 #endif /* !CURL_DISABLE_COOKIES */
907 
908   case CURLOPT_HTTPGET:
909     /*
910      * Set to force us do HTTP GET
911      */
912     if(va_arg(param, long)) {
913       data->set.method = HTTPREQ_GET;
914       data->set.opt_no_body = FALSE; /* this is implied */
915     }
916     break;
917 
918   case CURLOPT_HTTP_VERSION:
919     /*
920      * This sets a requested HTTP version to be used. The value is one of
921      * the listed enums in curl/curl.h.
922      */
923     arg = va_arg(param, long);
924     switch(arg) {
925     case CURL_HTTP_VERSION_NONE:
926 #ifdef USE_HTTP2
927       /* TODO: this seems an undesirable quirk to force a behaviour on
928        * lower implementations that they should recognize independently? */
929       arg = CURL_HTTP_VERSION_2TLS;
930 #endif
931       /* accepted */
932       break;
933     case CURL_HTTP_VERSION_1_0:
934     case CURL_HTTP_VERSION_1_1:
935       /* accepted */
936       break;
937 #ifdef USE_HTTP2
938     case CURL_HTTP_VERSION_2_0:
939     case CURL_HTTP_VERSION_2TLS:
940     case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
941       /* accepted */
942       break;
943 #endif
944 #ifdef USE_HTTP3
945     case CURL_HTTP_VERSION_3:
946     case CURL_HTTP_VERSION_3ONLY:
947       /* accepted */
948       break;
949 #endif
950     default:
951       /* not accepted */
952       if(arg < CURL_HTTP_VERSION_NONE)
953         return CURLE_BAD_FUNCTION_ARGUMENT;
954       return CURLE_UNSUPPORTED_PROTOCOL;
955     }
956     data->set.httpwant = (unsigned char)arg;
957     break;
958 
959   case CURLOPT_EXPECT_100_TIMEOUT_MS:
960     /*
961      * Time to wait for a response to an HTTP request containing an
962      * Expect: 100-continue header before sending the data anyway.
963      */
964     arg = va_arg(param, long);
965     if(arg < 0)
966       return CURLE_BAD_FUNCTION_ARGUMENT;
967     data->set.expect_100_timeout = arg;
968     break;
969 
970   case CURLOPT_HTTP09_ALLOWED:
971     arg = (long)va_arg(param, unsigned long);
972     if(arg > 1L)
973       return CURLE_BAD_FUNCTION_ARGUMENT;
974 #ifdef USE_HYPER
975     /* Hyper does not support HTTP/0.9 */
976     if(arg)
977       return CURLE_BAD_FUNCTION_ARGUMENT;
978 #else
979     data->set.http09_allowed = !!arg;
980 #endif
981     break;
982 
983   case CURLOPT_HTTP200ALIASES:
984     /*
985      * Set a list of aliases for HTTP 200 in response header
986      */
987     data->set.http200aliases = va_arg(param, struct curl_slist *);
988     break;
989 #endif   /* CURL_DISABLE_HTTP */
990 
991 #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) ||       \
992     !defined(CURL_DISABLE_IMAP)
993 # if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME)
994   case CURLOPT_HTTPHEADER:
995     /*
996      * Set a list with HTTP headers to use (or replace internals with)
997      */
998     data->set.headers = va_arg(param, struct curl_slist *);
999     break;
1000 # endif
1001 
1002 # ifndef CURL_DISABLE_MIME
1003   case CURLOPT_MIMEPOST:
1004     /*
1005      * Set to make us do MIME POST
1006      */
1007     result = Curl_mime_set_subparts(&data->set.mimepost,
1008                                     va_arg(param, curl_mime *), FALSE);
1009     if(!result) {
1010       data->set.method = HTTPREQ_POST_MIME;
1011       data->set.opt_no_body = FALSE; /* this is implied */
1012 #ifndef CURL_DISABLE_FORM_API
1013       Curl_mime_cleanpart(data->state.formp);
1014       Curl_safefree(data->state.formp);
1015       data->state.mimepost = NULL;
1016 #endif
1017     }
1018     break;
1019 
1020   case CURLOPT_MIME_OPTIONS:
1021     arg = va_arg(param, long);
1022     data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE);
1023   break;
1024 # endif
1025 #endif
1026 
1027   case CURLOPT_HTTPAUTH:
1028     /*
1029      * Set HTTP Authentication type BITMASK.
1030      */
1031   {
1032     int bitcheck;
1033     bool authbits;
1034     unsigned long auth = va_arg(param, unsigned long);
1035 
1036     if(auth == CURLAUTH_NONE) {
1037       data->set.httpauth = auth;
1038       break;
1039     }
1040 
1041     /* the DIGEST_IE bit is only used to set a special marker, for all the
1042        rest we need to handle it as normal DIGEST */
1043     data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
1044 
1045     if(auth & CURLAUTH_DIGEST_IE) {
1046       auth |= CURLAUTH_DIGEST; /* set standard digest bit */
1047       auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
1048     }
1049 
1050     /* switch off bits we can't support */
1051 #ifndef USE_NTLM
1052     auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
1053 #endif
1054 #ifndef USE_SPNEGO
1055     auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
1056                                     GSS-API or SSPI */
1057 #endif
1058 
1059     /* check if any auth bit lower than CURLAUTH_ONLY is still set */
1060     bitcheck = 0;
1061     authbits = FALSE;
1062     while(bitcheck < 31) {
1063       if(auth & (1UL << bitcheck++)) {
1064         authbits = TRUE;
1065         break;
1066       }
1067     }
1068     if(!authbits)
1069       return CURLE_NOT_BUILT_IN; /* no supported types left! */
1070 
1071     data->set.httpauth = auth;
1072   }
1073   break;
1074 
1075   case CURLOPT_CUSTOMREQUEST:
1076     /*
1077      * Set a custom string to use as request
1078      */
1079     result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
1080                             va_arg(param, char *));
1081 
1082     /* we don't set
1083        data->set.method = HTTPREQ_CUSTOM;
1084        here, we continue as if we were using the already set type
1085        and this just changes the actual request keyword */
1086     break;
1087 
1088 #ifndef CURL_DISABLE_PROXY
1089   case CURLOPT_HTTPPROXYTUNNEL:
1090     /*
1091      * Tunnel operations through the proxy instead of normal proxy use
1092      */
1093     data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long));
1094     break;
1095 
1096   case CURLOPT_PROXYPORT:
1097     /*
1098      * Explicitly set HTTP proxy port number.
1099      */
1100     arg = va_arg(param, long);
1101     if((arg < 0) || (arg > 65535))
1102       return CURLE_BAD_FUNCTION_ARGUMENT;
1103     data->set.proxyport = (unsigned short)arg;
1104     break;
1105 
1106   case CURLOPT_PROXYAUTH:
1107     /*
1108      * Set HTTP Authentication type BITMASK.
1109      */
1110   {
1111     int bitcheck;
1112     bool authbits;
1113     unsigned long auth = va_arg(param, unsigned long);
1114 
1115     if(auth == CURLAUTH_NONE) {
1116       data->set.proxyauth = auth;
1117       break;
1118     }
1119 
1120     /* the DIGEST_IE bit is only used to set a special marker, for all the
1121        rest we need to handle it as normal DIGEST */
1122     data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE);
1123 
1124     if(auth & CURLAUTH_DIGEST_IE) {
1125       auth |= CURLAUTH_DIGEST; /* set standard digest bit */
1126       auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
1127     }
1128     /* switch off bits we can't support */
1129 #ifndef USE_NTLM
1130     auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
1131 #endif
1132 #ifndef USE_SPNEGO
1133     auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
1134                                     GSS-API or SSPI */
1135 #endif
1136 
1137     /* check if any auth bit lower than CURLAUTH_ONLY is still set */
1138     bitcheck = 0;
1139     authbits = FALSE;
1140     while(bitcheck < 31) {
1141       if(auth & (1UL << bitcheck++)) {
1142         authbits = TRUE;
1143         break;
1144       }
1145     }
1146     if(!authbits)
1147       return CURLE_NOT_BUILT_IN; /* no supported types left! */
1148 
1149     data->set.proxyauth = auth;
1150   }
1151   break;
1152 
1153   case CURLOPT_PROXY:
1154     /*
1155      * Set proxy server:port to use as proxy.
1156      *
1157      * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
1158      * we explicitly say that we don't want to use a proxy
1159      * (even though there might be environment variables saying so).
1160      *
1161      * Setting it to NULL, means no proxy but allows the environment variables
1162      * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
1163      */
1164     result = Curl_setstropt(&data->set.str[STRING_PROXY],
1165                             va_arg(param, char *));
1166     break;
1167 
1168   case CURLOPT_PRE_PROXY:
1169     /*
1170      * Set proxy server:port to use as SOCKS proxy.
1171      *
1172      * If the proxy is set to "" or NULL we explicitly say that we don't want
1173      * to use the socks proxy.
1174      */
1175     result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
1176                             va_arg(param, char *));
1177     break;
1178 
1179   case CURLOPT_PROXYTYPE:
1180     /*
1181      * Set proxy type.
1182      */
1183     arg = va_arg(param, long);
1184     if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
1185       return CURLE_BAD_FUNCTION_ARGUMENT;
1186     data->set.proxytype = (unsigned char)(curl_proxytype)arg;
1187     break;
1188 
1189   case CURLOPT_PROXY_TRANSFER_MODE:
1190     /*
1191      * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
1192      */
1193     switch(va_arg(param, long)) {
1194     case 0:
1195       data->set.proxy_transfer_mode = FALSE;
1196       break;
1197     case 1:
1198       data->set.proxy_transfer_mode = TRUE;
1199       break;
1200     default:
1201       /* reserve other values for future use */
1202       result = CURLE_BAD_FUNCTION_ARGUMENT;
1203       break;
1204     }
1205     break;
1206 
1207   case CURLOPT_SOCKS5_AUTH:
1208     data->set.socks5auth = (unsigned char)va_arg(param, unsigned long);
1209     if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
1210       result = CURLE_NOT_BUILT_IN;
1211     break;
1212 #endif   /* CURL_DISABLE_PROXY */
1213 
1214 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1215   case CURLOPT_SOCKS5_GSSAPI_NEC:
1216     /*
1217      * Set flag for NEC SOCK5 support
1218      */
1219     data->set.socks5_gssapi_nec = (0 != va_arg(param, long));
1220     break;
1221 #endif
1222 #ifndef CURL_DISABLE_PROXY
1223   case CURLOPT_SOCKS5_GSSAPI_SERVICE:
1224   case CURLOPT_PROXY_SERVICE_NAME:
1225     /*
1226      * Set proxy authentication service name for Kerberos 5 and SPNEGO
1227      */
1228     result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
1229                             va_arg(param, char *));
1230     break;
1231 #endif
1232   case CURLOPT_SERVICE_NAME:
1233     /*
1234      * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
1235      */
1236     result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME],
1237                             va_arg(param, char *));
1238     break;
1239 
1240   case CURLOPT_HEADERDATA:
1241     /*
1242      * Custom pointer to pass the header write callback function
1243      */
1244     data->set.writeheader = (void *)va_arg(param, void *);
1245     break;
1246   case CURLOPT_ERRORBUFFER:
1247     /*
1248      * Error buffer provided by the caller to get the human readable
1249      * error string in.
1250      */
1251     data->set.errorbuffer = va_arg(param, char *);
1252     break;
1253   case CURLOPT_WRITEDATA:
1254     /*
1255      * FILE pointer to write to. Or possibly
1256      * used as argument to the write callback.
1257      */
1258     data->set.out = va_arg(param, void *);
1259     break;
1260 
1261 #ifdef CURL_LIST_ONLY_PROTOCOL
1262   case CURLOPT_DIRLISTONLY:
1263     /*
1264      * An option that changes the command to one that asks for a list only, no
1265      * file info details. Used for FTP, POP3 and SFTP.
1266      */
1267     data->set.list_only = (0 != va_arg(param, long));
1268     break;
1269 #endif
1270   case CURLOPT_APPEND:
1271     /*
1272      * We want to upload and append to an existing file. Used for FTP and
1273      * SFTP.
1274      */
1275     data->set.remote_append = (0 != va_arg(param, long));
1276     break;
1277 
1278 #ifndef CURL_DISABLE_FTP
1279   case CURLOPT_FTP_FILEMETHOD:
1280     /*
1281      * How do access files over FTP.
1282      */
1283     arg = va_arg(param, long);
1284     if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST))
1285       return CURLE_BAD_FUNCTION_ARGUMENT;
1286     data->set.ftp_filemethod = (unsigned char)arg;
1287     break;
1288   case CURLOPT_FTPPORT:
1289     /*
1290      * Use FTP PORT, this also specifies which IP address to use
1291      */
1292     result = Curl_setstropt(&data->set.str[STRING_FTPPORT],
1293                             va_arg(param, char *));
1294     data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]);
1295     break;
1296 
1297   case CURLOPT_FTP_USE_EPRT:
1298     data->set.ftp_use_eprt = (0 != va_arg(param, long));
1299     break;
1300 
1301   case CURLOPT_FTP_USE_EPSV:
1302     data->set.ftp_use_epsv = (0 != va_arg(param, long));
1303     break;
1304 
1305   case CURLOPT_FTP_USE_PRET:
1306     data->set.ftp_use_pret = (0 != va_arg(param, long));
1307     break;
1308 
1309   case CURLOPT_FTP_SSL_CCC:
1310     arg = va_arg(param, long);
1311     if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST))
1312       return CURLE_BAD_FUNCTION_ARGUMENT;
1313     data->set.ftp_ccc = (unsigned char)arg;
1314     break;
1315 
1316   case CURLOPT_FTP_SKIP_PASV_IP:
1317     /*
1318      * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
1319      * bypass of the IP address in PASV responses.
1320      */
1321     data->set.ftp_skip_ip = (0 != va_arg(param, long));
1322     break;
1323 
1324   case CURLOPT_FTP_ACCOUNT:
1325     result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
1326                             va_arg(param, char *));
1327     break;
1328 
1329   case CURLOPT_FTP_ALTERNATIVE_TO_USER:
1330     result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
1331                             va_arg(param, char *));
1332     break;
1333 
1334   case CURLOPT_FTPSSLAUTH:
1335     /*
1336      * Set a specific auth for FTP-SSL transfers.
1337      */
1338     arg = va_arg(param, long);
1339     if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST))
1340       return CURLE_BAD_FUNCTION_ARGUMENT;
1341     data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg;
1342     break;
1343 #ifdef HAVE_GSSAPI
1344   case CURLOPT_KRBLEVEL:
1345     /*
1346      * A string that defines the kerberos security level.
1347      */
1348     result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
1349                             va_arg(param, char *));
1350     data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
1351     break;
1352 #endif
1353 #endif
1354 #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
1355   case CURLOPT_FTP_CREATE_MISSING_DIRS:
1356     /*
1357      * An FTP/SFTP option that modifies an upload to create missing
1358      * directories on the server.
1359      */
1360     arg = va_arg(param, long);
1361     /* reserve other values for future use */
1362     if((arg < CURLFTP_CREATE_DIR_NONE) ||
1363        (arg > CURLFTP_CREATE_DIR_RETRY))
1364       result = CURLE_BAD_FUNCTION_ARGUMENT;
1365     else
1366       data->set.ftp_create_missing_dirs = (unsigned char)arg;
1367     break;
1368 
1369   case CURLOPT_POSTQUOTE:
1370     /*
1371      * List of RAW FTP commands to use after a transfer
1372      */
1373     data->set.postquote = va_arg(param, struct curl_slist *);
1374     break;
1375   case CURLOPT_PREQUOTE:
1376     /*
1377      * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
1378      */
1379     data->set.prequote = va_arg(param, struct curl_slist *);
1380     break;
1381   case CURLOPT_QUOTE:
1382     /*
1383      * List of RAW FTP commands to use before a transfer
1384      */
1385     data->set.quote = va_arg(param, struct curl_slist *);
1386     break;
1387 #endif
1388   case CURLOPT_READDATA:
1389     /*
1390      * FILE pointer to read the file to be uploaded from. Or possibly
1391      * used as argument to the read callback.
1392      */
1393     data->set.in_set = va_arg(param, void *);
1394     break;
1395   case CURLOPT_INFILESIZE:
1396     /*
1397      * If known, this should inform curl about the file size of the
1398      * to-be-uploaded file.
1399      */
1400     arg = va_arg(param, long);
1401     if(arg < -1)
1402       return CURLE_BAD_FUNCTION_ARGUMENT;
1403     data->set.filesize = arg;
1404     break;
1405   case CURLOPT_INFILESIZE_LARGE:
1406     /*
1407      * If known, this should inform curl about the file size of the
1408      * to-be-uploaded file.
1409      */
1410     bigsize = va_arg(param, curl_off_t);
1411     if(bigsize < -1)
1412       return CURLE_BAD_FUNCTION_ARGUMENT;
1413     data->set.filesize = bigsize;
1414     break;
1415   case CURLOPT_LOW_SPEED_LIMIT:
1416     /*
1417      * The low speed limit that if transfers are below this for
1418      * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
1419      */
1420     arg = va_arg(param, long);
1421     if(arg < 0)
1422       return CURLE_BAD_FUNCTION_ARGUMENT;
1423     data->set.low_speed_limit = arg;
1424     break;
1425   case CURLOPT_MAX_SEND_SPEED_LARGE:
1426     /*
1427      * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
1428      * bytes per second the transfer is throttled..
1429      */
1430     bigsize = va_arg(param, curl_off_t);
1431     if(bigsize < 0)
1432       return CURLE_BAD_FUNCTION_ARGUMENT;
1433     data->set.max_send_speed = bigsize;
1434     break;
1435   case CURLOPT_MAX_RECV_SPEED_LARGE:
1436     /*
1437      * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
1438      * second the transfer is throttled..
1439      */
1440     bigsize = va_arg(param, curl_off_t);
1441     if(bigsize < 0)
1442       return CURLE_BAD_FUNCTION_ARGUMENT;
1443     data->set.max_recv_speed = bigsize;
1444     break;
1445   case CURLOPT_LOW_SPEED_TIME:
1446     /*
1447      * The low speed time that if transfers are below the set
1448      * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
1449      */
1450     arg = va_arg(param, long);
1451     if(arg < 0)
1452       return CURLE_BAD_FUNCTION_ARGUMENT;
1453     data->set.low_speed_time = arg;
1454     break;
1455   case CURLOPT_CURLU:
1456     /*
1457      * pass CURLU to set URL
1458      */
1459     data->set.uh = va_arg(param, CURLU *);
1460     break;
1461   case CURLOPT_URL:
1462     /*
1463      * The URL to fetch.
1464      */
1465     if(data->state.url_alloc) {
1466       /* the already set URL is allocated, free it first! */
1467       Curl_safefree(data->state.url);
1468       data->state.url_alloc = FALSE;
1469     }
1470     result = Curl_setstropt(&data->set.str[STRING_SET_URL],
1471                             va_arg(param, char *));
1472     data->state.url = data->set.str[STRING_SET_URL];
1473     break;
1474   case CURLOPT_PORT:
1475     /*
1476      * The port number to use when getting the URL. 0 disables it.
1477      */
1478     arg = va_arg(param, long);
1479     if((arg < 0) || (arg > 65535))
1480       return CURLE_BAD_FUNCTION_ARGUMENT;
1481     data->set.use_port = (unsigned short)arg;
1482     break;
1483   case CURLOPT_TIMEOUT:
1484     /*
1485      * The maximum time you allow curl to use for a single transfer
1486      * operation.
1487      */
1488     arg = va_arg(param, long);
1489     if((arg >= 0) && (arg <= (INT_MAX/1000)))
1490       data->set.timeout = (unsigned int)arg * 1000;
1491     else
1492       return CURLE_BAD_FUNCTION_ARGUMENT;
1493     break;
1494 
1495   case CURLOPT_TIMEOUT_MS:
1496     uarg = va_arg(param, unsigned long);
1497     if(uarg > UINT_MAX)
1498       uarg = UINT_MAX;
1499     data->set.timeout = (unsigned int)uarg;
1500     break;
1501 
1502   case CURLOPT_CONNECTTIMEOUT:
1503     /*
1504      * The maximum time you allow curl to use to connect.
1505      */
1506     arg = va_arg(param, long);
1507     if((arg >= 0) && (arg <= (INT_MAX/1000)))
1508       data->set.connecttimeout = (unsigned int)arg * 1000;
1509     else
1510       return CURLE_BAD_FUNCTION_ARGUMENT;
1511     break;
1512 
1513   case CURLOPT_CONNECTTIMEOUT_MS:
1514     uarg = va_arg(param, unsigned long);
1515     if(uarg > UINT_MAX)
1516       uarg = UINT_MAX;
1517     data->set.connecttimeout = (unsigned int)uarg;
1518     break;
1519 
1520 #ifndef CURL_DISABLE_FTP
1521   case CURLOPT_ACCEPTTIMEOUT_MS:
1522     /*
1523      * The maximum time for curl to wait for FTP server connect
1524      */
1525     uarg = va_arg(param, unsigned long);
1526     if(uarg > UINT_MAX)
1527       uarg = UINT_MAX;
1528     data->set.accepttimeout = (unsigned int)uarg;
1529     break;
1530 #endif
1531 
1532   case CURLOPT_USERPWD:
1533     /*
1534      * user:password to use in the operation
1535      */
1536     result = setstropt_userpwd(va_arg(param, char *),
1537                                &data->set.str[STRING_USERNAME],
1538                                &data->set.str[STRING_PASSWORD]);
1539     break;
1540 
1541   case CURLOPT_USERNAME:
1542     /*
1543      * authentication user name to use in the operation
1544      */
1545     result = Curl_setstropt(&data->set.str[STRING_USERNAME],
1546                             va_arg(param, char *));
1547     break;
1548   case CURLOPT_PASSWORD:
1549     /*
1550      * authentication password to use in the operation
1551      */
1552     result = Curl_setstropt(&data->set.str[STRING_PASSWORD],
1553                             va_arg(param, char *));
1554     break;
1555 
1556   case CURLOPT_LOGIN_OPTIONS:
1557     /*
1558      * authentication options to use in the operation
1559      */
1560     result = Curl_setstropt(&data->set.str[STRING_OPTIONS],
1561                             va_arg(param, char *));
1562     break;
1563 
1564   case CURLOPT_XOAUTH2_BEARER:
1565     /*
1566      * OAuth 2.0 bearer token to use in the operation
1567      */
1568     result = Curl_setstropt(&data->set.str[STRING_BEARER],
1569                             va_arg(param, char *));
1570     break;
1571 
1572   case CURLOPT_RESOLVE:
1573     /*
1574      * List of HOST:PORT:[addresses] strings to populate the DNS cache with
1575      * Entries added this way will remain in the cache until explicitly
1576      * removed or the handle is cleaned up.
1577      *
1578      * Prefix the HOST with plus sign (+) to have the entry expire just like
1579      * automatically added entries.
1580      *
1581      * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
1582      *
1583      * This API can remove any entry from the DNS cache, but only entries
1584      * that aren't actually in use right now will be pruned immediately.
1585      */
1586     data->set.resolve = va_arg(param, struct curl_slist *);
1587     data->state.resolve = data->set.resolve;
1588     break;
1589   case CURLOPT_PROGRESSFUNCTION:
1590     /*
1591      * Progress callback function
1592      */
1593     data->set.fprogress = va_arg(param, curl_progress_callback);
1594     if(data->set.fprogress)
1595       data->progress.callback = TRUE; /* no longer internal */
1596     else
1597       data->progress.callback = FALSE; /* NULL enforces internal */
1598     break;
1599 
1600   case CURLOPT_XFERINFOFUNCTION:
1601     /*
1602      * Transfer info callback function
1603      */
1604     data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
1605     if(data->set.fxferinfo)
1606       data->progress.callback = TRUE; /* no longer internal */
1607     else
1608       data->progress.callback = FALSE; /* NULL enforces internal */
1609 
1610     break;
1611 
1612   case CURLOPT_PROGRESSDATA:
1613     /*
1614      * Custom client data to pass to the progress callback
1615      */
1616     data->set.progress_client = va_arg(param, void *);
1617     break;
1618 
1619 #ifndef CURL_DISABLE_PROXY
1620   case CURLOPT_PROXYUSERPWD: {
1621     /*
1622      * user:password needed to use the proxy
1623      */
1624     char *u = NULL;
1625     char *p = NULL;
1626     result = setstropt_userpwd(va_arg(param, char *), &u, &p);
1627 
1628     /* URL decode the components */
1629     if(!result && u)
1630       result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL,
1631                               REJECT_ZERO);
1632     if(!result && p)
1633       result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL,
1634                               REJECT_ZERO);
1635     free(u);
1636     free(p);
1637   }
1638     break;
1639   case CURLOPT_PROXYUSERNAME:
1640     /*
1641      * authentication user name to use in the operation
1642      */
1643     result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
1644                             va_arg(param, char *));
1645     break;
1646   case CURLOPT_PROXYPASSWORD:
1647     /*
1648      * authentication password to use in the operation
1649      */
1650     result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD],
1651                             va_arg(param, char *));
1652     break;
1653   case CURLOPT_NOPROXY:
1654     /*
1655      * proxy exception list
1656      */
1657     result = Curl_setstropt(&data->set.str[STRING_NOPROXY],
1658                             va_arg(param, char *));
1659     break;
1660 #endif
1661 
1662   case CURLOPT_RANGE:
1663     /*
1664      * What range of the file you want to transfer
1665      */
1666     result = Curl_setstropt(&data->set.str[STRING_SET_RANGE],
1667                             va_arg(param, char *));
1668     break;
1669   case CURLOPT_RESUME_FROM:
1670     /*
1671      * Resume transfer at the given file position
1672      */
1673     arg = va_arg(param, long);
1674     if(arg < -1)
1675       return CURLE_BAD_FUNCTION_ARGUMENT;
1676     data->set.set_resume_from = arg;
1677     break;
1678   case CURLOPT_RESUME_FROM_LARGE:
1679     /*
1680      * Resume transfer at the given file position
1681      */
1682     bigsize = va_arg(param, curl_off_t);
1683     if(bigsize < -1)
1684       return CURLE_BAD_FUNCTION_ARGUMENT;
1685     data->set.set_resume_from = bigsize;
1686     break;
1687   case CURLOPT_DEBUGFUNCTION:
1688     /*
1689      * stderr write callback.
1690      */
1691     data->set.fdebug = va_arg(param, curl_debug_callback);
1692     /*
1693      * if the callback provided is NULL, it'll use the default callback
1694      */
1695     break;
1696   case CURLOPT_DEBUGDATA:
1697     /*
1698      * Set to a void * that should receive all error writes. This
1699      * defaults to CURLOPT_STDERR for normal operations.
1700      */
1701     data->set.debugdata = va_arg(param, void *);
1702     break;
1703   case CURLOPT_STDERR:
1704     /*
1705      * Set to a FILE * that should receive all error writes. This
1706      * defaults to stderr for normal operations.
1707      */
1708     data->set.err = va_arg(param, FILE *);
1709     if(!data->set.err)
1710       data->set.err = stderr;
1711     break;
1712   case CURLOPT_HEADERFUNCTION:
1713     /*
1714      * Set header write callback
1715      */
1716     data->set.fwrite_header = va_arg(param, curl_write_callback);
1717     break;
1718   case CURLOPT_WRITEFUNCTION:
1719     /*
1720      * Set data write callback
1721      */
1722     data->set.fwrite_func = va_arg(param, curl_write_callback);
1723     if(!data->set.fwrite_func)
1724       /* When set to NULL, reset to our internal default function */
1725       data->set.fwrite_func = (curl_write_callback)fwrite;
1726     break;
1727   case CURLOPT_READFUNCTION:
1728     /*
1729      * Read data callback
1730      */
1731     data->set.fread_func_set = va_arg(param, curl_read_callback);
1732     if(!data->set.fread_func_set) {
1733       data->set.is_fread_set = 0;
1734       /* When set to NULL, reset to our internal default function */
1735       data->set.fread_func_set = (curl_read_callback)fread;
1736     }
1737     else
1738       data->set.is_fread_set = 1;
1739     break;
1740   case CURLOPT_SEEKFUNCTION:
1741     /*
1742      * Seek callback. Might be NULL.
1743      */
1744     data->set.seek_func = va_arg(param, curl_seek_callback);
1745     break;
1746   case CURLOPT_SEEKDATA:
1747     /*
1748      * Seek control callback. Might be NULL.
1749      */
1750     data->set.seek_client = va_arg(param, void *);
1751     break;
1752   case CURLOPT_IOCTLFUNCTION:
1753     /*
1754      * I/O control callback. Might be NULL.
1755      */
1756     data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
1757     break;
1758   case CURLOPT_IOCTLDATA:
1759     /*
1760      * I/O control data pointer. Might be NULL.
1761      */
1762     data->set.ioctl_client = va_arg(param, void *);
1763     break;
1764   case CURLOPT_SSLCERT:
1765     /*
1766      * String that holds file name of the SSL certificate to use
1767      */
1768     result = Curl_setstropt(&data->set.str[STRING_CERT],
1769                             va_arg(param, char *));
1770     break;
1771   case CURLOPT_SSLCERT_BLOB:
1772     /*
1773      * Blob that holds file content of the SSL certificate to use
1774      */
1775     result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
1776                              va_arg(param, struct curl_blob *));
1777     break;
1778 #ifndef CURL_DISABLE_PROXY
1779   case CURLOPT_PROXY_SSLCERT:
1780     /*
1781      * String that holds file name of the SSL certificate to use for proxy
1782      */
1783     result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
1784                             va_arg(param, char *));
1785     break;
1786   case CURLOPT_PROXY_SSLCERT_BLOB:
1787     /*
1788      * Blob that holds file content of the SSL certificate to use for proxy
1789      */
1790     result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
1791                              va_arg(param, struct curl_blob *));
1792     break;
1793 #endif
1794   case CURLOPT_SSLCERTTYPE:
1795     /*
1796      * String that holds file type of the SSL certificate to use
1797      */
1798     result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE],
1799                             va_arg(param, char *));
1800     break;
1801 #ifndef CURL_DISABLE_PROXY
1802   case CURLOPT_PROXY_SSLCERTTYPE:
1803     /*
1804      * String that holds file type of the SSL certificate to use for proxy
1805      */
1806     result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
1807                             va_arg(param, char *));
1808     break;
1809 #endif
1810   case CURLOPT_SSLKEY:
1811     /*
1812      * String that holds file name of the SSL key to use
1813      */
1814     result = Curl_setstropt(&data->set.str[STRING_KEY],
1815                             va_arg(param, char *));
1816     break;
1817   case CURLOPT_SSLKEY_BLOB:
1818     /*
1819      * Blob that holds file content of the SSL key to use
1820      */
1821     result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
1822                              va_arg(param, struct curl_blob *));
1823     break;
1824 #ifndef CURL_DISABLE_PROXY
1825   case CURLOPT_PROXY_SSLKEY:
1826     /*
1827      * String that holds file name of the SSL key to use for proxy
1828      */
1829     result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
1830                             va_arg(param, char *));
1831     break;
1832   case CURLOPT_PROXY_SSLKEY_BLOB:
1833     /*
1834      * Blob that holds file content of the SSL key to use for proxy
1835      */
1836     result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
1837                              va_arg(param, struct curl_blob *));
1838     break;
1839 #endif
1840   case CURLOPT_SSLKEYTYPE:
1841     /*
1842      * String that holds file type of the SSL key to use
1843      */
1844     result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE],
1845                             va_arg(param, char *));
1846     break;
1847 #ifndef CURL_DISABLE_PROXY
1848   case CURLOPT_PROXY_SSLKEYTYPE:
1849     /*
1850      * String that holds file type of the SSL key to use for proxy
1851      */
1852     result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
1853                             va_arg(param, char *));
1854     break;
1855 #endif
1856   case CURLOPT_KEYPASSWD:
1857     /*
1858      * String that holds the SSL or SSH private key password.
1859      */
1860     result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD],
1861                             va_arg(param, char *));
1862     break;
1863 #ifndef CURL_DISABLE_PROXY
1864   case CURLOPT_PROXY_KEYPASSWD:
1865     /*
1866      * String that holds the SSL private key password for proxy.
1867      */
1868     result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
1869                             va_arg(param, char *));
1870     break;
1871 #endif
1872   case CURLOPT_SSLENGINE:
1873     /*
1874      * String that holds the SSL crypto engine.
1875      */
1876     argptr = va_arg(param, char *);
1877     if(argptr && argptr[0]) {
1878       result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], argptr);
1879       if(!result) {
1880         result = Curl_ssl_set_engine(data, argptr);
1881       }
1882     }
1883     break;
1884 
1885   case CURLOPT_SSLENGINE_DEFAULT:
1886     /*
1887      * flag to set engine as default.
1888      */
1889     Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
1890     result = Curl_ssl_set_engine_default(data);
1891     break;
1892   case CURLOPT_CRLF:
1893     /*
1894      * Kludgy option to enable CRLF conversions. Subject for removal.
1895      */
1896     data->set.crlf = (0 != va_arg(param, long));
1897     break;
1898 #ifndef CURL_DISABLE_PROXY
1899   case CURLOPT_HAPROXYPROTOCOL:
1900     /*
1901      * Set to send the HAProxy Proxy Protocol header
1902      */
1903     data->set.haproxyprotocol = (0 != va_arg(param, long));
1904     break;
1905   case CURLOPT_HAPROXY_CLIENT_IP:
1906     /*
1907      * Set the client IP to send through HAProxy PROXY protocol
1908      */
1909     result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP],
1910                             va_arg(param, char *));
1911     /* We enable implicitly the HAProxy protocol if we use this flag. */
1912     data->set.haproxyprotocol = TRUE;
1913     break;
1914 #endif
1915   case CURLOPT_INTERFACE:
1916     /*
1917      * Set what interface or address/hostname to bind the socket to when
1918      * performing an operation and thus what from-IP your connection will use.
1919      */
1920     result = setstropt_interface(va_arg(param, char *),
1921                                  &data->set.str[STRING_DEVICE],
1922                                  &data->set.str[STRING_INTERFACE],
1923                                  &data->set.str[STRING_BINDHOST]);
1924     break;
1925 #ifndef CURL_DISABLE_BINDLOCAL
1926   case CURLOPT_LOCALPORT:
1927     /*
1928      * Set what local port to bind the socket to when performing an operation.
1929      */
1930     arg = va_arg(param, long);
1931     if((arg < 0) || (arg > 65535))
1932       return CURLE_BAD_FUNCTION_ARGUMENT;
1933     data->set.localport = curlx_sltous(arg);
1934     break;
1935   case CURLOPT_LOCALPORTRANGE:
1936     /*
1937      * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
1938      */
1939     arg = va_arg(param, long);
1940     if((arg < 0) || (arg > 65535))
1941       return CURLE_BAD_FUNCTION_ARGUMENT;
1942     data->set.localportrange = curlx_sltous(arg);
1943     break;
1944 #endif
1945   case CURLOPT_GSSAPI_DELEGATION:
1946     /*
1947      * GSS-API credential delegation bitmask
1948      */
1949     uarg = va_arg(param, unsigned long);
1950     data->set.gssapi_delegation = (unsigned char)uarg&
1951       (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG);
1952     break;
1953   case CURLOPT_SSL_VERIFYPEER:
1954     /*
1955      * Enable peer SSL verifying.
1956      */
1957     data->set.ssl.primary.verifypeer = (0 != va_arg(param, long));
1958 
1959     /* Update the current connection ssl_config. */
1960     Curl_ssl_conn_config_update(data, FALSE);
1961     break;
1962 #ifndef CURL_DISABLE_DOH
1963   case CURLOPT_DOH_SSL_VERIFYPEER:
1964     /*
1965      * Enable peer SSL verifying for DoH.
1966      */
1967     data->set.doh_verifypeer = (0 != va_arg(param, long));
1968     break;
1969 #endif
1970 #ifndef CURL_DISABLE_PROXY
1971   case CURLOPT_PROXY_SSL_VERIFYPEER:
1972     /*
1973      * Enable peer SSL verifying for proxy.
1974      */
1975     data->set.proxy_ssl.primary.verifypeer =
1976       (0 != va_arg(param, long))?TRUE:FALSE;
1977 
1978     /* Update the current connection proxy_ssl_config. */
1979     Curl_ssl_conn_config_update(data, TRUE);
1980     break;
1981 #endif
1982   case CURLOPT_SSL_VERIFYHOST:
1983     /*
1984      * Enable verification of the host name in the peer certificate
1985      */
1986     arg = va_arg(param, long);
1987 
1988     /* Obviously people are not reading documentation and too many thought
1989        this argument took a boolean when it wasn't and misused it.
1990        Treat 1 and 2 the same */
1991     data->set.ssl.primary.verifyhost = !!(arg & 3);
1992 
1993     /* Update the current connection ssl_config. */
1994     Curl_ssl_conn_config_update(data, FALSE);
1995     break;
1996 #ifndef CURL_DISABLE_DOH
1997   case CURLOPT_DOH_SSL_VERIFYHOST:
1998     /*
1999      * Enable verification of the host name in the peer certificate for DoH
2000      */
2001     arg = va_arg(param, long);
2002 
2003     /* Treat both 1 and 2 as TRUE */
2004     data->set.doh_verifyhost = !!(arg & 3);
2005     break;
2006 #endif
2007 #ifndef CURL_DISABLE_PROXY
2008   case CURLOPT_PROXY_SSL_VERIFYHOST:
2009     /*
2010      * Enable verification of the host name in the peer certificate for proxy
2011      */
2012     arg = va_arg(param, long);
2013 
2014     /* Treat both 1 and 2 as TRUE */
2015     data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE);
2016     /* Update the current connection proxy_ssl_config. */
2017     Curl_ssl_conn_config_update(data, TRUE);
2018     break;
2019 #endif
2020   case CURLOPT_SSL_VERIFYSTATUS:
2021     /*
2022      * Enable certificate status verifying.
2023      */
2024     if(!Curl_ssl_cert_status_request()) {
2025       result = CURLE_NOT_BUILT_IN;
2026       break;
2027     }
2028 
2029     data->set.ssl.primary.verifystatus = (0 != va_arg(param, long));
2030 
2031     /* Update the current connection ssl_config. */
2032     Curl_ssl_conn_config_update(data, FALSE);
2033     break;
2034 #ifndef CURL_DISABLE_DOH
2035   case CURLOPT_DOH_SSL_VERIFYSTATUS:
2036     /*
2037      * Enable certificate status verifying for DoH.
2038      */
2039     if(!Curl_ssl_cert_status_request()) {
2040       result = CURLE_NOT_BUILT_IN;
2041       break;
2042     }
2043 
2044     data->set.doh_verifystatus = (0 != va_arg(param, long));
2045     break;
2046 #endif
2047   case CURLOPT_SSL_CTX_FUNCTION:
2048     /*
2049      * Set a SSL_CTX callback
2050      */
2051 #ifdef USE_SSL
2052     if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
2053       data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
2054     else
2055 #endif
2056       result = CURLE_NOT_BUILT_IN;
2057     break;
2058   case CURLOPT_SSL_CTX_DATA:
2059     /*
2060      * Set a SSL_CTX callback parameter pointer
2061      */
2062 #ifdef USE_SSL
2063     if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
2064       data->set.ssl.fsslctxp = va_arg(param, void *);
2065     else
2066 #endif
2067       result = CURLE_NOT_BUILT_IN;
2068     break;
2069   case CURLOPT_SSL_FALSESTART:
2070     /*
2071      * Enable TLS false start.
2072      */
2073     if(!Curl_ssl_false_start(data)) {
2074       result = CURLE_NOT_BUILT_IN;
2075       break;
2076     }
2077 
2078     data->set.ssl.falsestart = (0 != va_arg(param, long));
2079     break;
2080   case CURLOPT_CERTINFO:
2081 #ifdef USE_SSL
2082     if(Curl_ssl_supports(data, SSLSUPP_CERTINFO))
2083       data->set.ssl.certinfo = (0 != va_arg(param, long));
2084     else
2085 #endif
2086       result = CURLE_NOT_BUILT_IN;
2087     break;
2088   case CURLOPT_PINNEDPUBLICKEY:
2089     /*
2090      * Set pinned public key for SSL connection.
2091      * Specify file name of the public key in DER format.
2092      */
2093 #ifdef USE_SSL
2094     if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
2095       result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
2096                               va_arg(param, char *));
2097     else
2098 #endif
2099       result = CURLE_NOT_BUILT_IN;
2100     break;
2101 #ifndef CURL_DISABLE_PROXY
2102   case CURLOPT_PROXY_PINNEDPUBLICKEY:
2103     /*
2104      * Set pinned public key for SSL connection.
2105      * Specify file name of the public key in DER format.
2106      */
2107 #ifdef USE_SSL
2108     if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
2109       result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
2110                               va_arg(param, char *));
2111     else
2112 #endif
2113       result = CURLE_NOT_BUILT_IN;
2114     break;
2115 #endif
2116   case CURLOPT_CAINFO:
2117     /*
2118      * Set CA info for SSL connection. Specify file name of the CA certificate
2119      */
2120     result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
2121                             va_arg(param, char *));
2122     break;
2123   case CURLOPT_CAINFO_BLOB:
2124     /*
2125      * Blob that holds CA info for SSL connection.
2126      * Specify entire PEM of the CA certificate
2127      */
2128 #ifdef USE_SSL
2129     if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
2130       result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
2131                                va_arg(param, struct curl_blob *));
2132       break;
2133     }
2134     else
2135 #endif
2136       return CURLE_NOT_BUILT_IN;
2137 #ifndef CURL_DISABLE_PROXY
2138   case CURLOPT_PROXY_CAINFO:
2139     /*
2140      * Set CA info SSL connection for proxy. Specify file name of the
2141      * CA certificate
2142      */
2143     result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
2144                             va_arg(param, char *));
2145     break;
2146   case CURLOPT_PROXY_CAINFO_BLOB:
2147     /*
2148      * Blob that holds CA info for SSL connection proxy.
2149      * Specify entire PEM of the CA certificate
2150      */
2151 #ifdef USE_SSL
2152     if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) {
2153       result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
2154                                va_arg(param, struct curl_blob *));
2155       break;
2156     }
2157     else
2158 #endif
2159       return CURLE_NOT_BUILT_IN;
2160 #endif
2161   case CURLOPT_CAPATH:
2162     /*
2163      * Set CA path info for SSL connection. Specify directory name of the CA
2164      * certificates which have been prepared using openssl c_rehash utility.
2165      */
2166 #ifdef USE_SSL
2167     if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
2168       /* This does not work on windows. */
2169       result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
2170                               va_arg(param, char *));
2171     else
2172 #endif
2173       result = CURLE_NOT_BUILT_IN;
2174     break;
2175 #ifndef CURL_DISABLE_PROXY
2176   case CURLOPT_PROXY_CAPATH:
2177     /*
2178      * Set CA path info for SSL connection proxy. Specify directory name of the
2179      * CA certificates which have been prepared using openssl c_rehash utility.
2180      */
2181 #ifdef USE_SSL
2182     if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
2183       /* This does not work on windows. */
2184       result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
2185                               va_arg(param, char *));
2186     else
2187 #endif
2188       result = CURLE_NOT_BUILT_IN;
2189     break;
2190 #endif
2191   case CURLOPT_CRLFILE:
2192     /*
2193      * Set CRL file info for SSL connection. Specify file name of the CRL
2194      * to check certificates revocation
2195      */
2196     result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
2197                             va_arg(param, char *));
2198     break;
2199 #ifndef CURL_DISABLE_PROXY
2200   case CURLOPT_PROXY_CRLFILE:
2201     /*
2202      * Set CRL file info for SSL connection for proxy. Specify file name of the
2203      * CRL to check certificates revocation
2204      */
2205     result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
2206                             va_arg(param, char *));
2207     break;
2208 #endif
2209   case CURLOPT_ISSUERCERT:
2210     /*
2211      * Set Issuer certificate file
2212      * to check certificates issuer
2213      */
2214     result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
2215                             va_arg(param, char *));
2216     break;
2217   case CURLOPT_ISSUERCERT_BLOB:
2218     /*
2219      * Blob that holds Issuer certificate to check certificates issuer
2220      */
2221     result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT],
2222                              va_arg(param, struct curl_blob *));
2223     break;
2224 #ifndef CURL_DISABLE_PROXY
2225   case CURLOPT_PROXY_ISSUERCERT:
2226     /*
2227      * Set Issuer certificate file
2228      * to check certificates issuer
2229      */
2230     result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY],
2231                             va_arg(param, char *));
2232     break;
2233   case CURLOPT_PROXY_ISSUERCERT_BLOB:
2234     /*
2235      * Blob that holds Issuer certificate to check certificates issuer
2236      */
2237     result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY],
2238                              va_arg(param, struct curl_blob *));
2239     break;
2240 #endif
2241 #ifndef CURL_DISABLE_TELNET
2242   case CURLOPT_TELNETOPTIONS:
2243     /*
2244      * Set a linked list of telnet options
2245      */
2246     data->set.telnet_options = va_arg(param, struct curl_slist *);
2247     break;
2248 #endif
2249   case CURLOPT_BUFFERSIZE:
2250     /*
2251      * The application kindly asks for a differently sized receive buffer.
2252      * If it seems reasonable, we'll use it.
2253      */
2254     arg = va_arg(param, long);
2255 
2256     if(arg > READBUFFER_MAX)
2257       arg = READBUFFER_MAX;
2258     else if(arg < 1)
2259       arg = READBUFFER_SIZE;
2260     else if(arg < READBUFFER_MIN)
2261       arg = READBUFFER_MIN;
2262 
2263     data->set.buffer_size = (unsigned int)arg;
2264     break;
2265 
2266   case CURLOPT_UPLOAD_BUFFERSIZE:
2267     /*
2268      * The application kindly asks for a differently sized upload buffer.
2269      * Cap it to sensible.
2270      */
2271     arg = va_arg(param, long);
2272 
2273     if(arg > UPLOADBUFFER_MAX)
2274       arg = UPLOADBUFFER_MAX;
2275     else if(arg < UPLOADBUFFER_MIN)
2276       arg = UPLOADBUFFER_MIN;
2277 
2278     data->set.upload_buffer_size = (unsigned int)arg;
2279     break;
2280 
2281   case CURLOPT_NOSIGNAL:
2282     /*
2283      * The application asks not to set any signal() or alarm() handlers,
2284      * even when using a timeout.
2285      */
2286     data->set.no_signal = (0 != va_arg(param, long));
2287     break;
2288 
2289   case CURLOPT_SHARE:
2290   {
2291     struct Curl_share *set;
2292     set = va_arg(param, struct Curl_share *);
2293 
2294     /* disconnect from old share, if any */
2295     if(data->share) {
2296       Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
2297 
2298       if(data->dns.hostcachetype == HCACHE_SHARED) {
2299         data->dns.hostcache = NULL;
2300         data->dns.hostcachetype = HCACHE_NONE;
2301       }
2302 
2303 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
2304       if(data->share->cookies == data->cookies)
2305         data->cookies = NULL;
2306 #endif
2307 
2308 #ifndef CURL_DISABLE_HSTS
2309       if(data->share->hsts == data->hsts)
2310         data->hsts = NULL;
2311 #endif
2312 #ifdef USE_SSL
2313       if(data->share->sslsession == data->state.session)
2314         data->state.session = NULL;
2315 #endif
2316 #ifdef USE_LIBPSL
2317       if(data->psl == &data->share->psl)
2318         data->psl = data->multi? &data->multi->psl: NULL;
2319 #endif
2320 
2321       data->share->dirty--;
2322 
2323       Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
2324       data->share = NULL;
2325     }
2326 
2327     if(GOOD_SHARE_HANDLE(set))
2328       /* use new share if it set */
2329       data->share = set;
2330     if(data->share) {
2331 
2332       Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
2333 
2334       data->share->dirty++;
2335 
2336       if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) {
2337         /* use shared host cache */
2338         data->dns.hostcache = &data->share->hostcache;
2339         data->dns.hostcachetype = HCACHE_SHARED;
2340       }
2341 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
2342       if(data->share->cookies) {
2343         /* use shared cookie list, first free own one if any */
2344         Curl_cookie_cleanup(data->cookies);
2345         /* enable cookies since we now use a share that uses cookies! */
2346         data->cookies = data->share->cookies;
2347       }
2348 #endif   /* CURL_DISABLE_HTTP */
2349 #ifndef CURL_DISABLE_HSTS
2350       if(data->share->hsts) {
2351         /* first free the private one if any */
2352         Curl_hsts_cleanup(&data->hsts);
2353         data->hsts = data->share->hsts;
2354       }
2355 #endif
2356 #ifdef USE_SSL
2357       if(data->share->sslsession) {
2358         data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
2359         data->state.session = data->share->sslsession;
2360       }
2361 #endif
2362 #ifdef USE_LIBPSL
2363       if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
2364         data->psl = &data->share->psl;
2365 #endif
2366 
2367       Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
2368     }
2369     /* check for host cache not needed,
2370      * it will be done by curl_easy_perform */
2371   }
2372   break;
2373 
2374   case CURLOPT_PRIVATE:
2375     /*
2376      * Set private data pointer.
2377      */
2378     data->set.private_data = va_arg(param, void *);
2379     break;
2380 
2381   case CURLOPT_MAXFILESIZE:
2382     /*
2383      * Set the maximum size of a file to download.
2384      */
2385     arg = va_arg(param, long);
2386     if(arg < 0)
2387       return CURLE_BAD_FUNCTION_ARGUMENT;
2388     data->set.max_filesize = arg;
2389     break;
2390 
2391 #ifdef USE_SSL
2392   case CURLOPT_USE_SSL:
2393     /*
2394      * Make transfers attempt to use SSL/TLS.
2395      */
2396     arg = va_arg(param, long);
2397     if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
2398       return CURLE_BAD_FUNCTION_ARGUMENT;
2399     data->set.use_ssl = (unsigned char)arg;
2400     break;
2401 
2402   case CURLOPT_SSL_OPTIONS:
2403     arg = va_arg(param, long);
2404     data->set.ssl.primary.ssl_options = (unsigned char)(arg & 0xff);
2405     data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
2406     data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
2407     data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
2408     data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
2409     data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
2410     data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
2411     /* If a setting is added here it should also be added in dohprobe()
2412        which sets its own CURLOPT_SSL_OPTIONS based on these settings. */
2413     break;
2414 
2415 #ifndef CURL_DISABLE_PROXY
2416   case CURLOPT_PROXY_SSL_OPTIONS:
2417     arg = va_arg(param, long);
2418     data->set.proxy_ssl.primary.ssl_options = (unsigned char)(arg & 0xff);
2419     data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
2420     data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
2421     data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
2422     data->set.proxy_ssl.revoke_best_effort =
2423       !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
2424     data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
2425     data->set.proxy_ssl.auto_client_cert =
2426       !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
2427     break;
2428 #endif
2429 
2430   case CURLOPT_SSL_EC_CURVES:
2431     /*
2432      * Set accepted curves in SSL connection setup.
2433      * Specify colon-delimited list of curve algorithm names.
2434      */
2435     result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES],
2436                             va_arg(param, char *));
2437     break;
2438 #endif
2439   case CURLOPT_IPRESOLVE:
2440     arg = va_arg(param, long);
2441     if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
2442       return CURLE_BAD_FUNCTION_ARGUMENT;
2443     data->set.ipver = (unsigned char) arg;
2444     break;
2445 
2446   case CURLOPT_MAXFILESIZE_LARGE:
2447     /*
2448      * Set the maximum size of a file to download.
2449      */
2450     bigsize = va_arg(param, curl_off_t);
2451     if(bigsize < 0)
2452       return CURLE_BAD_FUNCTION_ARGUMENT;
2453     data->set.max_filesize = bigsize;
2454     break;
2455 
2456   case CURLOPT_TCP_NODELAY:
2457     /*
2458      * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
2459      * algorithm
2460      */
2461     data->set.tcp_nodelay = (0 != va_arg(param, long));
2462     break;
2463 
2464   case CURLOPT_IGNORE_CONTENT_LENGTH:
2465     data->set.ignorecl = (0 != va_arg(param, long));
2466     break;
2467 
2468   case CURLOPT_CONNECT_ONLY:
2469     /*
2470      * No data transfer.
2471      * (1) - only do connection
2472      * (2) - do first get request but get no content
2473      */
2474     arg = va_arg(param, long);
2475     if(arg > 2)
2476       return CURLE_BAD_FUNCTION_ARGUMENT;
2477     data->set.connect_only = (unsigned char)arg;
2478     break;
2479 
2480   case CURLOPT_SOCKOPTFUNCTION:
2481     /*
2482      * socket callback function: called after socket() but before connect()
2483      */
2484     data->set.fsockopt = va_arg(param, curl_sockopt_callback);
2485     break;
2486 
2487   case CURLOPT_SOCKOPTDATA:
2488     /*
2489      * socket callback data pointer. Might be NULL.
2490      */
2491     data->set.sockopt_client = va_arg(param, void *);
2492     break;
2493 
2494   case CURLOPT_OPENSOCKETFUNCTION:
2495     /*
2496      * open/create socket callback function: called instead of socket(),
2497      * before connect()
2498      */
2499     data->set.fopensocket = va_arg(param, curl_opensocket_callback);
2500     break;
2501 
2502   case CURLOPT_OPENSOCKETDATA:
2503     /*
2504      * socket callback data pointer. Might be NULL.
2505      */
2506     data->set.opensocket_client = va_arg(param, void *);
2507     break;
2508 
2509   case CURLOPT_CLOSESOCKETFUNCTION:
2510     /*
2511      * close socket callback function: called instead of close()
2512      * when shutting down a connection
2513      */
2514     data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
2515     break;
2516 
2517   case CURLOPT_RESOLVER_START_FUNCTION:
2518     /*
2519      * resolver start callback function: called before a new resolver request
2520      * is started
2521      */
2522     data->set.resolver_start = va_arg(param, curl_resolver_start_callback);
2523     break;
2524 
2525   case CURLOPT_RESOLVER_START_DATA:
2526     /*
2527      * resolver start callback data pointer. Might be NULL.
2528      */
2529     data->set.resolver_start_client = va_arg(param, void *);
2530     break;
2531 
2532   case CURLOPT_CLOSESOCKETDATA:
2533     /*
2534      * socket callback data pointer. Might be NULL.
2535      */
2536     data->set.closesocket_client = va_arg(param, void *);
2537     break;
2538 
2539   case CURLOPT_SSL_SESSIONID_CACHE:
2540     data->set.ssl.primary.sessionid = (0 != va_arg(param, long));
2541 #ifndef CURL_DISABLE_PROXY
2542     data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
2543 #endif
2544     break;
2545 
2546 #ifdef USE_SSH
2547     /* we only include SSH options if explicitly built to support SSH */
2548   case CURLOPT_SSH_AUTH_TYPES:
2549     data->set.ssh_auth_types = (int)va_arg(param, long);
2550     break;
2551 
2552   case CURLOPT_SSH_PUBLIC_KEYFILE:
2553     /*
2554      * Use this file instead of the $HOME/.ssh/id_dsa.pub file
2555      */
2556     result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
2557                             va_arg(param, char *));
2558     break;
2559 
2560   case CURLOPT_SSH_PRIVATE_KEYFILE:
2561     /*
2562      * Use this file instead of the $HOME/.ssh/id_dsa file
2563      */
2564     result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
2565                             va_arg(param, char *));
2566     break;
2567   case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
2568     /*
2569      * Option to allow for the MD5 of the host public key to be checked
2570      * for validation purposes.
2571      */
2572     result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
2573                             va_arg(param, char *));
2574     break;
2575 
2576   case CURLOPT_SSH_KNOWNHOSTS:
2577     /*
2578      * Store the file name to read known hosts from.
2579      */
2580     result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
2581                             va_arg(param, char *));
2582     break;
2583 #ifdef USE_LIBSSH2
2584   case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
2585     /*
2586      * Option to allow for the SHA256 of the host public key to be checked
2587      * for validation purposes.
2588      */
2589     result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
2590                             va_arg(param, char *));
2591     break;
2592 
2593   case CURLOPT_SSH_HOSTKEYFUNCTION:
2594     /* the callback to check the hostkey without the knownhost file */
2595     data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback);
2596     break;
2597 
2598   case CURLOPT_SSH_HOSTKEYDATA:
2599     /*
2600      * Custom client data to pass to the SSH keyfunc callback
2601      */
2602     data->set.ssh_hostkeyfunc_userp = va_arg(param, void *);
2603     break;
2604 #endif
2605 
2606   case CURLOPT_SSH_KEYFUNCTION:
2607     /* setting to NULL is fine since the ssh.c functions themselves will
2608        then revert to use the internal default */
2609     data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
2610     break;
2611 
2612   case CURLOPT_SSH_KEYDATA:
2613     /*
2614      * Custom client data to pass to the SSH keyfunc callback
2615      */
2616     data->set.ssh_keyfunc_userp = va_arg(param, void *);
2617     break;
2618 
2619   case CURLOPT_SSH_COMPRESSION:
2620     data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
2621     break;
2622 #endif /* USE_SSH */
2623 
2624   case CURLOPT_HTTP_TRANSFER_DECODING:
2625     /*
2626      * disable libcurl transfer encoding is used
2627      */
2628 #ifndef USE_HYPER
2629     data->set.http_te_skip = (0 == va_arg(param, long));
2630     break;
2631 #else
2632     return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
2633 #endif
2634 
2635   case CURLOPT_HTTP_CONTENT_DECODING:
2636     /*
2637      * raw data passed to the application when content encoding is used
2638      */
2639     data->set.http_ce_skip = (0 == va_arg(param, long));
2640     break;
2641 
2642 #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
2643   case CURLOPT_NEW_FILE_PERMS:
2644     /*
2645      * Uses these permissions instead of 0644
2646      */
2647     arg = va_arg(param, long);
2648     if((arg < 0) || (arg > 0777))
2649       return CURLE_BAD_FUNCTION_ARGUMENT;
2650     data->set.new_file_perms = (unsigned int)arg;
2651     break;
2652 #endif
2653 #ifdef USE_SSH
2654   case CURLOPT_NEW_DIRECTORY_PERMS:
2655     /*
2656      * Uses these permissions instead of 0755
2657      */
2658     arg = va_arg(param, long);
2659     if((arg < 0) || (arg > 0777))
2660       return CURLE_BAD_FUNCTION_ARGUMENT;
2661     data->set.new_directory_perms = (unsigned int)arg;
2662     break;
2663 #endif
2664 
2665 #ifdef USE_IPV6
2666   case CURLOPT_ADDRESS_SCOPE:
2667     /*
2668      * Use this scope id when using IPv6
2669      * We always get longs when passed plain numericals so we should check
2670      * that the value fits into an unsigned 32 bit integer.
2671      */
2672     uarg = va_arg(param, unsigned long);
2673 #if SIZEOF_LONG > 4
2674     if(uarg > UINT_MAX)
2675       return CURLE_BAD_FUNCTION_ARGUMENT;
2676 #endif
2677     data->set.scope_id = (unsigned int)uarg;
2678     break;
2679 #endif
2680 
2681   case CURLOPT_PROTOCOLS:
2682     /* set the bitmask for the protocols that are allowed to be used for the
2683        transfer, which thus helps the app which takes URLs from users or other
2684        external inputs and want to restrict what protocol(s) to deal
2685        with. Defaults to CURLPROTO_ALL. */
2686     data->set.allowed_protocols = (curl_prot_t)va_arg(param, long);
2687     break;
2688 
2689   case CURLOPT_REDIR_PROTOCOLS:
2690     /* set the bitmask for the protocols that libcurl is allowed to follow to,
2691        as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
2692        to be set in both bitmasks to be allowed to get redirected to. */
2693     data->set.redir_protocols = (curl_prot_t)va_arg(param, long);
2694     break;
2695 
2696   case CURLOPT_PROTOCOLS_STR: {
2697     argptr = va_arg(param, char *);
2698     result = protocol2num(argptr, &data->set.allowed_protocols);
2699     if(result)
2700       return result;
2701     break;
2702   }
2703 
2704   case CURLOPT_REDIR_PROTOCOLS_STR: {
2705     argptr = va_arg(param, char *);
2706     result = protocol2num(argptr, &data->set.redir_protocols);
2707     if(result)
2708       return result;
2709     break;
2710   }
2711 
2712   case CURLOPT_DEFAULT_PROTOCOL:
2713     /* Set the protocol to use when the URL doesn't include any protocol */
2714     result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
2715                             va_arg(param, char *));
2716     break;
2717 #ifndef CURL_DISABLE_SMTP
2718   case CURLOPT_MAIL_FROM:
2719     /* Set the SMTP mail originator */
2720     result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],
2721                             va_arg(param, char *));
2722     break;
2723 
2724   case CURLOPT_MAIL_AUTH:
2725     /* Set the SMTP auth originator */
2726     result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH],
2727                             va_arg(param, char *));
2728     break;
2729 
2730   case CURLOPT_MAIL_RCPT:
2731     /* Set the list of mail recipients */
2732     data->set.mail_rcpt = va_arg(param, struct curl_slist *);
2733     break;
2734   case CURLOPT_MAIL_RCPT_ALLOWFAILS:
2735     /* allow RCPT TO command to fail for some recipients */
2736     data->set.mail_rcpt_allowfails = (0 != va_arg(param, long));
2737     break;
2738 #endif
2739 
2740   case CURLOPT_SASL_AUTHZID:
2741     /* Authorization identity (identity to act as) */
2742     result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],
2743                             va_arg(param, char *));
2744     break;
2745 
2746   case CURLOPT_SASL_IR:
2747     /* Enable/disable SASL initial response */
2748     data->set.sasl_ir = (0 != va_arg(param, long));
2749     break;
2750 #ifndef CURL_DISABLE_RTSP
2751   case CURLOPT_RTSP_REQUEST:
2752   {
2753     /*
2754      * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
2755      * Would this be better if the RTSPREQ_* were just moved into here?
2756      */
2757     long in_rtspreq = va_arg(param, long);
2758     Curl_RtspReq rtspreq = RTSPREQ_NONE;
2759     switch(in_rtspreq) {
2760     case CURL_RTSPREQ_OPTIONS:
2761       rtspreq = RTSPREQ_OPTIONS;
2762       break;
2763 
2764     case CURL_RTSPREQ_DESCRIBE:
2765       rtspreq = RTSPREQ_DESCRIBE;
2766       break;
2767 
2768     case CURL_RTSPREQ_ANNOUNCE:
2769       rtspreq = RTSPREQ_ANNOUNCE;
2770       break;
2771 
2772     case CURL_RTSPREQ_SETUP:
2773       rtspreq = RTSPREQ_SETUP;
2774       break;
2775 
2776     case CURL_RTSPREQ_PLAY:
2777       rtspreq = RTSPREQ_PLAY;
2778       break;
2779 
2780     case CURL_RTSPREQ_PAUSE:
2781       rtspreq = RTSPREQ_PAUSE;
2782       break;
2783 
2784     case CURL_RTSPREQ_TEARDOWN:
2785       rtspreq = RTSPREQ_TEARDOWN;
2786       break;
2787 
2788     case CURL_RTSPREQ_GET_PARAMETER:
2789       rtspreq = RTSPREQ_GET_PARAMETER;
2790       break;
2791 
2792     case CURL_RTSPREQ_SET_PARAMETER:
2793       rtspreq = RTSPREQ_SET_PARAMETER;
2794       break;
2795 
2796     case CURL_RTSPREQ_RECORD:
2797       rtspreq = RTSPREQ_RECORD;
2798       break;
2799 
2800     case CURL_RTSPREQ_RECEIVE:
2801       rtspreq = RTSPREQ_RECEIVE;
2802       break;
2803     default:
2804       rtspreq = RTSPREQ_NONE;
2805     }
2806 
2807     data->set.rtspreq = rtspreq;
2808     break;
2809   }
2810 
2811 
2812   case CURLOPT_RTSP_SESSION_ID:
2813     /*
2814      * Set the RTSP Session ID manually. Useful if the application is
2815      * resuming a previously established RTSP session
2816      */
2817     result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
2818                             va_arg(param, char *));
2819     break;
2820 
2821   case CURLOPT_RTSP_STREAM_URI:
2822     /*
2823      * Set the Stream URI for the RTSP request. Unless the request is
2824      * for generic server options, the application will need to set this.
2825      */
2826     result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
2827                             va_arg(param, char *));
2828     break;
2829 
2830   case CURLOPT_RTSP_TRANSPORT:
2831     /*
2832      * The content of the Transport: header for the RTSP request
2833      */
2834     result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
2835                             va_arg(param, char *));
2836     break;
2837 
2838   case CURLOPT_RTSP_CLIENT_CSEQ:
2839     /*
2840      * Set the CSEQ number to issue for the next RTSP request. Useful if the
2841      * application is resuming a previously broken connection. The CSEQ
2842      * will increment from this new number henceforth.
2843      */
2844     data->state.rtsp_next_client_CSeq = va_arg(param, long);
2845     break;
2846 
2847   case CURLOPT_RTSP_SERVER_CSEQ:
2848     /* Same as the above, but for server-initiated requests */
2849     data->state.rtsp_next_server_CSeq = va_arg(param, long);
2850     break;
2851 
2852   case CURLOPT_INTERLEAVEDATA:
2853     data->set.rtp_out = va_arg(param, void *);
2854     break;
2855   case CURLOPT_INTERLEAVEFUNCTION:
2856     /* Set the user defined RTP write function */
2857     data->set.fwrite_rtp = va_arg(param, curl_write_callback);
2858     break;
2859 #endif
2860 #ifndef CURL_DISABLE_FTP
2861   case CURLOPT_WILDCARDMATCH:
2862     data->set.wildcard_enabled = (0 != va_arg(param, long));
2863     break;
2864   case CURLOPT_CHUNK_BGN_FUNCTION:
2865     data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
2866     break;
2867   case CURLOPT_CHUNK_END_FUNCTION:
2868     data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
2869     break;
2870   case CURLOPT_FNMATCH_FUNCTION:
2871     data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
2872     break;
2873   case CURLOPT_CHUNK_DATA:
2874     data->set.wildcardptr = va_arg(param, void *);
2875     break;
2876   case CURLOPT_FNMATCH_DATA:
2877     data->set.fnmatch_data = va_arg(param, void *);
2878     break;
2879 #endif
2880 #ifdef USE_TLS_SRP
2881   case CURLOPT_TLSAUTH_USERNAME:
2882     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME],
2883                             va_arg(param, char *));
2884     break;
2885 #ifndef CURL_DISABLE_PROXY
2886   case CURLOPT_PROXY_TLSAUTH_USERNAME:
2887     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
2888                             va_arg(param, char *));
2889     break;
2890 #endif
2891   case CURLOPT_TLSAUTH_PASSWORD:
2892     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
2893                             va_arg(param, char *));
2894     break;
2895 #ifndef CURL_DISABLE_PROXY
2896   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
2897     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
2898                             va_arg(param, char *));
2899     break;
2900 #endif
2901   case CURLOPT_TLSAUTH_TYPE:
2902     argptr = va_arg(param, char *);
2903     if(argptr && !strcasecompare(argptr, "SRP"))
2904       return CURLE_BAD_FUNCTION_ARGUMENT;
2905     break;
2906 #ifndef CURL_DISABLE_PROXY
2907   case CURLOPT_PROXY_TLSAUTH_TYPE:
2908     argptr = va_arg(param, char *);
2909     if(argptr && !strcasecompare(argptr, "SRP"))
2910       return CURLE_BAD_FUNCTION_ARGUMENT;
2911     break;
2912 #endif
2913 #endif
2914 #ifdef USE_ARES
2915   case CURLOPT_DNS_SERVERS:
2916     result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS],
2917                             va_arg(param, char *));
2918     if(result)
2919       return result;
2920     result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
2921     break;
2922   case CURLOPT_DNS_INTERFACE:
2923     result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE],
2924                             va_arg(param, char *));
2925     if(result)
2926       return result;
2927     result = Curl_set_dns_interface(data, data->set.str[STRING_DNS_INTERFACE]);
2928     break;
2929   case CURLOPT_DNS_LOCAL_IP4:
2930     result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4],
2931                             va_arg(param, char *));
2932     if(result)
2933       return result;
2934     result = Curl_set_dns_local_ip4(data, data->set.str[STRING_DNS_LOCAL_IP4]);
2935     break;
2936   case CURLOPT_DNS_LOCAL_IP6:
2937     result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6],
2938                             va_arg(param, char *));
2939     if(result)
2940       return result;
2941     result = Curl_set_dns_local_ip6(data, data->set.str[STRING_DNS_LOCAL_IP6]);
2942     break;
2943 #endif
2944   case CURLOPT_TCP_KEEPALIVE:
2945     data->set.tcp_keepalive = (0 != va_arg(param, long));
2946     break;
2947   case CURLOPT_TCP_KEEPIDLE:
2948     arg = va_arg(param, long);
2949     if(arg < 0)
2950       return CURLE_BAD_FUNCTION_ARGUMENT;
2951     else if(arg > INT_MAX)
2952       arg = INT_MAX;
2953     data->set.tcp_keepidle = (int)arg;
2954     break;
2955   case CURLOPT_TCP_KEEPINTVL:
2956     arg = va_arg(param, long);
2957     if(arg < 0)
2958       return CURLE_BAD_FUNCTION_ARGUMENT;
2959     else if(arg > INT_MAX)
2960       arg = INT_MAX;
2961     data->set.tcp_keepintvl = (int)arg;
2962     break;
2963   case CURLOPT_TCP_KEEPCNT:
2964     arg = va_arg(param, long);
2965     if(arg < 0)
2966       return CURLE_BAD_FUNCTION_ARGUMENT;
2967     else if(arg > INT_MAX)
2968       arg = INT_MAX;
2969     data->set.tcp_keepcnt = (int)arg;
2970     break;
2971   case CURLOPT_TCP_FASTOPEN:
2972 #if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
2973    defined(TCP_FASTOPEN_CONNECT)
2974     data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
2975 #else
2976     result = CURLE_NOT_BUILT_IN;
2977 #endif
2978     break;
2979   case CURLOPT_SSL_ENABLE_NPN:
2980     break;
2981   case CURLOPT_SSL_ENABLE_ALPN:
2982     data->set.ssl_enable_alpn = (0 != va_arg(param, long));
2983     break;
2984 #ifdef USE_UNIX_SOCKETS
2985   case CURLOPT_UNIX_SOCKET_PATH:
2986     data->set.abstract_unix_socket = FALSE;
2987     result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
2988                             va_arg(param, char *));
2989     break;
2990   case CURLOPT_ABSTRACT_UNIX_SOCKET:
2991     data->set.abstract_unix_socket = TRUE;
2992     result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
2993                             va_arg(param, char *));
2994     break;
2995 #endif
2996 
2997   case CURLOPT_PATH_AS_IS:
2998     data->set.path_as_is = (0 != va_arg(param, long));
2999     break;
3000   case CURLOPT_PIPEWAIT:
3001     data->set.pipewait = (0 != va_arg(param, long));
3002     break;
3003   case CURLOPT_STREAM_WEIGHT:
3004 #if defined(USE_HTTP2) || defined(USE_HTTP3)
3005     arg = va_arg(param, long);
3006     if((arg >= 1) && (arg <= 256))
3007       data->set.priority.weight = (int)arg;
3008     break;
3009 #else
3010     return CURLE_NOT_BUILT_IN;
3011 #endif
3012   case CURLOPT_STREAM_DEPENDS:
3013   case CURLOPT_STREAM_DEPENDS_E:
3014   {
3015     struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
3016     if(!dep || GOOD_EASY_HANDLE(dep)) {
3017       return Curl_data_priority_add_child(dep, data,
3018                                           option == CURLOPT_STREAM_DEPENDS_E);
3019     }
3020     break;
3021   }
3022   case CURLOPT_CONNECT_TO:
3023     data->set.connect_to = va_arg(param, struct curl_slist *);
3024     break;
3025   case CURLOPT_SUPPRESS_CONNECT_HEADERS:
3026     data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
3027     break;
3028   case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
3029     uarg = va_arg(param, unsigned long);
3030     if(uarg > UINT_MAX)
3031       uarg = UINT_MAX;
3032     data->set.happy_eyeballs_timeout = (unsigned int)uarg;
3033     break;
3034 #ifndef CURL_DISABLE_SHUFFLE_DNS
3035   case CURLOPT_DNS_SHUFFLE_ADDRESSES:
3036     data->set.dns_shuffle_addresses = (0 != va_arg(param, long));
3037     break;
3038 #endif
3039   case CURLOPT_DISALLOW_USERNAME_IN_URL:
3040     data->set.disallow_username_in_url = (0 != va_arg(param, long));
3041     break;
3042 #ifndef CURL_DISABLE_DOH
3043   case CURLOPT_DOH_URL:
3044     result = Curl_setstropt(&data->set.str[STRING_DOH],
3045                             va_arg(param, char *));
3046     data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE;
3047     break;
3048 #endif
3049   case CURLOPT_UPKEEP_INTERVAL_MS:
3050     arg = va_arg(param, long);
3051     if(arg < 0)
3052       return CURLE_BAD_FUNCTION_ARGUMENT;
3053     data->set.upkeep_interval_ms = arg;
3054     break;
3055   case CURLOPT_MAXAGE_CONN:
3056     arg = va_arg(param, long);
3057     if(arg < 0)
3058       return CURLE_BAD_FUNCTION_ARGUMENT;
3059     data->set.maxage_conn = arg;
3060     break;
3061   case CURLOPT_MAXLIFETIME_CONN:
3062     arg = va_arg(param, long);
3063     if(arg < 0)
3064       return CURLE_BAD_FUNCTION_ARGUMENT;
3065     data->set.maxlifetime_conn = arg;
3066     break;
3067   case CURLOPT_TRAILERFUNCTION:
3068 #ifndef CURL_DISABLE_HTTP
3069     data->set.trailer_callback = va_arg(param, curl_trailer_callback);
3070 #endif
3071     break;
3072   case CURLOPT_TRAILERDATA:
3073 #ifndef CURL_DISABLE_HTTP
3074     data->set.trailer_data = va_arg(param, void *);
3075 #endif
3076     break;
3077 #ifndef CURL_DISABLE_HSTS
3078   case CURLOPT_HSTSREADFUNCTION:
3079     data->set.hsts_read = va_arg(param, curl_hstsread_callback);
3080     break;
3081   case CURLOPT_HSTSREADDATA:
3082     data->set.hsts_read_userp = va_arg(param, void *);
3083     break;
3084   case CURLOPT_HSTSWRITEFUNCTION:
3085     data->set.hsts_write = va_arg(param, curl_hstswrite_callback);
3086     break;
3087   case CURLOPT_HSTSWRITEDATA:
3088     data->set.hsts_write_userp = va_arg(param, void *);
3089     break;
3090   case CURLOPT_HSTS: {
3091     struct curl_slist *h;
3092     if(!data->hsts) {
3093       data->hsts = Curl_hsts_init();
3094       if(!data->hsts)
3095         return CURLE_OUT_OF_MEMORY;
3096     }
3097     argptr = va_arg(param, char *);
3098     if(argptr) {
3099       result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
3100       if(result)
3101         return result;
3102       /* this needs to build a list of file names to read from, so that it can
3103          read them later, as we might get a shared HSTS handle to load them
3104          into */
3105       h = curl_slist_append(data->state.hstslist, argptr);
3106       if(!h) {
3107         curl_slist_free_all(data->state.hstslist);
3108         data->state.hstslist = NULL;
3109         return CURLE_OUT_OF_MEMORY;
3110       }
3111       data->state.hstslist = h; /* store the list for later use */
3112     }
3113     else {
3114       /* clear the list of HSTS files */
3115       curl_slist_free_all(data->state.hstslist);
3116       data->state.hstslist = NULL;
3117       if(!data->share || !data->share->hsts)
3118         /* throw away the HSTS cache unless shared */
3119         Curl_hsts_cleanup(&data->hsts);
3120     }
3121     break;
3122   }
3123   case CURLOPT_HSTS_CTRL:
3124     arg = va_arg(param, long);
3125     if(arg & CURLHSTS_ENABLE) {
3126       if(!data->hsts) {
3127         data->hsts = Curl_hsts_init();
3128         if(!data->hsts)
3129           return CURLE_OUT_OF_MEMORY;
3130       }
3131     }
3132     else
3133       Curl_hsts_cleanup(&data->hsts);
3134     break;
3135 #endif
3136 #ifndef CURL_DISABLE_ALTSVC
3137   case CURLOPT_ALTSVC:
3138     if(!data->asi) {
3139       data->asi = Curl_altsvc_init();
3140       if(!data->asi)
3141         return CURLE_OUT_OF_MEMORY;
3142     }
3143     argptr = va_arg(param, char *);
3144     result = Curl_setstropt(&data->set.str[STRING_ALTSVC], argptr);
3145     if(result)
3146       return result;
3147     if(argptr)
3148       (void)Curl_altsvc_load(data->asi, argptr);
3149     break;
3150   case CURLOPT_ALTSVC_CTRL:
3151     if(!data->asi) {
3152       data->asi = Curl_altsvc_init();
3153       if(!data->asi)
3154         return CURLE_OUT_OF_MEMORY;
3155     }
3156     arg = va_arg(param, long);
3157     if(!arg) {
3158       DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input"));
3159       return CURLE_BAD_FUNCTION_ARGUMENT;
3160     }
3161     result = Curl_altsvc_ctrl(data->asi, arg);
3162     if(result)
3163       return result;
3164     break;
3165 #endif
3166   case CURLOPT_PREREQFUNCTION:
3167     data->set.fprereq = va_arg(param, curl_prereq_callback);
3168     break;
3169   case CURLOPT_PREREQDATA:
3170     data->set.prereq_userp = va_arg(param, void *);
3171     break;
3172 #ifdef USE_WEBSOCKETS
3173   case CURLOPT_WS_OPTIONS: {
3174     bool raw;
3175     arg = va_arg(param, long);
3176     raw = (arg & CURLWS_RAW_MODE);
3177     data->set.ws_raw_mode = raw;
3178     break;
3179   }
3180 #endif
3181 #ifdef USE_ECH
3182   case CURLOPT_ECH: {
3183     size_t plen = 0;
3184 
3185     argptr = va_arg(param, char *);
3186     if(!argptr) {
3187       data->set.tls_ech = CURLECH_DISABLE;
3188       result = CURLE_BAD_FUNCTION_ARGUMENT;
3189       return result;
3190     }
3191     plen = strlen(argptr);
3192     if(plen > CURL_MAX_INPUT_LENGTH) {
3193       data->set.tls_ech = CURLECH_DISABLE;
3194       result = CURLE_BAD_FUNCTION_ARGUMENT;
3195       return result;
3196     }
3197     /* set tls_ech flag value, preserving CLA_CFG bit */
3198     if(plen == 5 && !strcmp(argptr, "false"))
3199       data->set.tls_ech = CURLECH_DISABLE
3200                           | (data->set.tls_ech & CURLECH_CLA_CFG);
3201     else if(plen == 6 && !strcmp(argptr, "grease"))
3202       data->set.tls_ech = CURLECH_GREASE
3203                           | (data->set.tls_ech & CURLECH_CLA_CFG);
3204     else if(plen == 4 && !strcmp(argptr, "true"))
3205       data->set.tls_ech = CURLECH_ENABLE
3206                           | (data->set.tls_ech & CURLECH_CLA_CFG);
3207     else if(plen == 4 && !strcmp(argptr, "hard"))
3208       data->set.tls_ech = CURLECH_HARD
3209                           | (data->set.tls_ech & CURLECH_CLA_CFG);
3210     else if(plen > 5 && !strncmp(argptr, "ecl:", 4)) {
3211       result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], argptr + 4);
3212       if(result)
3213         return result;
3214       data->set.tls_ech |= CURLECH_CLA_CFG;
3215     }
3216     else if(plen > 4 && !strncmp(argptr, "pn:", 3)) {
3217       result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], argptr + 3);
3218       if(result)
3219         return result;
3220     }
3221     break;
3222   }
3223 #endif
3224   case CURLOPT_QUICK_EXIT:
3225     data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
3226     break;
3227   default:
3228     /* unknown tag and its companion, just ignore: */
3229     result = CURLE_UNKNOWN_OPTION;
3230     break;
3231   }
3232 
3233   return result;
3234 }
3235 
3236 /*
3237  * curl_easy_setopt() is the external interface for setting options on an
3238  * easy handle.
3239  *
3240  * NOTE: This is one of few API functions that are allowed to be called from
3241  * within a callback.
3242  */
3243 
3244 #undef curl_easy_setopt
curl_easy_setopt(struct Curl_easy * data,CURLoption tag,...)3245 CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
3246 {
3247   va_list arg;
3248   CURLcode result;
3249 
3250   if(!data)
3251     return CURLE_BAD_FUNCTION_ARGUMENT;
3252 
3253   va_start(arg, tag);
3254 
3255   result = Curl_vsetopt(data, tag, arg);
3256 
3257   va_end(arg);
3258 #ifdef DEBUGBUILD
3259   if(result == CURLE_BAD_FUNCTION_ARGUMENT)
3260     infof(data, "setopt arg 0x%x returned CURLE_BAD_FUNCTION_ARGUMENT", tag);
3261 #endif
3262   return result;
3263 }
3264