1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2014, 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 http://curl.haxx.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 34#include "memdebug.h" /* keep this as LAST include */ 35 36/* Lookup tables for converting setopt values back to symbols */ 37/* For enums, values may be in any order. */ 38/* For bit masks, put combinations first, then single bits, */ 39/* and finally any "NONE" value. */ 40 41#define NV(e) {#e, e} 42#define NV1(e, v) {#e, (v)} 43#define NVEND {NULL, 0} /* sentinel to mark end of list */ 44 45const NameValue setopt_nv_CURLPROXY[] = { 46 NV(CURLPROXY_HTTP), 47 NV(CURLPROXY_HTTP_1_0), 48 NV(CURLPROXY_SOCKS4), 49 NV(CURLPROXY_SOCKS5), 50 NV(CURLPROXY_SOCKS4A), 51 NV(CURLPROXY_SOCKS5_HOSTNAME), 52 NVEND, 53}; 54 55const NameValueUnsigned setopt_nv_CURLAUTH[] = { 56 NV(CURLAUTH_ANY), /* combination */ 57 NV(CURLAUTH_ANYSAFE), /* combination */ 58 NV(CURLAUTH_BASIC), 59 NV(CURLAUTH_DIGEST), 60 NV(CURLAUTH_GSSNEGOTIATE), 61 NV(CURLAUTH_NTLM), 62 NV(CURLAUTH_DIGEST_IE), 63 NV(CURLAUTH_NTLM_WB), 64 NV(CURLAUTH_ONLY), 65 NV(CURLAUTH_NONE), 66 NVEND, 67}; 68 69const NameValue setopt_nv_CURL_HTTP_VERSION[] = { 70 NV(CURL_HTTP_VERSION_NONE), 71 NV(CURL_HTTP_VERSION_1_0), 72 NV(CURL_HTTP_VERSION_1_1), 73 NVEND, 74}; 75 76const NameValue setopt_nv_CURL_SSLVERSION[] = { 77 NV(CURL_SSLVERSION_DEFAULT), 78 NV(CURL_SSLVERSION_TLSv1), 79 NV(CURL_SSLVERSION_SSLv2), 80 NV(CURL_SSLVERSION_SSLv3), 81 NV(CURL_SSLVERSION_TLSv1_0), 82 NV(CURL_SSLVERSION_TLSv1_1), 83 NV(CURL_SSLVERSION_TLSv1_2), 84 NVEND, 85}; 86 87const NameValue setopt_nv_CURL_TIMECOND[] = { 88 NV(CURL_TIMECOND_IFMODSINCE), 89 NV(CURL_TIMECOND_IFUNMODSINCE), 90 NV(CURL_TIMECOND_LASTMOD), 91 NV(CURL_TIMECOND_NONE), 92 NVEND, 93}; 94 95const NameValue setopt_nv_CURLFTPSSL_CCC[] = { 96 NV(CURLFTPSSL_CCC_NONE), 97 NV(CURLFTPSSL_CCC_PASSIVE), 98 NV(CURLFTPSSL_CCC_ACTIVE), 99 NVEND, 100}; 101 102const NameValue setopt_nv_CURLUSESSL[] = { 103 NV(CURLUSESSL_NONE), 104 NV(CURLUSESSL_TRY), 105 NV(CURLUSESSL_CONTROL), 106 NV(CURLUSESSL_ALL), 107 NVEND, 108}; 109 110const NameValue setopt_nv_CURL_NETRC[] = { 111 NV(CURL_NETRC_IGNORED), 112 NV(CURL_NETRC_OPTIONAL), 113 NV(CURL_NETRC_REQUIRED), 114 NVEND, 115}; 116 117/* These mappings essentially triplicated - see 118 * tool_libinfo.c and tool_paramhlp.c */ 119const NameValue setopt_nv_CURLPROTO[] = { 120 NV(CURLPROTO_ALL), /* combination */ 121 NV(CURLPROTO_DICT), 122 NV(CURLPROTO_FILE), 123 NV(CURLPROTO_FTP), 124 NV(CURLPROTO_FTPS), 125 NV(CURLPROTO_GOPHER), 126 NV(CURLPROTO_HTTP), 127 NV(CURLPROTO_HTTPS), 128 NV(CURLPROTO_IMAP), 129 NV(CURLPROTO_IMAPS), 130 NV(CURLPROTO_LDAP), 131 NV(CURLPROTO_LDAPS), 132 NV(CURLPROTO_POP3), 133 NV(CURLPROTO_POP3S), 134 NV(CURLPROTO_RTSP), 135 NV(CURLPROTO_SCP), 136 NV(CURLPROTO_SFTP), 137 NV(CURLPROTO_SMTP), 138 NV(CURLPROTO_SMTPS), 139 NV(CURLPROTO_TELNET), 140 NV(CURLPROTO_TFTP), 141 NVEND, 142}; 143 144/* These options have non-zero default values. */ 145static const NameValue setopt_nv_CURLNONZERODEFAULTS[] = { 146 NV1(CURLOPT_SSL_VERIFYPEER, 1), 147 NV1(CURLOPT_SSL_VERIFYHOST, 1), 148 NV1(CURLOPT_SSL_ENABLE_NPN, 1), 149 NV1(CURLOPT_SSL_ENABLE_ALPN, 1), 150 NVEND 151}; 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_FALSE 159#define ADDF(args) do { \ 160 ret = easysrc_addf args; \ 161 if(ret) \ 162 goto nomem; \ 163} WHILE_FALSE 164 165#define DECL0(s) ADD((&easysrc_decl, s)) 166#define DECL1(f,a) ADDF((&easysrc_decl, f,a)) 167 168#define DATA0(s) ADD((&easysrc_data, s)) 169#define DATA1(f,a) ADDF((&easysrc_data, f,a)) 170#define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b)) 171#define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c)) 172 173#define CODE0(s) ADD((&easysrc_code, s)) 174#define CODE1(f,a) ADDF((&easysrc_code, f,a)) 175#define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b)) 176#define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c)) 177 178#define CLEAN0(s) ADD((&easysrc_clean, s)) 179#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a)) 180 181#define REM0(s) ADD((&easysrc_toohard, s)) 182#define REM1(f,a) ADDF((&easysrc_toohard, f,a)) 183#define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b)) 184 185/* Escape string to C string syntax. Return NULL if out of memory. 186 * Is this correct for those wacky EBCDIC guys? */ 187static char *c_escape(const char *str) 188{ 189 size_t len = 0; 190 const char *s; 191 unsigned char c; 192 char *escaped, *e; 193 /* Allocate space based on worst-case */ 194 len = strlen(str); 195 escaped = malloc(4 * len + 1); 196 if(!escaped) 197 return NULL; 198 199 e = escaped; 200 for(s=str; (c=*s) != '\0'; s++) { 201 if(c=='\n') { 202 strcpy(e, "\\n"); 203 e += 2; 204 } 205 else if(c=='\r') { 206 strcpy(e, "\\r"); 207 e += 2; 208 } 209 else if(c=='\t') { 210 strcpy(e, "\\t"); 211 e += 2; 212 } 213 else if(c=='\\') { 214 strcpy(e, "\\\\"); 215 e += 2; 216 } 217 else if(c=='"') { 218 strcpy(e, "\\\""); 219 e += 2; 220 } 221 else if(! isprint(c)) { 222 snprintf(e, 4, "\\%03o", c); 223 e += 4; 224 } 225 else 226 *e++ = c; 227 } 228 *e = '\0'; 229 return escaped; 230} 231 232/* setopt wrapper for enum types */ 233CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config, 234 const char *name, CURLoption tag, 235 const NameValue *nvlist, long lval) 236{ 237 CURLcode ret = CURLE_OK; 238 bool skip = FALSE; 239 240 ret = curl_easy_setopt(curl, tag, lval); 241 if(!lval) 242 skip = TRUE; 243 244 if(config->libcurl && !skip && !ret) { 245 /* we only use this for real if --libcurl was used */ 246 const NameValue *nv = NULL; 247 for(nv=nvlist; nv->name; nv++) { 248 if(nv->value == lval) break; /* found it */ 249 } 250 if(! nv->name) { 251 /* If no definition was found, output an explicit value. 252 * This could happen if new values are defined and used 253 * but the NameValue list is not updated. */ 254 CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval); 255 } 256 else { 257 CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name); 258 } 259 } 260 261 nomem: 262 return ret; 263} 264 265/* setopt wrapper for flags */ 266CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config, 267 const char *name, CURLoption tag, 268 const NameValue *nvlist, long lval) 269{ 270 CURLcode ret = CURLE_OK; 271 bool skip = FALSE; 272 273 ret = curl_easy_setopt(curl, tag, lval); 274 if(!lval) 275 skip = TRUE; 276 277 if(config->libcurl && !skip && !ret) { 278 /* we only use this for real if --libcurl was used */ 279 char preamble[80]; /* should accommodate any symbol name */ 280 long rest = lval; /* bits not handled yet */ 281 const NameValue *nv = NULL; 282 snprintf(preamble, sizeof(preamble), 283 "curl_easy_setopt(hnd, %s, ", name); 284 for(nv=nvlist; nv->name; nv++) { 285 if((nv->value & ~ rest) == 0) { 286 /* all value flags contained in rest */ 287 rest &= ~ nv->value; /* remove bits handled here */ 288 CODE3("%s(long)%s%s", 289 preamble, nv->name, rest ? " |" : ");"); 290 if(!rest) 291 break; /* handled them all */ 292 /* replace with all spaces for continuation line */ 293 snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); 294 } 295 } 296 /* If any bits have no definition, output an explicit value. 297 * This could happen if new bits are defined and used 298 * but the NameValue list is not updated. */ 299 if(rest) 300 CODE2("%s%ldL);", preamble, rest); 301 } 302 303 nomem: 304 return ret; 305} 306 307/* setopt wrapper for bitmasks */ 308CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config, 309 const char *name, CURLoption tag, 310 const NameValueUnsigned *nvlist, 311 long lval) 312{ 313 CURLcode ret = CURLE_OK; 314 bool skip = FALSE; 315 316 ret = curl_easy_setopt(curl, tag, lval); 317 if(!lval) 318 skip = TRUE; 319 320 if(config->libcurl && !skip && !ret) { 321 /* we only use this for real if --libcurl was used */ 322 char preamble[80]; 323 unsigned long rest = (unsigned long)lval; 324 const NameValueUnsigned *nv = NULL; 325 snprintf(preamble, sizeof(preamble), 326 "curl_easy_setopt(hnd, %s, ", name); 327 for(nv=nvlist; nv->name; nv++) { 328 if((nv->value & ~ rest) == 0) { 329 /* all value flags contained in rest */ 330 rest &= ~ nv->value; /* remove bits handled here */ 331 CODE3("%s(long)%s%s", 332 preamble, nv->name, rest ? " |" : ");"); 333 if(!rest) 334 break; /* handled them all */ 335 /* replace with all spaces for continuation line */ 336 snprintf(preamble, sizeof(preamble), "%*s", strlen(preamble), ""); 337 } 338 } 339 /* If any bits have no definition, output an explicit value. 340 * This could happen if new bits are defined and used 341 * but the NameValue list is not updated. */ 342 if(rest) 343 CODE2("%s%luUL);", preamble, rest); 344 } 345 346 nomem: 347 return ret; 348} 349 350/* setopt wrapper for CURLOPT_HTTPPOST */ 351CURLcode tool_setopt_httppost(CURL *curl, struct GlobalConfig *config, 352 const char *name, CURLoption tag, 353 struct curl_httppost *post) 354{ 355 CURLcode ret = CURLE_OK; 356 char *escaped = NULL; 357 bool skip = FALSE; 358 359 ret = curl_easy_setopt(curl, tag, post); 360 if(!post) 361 skip = TRUE; 362 363 if(config->libcurl && !skip && !ret) { 364 struct curl_httppost *pp, *p; 365 int i; 366 /* May use several httppost lists, if multiple POST actions */ 367 i = ++ easysrc_form_count; 368 DECL1("struct curl_httppost *post%d;", i); 369 DATA1("post%d = NULL;", i); 370 CLEAN1("curl_formfree(post%d);", i); 371 CLEAN1("post%d = NULL;", i); 372 if(i == 1) 373 DECL0("struct curl_httppost *postend;"); 374 DATA0("postend = NULL;"); 375 for(p=post; p; p=p->next) { 376 DATA1("curl_formadd(&post%d, &postend,", i); 377 DATA1(" CURLFORM_COPYNAME, \"%s\",", p->name); 378 for(pp=p; pp; pp=pp->more) { 379 /* May be several files uploaded for one name; 380 * these are linked through the 'more' pointer */ 381 Curl_safefree(escaped); 382 escaped = c_escape(pp->contents); 383 if(!escaped) { 384 ret = CURLE_OUT_OF_MEMORY; 385 goto nomem; 386 } 387 if(pp->flags & HTTPPOST_FILENAME) { 388 /* file upload as for -F @filename */ 389 DATA1(" CURLFORM_FILE, \"%s\",", escaped); 390 } 391 else if(pp->flags & HTTPPOST_READFILE) { 392 /* content from file as for -F <filename */ 393 DATA1(" CURLFORM_FILECONTENT, \"%s\",", escaped); 394 } 395 else 396 DATA1(" CURLFORM_COPYCONTENTS, \"%s\",", escaped); 397 if(pp->showfilename) { 398 Curl_safefree(escaped); 399 escaped = c_escape(pp->showfilename); 400 if(!escaped) { 401 ret = CURLE_OUT_OF_MEMORY; 402 goto nomem; 403 } 404 DATA1(" CURLFORM_FILENAME, \"%s\",", escaped); 405 } 406 if(pp->contenttype) { 407 Curl_safefree(escaped); 408 escaped = c_escape(pp->contenttype); 409 if(!escaped) { 410 ret = CURLE_OUT_OF_MEMORY; 411 goto nomem; 412 } 413 DATA1(" CURLFORM_CONTENTTYPE, \"%s\",", escaped); 414 } 415 } 416 DATA0(" CURLFORM_END);"); 417 } 418 CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i); 419 } 420 421 nomem: 422 Curl_safefree(escaped); 423 return ret; 424} 425 426/* setopt wrapper for curl_slist options */ 427CURLcode tool_setopt_slist(CURL *curl, struct GlobalConfig *config, 428 const char *name, CURLoption tag, 429 struct curl_slist *list) 430{ 431 CURLcode ret = CURLE_OK; 432 char *escaped = NULL; 433 bool skip = FALSE; 434 435 ret = curl_easy_setopt(curl, tag, list); 436 if(!list) 437 skip = TRUE; 438 439 if(config->libcurl && !skip && !ret) { 440 struct curl_slist *s; 441 int i; 442 /* May need several slist variables, so invent name */ 443 i = ++ easysrc_slist_count; 444 DECL1("struct curl_slist *slist%d;", i); 445 DATA1("slist%d = NULL;", i); 446 CLEAN1("curl_slist_free_all(slist%d);", i); 447 CLEAN1("slist%d = NULL;", i); 448 for(s=list; s; s=s->next) { 449 Curl_safefree(escaped); 450 escaped = c_escape(s->data); 451 if(!escaped) { 452 ret = CURLE_OUT_OF_MEMORY; 453 goto nomem; 454 } 455 DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, escaped); 456 } 457 CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i); 458 } 459 460 nomem: 461 Curl_safefree(escaped); 462 return ret; 463} 464 465/* generic setopt wrapper for all other options. 466 * Some type information is encoded in the tag value. */ 467CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *config, 468 const char *name, CURLoption tag, ...) 469{ 470 va_list arg; 471 char buf[256]; 472 const char *value = NULL; 473 bool remark = FALSE; 474 bool skip = FALSE; 475 bool escape = FALSE; 476 char *escaped = NULL; 477 CURLcode ret = CURLE_OK; 478 479 va_start(arg, tag); 480 481 if(tag < CURLOPTTYPE_OBJECTPOINT) { 482 /* Value is expected to be a long */ 483 long lval = va_arg(arg, long); 484 long defval = 0L; 485 const NameValue *nv = NULL; 486 for(nv=setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) { 487 if(!strcmp(name, nv->name)) { 488 defval = nv->value; 489 break; /* found it */ 490 } 491 } 492 493 snprintf(buf, sizeof(buf), "%ldL", lval); 494 value = buf; 495 ret = curl_easy_setopt(curl, tag, lval); 496 if(lval == defval) 497 skip = TRUE; 498 } 499 else if(tag < CURLOPTTYPE_OFF_T) { 500 /* Value is some sort of object pointer */ 501 void *pval = va_arg(arg, void *); 502 503 /* function pointers are never printable */ 504 if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { 505 if(pval) { 506 value = "functionpointer"; 507 remark = TRUE; 508 } 509 else 510 skip = TRUE; 511 } 512 513 else if(pval && str) { 514 value = (char *)pval; 515 escape = TRUE; 516 } 517 else if(pval) { 518 value = "objectpointer"; 519 remark = TRUE; 520 } 521 else 522 skip = TRUE; 523 524 ret = curl_easy_setopt(curl, tag, pval); 525 526 } 527 else { 528 /* Value is expected to be curl_off_t */ 529 curl_off_t oval = va_arg(arg, curl_off_t); 530 snprintf(buf, sizeof(buf), 531 "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); 532 value = buf; 533 ret = curl_easy_setopt(curl, tag, oval); 534 535 if(!oval) 536 skip = TRUE; 537 } 538 539 va_end(arg); 540 541 if(config->libcurl && !skip && !ret) { 542 /* we only use this for real if --libcurl was used */ 543 544 if(remark) 545 REM2("%s set to a %s", name, value); 546 else { 547 if(escape) { 548 escaped = c_escape(value); 549 if(!escaped) { 550 ret = CURLE_OUT_OF_MEMORY; 551 goto nomem; 552 } 553 CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped); 554 } 555 else 556 CODE2("curl_easy_setopt(hnd, %s, %s);", name, value); 557 } 558 } 559 560 nomem: 561 Curl_safefree(escaped); 562 return ret; 563} 564 565#endif /* CURL_DISABLE_LIBCURL_OPTION */ 566