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