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