1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22 #include "tool_setup.h"
23
24 #ifndef CURL_DISABLE_LIBCURL_OPTION
25
26 #define ENABLE_CURLX_PRINTF
27 /* use our own printf() functions */
28 #include "curlx.h"
29
30 #include "tool_cfgable.h"
31 #include "tool_easysrc.h"
32 #include "tool_setopt.h"
33 #include "tool_convert.h"
34 #include "tool_msgs.h"
35
36 #include "memdebug.h" /* keep this as LAST include */
37
38 /* Lookup tables for converting setopt values back to symbols */
39 /* For enums, values may be in any order. */
40 /* For bit masks, put combinations first, then single bits, */
41 /* and finally any "NONE" value. */
42
43 #define NV(e) {#e, e}
44 #define NV1(e, v) {#e, (v)}
45 #define NVEND {NULL, 0} /* sentinel to mark end of list */
46
47 const struct NameValue setopt_nv_CURLPROXY[] = {
48 NV(CURLPROXY_HTTP),
49 NV(CURLPROXY_HTTP_1_0),
50 NV(CURLPROXY_HTTPS),
51 NV(CURLPROXY_SOCKS4),
52 NV(CURLPROXY_SOCKS5),
53 NV(CURLPROXY_SOCKS4A),
54 NV(CURLPROXY_SOCKS5_HOSTNAME),
55 NVEND,
56 };
57
58 const struct NameValue setopt_nv_CURL_SOCKS_PROXY[] = {
59 NV(CURLPROXY_SOCKS4),
60 NV(CURLPROXY_SOCKS5),
61 NV(CURLPROXY_SOCKS4A),
62 NV(CURLPROXY_SOCKS5_HOSTNAME),
63 NVEND,
64 };
65
66 const struct NameValueUnsigned setopt_nv_CURLHSTS[] = {
67 NV(CURLHSTS_ENABLE),
68 NVEND,
69 };
70
71 const struct NameValueUnsigned setopt_nv_CURLAUTH[] = {
72 NV(CURLAUTH_ANY), /* combination */
73 NV(CURLAUTH_ANYSAFE), /* combination */
74 NV(CURLAUTH_BASIC),
75 NV(CURLAUTH_DIGEST),
76 NV(CURLAUTH_GSSNEGOTIATE),
77 NV(CURLAUTH_NTLM),
78 NV(CURLAUTH_DIGEST_IE),
79 NV(CURLAUTH_NTLM_WB),
80 NV(CURLAUTH_ONLY),
81 NV(CURLAUTH_NONE),
82 NVEND,
83 };
84
85 const struct NameValue setopt_nv_CURL_HTTP_VERSION[] = {
86 NV(CURL_HTTP_VERSION_NONE),
87 NV(CURL_HTTP_VERSION_1_0),
88 NV(CURL_HTTP_VERSION_1_1),
89 NV(CURL_HTTP_VERSION_2_0),
90 NV(CURL_HTTP_VERSION_2TLS),
91 NV(CURL_HTTP_VERSION_3),
92 NVEND,
93 };
94
95 const struct NameValue setopt_nv_CURL_SSLVERSION[] = {
96 NV(CURL_SSLVERSION_DEFAULT),
97 NV(CURL_SSLVERSION_TLSv1),
98 NV(CURL_SSLVERSION_SSLv2),
99 NV(CURL_SSLVERSION_SSLv3),
100 NV(CURL_SSLVERSION_TLSv1_0),
101 NV(CURL_SSLVERSION_TLSv1_1),
102 NV(CURL_SSLVERSION_TLSv1_2),
103 NV(CURL_SSLVERSION_TLSv1_3),
104 NVEND,
105 };
106
107 const struct NameValue setopt_nv_CURL_TIMECOND[] = {
108 NV(CURL_TIMECOND_IFMODSINCE),
109 NV(CURL_TIMECOND_IFUNMODSINCE),
110 NV(CURL_TIMECOND_LASTMOD),
111 NV(CURL_TIMECOND_NONE),
112 NVEND,
113 };
114
115 const struct NameValue setopt_nv_CURLFTPSSL_CCC[] = {
116 NV(CURLFTPSSL_CCC_NONE),
117 NV(CURLFTPSSL_CCC_PASSIVE),
118 NV(CURLFTPSSL_CCC_ACTIVE),
119 NVEND,
120 };
121
122 const struct NameValue setopt_nv_CURLUSESSL[] = {
123 NV(CURLUSESSL_NONE),
124 NV(CURLUSESSL_TRY),
125 NV(CURLUSESSL_CONTROL),
126 NV(CURLUSESSL_ALL),
127 NVEND,
128 };
129
130 const struct NameValueUnsigned setopt_nv_CURLSSLOPT[] = {
131 NV(CURLSSLOPT_ALLOW_BEAST),
132 NV(CURLSSLOPT_NO_REVOKE),
133 NV(CURLSSLOPT_NO_PARTIALCHAIN),
134 NV(CURLSSLOPT_REVOKE_BEST_EFFORT),
135 NV(CURLSSLOPT_NATIVE_CA),
136 NV(CURLSSLOPT_AUTO_CLIENT_CERT),
137 NVEND,
138 };
139
140 const struct NameValue setopt_nv_CURL_NETRC[] = {
141 NV(CURL_NETRC_IGNORED),
142 NV(CURL_NETRC_OPTIONAL),
143 NV(CURL_NETRC_REQUIRED),
144 NVEND,
145 };
146
147 /* These mappings essentially triplicated - see
148 * tool_libinfo.c and tool_paramhlp.c */
149 const struct NameValue setopt_nv_CURLPROTO[] = {
150 NV(CURLPROTO_ALL), /* combination */
151 NV(CURLPROTO_DICT),
152 NV(CURLPROTO_FILE),
153 NV(CURLPROTO_FTP),
154 NV(CURLPROTO_FTPS),
155 NV(CURLPROTO_GOPHER),
156 NV(CURLPROTO_HTTP),
157 NV(CURLPROTO_HTTPS),
158 NV(CURLPROTO_IMAP),
159 NV(CURLPROTO_IMAPS),
160 NV(CURLPROTO_LDAP),
161 NV(CURLPROTO_LDAPS),
162 NV(CURLPROTO_POP3),
163 NV(CURLPROTO_POP3S),
164 NV(CURLPROTO_RTSP),
165 NV(CURLPROTO_SCP),
166 NV(CURLPROTO_SFTP),
167 NV(CURLPROTO_SMB),
168 NV(CURLPROTO_SMBS),
169 NV(CURLPROTO_SMTP),
170 NV(CURLPROTO_SMTPS),
171 NV(CURLPROTO_TELNET),
172 NV(CURLPROTO_TFTP),
173 NVEND,
174 };
175
176 /* These options have non-zero default values. */
177 static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
178 NV1(CURLOPT_SSL_VERIFYPEER, 1),
179 NV1(CURLOPT_SSL_VERIFYHOST, 1),
180 NV1(CURLOPT_SSL_ENABLE_NPN, 1),
181 NV1(CURLOPT_SSL_ENABLE_ALPN, 1),
182 NV1(CURLOPT_TCP_NODELAY, 1),
183 NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
184 NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
185 NV1(CURLOPT_SOCKS5_AUTH, 1),
186 NVEND
187 };
188
189 /* Format and add code; jump to nomem on malloc error */
190 #define ADD(args) do { \
191 ret = easysrc_add args; \
192 if(ret) \
193 goto nomem; \
194 } while(0)
195 #define ADDF(args) do { \
196 ret = easysrc_addf args; \
197 if(ret) \
198 goto nomem; \
199 } while(0)
200 #define NULL_CHECK(p) do { \
201 if(!p) { \
202 ret = CURLE_OUT_OF_MEMORY; \
203 goto nomem; \
204 } \
205 } while(0)
206
207 #define DECL0(s) ADD((&easysrc_decl, s))
208 #define DECL1(f,a) ADDF((&easysrc_decl, f,a))
209
210 #define DATA0(s) ADD((&easysrc_data, s))
211 #define DATA1(f,a) ADDF((&easysrc_data, f,a))
212 #define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b))
213 #define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c))
214
215 #define CODE0(s) ADD((&easysrc_code, s))
216 #define CODE1(f,a) ADDF((&easysrc_code, f,a))
217 #define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b))
218 #define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c))
219
220 #define CLEAN0(s) ADD((&easysrc_clean, s))
221 #define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))
222
223 #define REM0(s) ADD((&easysrc_toohard, s))
224 #define REM1(f,a) ADDF((&easysrc_toohard, f,a))
225 #define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b))
226
227 /* Escape string to C string syntax. Return NULL if out of memory.
228 * Is this correct for those wacky EBCDIC guys? */
229
230 #define MAX_STRING_LENGTH_OUTPUT 2000
231 #define ZERO_TERMINATED -1
232
c_escape(const char * str,curl_off_t len)233 static char *c_escape(const char *str, curl_off_t len)
234 {
235 const char *s;
236 unsigned char c;
237 char *escaped, *e;
238 unsigned int cutoff = 0;
239
240 if(len == ZERO_TERMINATED)
241 len = strlen(str);
242
243 if(len > MAX_STRING_LENGTH_OUTPUT) {
244 /* cap ridiculously long strings */
245 len = MAX_STRING_LENGTH_OUTPUT;
246 cutoff = 3;
247 }
248
249 /* Allocate space based on worst-case */
250 escaped = malloc(4 * (size_t)len + 1 + cutoff);
251 if(!escaped)
252 return NULL;
253
254 e = escaped;
255 for(s = str; len; s++, len--) {
256 c = *s;
257 if(c == '\n') {
258 strcpy(e, "\\n");
259 e += 2;
260 }
261 else if(c == '\r') {
262 strcpy(e, "\\r");
263 e += 2;
264 }
265 else if(c == '\t') {
266 strcpy(e, "\\t");
267 e += 2;
268 }
269 else if(c == '\\') {
270 strcpy(e, "\\\\");
271 e += 2;
272 }
273 else if(c == '"') {
274 strcpy(e, "\\\"");
275 e += 2;
276 }
277 else if(!isprint(c)) {
278 msnprintf(e, 5, "\\x%02x", (unsigned)c);
279 e += 4;
280 }
281 else
282 *e++ = c;
283 }
284 while(cutoff--)
285 *e++ = '.';
286 *e = '\0';
287 return escaped;
288 }
289
290 /* setopt wrapper for enum types */
tool_setopt_enum(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,const struct NameValue * nvlist,long lval)291 CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config,
292 const char *name, CURLoption tag,
293 const struct NameValue *nvlist, long lval)
294 {
295 CURLcode ret = CURLE_OK;
296 bool skip = FALSE;
297
298 ret = curl_easy_setopt(curl, tag, lval);
299 if(!lval)
300 skip = TRUE;
301
302 if(config->libcurl && !skip && !ret) {
303 /* we only use this for real if --libcurl was used */
304 const struct NameValue *nv = NULL;
305 for(nv = nvlist; nv->name; nv++) {
306 if(nv->value == lval)
307 break; /* found it */
308 }
309 if(!nv->name) {
310 /* If no definition was found, output an explicit value.
311 * This could happen if new values are defined and used
312 * but the NameValue list is not updated. */
313 CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
314 }
315 else {
316 CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name);
317 }
318 }
319
320 #ifdef DEBUGBUILD
321 if(ret)
322 warnf(config, "option %s returned error (%d)\n", name, (int)ret);
323 #endif
324 nomem:
325 return ret;
326 }
327
328 /* setopt wrapper for flags */
tool_setopt_flags(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,const struct NameValue * nvlist,long lval)329 CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config,
330 const char *name, CURLoption tag,
331 const struct NameValue *nvlist, long lval)
332 {
333 CURLcode ret = CURLE_OK;
334 bool skip = FALSE;
335
336 ret = curl_easy_setopt(curl, tag, lval);
337 if(!lval)
338 skip = TRUE;
339
340 if(config->libcurl && !skip && !ret) {
341 /* we only use this for real if --libcurl was used */
342 char preamble[80]; /* should accommodate any symbol name */
343 long rest = lval; /* bits not handled yet */
344 const struct NameValue *nv = NULL;
345 msnprintf(preamble, sizeof(preamble),
346 "curl_easy_setopt(hnd, %s, ", name);
347 for(nv = nvlist; nv->name; nv++) {
348 if((nv->value & ~ rest) == 0) {
349 /* all value flags contained in rest */
350 rest &= ~ nv->value; /* remove bits handled here */
351 CODE3("%s(long)%s%s",
352 preamble, nv->name, rest ? " |" : ");");
353 if(!rest)
354 break; /* handled them all */
355 /* replace with all spaces for continuation line */
356 msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), "");
357 }
358 }
359 /* If any bits have no definition, output an explicit value.
360 * This could happen if new bits are defined and used
361 * but the NameValue list is not updated. */
362 if(rest)
363 CODE2("%s%ldL);", preamble, rest);
364 }
365
366 nomem:
367 return ret;
368 }
369
370 /* setopt wrapper for bitmasks */
tool_setopt_bitmask(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,const struct NameValueUnsigned * nvlist,long lval)371 CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config,
372 const char *name, CURLoption tag,
373 const struct NameValueUnsigned *nvlist,
374 long lval)
375 {
376 CURLcode ret = CURLE_OK;
377 bool skip = FALSE;
378
379 ret = curl_easy_setopt(curl, tag, lval);
380 if(!lval)
381 skip = TRUE;
382
383 if(config->libcurl && !skip && !ret) {
384 /* we only use this for real if --libcurl was used */
385 char preamble[80];
386 unsigned long rest = (unsigned long)lval;
387 const struct NameValueUnsigned *nv = NULL;
388 msnprintf(preamble, sizeof(preamble),
389 "curl_easy_setopt(hnd, %s, ", name);
390 for(nv = nvlist; nv->name; nv++) {
391 if((nv->value & ~ rest) == 0) {
392 /* all value flags contained in rest */
393 rest &= ~ nv->value; /* remove bits handled here */
394 CODE3("%s(long)%s%s",
395 preamble, nv->name, rest ? " |" : ");");
396 if(!rest)
397 break; /* handled them all */
398 /* replace with all spaces for continuation line */
399 msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), "");
400 }
401 }
402 /* If any bits have no definition, output an explicit value.
403 * This could happen if new bits are defined and used
404 * but the NameValue list is not updated. */
405 if(rest)
406 CODE2("%s%luUL);", preamble, rest);
407 }
408
409 nomem:
410 return ret;
411 }
412
413 /* Generate code for a struct curl_slist. */
libcurl_generate_slist(struct curl_slist * slist,int * slistno)414 static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno)
415 {
416 CURLcode ret = CURLE_OK;
417 char *escaped = NULL;
418
419 /* May need several slist variables, so invent name */
420 *slistno = ++easysrc_slist_count;
421
422 DECL1("struct curl_slist *slist%d;", *slistno);
423 DATA1("slist%d = NULL;", *slistno);
424 CLEAN1("curl_slist_free_all(slist%d);", *slistno);
425 CLEAN1("slist%d = NULL;", *slistno);
426 for(; slist; slist = slist->next) {
427 Curl_safefree(escaped);
428 escaped = c_escape(slist->data, ZERO_TERMINATED);
429 if(!escaped)
430 return CURLE_OUT_OF_MEMORY;
431 DATA3("slist%d = curl_slist_append(slist%d, \"%s\");",
432 *slistno, *slistno, escaped);
433 }
434
435 nomem:
436 Curl_safefree(escaped);
437 return ret;
438 }
439
440 static CURLcode libcurl_generate_mime(CURL *curl,
441 struct GlobalConfig *config,
442 struct tool_mime *toolmime,
443 int *mimeno); /* Forward. */
444
445 /* Wrapper to generate source code for a mime part. */
libcurl_generate_mime_part(CURL * curl,struct GlobalConfig * config,struct tool_mime * part,int mimeno)446 static CURLcode libcurl_generate_mime_part(CURL *curl,
447 struct GlobalConfig *config,
448 struct tool_mime *part,
449 int mimeno)
450 {
451 CURLcode ret = CURLE_OK;
452 int submimeno = 0;
453 char *escaped = NULL;
454 const char *data = NULL;
455 const char *filename = part->filename;
456
457 /* Parts are linked in reverse order. */
458 if(part->prev) {
459 ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno);
460 if(ret)
461 return ret;
462 }
463
464 /* Create the part. */
465 CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno);
466
467 switch(part->kind) {
468 case TOOLMIME_PARTS:
469 ret = libcurl_generate_mime(curl, config, part, &submimeno);
470 if(!ret) {
471 CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno);
472 CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */
473 }
474 break;
475
476 case TOOLMIME_DATA:
477 #ifdef CURL_DOES_CONVERSIONS
478 /* Data will be set in ASCII, thus issue a comment with clear text. */
479 escaped = c_escape(part->data, ZERO_TERMINATED);
480 NULL_CHECK(escaped);
481 CODE1("/* \"%s\" */", escaped);
482
483 /* Our data is always textual: convert it to ASCII. */
484 {
485 size_t size = strlen(part->data);
486 char *cp = malloc(size + 1);
487
488 NULL_CHECK(cp);
489 memcpy(cp, part->data, size + 1);
490 ret = convert_to_network(cp, size);
491 data = cp;
492 }
493 #else
494 data = part->data;
495 #endif
496 if(!ret) {
497 Curl_safefree(escaped);
498 escaped = c_escape(data, ZERO_TERMINATED);
499 NULL_CHECK(escaped);
500 CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);",
501 mimeno, escaped);
502 }
503 break;
504
505 case TOOLMIME_FILE:
506 case TOOLMIME_FILEDATA:
507 escaped = c_escape(part->data, ZERO_TERMINATED);
508 NULL_CHECK(escaped);
509 CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped);
510 if(part->kind == TOOLMIME_FILEDATA && !filename) {
511 CODE1("curl_mime_filename(part%d, NULL);", mimeno);
512 }
513 break;
514
515 case TOOLMIME_STDIN:
516 if(!filename)
517 filename = "-";
518 /* FALLTHROUGH */
519 case TOOLMIME_STDINDATA:
520 /* Can only be reading stdin in the current context. */
521 CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\",
522 mimeno);
523 CODE0(" (curl_seek_callback) fseek, NULL, stdin);");
524 break;
525 default:
526 /* Other cases not possible in this context. */
527 break;
528 }
529
530 if(!ret && part->encoder) {
531 Curl_safefree(escaped);
532 escaped = c_escape(part->encoder, ZERO_TERMINATED);
533 NULL_CHECK(escaped);
534 CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped);
535 }
536
537 if(!ret && filename) {
538 Curl_safefree(escaped);
539 escaped = c_escape(filename, ZERO_TERMINATED);
540 NULL_CHECK(escaped);
541 CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped);
542 }
543
544 if(!ret && part->name) {
545 Curl_safefree(escaped);
546 escaped = c_escape(part->name, ZERO_TERMINATED);
547 NULL_CHECK(escaped);
548 CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped);
549 }
550
551 if(!ret && part->type) {
552 Curl_safefree(escaped);
553 escaped = c_escape(part->type, ZERO_TERMINATED);
554 NULL_CHECK(escaped);
555 CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped);
556 }
557
558 if(!ret && part->headers) {
559 int slistno;
560
561 ret = libcurl_generate_slist(part->headers, &slistno);
562 if(!ret) {
563 CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno);
564 CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */
565 }
566 }
567
568 nomem:
569 #ifdef CURL_DOES_CONVERSIONS
570 if(data)
571 free((char *) data);
572 #endif
573
574 Curl_safefree(escaped);
575 return ret;
576 }
577
578 /* Wrapper to generate source code for a mime structure. */
libcurl_generate_mime(CURL * curl,struct GlobalConfig * config,struct tool_mime * toolmime,int * mimeno)579 static CURLcode libcurl_generate_mime(CURL *curl,
580 struct GlobalConfig *config,
581 struct tool_mime *toolmime,
582 int *mimeno)
583 {
584 CURLcode ret = CURLE_OK;
585
586 /* May need several mime variables, so invent name. */
587 *mimeno = ++easysrc_mime_count;
588 DECL1("curl_mime *mime%d;", *mimeno);
589 DATA1("mime%d = NULL;", *mimeno);
590 CODE1("mime%d = curl_mime_init(hnd);", *mimeno);
591 CLEAN1("curl_mime_free(mime%d);", *mimeno);
592 CLEAN1("mime%d = NULL;", *mimeno);
593
594 if(toolmime->subparts) {
595 DECL1("curl_mimepart *part%d;", *mimeno);
596 ret = libcurl_generate_mime_part(curl, config,
597 toolmime->subparts, *mimeno);
598 }
599
600 nomem:
601 return ret;
602 }
603
604 /* setopt wrapper for CURLOPT_MIMEPOST */
tool_setopt_mimepost(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,curl_mime * mimepost)605 CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config,
606 const char *name, CURLoption tag,
607 curl_mime *mimepost)
608 {
609 CURLcode ret = curl_easy_setopt(curl, tag, mimepost);
610 int mimeno = 0;
611
612 if(!ret && config->libcurl) {
613 ret = libcurl_generate_mime(curl, config,
614 config->current->mimeroot, &mimeno);
615
616 if(!ret)
617 CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, mimeno);
618 }
619
620 nomem:
621 return ret;
622 }
623
624 /* setopt wrapper for curl_slist options */
tool_setopt_slist(CURL * curl,struct GlobalConfig * config,const char * name,CURLoption tag,struct curl_slist * list)625 CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config,
626 const char *name, CURLoption tag,
627 struct curl_slist *list)
628 {
629 CURLcode ret = CURLE_OK;
630
631 ret = curl_easy_setopt(curl, tag, list);
632
633 if(config->libcurl && list && !ret) {
634 int i;
635
636 ret = libcurl_generate_slist(list, &i);
637 if(!ret)
638 CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
639 }
640
641 nomem:
642 return ret;
643 }
644
645 /* generic setopt wrapper for all other options.
646 * Some type information is encoded in the tag value. */
tool_setopt(CURL * curl,bool str,struct GlobalConfig * global,struct OperationConfig * config,const char * name,CURLoption tag,...)647 CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global,
648 struct OperationConfig *config,
649 const char *name, CURLoption tag, ...)
650 {
651 va_list arg;
652 char buf[256];
653 const char *value = NULL;
654 bool remark = FALSE;
655 bool skip = FALSE;
656 bool escape = FALSE;
657 char *escaped = NULL;
658 CURLcode ret = CURLE_OK;
659
660 va_start(arg, tag);
661
662 if(tag < CURLOPTTYPE_OBJECTPOINT) {
663 /* Value is expected to be a long */
664 long lval = va_arg(arg, long);
665 long defval = 0L;
666 const struct NameValue *nv = NULL;
667 for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) {
668 if(!strcmp(name, nv->name)) {
669 defval = nv->value;
670 break; /* found it */
671 }
672 }
673
674 msnprintf(buf, sizeof(buf), "%ldL", lval);
675 value = buf;
676 ret = curl_easy_setopt(curl, tag, lval);
677 if(lval == defval)
678 skip = TRUE;
679 }
680 else if(tag < CURLOPTTYPE_OFF_T) {
681 /* Value is some sort of object pointer */
682 void *pval = va_arg(arg, void *);
683
684 /* function pointers are never printable */
685 if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
686 if(pval) {
687 value = "functionpointer";
688 remark = TRUE;
689 }
690 else
691 skip = TRUE;
692 }
693
694 else if(pval && str) {
695 value = (char *)pval;
696 escape = TRUE;
697 }
698 else if(pval) {
699 value = "objectpointer";
700 remark = TRUE;
701 }
702 else
703 skip = TRUE;
704
705 ret = curl_easy_setopt(curl, tag, pval);
706
707 }
708 else if(tag < CURLOPTTYPE_BLOB) {
709 /* Value is expected to be curl_off_t */
710 curl_off_t oval = va_arg(arg, curl_off_t);
711 msnprintf(buf, sizeof(buf),
712 "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
713 value = buf;
714 ret = curl_easy_setopt(curl, tag, oval);
715
716 if(!oval)
717 skip = TRUE;
718 }
719 else {
720 /* Value is a blob */
721 void *pblob = va_arg(arg, void *);
722
723 /* blobs are never printable */
724 if(pblob) {
725 value = "blobpointer";
726 remark = TRUE;
727 }
728 else
729 skip = TRUE;
730
731 ret = curl_easy_setopt(curl, tag, pblob);
732 }
733
734 va_end(arg);
735
736 if(global->libcurl && !skip && !ret) {
737 /* we only use this for real if --libcurl was used */
738
739 if(remark)
740 REM2("%s set to a %s", name, value);
741 else {
742 if(escape) {
743 curl_off_t len = ZERO_TERMINATED;
744 if(tag == CURLOPT_POSTFIELDS)
745 len = config->postfieldsize;
746 escaped = c_escape(value, len);
747 NULL_CHECK(escaped);
748 CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped);
749 }
750 else
751 CODE2("curl_easy_setopt(hnd, %s, %s);", name, value);
752 }
753 }
754
755 nomem:
756 Curl_safefree(escaped);
757 return ret;
758 }
759
760 #else /* CURL_DISABLE_LIBCURL_OPTION */
761
762 #include "tool_cfgable.h"
763 #include "tool_setopt.h"
764
765 #endif /* CURL_DISABLE_LIBCURL_OPTION */
766
767 /*
768 * tool_setopt_skip() allows the curl tool code to avoid setopt options that
769 * are explicitly disabled in the build.
770 */
tool_setopt_skip(CURLoption tag)771 bool tool_setopt_skip(CURLoption tag)
772 {
773 #ifdef CURL_DISABLE_PROXY
774 #define USED_TAG
775 switch(tag) {
776 case CURLOPT_HAPROXYPROTOCOL:
777 case CURLOPT_HTTPPROXYTUNNEL:
778 case CURLOPT_NOPROXY:
779 case CURLOPT_PRE_PROXY:
780 case CURLOPT_PROXY:
781 case CURLOPT_PROXYAUTH:
782 case CURLOPT_PROXY_CAINFO:
783 case CURLOPT_PROXY_CAPATH:
784 case CURLOPT_PROXY_CRLFILE:
785 case CURLOPT_PROXYHEADER:
786 case CURLOPT_PROXY_KEYPASSWD:
787 case CURLOPT_PROXYPASSWORD:
788 case CURLOPT_PROXY_PINNEDPUBLICKEY:
789 case CURLOPT_PROXYPORT:
790 case CURLOPT_PROXY_SERVICE_NAME:
791 case CURLOPT_PROXY_SSLCERT:
792 case CURLOPT_PROXY_SSLCERTTYPE:
793 case CURLOPT_PROXY_SSL_CIPHER_LIST:
794 case CURLOPT_PROXY_SSLKEY:
795 case CURLOPT_PROXY_SSLKEYTYPE:
796 case CURLOPT_PROXY_SSL_OPTIONS:
797 case CURLOPT_PROXY_SSL_VERIFYHOST:
798 case CURLOPT_PROXY_SSL_VERIFYPEER:
799 case CURLOPT_PROXY_SSLVERSION:
800 case CURLOPT_PROXY_TLS13_CIPHERS:
801 case CURLOPT_PROXY_TLSAUTH_PASSWORD:
802 case CURLOPT_PROXY_TLSAUTH_TYPE:
803 case CURLOPT_PROXY_TLSAUTH_USERNAME:
804 case CURLOPT_PROXY_TRANSFER_MODE:
805 case CURLOPT_PROXYTYPE:
806 case CURLOPT_PROXYUSERNAME:
807 case CURLOPT_PROXYUSERPWD:
808 return TRUE;
809 default:
810 break;
811 }
812 #endif
813 #ifdef CURL_DISABLE_FTP
814 #define USED_TAG
815 switch(tag) {
816 case CURLOPT_FTPPORT:
817 case CURLOPT_FTP_ACCOUNT:
818 case CURLOPT_FTP_ALTERNATIVE_TO_USER:
819 case CURLOPT_FTP_FILEMETHOD:
820 case CURLOPT_FTP_SKIP_PASV_IP:
821 case CURLOPT_FTP_USE_EPRT:
822 case CURLOPT_FTP_USE_EPSV:
823 case CURLOPT_FTP_USE_PRET:
824 case CURLOPT_KRBLEVEL:
825 return TRUE;
826 default:
827 break;
828 }
829 #endif
830 #ifdef CURL_DISABLE_RTSP
831 #define USED_TAG
832 switch(tag) {
833 case CURLOPT_INTERLEAVEDATA:
834 return TRUE;
835 default:
836 break;
837 }
838 #endif
839 #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
840 #define USED_TAG
841 switch(tag) {
842 case CURLOPT_COOKIE:
843 case CURLOPT_COOKIEFILE:
844 case CURLOPT_COOKIEJAR:
845 case CURLOPT_COOKIESESSION:
846 return TRUE;
847 default:
848 break;
849 }
850 #endif
851 #if defined(CURL_DISABLE_TELNET)
852 #define USED_TAG
853 switch(tag) {
854 case CURLOPT_TELNETOPTIONS:
855 return TRUE;
856 default:
857 break;
858 }
859 #endif
860 #ifdef CURL_DISABLE_TFTP
861 #define USED_TAG
862 switch(tag) {
863 case CURLOPT_TFTP_BLKSIZE:
864 case CURLOPT_TFTP_NO_OPTIONS:
865 return TRUE;
866 default:
867 break;
868 }
869 #endif
870 #ifdef CURL_DISABLE_NETRC
871 #define USED_TAG
872 switch(tag) {
873 case CURLOPT_NETRC:
874 case CURLOPT_NETRC_FILE:
875 return TRUE;
876 default:
877 break;
878 }
879 #endif
880
881 #ifndef USED_TAG
882 (void)tag;
883 #endif
884 return FALSE;
885 }
886