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