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