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