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