tool_setopt.c 20 KB

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