config2setopts.c (36699B)
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 26 #include "tool_cfgable.h" 27 #include "tool_setopt.h" 28 #include "tool_findfile.h" 29 #include "tool_msgs.h" 30 #include "tool_libinfo.h" 31 #include "tool_cb_soc.h" 32 #include "tool_operate.h" 33 #include "config2setopts.h" 34 #include "tool_ipfs.h" 35 #include "tool_cb_wrt.h" 36 #include "tool_cb_rea.h" 37 #include "tool_cb_see.h" 38 #include "tool_cb_dbg.h" 39 #include "tool_helpers.h" 40 41 #define BUFFER_SIZE 102400L 42 43 /* When doing serial transfers, we use a single fixed error area */ 44 static char global_errorbuffer[CURL_ERROR_SIZE]; 45 46 #ifdef IP_TOS 47 static int get_address_family(curl_socket_t sockfd) 48 { 49 struct sockaddr addr; 50 curl_socklen_t addrlen = sizeof(addr); 51 memset(&addr, 0, sizeof(addr)); 52 if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0) 53 return addr.sa_family; 54 return AF_UNSPEC; 55 } 56 #endif 57 58 #ifndef SOL_IP 59 # define SOL_IP IPPROTO_IP 60 #endif 61 62 #if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY) 63 static int sockopt_callback(void *clientp, curl_socket_t curlfd, 64 curlsocktype purpose) 65 { 66 struct OperationConfig *config = (struct OperationConfig *)clientp; 67 if(purpose != CURLSOCKTYPE_IPCXN) 68 return CURL_SOCKOPT_OK; 69 (void)config; 70 (void)curlfd; 71 #if defined(IP_TOS) || defined(IPV6_TCLASS) 72 if(config->ip_tos > 0) { 73 int tos = (int)config->ip_tos; 74 int result = 0; 75 switch(get_address_family(curlfd)) { 76 case AF_INET: 77 #ifdef IP_TOS 78 result = setsockopt(curlfd, SOL_IP, IP_TOS, (void *)&tos, sizeof(tos)); 79 #endif 80 break; 81 #if defined(IPV6_TCLASS) && defined(AF_INET6) 82 case AF_INET6: 83 result = setsockopt(curlfd, IPPROTO_IPV6, IPV6_TCLASS, 84 (void *)&tos, sizeof(tos)); 85 break; 86 #endif 87 } 88 if(result < 0) { 89 int error = errno; 90 warnf(config->global, 91 "Setting type of service to %d failed with errno %d: %s;\n", 92 tos, error, strerror(error)); 93 } 94 } 95 #endif 96 #ifdef SO_PRIORITY 97 if(config->vlan_priority > 0) { 98 int priority = (int)config->vlan_priority; 99 if(setsockopt(curlfd, SOL_SOCKET, SO_PRIORITY, 100 (void *)&priority, sizeof(priority)) != 0) { 101 int error = errno; 102 warnf(config->global, "VLAN priority %d failed with errno %d: %s;\n", 103 priority, error, strerror(error)); 104 } 105 } 106 #endif 107 return CURL_SOCKOPT_OK; 108 } 109 #endif /* IP_TOD || IPV6_TCLASS || SO_PRIORITY */ 110 111 /* return current SSL backend name, chop off multissl */ 112 static char *ssl_backend(void) 113 { 114 static char ssl_ver[80] = "no ssl"; 115 static bool already = FALSE; 116 if(!already) { /* if there is no existing version */ 117 const char *v = curl_version_info(CURLVERSION_NOW)->ssl_version; 118 if(v) 119 msnprintf(ssl_ver, sizeof(ssl_ver), "%.*s", (int) strcspn(v, " "), v); 120 already = TRUE; 121 } 122 return ssl_ver; 123 } 124 125 /* 126 * Possibly rewrite the URL for IPFS and return the protocol token for the 127 * scheme used in the given URL. 128 */ 129 static CURLcode url_proto_and_rewrite(char **url, 130 struct OperationConfig *config, 131 const char **scheme) 132 { 133 CURLcode result = CURLE_OK; 134 CURLU *uh = curl_url(); 135 const char *proto = NULL; 136 *scheme = NULL; 137 138 DEBUGASSERT(url && *url); 139 if(uh) { 140 char *schemep = NULL; 141 if(!curl_url_set(uh, CURLUPART_URL, *url, 142 CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) && 143 !curl_url_get(uh, CURLUPART_SCHEME, &schemep, 144 CURLU_DEFAULT_SCHEME)) { 145 #ifdef CURL_DISABLE_IPFS 146 (void)config; 147 #else 148 if(curl_strequal(schemep, proto_ipfs) || 149 curl_strequal(schemep, proto_ipns)) { 150 result = ipfs_url_rewrite(uh, schemep, url, config); 151 /* short-circuit proto_token, we know it is ipfs or ipns */ 152 if(curl_strequal(schemep, proto_ipfs)) 153 proto = proto_ipfs; 154 else if(curl_strequal(schemep, proto_ipns)) 155 proto = proto_ipns; 156 if(result) 157 config->synthetic_error = TRUE; 158 } 159 else 160 #endif /* !CURL_DISABLE_IPFS */ 161 proto = proto_token(schemep); 162 163 curl_free(schemep); 164 } 165 curl_url_cleanup(uh); 166 } 167 else 168 result = CURLE_OUT_OF_MEMORY; 169 170 *scheme = proto ? proto : "?"; /* Never match if not found. */ 171 return result; 172 } 173 174 static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl) 175 { 176 struct GlobalConfig *global = config->global; 177 CURLcode result; 178 179 /* SSH and SSL private key uses same command-line option */ 180 /* new in libcurl 7.16.1 */ 181 my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key); 182 /* new in libcurl 7.16.1 */ 183 my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); 184 185 /* new in libcurl 7.17.1: SSH host key md5 checking allows us 186 to fail if we are not talking to who we think we should */ 187 my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, 188 config->hostpubmd5); 189 190 /* new in libcurl 7.80.0: SSH host key sha256 checking allows us 191 to fail if we are not talking to who we think we should */ 192 my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, 193 config->hostpubsha256); 194 195 /* new in libcurl 7.56.0 */ 196 if(config->ssh_compression) 197 my_setopt_long(curl, CURLOPT_SSH_COMPRESSION, 1); 198 199 if(!config->insecure_ok) { 200 char *known = global->knownhosts; 201 202 if(!known) 203 known = findfile(".ssh/known_hosts", FALSE); 204 if(known) { 205 /* new in curl 7.19.6 */ 206 result = my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known); 207 if(result) { 208 global->knownhosts = NULL; 209 curl_free(known); 210 return result; 211 } 212 /* store it in global to avoid repeated checks */ 213 global->knownhosts = known; 214 } 215 else if(!config->hostpubmd5 && !config->hostpubsha256) { 216 errorf(global, "Couldn't find a known_hosts file"); 217 return CURLE_FAILED_INIT; 218 } 219 else 220 warnf(global, "Couldn't find a known_hosts file"); 221 } 222 return CURLE_OK; /* ignore if SHA256 did not work */ 223 } 224 225 #ifdef CURL_CA_EMBED 226 #ifndef CURL_DECLARED_CURL_CA_EMBED 227 #define CURL_DECLARED_CURL_CA_EMBED 228 extern const unsigned char curl_ca_embed[]; 229 #endif 230 #endif 231 232 /* only called if libcurl supports TLS */ 233 static CURLcode ssl_setopts(struct OperationConfig *config, CURL *curl) 234 { 235 struct GlobalConfig *global = config->global; 236 CURLcode result = CURLE_OK; 237 238 if(config->cacert) 239 my_setopt_str(curl, CURLOPT_CAINFO, config->cacert); 240 if(config->proxy_cacert) 241 my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert); 242 243 if(config->capath) { 244 result = my_setopt_str(curl, CURLOPT_CAPATH, config->capath); 245 if(result) 246 return result; 247 } 248 /* For the time being if --proxy-capath is not set then we use the 249 --capath value for it, if any. See #1257 */ 250 if(config->proxy_capath || config->capath) { 251 result = my_setopt_str(curl, CURLOPT_PROXY_CAPATH, 252 (config->proxy_capath ? config->proxy_capath : 253 config->capath)); 254 if((result == CURLE_NOT_BUILT_IN) || 255 (result == CURLE_UNKNOWN_OPTION)) { 256 if(config->proxy_capath) { 257 warnf(global, "ignoring %s, not supported by libcurl with %s", 258 config->proxy_capath ? "--proxy-capath" : "--capath", 259 ssl_backend()); 260 } 261 } 262 else if(result) 263 return result; 264 } 265 266 #ifdef CURL_CA_EMBED 267 if(!config->cacert && !config->capath) { 268 struct curl_blob blob; 269 blob.data = CURL_UNCONST(curl_ca_embed); 270 blob.len = strlen((const char *)curl_ca_embed); 271 blob.flags = CURL_BLOB_NOCOPY; 272 notef(config->global, 273 "Using embedded CA bundle (%zu bytes)", 274 blob.len); 275 result = curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob); 276 if(result == CURLE_NOT_BUILT_IN) { 277 warnf(global, "ignoring %s, not supported by libcurl with %s", 278 "embedded CA bundle", ssl_backend()); 279 } 280 } 281 if(!config->proxy_cacert && !config->proxy_capath) { 282 struct curl_blob blob; 283 blob.data = CURL_UNCONST(curl_ca_embed); 284 blob.len = strlen((const char *)curl_ca_embed); 285 blob.flags = CURL_BLOB_NOCOPY; 286 notef(config->global, 287 "Using embedded CA bundle, for proxies (%zu bytes)", 288 blob.len); 289 result = curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob); 290 if(result == CURLE_NOT_BUILT_IN) { 291 warnf(global, "ignoring %s, not supported by libcurl with %s", 292 "embedded CA bundle", ssl_backend()); 293 } 294 } 295 #endif 296 297 if(config->crlfile) 298 my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile); 299 if(config->proxy_crlfile) 300 my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile); 301 else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */ 302 my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile); 303 304 if(config->pinnedpubkey) { 305 result = my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, 306 config->pinnedpubkey); 307 if(result == CURLE_NOT_BUILT_IN) 308 warnf(global, "ignoring %s, not supported by libcurl with %s", 309 "--pinnedpubkey", ssl_backend()); 310 } 311 if(config->proxy_pinnedpubkey) { 312 result = my_setopt_str(curl, CURLOPT_PROXY_PINNEDPUBLICKEY, 313 config->proxy_pinnedpubkey); 314 if(result == CURLE_NOT_BUILT_IN) 315 warnf(global, "ignoring %s, not supported by libcurl with %s", 316 "--proxy-pinnedpubkey", ssl_backend()); 317 } 318 319 if(config->ssl_ec_curves) 320 my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves); 321 322 if(config->ssl_signature_algorithms) 323 my_setopt_str(curl, CURLOPT_SSL_SIGNATURE_ALGORITHMS, 324 config->ssl_signature_algorithms); 325 326 if(config->writeout) 327 my_setopt_long(curl, CURLOPT_CERTINFO, 1); 328 329 my_setopt_str(curl, CURLOPT_SSLCERT, config->cert); 330 my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert); 331 my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type); 332 my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE, 333 config->proxy_cert_type); 334 my_setopt_str(curl, CURLOPT_SSLKEY, config->key); 335 my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key); 336 my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type); 337 my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE, 338 config->proxy_key_type); 339 340 /* libcurl default is strict verifyhost -> 1L, verifypeer -> 1L */ 341 if(config->insecure_ok) { 342 my_setopt_long(curl, CURLOPT_SSL_VERIFYPEER, 0); 343 my_setopt_long(curl, CURLOPT_SSL_VERIFYHOST, 0); 344 } 345 346 if(config->doh_insecure_ok) { 347 my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0); 348 my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0); 349 } 350 351 if(config->proxy_insecure_ok) { 352 my_setopt_long(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0); 353 my_setopt_long(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0); 354 } 355 356 if(config->verifystatus) 357 my_setopt_long(curl, CURLOPT_SSL_VERIFYSTATUS, 1); 358 359 if(config->doh_verifystatus) 360 my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1); 361 362 my_setopt_SSLVERSION(curl, CURLOPT_SSLVERSION, 363 config->ssl_version | config->ssl_version_max); 364 if(config->proxy) 365 my_setopt_SSLVERSION(curl, CURLOPT_PROXY_SSLVERSION, 366 config->proxy_ssl_version); 367 368 { 369 long mask = 370 (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) | 371 (config->ssl_allow_earlydata ? CURLSSLOPT_EARLYDATA : 0) | 372 (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0) | 373 (config->ssl_revoke_best_effort ? CURLSSLOPT_REVOKE_BEST_EFFORT : 0) | 374 (config->native_ca_store ? CURLSSLOPT_NATIVE_CA : 0) | 375 (config->ssl_auto_client_cert ? CURLSSLOPT_AUTO_CLIENT_CERT : 0); 376 377 if(mask) 378 my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask); 379 } 380 381 { 382 long mask = 383 (config->proxy_ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) | 384 (config->proxy_ssl_auto_client_cert ? 385 CURLSSLOPT_AUTO_CLIENT_CERT : 0) | 386 (config->proxy_native_ca_store ? CURLSSLOPT_NATIVE_CA : 0); 387 388 if(mask) 389 my_setopt_bitmask(curl, CURLOPT_PROXY_SSL_OPTIONS, mask); 390 } 391 392 if(config->cipher_list) { 393 result = my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, 394 config->cipher_list); 395 if(result == CURLE_NOT_BUILT_IN) 396 warnf(global, "ignoring %s, not supported by libcurl with %s", 397 "--ciphers", ssl_backend()); 398 } 399 if(config->proxy_cipher_list) { 400 result = my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, 401 config->proxy_cipher_list); 402 if(result == CURLE_NOT_BUILT_IN) 403 warnf(global, "ignoring %s, not supported by libcurl with %s", 404 "--proxy-ciphers", ssl_backend()); 405 } 406 if(config->cipher13_list) { 407 result = my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, 408 config->cipher13_list); 409 if(result == CURLE_NOT_BUILT_IN) 410 warnf(global, "ignoring %s, not supported by libcurl with %s", 411 "--tls13-ciphers", ssl_backend()); 412 } 413 if(config->proxy_cipher13_list) { 414 result = my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, 415 config->proxy_cipher13_list); 416 if(result == CURLE_NOT_BUILT_IN) 417 warnf(global, "ignoring %s, not supported by libcurl with %s", 418 "--proxy-tls13-ciphers", ssl_backend()); 419 } 420 421 /* curl 7.16.0 */ 422 if(config->disable_sessionid) 423 /* disable it */ 424 my_setopt_long(curl, CURLOPT_SSL_SESSIONID_CACHE, 0); 425 426 if(feature_ech) { 427 /* only if enabled in libcurl */ 428 if(config->ech) /* only if set (optional) */ 429 my_setopt_str(curl, CURLOPT_ECH, config->ech); 430 if(config->ech_public) /* only if set (optional) */ 431 my_setopt_str(curl, CURLOPT_ECH, config->ech_public); 432 if(config->ech_config) /* only if set (optional) */ 433 my_setopt_str(curl, CURLOPT_ECH, config->ech_config); 434 } 435 436 /* new in curl 7.9.3 */ 437 if(config->engine) { 438 result = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine); 439 if(result) 440 return result; 441 } 442 443 /* new in curl 7.15.5 */ 444 if(config->ftp_ssl_reqd) 445 my_setopt_enum(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); 446 447 /* new in curl 7.11.0 */ 448 else if(config->ftp_ssl) 449 my_setopt_enum(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); 450 451 /* new in curl 7.16.0 */ 452 else if(config->ftp_ssl_control) 453 my_setopt_enum(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL); 454 455 if(config->noalpn) 456 my_setopt_long(curl, CURLOPT_SSL_ENABLE_ALPN, 0); 457 458 return CURLE_OK; 459 } 460 461 /* only called for HTTP transfers */ 462 static CURLcode http_setopts(struct OperationConfig *config, 463 CURL *curl) 464 { 465 long postRedir = 0; 466 467 my_setopt_long(curl, CURLOPT_FOLLOWLOCATION, 468 config->followlocation); 469 my_setopt_long(curl, CURLOPT_UNRESTRICTED_AUTH, 470 config->unrestricted_auth); 471 my_setopt_str(curl, CURLOPT_AWS_SIGV4, config->aws_sigv4); 472 my_setopt_long(curl, CURLOPT_AUTOREFERER, config->autoreferer); 473 474 /* new in libcurl 7.36.0 */ 475 if(config->proxyheaders) { 476 my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders); 477 my_setopt_long(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE); 478 } 479 480 /* new in libcurl 7.5 */ 481 my_setopt_long(curl, CURLOPT_MAXREDIRS, config->maxredirs); 482 483 if(config->httpversion) 484 my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion); 485 486 /* curl 7.19.1 (the 301 version existed in 7.18.2), 487 303 was added in 7.26.0 */ 488 if(config->post301) 489 postRedir |= CURL_REDIR_POST_301; 490 if(config->post302) 491 postRedir |= CURL_REDIR_POST_302; 492 if(config->post303) 493 postRedir |= CURL_REDIR_POST_303; 494 my_setopt_long(curl, CURLOPT_POSTREDIR, postRedir); 495 496 /* new in libcurl 7.21.6 */ 497 if(config->encoding) 498 my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, ""); 499 500 /* new in libcurl 7.21.6 */ 501 if(config->tr_encoding) 502 my_setopt_long(curl, CURLOPT_TRANSFER_ENCODING, 1); 503 /* new in libcurl 7.64.0 */ 504 my_setopt_long(curl, CURLOPT_HTTP09_ALLOWED, config->http09_allowed); 505 506 if(config->altsvc) 507 my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc); 508 509 if(config->hsts) 510 my_setopt_str(curl, CURLOPT_HSTS, config->hsts); 511 512 /* new in 7.47.0 */ 513 if(config->expect100timeout_ms > 0) 514 my_setopt_long(curl, CURLOPT_EXPECT_100_TIMEOUT_MS, 515 config->expect100timeout_ms); 516 517 return CURLE_OK; 518 } 519 520 static CURLcode cookie_setopts(struct OperationConfig *config, CURL *curl) 521 { 522 CURLcode result = CURLE_OK; 523 if(config->cookies) { 524 struct dynbuf cookies; 525 struct curl_slist *cl; 526 527 /* The maximum size needs to match MAX_NAME in cookie.h */ 528 #define MAX_COOKIE_LINE 8200 529 curlx_dyn_init(&cookies, MAX_COOKIE_LINE); 530 for(cl = config->cookies; cl; cl = cl->next) { 531 if(cl == config->cookies) 532 result = curlx_dyn_addf(&cookies, "%s", cl->data); 533 else 534 result = curlx_dyn_addf(&cookies, ";%s", cl->data); 535 536 if(result) { 537 warnf(config->global, 538 "skipped provided cookie, the cookie header " 539 "would go over %u bytes", MAX_COOKIE_LINE); 540 return result; 541 } 542 } 543 544 my_setopt_str(curl, CURLOPT_COOKIE, curlx_dyn_ptr(&cookies)); 545 curlx_dyn_free(&cookies); 546 } 547 548 if(config->cookiefiles) { 549 struct curl_slist *cfl; 550 551 for(cfl = config->cookiefiles; cfl; cfl = cfl->next) 552 my_setopt_str(curl, CURLOPT_COOKIEFILE, cfl->data); 553 } 554 555 /* new in libcurl 7.9 */ 556 if(config->cookiejar) 557 my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar); 558 559 /* new in libcurl 7.9.7 */ 560 my_setopt_long(curl, CURLOPT_COOKIESESSION, config->cookiesession); 561 562 return result; 563 } 564 565 static CURLcode tcp_setopts(struct OperationConfig *config, 566 CURL *curl) 567 { 568 if(!config->tcp_nodelay) 569 my_setopt_long(curl, CURLOPT_TCP_NODELAY, 0); 570 571 if(config->tcp_fastopen) 572 my_setopt_long(curl, CURLOPT_TCP_FASTOPEN, 1); 573 574 if(config->mptcp) 575 my_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, tool_socket_open_mptcp_cb); 576 577 /* curl 7.17.1 */ 578 if(!config->nokeepalive) { 579 my_setopt_long(curl, CURLOPT_TCP_KEEPALIVE, 1); 580 if(config->alivetime) { 581 my_setopt_long(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime); 582 my_setopt_long(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime); 583 } 584 if(config->alivecnt) 585 my_setopt_long(curl, CURLOPT_TCP_KEEPCNT, config->alivecnt); 586 } 587 else 588 my_setopt_long(curl, CURLOPT_TCP_KEEPALIVE, 0); 589 return CURLE_OK; 590 } 591 592 static CURLcode ftp_setopts(struct OperationConfig *config, CURL *curl) 593 { 594 my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); 595 596 /* new in libcurl 7.9.2: */ 597 if(config->disable_epsv) 598 /* disable it */ 599 my_setopt_long(curl, CURLOPT_FTP_USE_EPSV, 0); 600 601 /* new in libcurl 7.10.5 */ 602 if(config->disable_eprt) 603 /* disable it */ 604 my_setopt_long(curl, CURLOPT_FTP_USE_EPRT, 0); 605 606 /* new in curl 7.16.1 */ 607 if(config->ftp_ssl_ccc) 608 my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, (long)config->ftp_ssl_ccc_mode); 609 610 my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account); 611 612 /* curl 7.14.2 */ 613 my_setopt_long(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip); 614 615 /* curl 7.15.1 */ 616 my_setopt_long(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod); 617 618 /* curl 7.15.5 */ 619 my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, 620 config->ftp_alternative_to_user); 621 622 /* curl 7.20.x */ 623 if(config->ftp_pret) 624 my_setopt_long(curl, CURLOPT_FTP_USE_PRET, 1); 625 626 return CURLE_OK; 627 } 628 629 static void gen_trace_setopts(struct OperationConfig *config, CURL *curl) 630 { 631 if(config->global->tracetype != TRACE_NONE) { 632 my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb); 633 my_setopt(curl, CURLOPT_DEBUGDATA, config); 634 my_setopt_long(curl, CURLOPT_VERBOSE, 1L); 635 } 636 } 637 638 static void gen_cb_setopts(struct OperationConfig *config, 639 struct per_transfer *per, 640 CURL *curl) 641 { 642 struct GlobalConfig *global = config->global; 643 (void) config; 644 /* where to store */ 645 my_setopt(curl, CURLOPT_WRITEDATA, per); 646 my_setopt(curl, CURLOPT_INTERLEAVEDATA, per); 647 648 /* what call to write */ 649 my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); 650 651 /* what to read */ 652 my_setopt(curl, CURLOPT_READDATA, per); 653 my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb); 654 655 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what 656 CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */ 657 my_setopt(curl, CURLOPT_SEEKDATA, per); 658 my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb); 659 660 if((global->progressmode == CURL_PROGRESS_BAR) && 661 !global->noprogress && !global->silent) { 662 /* we want the alternative style, then we have to implement it 663 ourselves! */ 664 my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb); 665 my_setopt(curl, CURLOPT_XFERINFODATA, per); 666 } 667 else if(per->uploadfile && !strcmp(per->uploadfile, ".")) { 668 /* when reading from stdin in non-blocking mode, we use the progress 669 function to unpause a busy read */ 670 my_setopt_long(curl, CURLOPT_NOPROGRESS, 0); 671 my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb); 672 my_setopt(curl, CURLOPT_XFERINFODATA, per); 673 } 674 675 my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb); 676 my_setopt(curl, CURLOPT_HEADERDATA, per); 677 } 678 679 static CURLcode proxy_setopts(struct OperationConfig *config, CURL *curl) 680 { 681 if(config->proxy) { 682 CURLcode result = my_setopt_str(curl, CURLOPT_PROXY, config->proxy); 683 684 if(result) { 685 errorf(config->global, "proxy support is disabled in this libcurl"); 686 config->synthetic_error = TRUE; 687 return CURLE_NOT_BUILT_IN; 688 } 689 } 690 691 /* new in libcurl 7.5 */ 692 if(config->proxy) 693 my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver); 694 695 my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd); 696 697 /* new in libcurl 7.3 */ 698 my_setopt_long(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel); 699 700 /* new in libcurl 7.52.0 */ 701 if(config->preproxy) 702 my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy); 703 704 /* new in libcurl 7.10.6 */ 705 if(config->proxyanyauth) 706 my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); 707 else if(config->proxynegotiate) 708 my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE); 709 else if(config->proxyntlm) 710 my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); 711 else if(config->proxydigest) 712 my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); 713 else if(config->proxybasic) 714 my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); 715 716 /* new in libcurl 7.19.4 */ 717 my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy); 718 719 my_setopt_long(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS, 720 config->suppress_connect_headers); 721 722 /* new in curl 7.43.0 */ 723 if(config->proxy_service_name) 724 my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME, 725 config->proxy_service_name); 726 727 /* new in 7.60.0 */ 728 if(config->haproxy_protocol) 729 my_setopt_long(curl, CURLOPT_HAPROXYPROTOCOL, 1); 730 731 /* new in 8.2.0 */ 732 if(config->haproxy_clientip) 733 my_setopt_str(curl, CURLOPT_HAPROXY_CLIENT_IP, config->haproxy_clientip); 734 735 return CURLE_OK; 736 } 737 738 static void tls_srp_setopts(struct OperationConfig *config, CURL *curl) 739 { 740 if(config->tls_username) 741 my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME, config->tls_username); 742 if(config->tls_password) 743 my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD, config->tls_password); 744 if(config->tls_authtype) 745 my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE, config->tls_authtype); 746 if(config->proxy_tls_username) 747 my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, 748 config->proxy_tls_username); 749 if(config->proxy_tls_password) 750 my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, 751 config->proxy_tls_password); 752 if(config->proxy_tls_authtype) 753 my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE, 754 config->proxy_tls_authtype); 755 } 756 757 CURLcode config2setopts(struct OperationConfig *config, 758 struct per_transfer *per, 759 CURL *curl, 760 CURLSH *share) 761 { 762 struct GlobalConfig *global = config->global; 763 const char *use_proto; 764 CURLcode result = url_proto_and_rewrite(&per->url, config, &use_proto); 765 766 /* Avoid having this setopt added to the --libcurl source output. */ 767 if(!result) 768 result = curl_easy_setopt(curl, CURLOPT_SHARE, share); 769 if(result) 770 return result; 771 772 #ifndef DEBUGBUILD 773 /* On most modern OSes, exiting works thoroughly, 774 we will clean everything up via exit(), so do not bother with 775 slow cleanups. Crappy ones might need to skip this. 776 Note: avoid having this setopt added to the --libcurl source 777 output. */ 778 result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L); 779 if(result) 780 return result; 781 #endif 782 783 gen_trace_setopts(config, curl); 784 785 { 786 #ifdef DEBUGBUILD 787 char *env = getenv("CURL_BUFFERSIZE"); 788 if(env) { 789 curl_off_t num; 790 const char *p = env; 791 if(!curlx_str_number(&p, &num, LONG_MAX)) 792 my_setopt_long(curl, CURLOPT_BUFFERSIZE, (long)num); 793 } 794 else 795 #endif 796 if(config->recvpersecond && (config->recvpersecond < BUFFER_SIZE)) 797 /* use a smaller sized buffer for better sleeps */ 798 my_setopt_long(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond); 799 else 800 my_setopt_long(curl, CURLOPT_BUFFERSIZE, BUFFER_SIZE); 801 } 802 803 my_setopt_str(curl, CURLOPT_URL, per->url); 804 my_setopt_long(curl, CURLOPT_NOPROGRESS, 805 global->noprogress || global->silent); 806 /* call after the line above. It may override CURLOPT_NOPROGRESS */ 807 gen_cb_setopts(config, per, curl); 808 809 if(config->no_body) 810 my_setopt_long(curl, CURLOPT_NOBODY, 1); 811 812 if(config->oauth_bearer) 813 my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer); 814 815 result = proxy_setopts(config, curl); 816 if(result) 817 return result; 818 819 my_setopt_long(curl, CURLOPT_FAILONERROR, config->failonerror); 820 my_setopt_str(curl, CURLOPT_REQUEST_TARGET, config->request_target); 821 my_setopt_long(curl, CURLOPT_UPLOAD, !!per->uploadfile); 822 my_setopt_long(curl, CURLOPT_DIRLISTONLY, config->dirlistonly); 823 my_setopt_long(curl, CURLOPT_APPEND, config->ftp_append); 824 825 if(config->netrc_opt) 826 my_setopt_enum(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); 827 else if(config->netrc || config->netrc_file) 828 my_setopt_enum(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED); 829 else 830 my_setopt_enum(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED); 831 832 if(config->netrc_file) 833 my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file); 834 835 my_setopt_long(curl, CURLOPT_TRANSFERTEXT, config->use_ascii); 836 if(config->login_options) 837 my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options); 838 my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd); 839 my_setopt_str(curl, CURLOPT_RANGE, config->range); 840 if(!global->parallel) { 841 per->errorbuffer = global_errorbuffer; 842 my_setopt(curl, CURLOPT_ERRORBUFFER, global_errorbuffer); 843 } 844 my_setopt_long(curl, CURLOPT_TIMEOUT_MS, config->timeout_ms); 845 846 switch(config->httpreq) { 847 case TOOL_HTTPREQ_SIMPLEPOST: 848 if(config->resume_from) { 849 errorf(global, "cannot mix --continue-at with --data"); 850 result = CURLE_FAILED_INIT; 851 } 852 else { 853 my_setopt_str(curl, CURLOPT_POSTFIELDS, 854 curlx_dyn_ptr(&config->postdata)); 855 my_setopt_offt(curl, CURLOPT_POSTFIELDSIZE_LARGE, 856 curlx_dyn_len(&config->postdata)); 857 } 858 break; 859 case TOOL_HTTPREQ_MIMEPOST: 860 /* free previous remainders */ 861 curl_mime_free(config->mimepost); 862 config->mimepost = NULL; 863 if(config->resume_from) { 864 errorf(global, "cannot mix --continue-at with --form"); 865 result = CURLE_FAILED_INIT; 866 } 867 else { 868 result = tool2curlmime(curl, config->mimeroot, &config->mimepost); 869 if(!result) 870 my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost); 871 } 872 break; 873 default: 874 break; 875 } 876 if(result) 877 return result; 878 879 /* new in libcurl 7.81.0 */ 880 if(config->mime_options) 881 my_setopt_long(curl, CURLOPT_MIME_OPTIONS, config->mime_options); 882 883 /* new in libcurl 7.10.6 (default is Basic) */ 884 if(config->authtype) 885 my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, config->authtype); 886 887 my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers); 888 889 if(proto_http || proto_rtsp) { 890 my_setopt_str(curl, CURLOPT_REFERER, config->referer); 891 my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); 892 } 893 894 if(use_proto == proto_http || use_proto == proto_https) { 895 result = http_setopts(config, curl); 896 if(!result) 897 result = cookie_setopts(config, curl); 898 if(result) 899 return result; 900 } 901 902 if(use_proto == proto_ftp || use_proto == proto_ftps) { 903 result = ftp_setopts(config, curl); 904 if(result) 905 return result; 906 } 907 908 my_setopt_long(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit); 909 my_setopt_long(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); 910 my_setopt_offt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, config->sendpersecond); 911 my_setopt_offt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, config->recvpersecond); 912 913 if(config->use_resume) 914 my_setopt_offt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from); 915 else 916 my_setopt_offt(curl, CURLOPT_RESUME_FROM_LARGE, 0); 917 918 my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); 919 my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd); 920 921 if(use_proto == proto_scp || use_proto == proto_sftp) { 922 result = ssh_setopts(config, curl); 923 if(result) 924 return result; 925 } 926 927 if(feature_ssl) { 928 result = ssl_setopts(config, curl); 929 if(result) 930 return result; 931 } 932 933 if(config->path_as_is) 934 my_setopt_long(curl, CURLOPT_PATH_AS_IS, 1); 935 936 if(config->no_body || config->remote_time) { 937 /* no body or use remote time */ 938 my_setopt_long(curl, CURLOPT_FILETIME, 1); 939 } 940 941 my_setopt_long(curl, CURLOPT_CRLF, config->crlf); 942 my_setopt_slist(curl, CURLOPT_QUOTE, config->quote); 943 my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote); 944 my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote); 945 946 my_setopt_enum(curl, CURLOPT_TIMECONDITION, config->timecond); 947 my_setopt_offt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime); 948 my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest); 949 customrequest_helper(config, config->httpreq, config->customrequest); 950 my_setopt(curl, CURLOPT_STDERR, tool_stderr); 951 952 /* three new ones in libcurl 7.3: */ 953 my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); 954 my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); 955 progressbarinit(&per->progressbar, config); 956 957 /* new in libcurl 7.24.0: */ 958 if(config->dns_servers) 959 my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers); 960 961 /* new in libcurl 7.33.0: */ 962 if(config->dns_interface) 963 my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface); 964 if(config->dns_ipv4_addr) 965 my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr); 966 if(config->dns_ipv6_addr) 967 my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr); 968 969 /* new in libcurl 7.6.2: */ 970 my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); 971 972 /* new in libcurl 7.7: */ 973 my_setopt_long(curl, CURLOPT_CONNECTTIMEOUT_MS, config->connecttimeout_ms); 974 975 if(config->doh_url) 976 my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url); 977 978 /* new in curl 7.10.7, extended in 7.19.4. Modified to use 979 CREATE_DIR_RETRY in 7.49.0 */ 980 my_setopt_long(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 981 (config->ftp_create_dirs ? 982 CURLFTP_CREATE_DIR_RETRY : CURLFTP_CREATE_DIR_NONE)); 983 984 /* new in curl 7.10.8 */ 985 if(config->max_filesize) 986 my_setopt_offt(curl, CURLOPT_MAXFILESIZE_LARGE, 987 config->max_filesize); 988 989 my_setopt_long(curl, CURLOPT_IPRESOLVE, config->ip_version); 990 991 /* new in curl 7.19.4 */ 992 if(config->socks5_gssapi_nec) 993 my_setopt_long(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1); 994 995 /* new in curl 7.55.0 */ 996 if(config->socks5_auth) 997 my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH, config->socks5_auth); 998 999 /* new in curl 7.43.0 */ 1000 if(config->service_name) 1001 my_setopt_str(curl, CURLOPT_SERVICE_NAME, config->service_name); 1002 1003 /* curl 7.13.0 */ 1004 my_setopt_long(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl); 1005 1006 /* curl 7.15.2 */ 1007 if(config->localport) { 1008 my_setopt_long(curl, CURLOPT_LOCALPORT, config->localport); 1009 my_setopt_long(curl, CURLOPT_LOCALPORTRANGE, config->localportrange); 1010 } 1011 1012 /* curl 7.16.2 */ 1013 if(config->raw) { 1014 my_setopt_long(curl, CURLOPT_HTTP_CONTENT_DECODING, 0); 1015 my_setopt_long(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0); 1016 } 1017 1018 result = tcp_setopts(config, curl); 1019 if(result) 1020 return result; 1021 1022 /* curl 7.20.0 */ 1023 if(config->tftp_blksize && proto_tftp) 1024 my_setopt_long(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize); 1025 1026 if(config->mail_from) 1027 my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from); 1028 1029 if(config->mail_rcpt) 1030 my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); 1031 1032 /* curl 7.69.x */ 1033 my_setopt_long(curl, CURLOPT_MAIL_RCPT_ALLOWFAILS, 1034 config->mail_rcpt_allowfails); 1035 1036 if(config->create_file_mode) 1037 my_setopt_long(curl, CURLOPT_NEW_FILE_PERMS, config->create_file_mode); 1038 1039 if(config->proto_present) 1040 my_setopt_str(curl, CURLOPT_PROTOCOLS_STR, config->proto_str); 1041 if(config->proto_redir_present) 1042 my_setopt_str(curl, CURLOPT_REDIR_PROTOCOLS_STR, config->proto_redir_str); 1043 1044 if(config->resolve) 1045 /* new in 7.21.3 */ 1046 my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve); 1047 1048 if(config->connect_to) 1049 /* new in 7.49.0 */ 1050 my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to); 1051 1052 /* new in 7.21.4 */ 1053 if(feature_tls_srp) 1054 tls_srp_setopts(config, curl); 1055 1056 /* new in 7.22.0 */ 1057 if(config->gssapi_delegation) 1058 my_setopt_long(curl, CURLOPT_GSSAPI_DELEGATION, config->gssapi_delegation); 1059 1060 if(config->mail_auth) 1061 my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth); 1062 1063 /* new in 7.66.0 */ 1064 if(config->sasl_authzid) 1065 my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid); 1066 1067 /* new in 7.31.0 */ 1068 if(config->sasl_ir) 1069 my_setopt_long(curl, CURLOPT_SASL_IR, 1); 1070 1071 /* new in 7.40.0, abstract support added in 7.53.0 */ 1072 if(config->unix_socket_path) { 1073 if(config->abstract_unix_socket) { 1074 my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET, 1075 config->unix_socket_path); 1076 } 1077 else { 1078 my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH, 1079 config->unix_socket_path); 1080 } 1081 } 1082 1083 /* new in 7.45.0 */ 1084 if(config->proto_default) 1085 my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default); 1086 1087 /* new in 7.48.0 */ 1088 if(config->tftp_no_options && proto_tftp) 1089 my_setopt_long(curl, CURLOPT_TFTP_NO_OPTIONS, 1); 1090 1091 /* new in 7.59.0 */ 1092 if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT) 1093 my_setopt_long(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, 1094 config->happy_eyeballs_timeout_ms); 1095 1096 if(config->disallow_username_in_url) 1097 my_setopt_long(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1); 1098 1099 /* new in 8.9.0 */ 1100 if(config->ip_tos > 0 || config->vlan_priority > 0) { 1101 #if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY) 1102 my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback); 1103 my_setopt(curl, CURLOPT_SOCKOPTDATA, config); 1104 #else 1105 if(config->ip_tos > 0) { 1106 errorf(config->global, 1107 "Type of service is not supported in this build."); 1108 result = CURLE_NOT_BUILT_IN; 1109 } 1110 if(config->vlan_priority > 0) { 1111 errorf(config->global, 1112 "VLAN priority is not supported in this build."); 1113 result = CURLE_NOT_BUILT_IN; 1114 } 1115 #endif 1116 } 1117 /* new in 8.13.0 */ 1118 if(config->upload_flags) 1119 my_setopt_long(curl, CURLOPT_UPLOAD_FLAGS, config->upload_flags); 1120 return result; 1121 }