tool_setopt.c 20 KB

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