tool_setopt.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2022, 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. #include "tool_setup.h"
  25. #ifndef CURL_DISABLE_LIBCURL_OPTION
  26. #define ENABLE_CURLX_PRINTF
  27. /* use our own printf() functions */
  28. #include "curlx.h"
  29. #include "tool_cfgable.h"
  30. #include "tool_easysrc.h"
  31. #include "tool_setopt.h"
  32. #include "tool_msgs.h"
  33. #include "dynbuf.h"
  34. #include "memdebug.h" /* keep this as LAST include */
  35. /* Lookup tables for converting setopt values back to symbols */
  36. /* For enums, values may be in any order. */
  37. /* For bit masks, put combinations first, then single bits, */
  38. /* and finally any "NONE" value. */
  39. #define NV(e) {#e, e}
  40. #define NV1(e, v) {#e, (v)}
  41. #define NVEND {NULL, 0} /* sentinel to mark end of list */
  42. const struct NameValue setopt_nv_CURLPROXY[] = {
  43. NV(CURLPROXY_HTTP),
  44. NV(CURLPROXY_HTTP_1_0),
  45. NV(CURLPROXY_HTTPS),
  46. NV(CURLPROXY_SOCKS4),
  47. NV(CURLPROXY_SOCKS5),
  48. NV(CURLPROXY_SOCKS4A),
  49. NV(CURLPROXY_SOCKS5_HOSTNAME),
  50. NVEND,
  51. };
  52. const struct NameValue setopt_nv_CURL_SOCKS_PROXY[] = {
  53. NV(CURLPROXY_SOCKS4),
  54. NV(CURLPROXY_SOCKS5),
  55. NV(CURLPROXY_SOCKS4A),
  56. NV(CURLPROXY_SOCKS5_HOSTNAME),
  57. NVEND,
  58. };
  59. const struct NameValueUnsigned setopt_nv_CURLHSTS[] = {
  60. NV(CURLHSTS_ENABLE),
  61. NVEND,
  62. };
  63. const struct NameValueUnsigned setopt_nv_CURLAUTH[] = {
  64. NV(CURLAUTH_ANY), /* combination */
  65. NV(CURLAUTH_ANYSAFE), /* combination */
  66. NV(CURLAUTH_BASIC),
  67. NV(CURLAUTH_DIGEST),
  68. NV(CURLAUTH_GSSNEGOTIATE),
  69. NV(CURLAUTH_NTLM),
  70. NV(CURLAUTH_DIGEST_IE),
  71. NV(CURLAUTH_NTLM_WB),
  72. NV(CURLAUTH_ONLY),
  73. NV(CURLAUTH_NONE),
  74. NVEND,
  75. };
  76. const struct NameValue setopt_nv_CURL_HTTP_VERSION[] = {
  77. NV(CURL_HTTP_VERSION_NONE),
  78. NV(CURL_HTTP_VERSION_1_0),
  79. NV(CURL_HTTP_VERSION_1_1),
  80. NV(CURL_HTTP_VERSION_2_0),
  81. NV(CURL_HTTP_VERSION_2TLS),
  82. NV(CURL_HTTP_VERSION_3),
  83. NVEND,
  84. };
  85. const struct NameValue setopt_nv_CURL_SSLVERSION[] = {
  86. NV(CURL_SSLVERSION_DEFAULT),
  87. NV(CURL_SSLVERSION_TLSv1),
  88. NV(CURL_SSLVERSION_SSLv2),
  89. NV(CURL_SSLVERSION_SSLv3),
  90. NV(CURL_SSLVERSION_TLSv1_0),
  91. NV(CURL_SSLVERSION_TLSv1_1),
  92. NV(CURL_SSLVERSION_TLSv1_2),
  93. NV(CURL_SSLVERSION_TLSv1_3),
  94. NVEND,
  95. };
  96. const struct NameValue setopt_nv_CURL_TIMECOND[] = {
  97. NV(CURL_TIMECOND_IFMODSINCE),
  98. NV(CURL_TIMECOND_IFUNMODSINCE),
  99. NV(CURL_TIMECOND_LASTMOD),
  100. NV(CURL_TIMECOND_NONE),
  101. NVEND,
  102. };
  103. const struct NameValue setopt_nv_CURLFTPSSL_CCC[] = {
  104. NV(CURLFTPSSL_CCC_NONE),
  105. NV(CURLFTPSSL_CCC_PASSIVE),
  106. NV(CURLFTPSSL_CCC_ACTIVE),
  107. NVEND,
  108. };
  109. const struct NameValue setopt_nv_CURLUSESSL[] = {
  110. NV(CURLUSESSL_NONE),
  111. NV(CURLUSESSL_TRY),
  112. NV(CURLUSESSL_CONTROL),
  113. NV(CURLUSESSL_ALL),
  114. NVEND,
  115. };
  116. const struct NameValueUnsigned setopt_nv_CURLSSLOPT[] = {
  117. NV(CURLSSLOPT_ALLOW_BEAST),
  118. NV(CURLSSLOPT_NO_REVOKE),
  119. NV(CURLSSLOPT_NO_PARTIALCHAIN),
  120. NV(CURLSSLOPT_REVOKE_BEST_EFFORT),
  121. NV(CURLSSLOPT_NATIVE_CA),
  122. NV(CURLSSLOPT_AUTO_CLIENT_CERT),
  123. NVEND,
  124. };
  125. const struct NameValue setopt_nv_CURL_NETRC[] = {
  126. NV(CURL_NETRC_IGNORED),
  127. NV(CURL_NETRC_OPTIONAL),
  128. NV(CURL_NETRC_REQUIRED),
  129. NVEND,
  130. };
  131. /* These options have non-zero default values. */
  132. static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
  133. NV1(CURLOPT_SSL_VERIFYPEER, 1),
  134. NV1(CURLOPT_SSL_VERIFYHOST, 1),
  135. NV1(CURLOPT_SSL_ENABLE_NPN, 1),
  136. NV1(CURLOPT_SSL_ENABLE_ALPN, 1),
  137. NV1(CURLOPT_TCP_NODELAY, 1),
  138. NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
  139. NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
  140. NV1(CURLOPT_SOCKS5_AUTH, 1),
  141. NVEND
  142. };
  143. /* Format and add code; jump to nomem on malloc error */
  144. #define ADD(args) do { \
  145. ret = easysrc_add args; \
  146. if(ret) \
  147. goto nomem; \
  148. } while(0)
  149. #define ADDF(args) do { \
  150. ret = easysrc_addf args; \
  151. if(ret) \
  152. goto nomem; \
  153. } while(0)
  154. #define NULL_CHECK(p) do { \
  155. if(!p) { \
  156. ret = CURLE_OUT_OF_MEMORY; \
  157. goto nomem; \
  158. } \
  159. } while(0)
  160. #define DECL0(s) ADD((&easysrc_decl, s))
  161. #define DECL1(f,a) ADDF((&easysrc_decl, f,a))
  162. #define DATA0(s) ADD((&easysrc_data, s))
  163. #define DATA1(f,a) ADDF((&easysrc_data, f,a))
  164. #define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b))
  165. #define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c))
  166. #define CODE0(s) ADD((&easysrc_code, s))
  167. #define CODE1(f,a) ADDF((&easysrc_code, f,a))
  168. #define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b))
  169. #define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c))
  170. #define CLEAN0(s) ADD((&easysrc_clean, s))
  171. #define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))
  172. #define REM0(s) ADD((&easysrc_toohard, s))
  173. #define REM1(f,a) ADDF((&easysrc_toohard, f,a))
  174. #define REM3(f,a,b,c) ADDF((&easysrc_toohard, f,a,b,c))
  175. /* Escape string to C string syntax. Return NULL if out of memory.
  176. * Is this correct for those wacky EBCDIC guys? */
  177. #define MAX_STRING_LENGTH_OUTPUT 2000
  178. #define ZERO_TERMINATED -1
  179. static char *c_escape(const char *str, curl_off_t len)
  180. {
  181. const char *s;
  182. unsigned int cutoff = 0;
  183. CURLcode result;
  184. struct curlx_dynbuf escaped;
  185. curlx_dyn_init(&escaped, 4 * MAX_STRING_LENGTH_OUTPUT + 3);
  186. if(len == ZERO_TERMINATED)
  187. len = strlen(str);
  188. if(len > MAX_STRING_LENGTH_OUTPUT) {
  189. /* cap ridiculously long strings */
  190. len = MAX_STRING_LENGTH_OUTPUT;
  191. cutoff = 3;
  192. }
  193. result = curlx_dyn_addn(&escaped, STRCONST(""));
  194. for(s = str; !result && len; s++, len--) {
  195. /* escape question marks as well, to prevent generating accidental
  196. trigraphs */
  197. static const char from[] = "\t\r\n?\"\\";
  198. static const char to[] = "\\t\\r\\n\\?\\\"\\\\";
  199. const char *p = strchr(from, *s);
  200. if(!p && ISPRINT(*s))
  201. continue;
  202. result = curlx_dyn_addn(&escaped, str, s - str);
  203. str = s + 1;
  204. if(!result) {
  205. if(p && *p)
  206. result = curlx_dyn_addn(&escaped, to + 2 * (p - from), 2);
  207. else {
  208. const char *format = "\\x%02x";
  209. if(len > 1 && ISXDIGIT(s[1])) {
  210. /* Octal escape to avoid >2 digit hex. */
  211. format = "\\%03o";
  212. }
  213. result = curlx_dyn_addf(&escaped, format,
  214. (unsigned int) *(unsigned char *) s);
  215. }
  216. }
  217. }
  218. if(!result)
  219. result = curlx_dyn_addn(&escaped, str, s - str);
  220. if(!result)
  221. (void) !curlx_dyn_addn(&escaped, "...", cutoff);
  222. return curlx_dyn_ptr(&escaped);
  223. }
  224. /* setopt wrapper for enum types */
  225. CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config,
  226. const char *name, CURLoption tag,
  227. const struct NameValue *nvlist, long lval)
  228. {
  229. CURLcode ret = CURLE_OK;
  230. bool skip = FALSE;
  231. ret = curl_easy_setopt(curl, tag, lval);
  232. if(!lval)
  233. skip = TRUE;
  234. if(config->libcurl && !skip && !ret) {
  235. /* we only use this for real if --libcurl was used */
  236. const struct NameValue *nv = NULL;
  237. for(nv = nvlist; nv->name; nv++) {
  238. if(nv->value == lval)
  239. break; /* found it */
  240. }
  241. if(!nv->name) {
  242. /* If no definition was found, output an explicit value.
  243. * This could happen if new values are defined and used
  244. * but the NameValue list is not updated. */
  245. CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
  246. }
  247. else {
  248. CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name);
  249. }
  250. }
  251. #ifdef DEBUGBUILD
  252. if(ret)
  253. warnf(config, "option %s returned error (%d)\n", name, (int)ret);
  254. #endif
  255. nomem:
  256. return ret;
  257. }
  258. /* setopt wrapper for flags */
  259. CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config,
  260. const char *name, CURLoption tag,
  261. const struct NameValue *nvlist, long lval)
  262. {
  263. CURLcode ret = CURLE_OK;
  264. bool skip = FALSE;
  265. ret = curl_easy_setopt(curl, tag, lval);
  266. if(!lval)
  267. skip = TRUE;
  268. if(config->libcurl && !skip && !ret) {
  269. /* we only use this for real if --libcurl was used */
  270. char preamble[80]; /* should accommodate any symbol name */
  271. long rest = lval; /* bits not handled yet */
  272. const struct NameValue *nv = NULL;
  273. msnprintf(preamble, sizeof(preamble),
  274. "curl_easy_setopt(hnd, %s, ", name);
  275. for(nv = nvlist; nv->name; nv++) {
  276. if((nv->value & ~ rest) == 0) {
  277. /* all value flags contained in rest */
  278. rest &= ~ nv->value; /* remove bits handled here */
  279. CODE3("%s(long)%s%s",
  280. preamble, nv->name, rest ? " |" : ");");
  281. if(!rest)
  282. break; /* handled them all */
  283. /* replace with all spaces for continuation line */
  284. msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), "");
  285. }
  286. }
  287. /* If any bits have no definition, output an explicit value.
  288. * This could happen if new bits are defined and used
  289. * but the NameValue list is not updated. */
  290. if(rest)
  291. CODE2("%s%ldL);", preamble, rest);
  292. }
  293. nomem:
  294. return ret;
  295. }
  296. /* setopt wrapper for bitmasks */
  297. CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config,
  298. const char *name, CURLoption tag,
  299. const struct NameValueUnsigned *nvlist,
  300. long lval)
  301. {
  302. CURLcode ret = CURLE_OK;
  303. bool skip = FALSE;
  304. ret = curl_easy_setopt(curl, tag, lval);
  305. if(!lval)
  306. skip = TRUE;
  307. if(config->libcurl && !skip && !ret) {
  308. /* we only use this for real if --libcurl was used */
  309. char preamble[80];
  310. unsigned long rest = (unsigned long)lval;
  311. const struct NameValueUnsigned *nv = NULL;
  312. msnprintf(preamble, sizeof(preamble),
  313. "curl_easy_setopt(hnd, %s, ", name);
  314. for(nv = nvlist; nv->name; nv++) {
  315. if((nv->value & ~ rest) == 0) {
  316. /* all value flags contained in rest */
  317. rest &= ~ nv->value; /* remove bits handled here */
  318. CODE3("%s(long)%s%s",
  319. preamble, nv->name, rest ? " |" : ");");
  320. if(!rest)
  321. break; /* handled them all */
  322. /* replace with all spaces for continuation line */
  323. msnprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), "");
  324. }
  325. }
  326. /* If any bits have no definition, output an explicit value.
  327. * This could happen if new bits are defined and used
  328. * but the NameValue list is not updated. */
  329. if(rest)
  330. CODE2("%s%luUL);", preamble, rest);
  331. }
  332. nomem:
  333. return ret;
  334. }
  335. /* Generate code for a struct curl_slist. */
  336. static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno)
  337. {
  338. CURLcode ret = CURLE_OK;
  339. char *escaped = NULL;
  340. /* May need several slist variables, so invent name */
  341. *slistno = ++easysrc_slist_count;
  342. DECL1("struct curl_slist *slist%d;", *slistno);
  343. DATA1("slist%d = NULL;", *slistno);
  344. CLEAN1("curl_slist_free_all(slist%d);", *slistno);
  345. CLEAN1("slist%d = NULL;", *slistno);
  346. for(; slist; slist = slist->next) {
  347. Curl_safefree(escaped);
  348. escaped = c_escape(slist->data, ZERO_TERMINATED);
  349. if(!escaped)
  350. return CURLE_OUT_OF_MEMORY;
  351. DATA3("slist%d = curl_slist_append(slist%d, \"%s\");",
  352. *slistno, *slistno, escaped);
  353. }
  354. nomem:
  355. Curl_safefree(escaped);
  356. return ret;
  357. }
  358. static CURLcode libcurl_generate_mime(CURL *curl,
  359. struct GlobalConfig *config,
  360. struct tool_mime *toolmime,
  361. int *mimeno); /* Forward. */
  362. /* Wrapper to generate source code for a mime part. */
  363. static CURLcode libcurl_generate_mime_part(CURL *curl,
  364. struct GlobalConfig *config,
  365. struct tool_mime *part,
  366. int mimeno)
  367. {
  368. CURLcode ret = CURLE_OK;
  369. int submimeno = 0;
  370. char *escaped = NULL;
  371. const char *data = NULL;
  372. const char *filename = part->filename;
  373. /* Parts are linked in reverse order. */
  374. if(part->prev) {
  375. ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno);
  376. if(ret)
  377. return ret;
  378. }
  379. /* Create the part. */
  380. CODE2("part%d = curl_mime_addpart(mime%d);", mimeno, mimeno);
  381. switch(part->kind) {
  382. case TOOLMIME_PARTS:
  383. ret = libcurl_generate_mime(curl, config, part, &submimeno);
  384. if(!ret) {
  385. CODE2("curl_mime_subparts(part%d, mime%d);", mimeno, submimeno);
  386. CODE1("mime%d = NULL;", submimeno); /* Avoid freeing in CLEAN. */
  387. }
  388. break;
  389. case TOOLMIME_DATA:
  390. data = part->data;
  391. if(!ret) {
  392. Curl_safefree(escaped);
  393. escaped = c_escape(data, ZERO_TERMINATED);
  394. NULL_CHECK(escaped);
  395. CODE2("curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);",
  396. mimeno, escaped);
  397. }
  398. break;
  399. case TOOLMIME_FILE:
  400. case TOOLMIME_FILEDATA:
  401. escaped = c_escape(part->data, ZERO_TERMINATED);
  402. NULL_CHECK(escaped);
  403. CODE2("curl_mime_filedata(part%d, \"%s\");", mimeno, escaped);
  404. if(part->kind == TOOLMIME_FILEDATA && !filename) {
  405. CODE1("curl_mime_filename(part%d, NULL);", mimeno);
  406. }
  407. break;
  408. case TOOLMIME_STDIN:
  409. if(!filename)
  410. filename = "-";
  411. /* FALLTHROUGH */
  412. case TOOLMIME_STDINDATA:
  413. /* Can only be reading stdin in the current context. */
  414. CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\",
  415. mimeno);
  416. CODE0(" (curl_seek_callback) fseek, NULL, stdin);");
  417. break;
  418. default:
  419. /* Other cases not possible in this context. */
  420. break;
  421. }
  422. if(!ret && part->encoder) {
  423. Curl_safefree(escaped);
  424. escaped = c_escape(part->encoder, ZERO_TERMINATED);
  425. NULL_CHECK(escaped);
  426. CODE2("curl_mime_encoder(part%d, \"%s\");", mimeno, escaped);
  427. }
  428. if(!ret && filename) {
  429. Curl_safefree(escaped);
  430. escaped = c_escape(filename, ZERO_TERMINATED);
  431. NULL_CHECK(escaped);
  432. CODE2("curl_mime_filename(part%d, \"%s\");", mimeno, escaped);
  433. }
  434. if(!ret && part->name) {
  435. Curl_safefree(escaped);
  436. escaped = c_escape(part->name, ZERO_TERMINATED);
  437. NULL_CHECK(escaped);
  438. CODE2("curl_mime_name(part%d, \"%s\");", mimeno, escaped);
  439. }
  440. if(!ret && part->type) {
  441. Curl_safefree(escaped);
  442. escaped = c_escape(part->type, ZERO_TERMINATED);
  443. NULL_CHECK(escaped);
  444. CODE2("curl_mime_type(part%d, \"%s\");", mimeno, escaped);
  445. }
  446. if(!ret && part->headers) {
  447. int slistno;
  448. ret = libcurl_generate_slist(part->headers, &slistno);
  449. if(!ret) {
  450. CODE2("curl_mime_headers(part%d, slist%d, 1);", mimeno, slistno);
  451. CODE1("slist%d = NULL;", slistno); /* Prevent CLEANing. */
  452. }
  453. }
  454. nomem:
  455. Curl_safefree(escaped);
  456. return ret;
  457. }
  458. /* Wrapper to generate source code for a mime structure. */
  459. static CURLcode libcurl_generate_mime(CURL *curl,
  460. struct GlobalConfig *config,
  461. struct tool_mime *toolmime,
  462. int *mimeno)
  463. {
  464. CURLcode ret = CURLE_OK;
  465. /* May need several mime variables, so invent name. */
  466. *mimeno = ++easysrc_mime_count;
  467. DECL1("curl_mime *mime%d;", *mimeno);
  468. DATA1("mime%d = NULL;", *mimeno);
  469. CODE1("mime%d = curl_mime_init(hnd);", *mimeno);
  470. CLEAN1("curl_mime_free(mime%d);", *mimeno);
  471. CLEAN1("mime%d = NULL;", *mimeno);
  472. if(toolmime->subparts) {
  473. DECL1("curl_mimepart *part%d;", *mimeno);
  474. ret = libcurl_generate_mime_part(curl, config,
  475. toolmime->subparts, *mimeno);
  476. }
  477. nomem:
  478. return ret;
  479. }
  480. /* setopt wrapper for CURLOPT_MIMEPOST */
  481. CURLcode tool_setopt_mimepost(CURL *curl, struct GlobalConfig *config,
  482. const char *name, CURLoption tag,
  483. curl_mime *mimepost)
  484. {
  485. CURLcode ret = curl_easy_setopt(curl, tag, mimepost);
  486. int mimeno = 0;
  487. if(!ret && config->libcurl) {
  488. ret = libcurl_generate_mime(curl, config,
  489. config->current->mimeroot, &mimeno);
  490. if(!ret)
  491. CODE2("curl_easy_setopt(hnd, %s, mime%d);", name, mimeno);
  492. }
  493. nomem:
  494. return ret;
  495. }
  496. /* setopt wrapper for curl_slist options */
  497. CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config,
  498. const char *name, CURLoption tag,
  499. struct curl_slist *list)
  500. {
  501. CURLcode ret = CURLE_OK;
  502. ret = curl_easy_setopt(curl, tag, list);
  503. if(config->libcurl && list && !ret) {
  504. int i;
  505. ret = libcurl_generate_slist(list, &i);
  506. if(!ret)
  507. CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
  508. }
  509. nomem:
  510. return ret;
  511. }
  512. /* generic setopt wrapper for all other options.
  513. * Some type information is encoded in the tag value. */
  514. CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global,
  515. struct OperationConfig *config,
  516. const char *name, CURLoption tag, ...)
  517. {
  518. va_list arg;
  519. char buf[256];
  520. const char *value = NULL;
  521. bool remark = FALSE;
  522. bool skip = FALSE;
  523. bool escape = FALSE;
  524. char *escaped = NULL;
  525. CURLcode ret = CURLE_OK;
  526. va_start(arg, tag);
  527. if(tag < CURLOPTTYPE_OBJECTPOINT) {
  528. /* Value is expected to be a long */
  529. long lval = va_arg(arg, long);
  530. long defval = 0L;
  531. const struct NameValue *nv = NULL;
  532. for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) {
  533. if(!strcmp(name, nv->name)) {
  534. defval = nv->value;
  535. break; /* found it */
  536. }
  537. }
  538. msnprintf(buf, sizeof(buf), "%ldL", lval);
  539. value = buf;
  540. ret = curl_easy_setopt(curl, tag, lval);
  541. if(lval == defval)
  542. skip = TRUE;
  543. }
  544. else if(tag < CURLOPTTYPE_OFF_T) {
  545. /* Value is some sort of object pointer */
  546. void *pval = va_arg(arg, void *);
  547. /* function pointers are never printable */
  548. if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
  549. if(pval) {
  550. value = "function pointer";
  551. remark = TRUE;
  552. }
  553. else
  554. skip = TRUE;
  555. }
  556. else if(pval && str) {
  557. value = (char *)pval;
  558. escape = TRUE;
  559. }
  560. else if(pval) {
  561. value = "object pointer";
  562. remark = TRUE;
  563. }
  564. else
  565. skip = TRUE;
  566. ret = curl_easy_setopt(curl, tag, pval);
  567. }
  568. else if(tag < CURLOPTTYPE_BLOB) {
  569. /* Value is expected to be curl_off_t */
  570. curl_off_t oval = va_arg(arg, curl_off_t);
  571. msnprintf(buf, sizeof(buf),
  572. "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
  573. value = buf;
  574. ret = curl_easy_setopt(curl, tag, oval);
  575. if(!oval)
  576. skip = TRUE;
  577. }
  578. else {
  579. /* Value is a blob */
  580. void *pblob = va_arg(arg, void *);
  581. /* blobs are never printable */
  582. if(pblob) {
  583. value = "blob pointer";
  584. remark = TRUE;
  585. }
  586. else
  587. skip = TRUE;
  588. ret = curl_easy_setopt(curl, tag, pblob);
  589. }
  590. va_end(arg);
  591. if(global->libcurl && !skip && !ret) {
  592. /* we only use this for real if --libcurl was used */
  593. if(remark)
  594. REM3("%s was set to a%s %s", name, (*value == 'o' ? "n" : ""), value);
  595. else {
  596. if(escape) {
  597. curl_off_t len = ZERO_TERMINATED;
  598. if(tag == CURLOPT_POSTFIELDS)
  599. len = config->postfieldsize;
  600. escaped = c_escape(value, len);
  601. NULL_CHECK(escaped);
  602. CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped);
  603. }
  604. else
  605. CODE2("curl_easy_setopt(hnd, %s, %s);", name, value);
  606. }
  607. }
  608. nomem:
  609. Curl_safefree(escaped);
  610. return ret;
  611. }
  612. #else /* CURL_DISABLE_LIBCURL_OPTION */
  613. #include "tool_cfgable.h"
  614. #include "tool_setopt.h"
  615. #endif /* CURL_DISABLE_LIBCURL_OPTION */