#include "tool_setup.h"
#include "tool_cfgable.h"
#include "tool_setopt.h"
#include "tool_findfile.h"
#include "tool_msgs.h"
#include "tool_libinfo.h"
#include "tool_cb_soc.h"
#include "tool_operate.h"
#include "config2setopts.h"
#include "tool_ipfs.h"
#include "tool_cb_wrt.h"
#include "tool_cb_rea.h"
#include "tool_cb_see.h"
#include "tool_cb_dbg.h"
#include "tool_helpers.h"
#define BUFFER_SIZE 102400L
static char global_errorbuffer[CURL_ERROR_SIZE];
#ifdef IP_TOS
static int get_address_family(curl_socket_t sockfd)
{
struct sockaddr addr;
curl_socklen_t addrlen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
return addr.sa_family;
return AF_UNSPEC;
}
#endif
#ifndef SOL_IP
# define SOL_IP IPPROTO_IP
#endif
#if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY)
static int sockopt_callback(void *clientp, curl_socket_t curlfd,
curlsocktype purpose)
{
struct OperationConfig *config = (struct OperationConfig *)clientp;
if(purpose != CURLSOCKTYPE_IPCXN)
return CURL_SOCKOPT_OK;
(void)config;
(void)curlfd;
#if defined(IP_TOS) || defined(IPV6_TCLASS)
if(config->ip_tos > 0) {
int tos = (int)config->ip_tos;
int result = 0;
switch(get_address_family(curlfd)) {
case AF_INET:
#ifdef IP_TOS
result = setsockopt(curlfd, SOL_IP, IP_TOS, (void *)&tos, sizeof(tos));
#endif
break;
#if defined(IPV6_TCLASS) && defined(AF_INET6)
case AF_INET6:
result = setsockopt(curlfd, IPPROTO_IPV6, IPV6_TCLASS,
(void *)&tos, sizeof(tos));
break;
#endif
}
if(result < 0) {
int error = errno;
warnf(config->global,
"Setting type of service to %d failed with errno %d: %s;\n",
tos, error, strerror(error));
}
}
#endif
#ifdef SO_PRIORITY
if(config->vlan_priority > 0) {
int priority = (int)config->vlan_priority;
if(setsockopt(curlfd, SOL_SOCKET, SO_PRIORITY,
(void *)&priority, sizeof(priority)) != 0) {
int error = errno;
warnf(config->global, "VLAN priority %d failed with errno %d: %s;\n",
priority, error, strerror(error));
}
}
#endif
return CURL_SOCKOPT_OK;
}
#endif
static char *ssl_backend(void)
{
static char ssl_ver[80] = "no ssl";
static bool already = FALSE;
if(!already) {
const char *v = curl_version_info(CURLVERSION_NOW)->ssl_version;
if(v)
msnprintf(ssl_ver, sizeof(ssl_ver), "%.*s", (int) strcspn(v, " "), v);
already = TRUE;
}
return ssl_ver;
}
static CURLcode url_proto_and_rewrite(char **url,
struct OperationConfig *config,
const char **scheme)
{
CURLcode result = CURLE_OK;
CURLU *uh = curl_url();
const char *proto = NULL;
*scheme = NULL;
DEBUGASSERT(url && *url);
if(uh) {
char *schemep = NULL;
if(!curl_url_set(uh, CURLUPART_URL, *url,
CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) &&
!curl_url_get(uh, CURLUPART_SCHEME, &schemep,
CURLU_DEFAULT_SCHEME)) {
#ifdef CURL_DISABLE_IPFS
(void)config;
#else
if(curl_strequal(schemep, proto_ipfs) ||
curl_strequal(schemep, proto_ipns)) {
result = ipfs_url_rewrite(uh, schemep, url, config);
if(curl_strequal(schemep, proto_ipfs))
proto = proto_ipfs;
else if(curl_strequal(schemep, proto_ipns))
proto = proto_ipns;
if(result)
config->synthetic_error = TRUE;
}
else
#endif
proto = proto_token(schemep);
curl_free(schemep);
}
curl_url_cleanup(uh);
}
else
result = CURLE_OUT_OF_MEMORY;
*scheme = proto ? proto : "?";
return result;
}
static CURLcode ssh_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
CURLcode result;
my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
config->hostpubmd5);
my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
config->hostpubsha256);
if(config->ssh_compression)
my_setopt_long(curl, CURLOPT_SSH_COMPRESSION, 1);
if(!config->insecure_ok) {
char *known = global->knownhosts;
if(!known)
known = findfile(".ssh/known_hosts", FALSE);
if(known) {
result = my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known);
if(result) {
global->knownhosts = NULL;
curl_free(known);
return result;
}
global->knownhosts = known;
}
else if(!config->hostpubmd5 && !config->hostpubsha256) {
errorf(global, "Couldn't find a known_hosts file");
return CURLE_FAILED_INIT;
}
else
warnf(global, "Couldn't find a known_hosts file");
}
return CURLE_OK;
}
#ifdef CURL_CA_EMBED
#ifndef CURL_DECLARED_CURL_CA_EMBED
#define CURL_DECLARED_CURL_CA_EMBED
extern const unsigned char curl_ca_embed[];
#endif
#endif
static CURLcode ssl_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
CURLcode result = CURLE_OK;
if(config->cacert)
my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
if(config->proxy_cacert)
my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
if(config->capath) {
result = my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
if(result)
return result;
}
if(config->proxy_capath || config->capath) {
result = my_setopt_str(curl, CURLOPT_PROXY_CAPATH,
(config->proxy_capath ? config->proxy_capath :
config->capath));
if((result == CURLE_NOT_BUILT_IN) ||
(result == CURLE_UNKNOWN_OPTION)) {
if(config->proxy_capath) {
warnf(global, "ignoring %s, not supported by libcurl with %s",
config->proxy_capath ? "--proxy-capath" : "--capath",
ssl_backend());
}
}
else if(result)
return result;
}
#ifdef CURL_CA_EMBED
if(!config->cacert && !config->capath) {
struct curl_blob blob;
blob.data = CURL_UNCONST(curl_ca_embed);
blob.len = strlen((const char *)curl_ca_embed);
blob.flags = CURL_BLOB_NOCOPY;
notef(config->global,
"Using embedded CA bundle (%zu bytes)",
blob.len);
result = curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
if(result == CURLE_NOT_BUILT_IN) {
warnf(global, "ignoring %s, not supported by libcurl with %s",
"embedded CA bundle", ssl_backend());
}
}
if(!config->proxy_cacert && !config->proxy_capath) {
struct curl_blob blob;
blob.data = CURL_UNCONST(curl_ca_embed);
blob.len = strlen((const char *)curl_ca_embed);
blob.flags = CURL_BLOB_NOCOPY;
notef(config->global,
"Using embedded CA bundle, for proxies (%zu bytes)",
blob.len);
result = curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob);
if(result == CURLE_NOT_BUILT_IN) {
warnf(global, "ignoring %s, not supported by libcurl with %s",
"embedded CA bundle", ssl_backend());
}
}
#endif
if(config->crlfile)
my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
if(config->proxy_crlfile)
my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
else if(config->crlfile)
my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
if(config->pinnedpubkey) {
result = my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY,
config->pinnedpubkey);
if(result == CURLE_NOT_BUILT_IN)
warnf(global, "ignoring %s, not supported by libcurl with %s",
"--pinnedpubkey", ssl_backend());
}
if(config->proxy_pinnedpubkey) {
result = my_setopt_str(curl, CURLOPT_PROXY_PINNEDPUBLICKEY,
config->proxy_pinnedpubkey);
if(result == CURLE_NOT_BUILT_IN)
warnf(global, "ignoring %s, not supported by libcurl with %s",
"--proxy-pinnedpubkey", ssl_backend());
}
if(config->ssl_ec_curves)
my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves);
if(config->ssl_signature_algorithms)
my_setopt_str(curl, CURLOPT_SSL_SIGNATURE_ALGORITHMS,
config->ssl_signature_algorithms);
if(config->writeout)
my_setopt_long(curl, CURLOPT_CERTINFO, 1);
my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
config->proxy_cert_type);
my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
config->proxy_key_type);
if(config->insecure_ok) {
my_setopt_long(curl, CURLOPT_SSL_VERIFYPEER, 0);
my_setopt_long(curl, CURLOPT_SSL_VERIFYHOST, 0);
}
if(config->doh_insecure_ok) {
my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0);
my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0);
}
if(config->proxy_insecure_ok) {
my_setopt_long(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0);
my_setopt_long(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0);
}
if(config->verifystatus)
my_setopt_long(curl, CURLOPT_SSL_VERIFYSTATUS, 1);
if(config->doh_verifystatus)
my_setopt_long(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1);
if(config->falsestart)
my_setopt_long(curl, CURLOPT_SSL_FALSESTART, 1);
my_setopt_SSLVERSION(curl, CURLOPT_SSLVERSION,
config->ssl_version | config->ssl_version_max);
if(config->proxy)
my_setopt_SSLVERSION(curl, CURLOPT_PROXY_SSLVERSION,
config->proxy_ssl_version);
{
long mask =
(config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
(config->ssl_allow_earlydata ? CURLSSLOPT_EARLYDATA : 0) |
(config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0) |
(config->ssl_revoke_best_effort ? CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
(config->native_ca_store ? CURLSSLOPT_NATIVE_CA : 0) |
(config->ssl_auto_client_cert ? CURLSSLOPT_AUTO_CLIENT_CERT : 0);
if(mask)
my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
}
{
long mask =
(config->proxy_ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
(config->proxy_ssl_auto_client_cert ?
CURLSSLOPT_AUTO_CLIENT_CERT : 0) |
(config->proxy_native_ca_store ? CURLSSLOPT_NATIVE_CA : 0);
if(mask)
my_setopt_bitmask(curl, CURLOPT_PROXY_SSL_OPTIONS, mask);
}
if(config->cipher_list) {
result = my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST,
config->cipher_list);
if(result == CURLE_NOT_BUILT_IN)
warnf(global, "ignoring %s, not supported by libcurl with %s",
"--ciphers", ssl_backend());
}
if(config->proxy_cipher_list) {
result = my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
config->proxy_cipher_list);
if(result == CURLE_NOT_BUILT_IN)
warnf(global, "ignoring %s, not supported by libcurl with %s",
"--proxy-ciphers", ssl_backend());
}
if(config->cipher13_list) {
result = my_setopt_str(curl, CURLOPT_TLS13_CIPHERS,
config->cipher13_list);
if(result == CURLE_NOT_BUILT_IN)
warnf(global, "ignoring %s, not supported by libcurl with %s",
"--tls13-ciphers", ssl_backend());
}
if(config->proxy_cipher13_list) {
result = my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS,
config->proxy_cipher13_list);
if(result == CURLE_NOT_BUILT_IN)
warnf(global, "ignoring %s, not supported by libcurl with %s",
"--proxy-tls13-ciphers", ssl_backend());
}
if(config->disable_sessionid)
my_setopt_long(curl, CURLOPT_SSL_SESSIONID_CACHE, 0);
if(feature_ech) {
if(config->ech)
my_setopt_str(curl, CURLOPT_ECH, config->ech);
if(config->ech_public)
my_setopt_str(curl, CURLOPT_ECH, config->ech_public);
if(config->ech_config)
my_setopt_str(curl, CURLOPT_ECH, config->ech_config);
}
if(config->engine) {
result = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
if(result)
return result;
}
if(config->ftp_ssl_reqd)
my_setopt_enum(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
else if(config->ftp_ssl)
my_setopt_enum(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
else if(config->ftp_ssl_control)
my_setopt_enum(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
if(config->noalpn)
my_setopt_long(curl, CURLOPT_SSL_ENABLE_ALPN, 0);
return CURLE_OK;
}
static CURLcode http_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
long postRedir = 0;
(void) global;
my_setopt_long(curl, CURLOPT_FOLLOWLOCATION,
config->followlocation);
my_setopt_long(curl, CURLOPT_UNRESTRICTED_AUTH,
config->unrestricted_auth);
my_setopt_str(curl, CURLOPT_AWS_SIGV4, config->aws_sigv4);
my_setopt_long(curl, CURLOPT_AUTOREFERER, config->autoreferer);
if(config->proxyheaders) {
my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders);
my_setopt_long(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
}
my_setopt_long(curl, CURLOPT_MAXREDIRS, config->maxredirs);
if(config->httpversion)
my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
if(config->post301)
postRedir |= CURL_REDIR_POST_301;
if(config->post302)
postRedir |= CURL_REDIR_POST_302;
if(config->post303)
postRedir |= CURL_REDIR_POST_303;
my_setopt_long(curl, CURLOPT_POSTREDIR, postRedir);
if(config->encoding)
my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
if(config->tr_encoding)
my_setopt_long(curl, CURLOPT_TRANSFER_ENCODING, 1);
my_setopt_long(curl, CURLOPT_HTTP09_ALLOWED, config->http09_allowed);
if(config->altsvc)
my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc);
if(config->hsts)
my_setopt_str(curl, CURLOPT_HSTS, config->hsts);
if(config->expect100timeout_ms > 0)
my_setopt_long(curl, CURLOPT_EXPECT_100_TIMEOUT_MS,
config->expect100timeout_ms);
return CURLE_OK;
}
static CURLcode cookie_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
CURLcode result = CURLE_OK;
if(config->cookies) {
struct dynbuf cookies;
struct curl_slist *cl;
#define MAX_COOKIE_LINE 8200
curlx_dyn_init(&cookies, MAX_COOKIE_LINE);
for(cl = config->cookies; cl; cl = cl->next) {
if(cl == config->cookies)
result = curlx_dyn_addf(&cookies, "%s", cl->data);
else
result = curlx_dyn_addf(&cookies, ";%s", cl->data);
if(result) {
warnf(global,
"skipped provided cookie, the cookie header "
"would go over %u bytes", MAX_COOKIE_LINE);
return result;
}
}
my_setopt_str(curl, CURLOPT_COOKIE, curlx_dyn_ptr(&cookies));
curlx_dyn_free(&cookies);
}
if(config->cookiefiles) {
struct curl_slist *cfl;
for(cfl = config->cookiefiles; cfl; cfl = cfl->next)
my_setopt_str(curl, CURLOPT_COOKIEFILE, cfl->data);
}
if(config->cookiejar)
my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
my_setopt_long(curl, CURLOPT_COOKIESESSION, config->cookiesession);
return result;
}
static CURLcode tcp_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
(void) global;
if(!config->tcp_nodelay)
my_setopt_long(curl, CURLOPT_TCP_NODELAY, 0);
if(config->tcp_fastopen)
my_setopt_long(curl, CURLOPT_TCP_FASTOPEN, 1);
if(config->mptcp)
my_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, tool_socket_open_mptcp_cb);
if(!config->nokeepalive) {
my_setopt_long(curl, CURLOPT_TCP_KEEPALIVE, 1);
if(config->alivetime) {
my_setopt_long(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
my_setopt_long(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
}
if(config->alivecnt)
my_setopt_long(curl, CURLOPT_TCP_KEEPCNT, config->alivecnt);
}
else
my_setopt_long(curl, CURLOPT_TCP_KEEPALIVE, 0);
return CURLE_OK;
}
static CURLcode ftp_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
(void) global;
my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
if(config->disable_epsv)
my_setopt_long(curl, CURLOPT_FTP_USE_EPSV, 0);
if(config->disable_eprt)
my_setopt_long(curl, CURLOPT_FTP_USE_EPRT, 0);
if(config->ftp_ssl_ccc)
my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, (long)config->ftp_ssl_ccc_mode);
my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
my_setopt_long(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
my_setopt_long(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
config->ftp_alternative_to_user);
if(config->ftp_pret)
my_setopt_long(curl, CURLOPT_FTP_USE_PRET, 1);
return CURLE_OK;
}
static void gen_trace_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
if(global->tracetype != TRACE_NONE) {
my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
my_setopt(curl, CURLOPT_DEBUGDATA, config);
my_setopt_long(curl, CURLOPT_VERBOSE, 1L);
}
}
static void gen_cb_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
struct per_transfer *per,
CURL *curl)
{
(void) global;
(void) config;
my_setopt(curl, CURLOPT_WRITEDATA, per);
my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);
my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
my_setopt(curl, CURLOPT_READDATA, per);
my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
my_setopt(curl, CURLOPT_SEEKDATA, per);
my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
if((global->progressmode == CURL_PROGRESS_BAR) &&
!global->noprogress && !global->silent) {
my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
my_setopt(curl, CURLOPT_XFERINFODATA, per);
}
else if(per->uploadfile && !strcmp(per->uploadfile, ".")) {
my_setopt_long(curl, CURLOPT_NOPROGRESS, 0);
my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb);
my_setopt(curl, CURLOPT_XFERINFODATA, per);
}
my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
my_setopt(curl, CURLOPT_HEADERDATA, per);
}
static CURLcode proxy_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
(void) global;
if(config->proxy) {
CURLcode result = my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
if(result) {
errorf(global, "proxy support is disabled in this libcurl");
config->synthetic_error = TRUE;
return CURLE_NOT_BUILT_IN;
}
}
if(config->proxy)
my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
my_setopt_long(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
if(config->preproxy)
my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
if(config->proxyanyauth)
my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY);
else if(config->proxynegotiate)
my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
else if(config->proxyntlm)
my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
else if(config->proxydigest)
my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
else if(config->proxybasic)
my_setopt_bitmask(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy);
my_setopt_long(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS,
config->suppress_connect_headers);
if(config->proxy_service_name)
my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME,
config->proxy_service_name);
if(config->haproxy_protocol)
my_setopt_long(curl, CURLOPT_HAPROXYPROTOCOL, 1);
if(config->haproxy_clientip)
my_setopt_str(curl, CURLOPT_HAPROXY_CLIENT_IP, config->haproxy_clientip);
return CURLE_OK;
}
static void tls_srp_setopts(struct GlobalConfig *global,
struct OperationConfig *config,
CURL *curl)
{
(void) global;
if(config->tls_username)
my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME, config->tls_username);
if(config->tls_password)
my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD, config->tls_password);
if(config->tls_authtype)
my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE, config->tls_authtype);
if(config->proxy_tls_username)
my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
config->proxy_tls_username);
if(config->proxy_tls_password)
my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
config->proxy_tls_password);
if(config->proxy_tls_authtype)
my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
config->proxy_tls_authtype);
}
CURLcode config2setopts(struct GlobalConfig *global,
struct OperationConfig *config,
struct per_transfer *per,
CURL *curl,
CURLSH *share)
{
const char *use_proto;
CURLcode result = url_proto_and_rewrite(&per->url, config, &use_proto);
if(!result)
result = curl_easy_setopt(curl, CURLOPT_SHARE, share);
if(result)
return result;
#ifndef DEBUGBUILD
result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
if(result)
return result;
#endif
gen_trace_setopts(global, config, curl);
{
#ifdef DEBUGBUILD
char *env = getenv("CURL_BUFFERSIZE");
if(env) {
curl_off_t num;
const char *p = env;
if(!curlx_str_number(&p, &num, LONG_MAX))
my_setopt_long(curl, CURLOPT_BUFFERSIZE, (long)num);
}
else
#endif
if(config->recvpersecond && (config->recvpersecond < BUFFER_SIZE))
my_setopt_long(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond);
else
my_setopt_long(curl, CURLOPT_BUFFERSIZE, BUFFER_SIZE);
}
my_setopt_str(curl, CURLOPT_URL, per->url);
my_setopt_long(curl, CURLOPT_NOPROGRESS,
global->noprogress || global->silent);
gen_cb_setopts(global, config, per, curl);
if(config->no_body)
my_setopt_long(curl, CURLOPT_NOBODY, 1);
if(config->oauth_bearer)
my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
result = proxy_setopts(global, config, curl);
if(result)
return result;
my_setopt_long(curl, CURLOPT_FAILONERROR, config->failonerror);
my_setopt_str(curl, CURLOPT_REQUEST_TARGET, config->request_target);
my_setopt_long(curl, CURLOPT_UPLOAD, !!per->uploadfile);
my_setopt_long(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
my_setopt_long(curl, CURLOPT_APPEND, config->ftp_append);
if(config->netrc_opt)
my_setopt_enum(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
else if(config->netrc || config->netrc_file)
my_setopt_enum(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
else
my_setopt_enum(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
if(config->netrc_file)
my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file);
my_setopt_long(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
if(config->login_options)
my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options);
my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
my_setopt_str(curl, CURLOPT_RANGE, config->range);
if(!global->parallel) {
per->errorbuffer = global_errorbuffer;
my_setopt(curl, CURLOPT_ERRORBUFFER, global_errorbuffer);
}
my_setopt_long(curl, CURLOPT_TIMEOUT_MS, config->timeout_ms);
switch(config->httpreq) {
case TOOL_HTTPREQ_SIMPLEPOST:
if(config->resume_from) {
errorf(global, "cannot mix --continue-at with --data");
result = CURLE_FAILED_INIT;
}
else {
my_setopt_str(curl, CURLOPT_POSTFIELDS,
curlx_dyn_ptr(&config->postdata));
my_setopt_offt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
curlx_dyn_len(&config->postdata));
}
break;
case TOOL_HTTPREQ_MIMEPOST:
curl_mime_free(config->mimepost);
config->mimepost = NULL;
if(config->resume_from) {
errorf(global, "cannot mix --continue-at with --form");
result = CURLE_FAILED_INIT;
}
else {
result = tool2curlmime(curl, config->mimeroot, &config->mimepost);
if(!result)
my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost);
}
break;
default:
break;
}
if(result)
return result;
if(config->mime_options)
my_setopt_long(curl, CURLOPT_MIME_OPTIONS, config->mime_options);
if(config->authtype)
my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, config->authtype);
my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
if(proto_http || proto_rtsp) {
my_setopt_str(curl, CURLOPT_REFERER, config->referer);
my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
}
if(use_proto == proto_http || use_proto == proto_https) {
result = http_setopts(global, config, curl);
if(!result)
result = cookie_setopts(global, config, curl);
if(result)
return result;
}
if(use_proto == proto_ftp || use_proto == proto_ftps) {
result = ftp_setopts(global, config, curl);
if(result)
return result;
}
my_setopt_long(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit);
my_setopt_long(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
my_setopt_offt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, config->sendpersecond);
my_setopt_offt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, config->recvpersecond);
if(config->use_resume)
my_setopt_offt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from);
else
my_setopt_offt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
if(use_proto == proto_scp || use_proto == proto_sftp) {
result = ssh_setopts(global, config, curl);
if(result)
return result;
}
if(feature_ssl) {
result = ssl_setopts(global, config, curl);
if(result)
return result;
}
if(config->path_as_is)
my_setopt_long(curl, CURLOPT_PATH_AS_IS, 1);
if(config->no_body || config->remote_time) {
my_setopt_long(curl, CURLOPT_FILETIME, 1);
}
my_setopt_long(curl, CURLOPT_CRLF, config->crlf);
my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
my_setopt_enum(curl, CURLOPT_TIMECONDITION, config->timecond);
my_setopt_offt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
customrequest_helper(config, config->httpreq, config->customrequest);
my_setopt(curl, CURLOPT_STDERR, tool_stderr);
my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
progressbarinit(&per->progressbar, config);
if(config->dns_servers)
my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
if(config->dns_interface)
my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);
if(config->dns_ipv4_addr)
my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr);
if(config->dns_ipv6_addr)
my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr);
my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
my_setopt_long(curl, CURLOPT_CONNECTTIMEOUT_MS, config->connecttimeout_ms);
if(config->doh_url)
my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url);
my_setopt_long(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
(config->ftp_create_dirs ?
CURLFTP_CREATE_DIR_RETRY : CURLFTP_CREATE_DIR_NONE));
if(config->max_filesize)
my_setopt_offt(curl, CURLOPT_MAXFILESIZE_LARGE,
config->max_filesize);
my_setopt_long(curl, CURLOPT_IPRESOLVE, config->ip_version);
if(config->socks5_gssapi_nec)
my_setopt_long(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1);
if(config->socks5_auth)
my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH, config->socks5_auth);
if(config->service_name)
my_setopt_str(curl, CURLOPT_SERVICE_NAME, config->service_name);
my_setopt_long(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
if(config->localport) {
my_setopt_long(curl, CURLOPT_LOCALPORT, config->localport);
my_setopt_long(curl, CURLOPT_LOCALPORTRANGE, config->localportrange);
}
if(config->raw) {
my_setopt_long(curl, CURLOPT_HTTP_CONTENT_DECODING, 0);
my_setopt_long(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0);
}
result = tcp_setopts(global, config, curl);
if(result)
return result;
if(config->tftp_blksize && proto_tftp)
my_setopt_long(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
if(config->mail_from)
my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
if(config->mail_rcpt)
my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
my_setopt_long(curl, CURLOPT_MAIL_RCPT_ALLOWFAILS,
config->mail_rcpt_allowfails);
if(config->create_file_mode)
my_setopt_long(curl, CURLOPT_NEW_FILE_PERMS, config->create_file_mode);
if(config->proto_present)
my_setopt_str(curl, CURLOPT_PROTOCOLS_STR, config->proto_str);
if(config->proto_redir_present)
my_setopt_str(curl, CURLOPT_REDIR_PROTOCOLS_STR, config->proto_redir_str);
if(config->resolve)
my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
if(config->connect_to)
my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
if(feature_tls_srp)
tls_srp_setopts(global, config, curl);
if(config->gssapi_delegation)
my_setopt_long(curl, CURLOPT_GSSAPI_DELEGATION, config->gssapi_delegation);
if(config->mail_auth)
my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
if(config->sasl_authzid)
my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid);
if(config->sasl_ir)
my_setopt_long(curl, CURLOPT_SASL_IR, 1);
if(config->unix_socket_path) {
if(config->abstract_unix_socket) {
my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
config->unix_socket_path);
}
else {
my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
config->unix_socket_path);
}
}
if(config->proto_default)
my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
if(config->tftp_no_options && proto_tftp)
my_setopt_long(curl, CURLOPT_TFTP_NO_OPTIONS, 1);
if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT)
my_setopt_long(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
config->happy_eyeballs_timeout_ms);
if(config->disallow_username_in_url)
my_setopt_long(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1);
if(config->ip_tos > 0 || config->vlan_priority > 0) {
#if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY)
my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
#else
if(config->ip_tos > 0) {
errorf(config->global,
"Type of service is not supported in this build.");
result = CURLE_NOT_BUILT_IN;
}
if(config->vlan_priority > 0) {
errorf(config->global,
"VLAN priority is not supported in this build.");
result = CURLE_NOT_BUILT_IN;
}
#endif
}
if(config->upload_flags)
my_setopt_long(curl, CURLOPT_UPLOAD_FLAGS, config->upload_flags);
return result;
}