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