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